From 541ac22a7ece4a57a996f3f51b6f5aea083cdca4 Mon Sep 17 00:00:00 2001
From: Yingzhou Li <yingzhouli0417@gmail.com>
Date: Mon, 7 Feb 2022 16:09:47 +0800
Subject: [PATCH] Updated exec to be compatible with current mautrix library
 and python 3.8+

---
 .github/workflows/main.yml | 39 ++++++++++++++++++++++++++++++
 .gitlab-ci.yml             | 27 ---------------------
 README.md                  | 10 ++++++++
 exec/runner/python.py      | 49 ++++++++++++++++++++++++++------------
 maubot.yaml                |  2 +-
 mbcbuild.sh                |  1 +
 6 files changed, 85 insertions(+), 43 deletions(-)
 create mode 100644 .github/workflows/main.yml
 delete mode 100644 .gitlab-ci.yml
 create mode 100755 mbcbuild.sh

diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
new file mode 100644
index 0000000..738c97d
--- /dev/null
+++ b/.github/workflows/main.yml
@@ -0,0 +1,39 @@
+name: tag-release
+on:
+  push:
+    tags:
+      - 'v*'
+
+jobs:
+  build:
+    name: tag-release
+    runs-on: ubuntu-latest
+    steps:
+      - name: Checkout
+        uses: actions/checkout@v2
+      - name: Zip
+        run: |
+          zip -9r smartpoll.mbp polls maubot.yaml upload.py
+      - name: Get the version
+        id: get_version
+        run: echo ::set-output name=VERSION::${GITHUB_REF/refs\/tags\//}
+      - name: Create Release
+        id: create_release
+        uses: actions/create-release@v1
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+        with:
+          tag_name: ${{steps.get_version.outputs.VERSION}}
+          release_name: Release ${{steps.get_version.outputs.VERSION}}
+          draft: false
+          prerelease: false
+      - name: Upload Release Asset
+        id: upload-release-asset 
+        uses: actions/upload-release-asset@v1
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+        with:
+          upload_url: ${{ steps.create_release.outputs.upload_url }}
+          asset_path: ./smartpoll.mbp
+          asset_name: smartpoll-${{steps.get_version.outputs.VERSION}}.mbp
+          asset_content_type: application/zip
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
deleted file mode 100644
index c649b91..0000000
--- a/.gitlab-ci.yml
+++ /dev/null
@@ -1,27 +0,0 @@
-image: dock.mau.dev/maubot/maubot
-
-stages:
-- build
-
-variables:
-  PYTHONPATH: /opt/maubot
-
-build:
-  stage: build
-  except:
-  - tags
-  script:
-  - python3 -m maubot.cli build -o xyz.maubot.$CI_PROJECT_NAME-$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA.mbp
-  artifacts:
-    paths:
-    - "*.mbp"
-
-build tags:
-  stage: build
-  only:
-  - tags
-  script:
-  - python3 -m maubot.cli build -o xyz.maubot.$CI_PROJECT_NAME-$CI_COMMIT_TAG.mbp
-  artifacts:
-    paths:
-    - "*.mbp"
diff --git a/README.md b/README.md
index ae28e49..b7dd7dc 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,6 @@
 # exec
 A [maubot](https://github.com/maubot/maubot) that executes code.
+exec is updated to be compatible with python 3.8+.
 
 ## Usage
 The bot is triggered by a specific message prefix (defaults to `!exec`) and
@@ -34,3 +35,12 @@ If running in userbot mode, the bot will edit your original message instead of
 making a new reply message.
 
 Currently, the bot supports `python` and `shell` as languages.
+
+
+## Contributors
+
+  <a href="https://github.com/YingzhouLi/exec/graphs/contributors">
+  <img src="https://contrib.rocks/image?repo=YingzhouLi/exec" />
+  </a>
+
+  Made with [contrib.rocks](https://contrib.rocks).
diff --git a/exec/runner/python.py b/exec/runner/python.py
index 1fdf0ad..b6b6845 100644
--- a/exec/runner/python.py
+++ b/exec/runner/python.py
@@ -19,13 +19,15 @@ from io import IOBase, StringIO
 import contextlib
 import traceback
 import asyncio
+import inspect
 import ast
 import sys
 
-from mautrix.util.manhole import asyncify
+from mautrix.util.manhole import compile_async
 
 from .base import Runner, OutputType, AsyncTextOutput
 
+TOP_LEVEL_AWAIT = sys.version_info >= (3, 8)
 
 class SyncTextProxy(AsyncTextOutput):
     writers: Dict[OutputType, 'ProxyWriter']
@@ -116,7 +118,7 @@ class PythonRunner(Runner):
         line: traceback.FrameSummary
         for i, line in enumerate(tb):
             if line.filename == "<input>":
-                line.name = "<module>"
+                line.name = "<node>"
                 tb = tb[i:]
                 break
 
@@ -127,17 +129,34 @@ class PythonRunner(Runner):
     async def run(self, code: str, stdin: str = "", loop: Optional[asyncio.AbstractEventLoop] = None
                   ) -> AsyncGenerator[Tuple[OutputType, Any], None]:
         loop = loop or asyncio.get_event_loop()
-        codeobj = asyncify(compile(code, "<input>", "exec", optimize=1, flags=ast.PyCF_ONLY_AST),
-                           module="<input>")
+        codeobj = compile_async(code)
         namespace = {**self.namespace} if self.per_run_namespace else self.namespace
-        exec(codeobj, namespace)
-        with self._redirect_io(SyncTextProxy(loop), StringIO(stdin)) as output:
-            task = asyncio.ensure_future(self._wait_task(namespace, output), loop=loop)
-            async for part in output:
-                yield part
-            try:
-                return_value = await task
-            except Exception:
-                yield (OutputType.EXCEPTION, ExcInfo(*sys.exc_info()))
-            else:
-                yield (OutputType.RETURN, return_value)
+        if TOP_LEVEL_AWAIT:
+            with self._redirect_io(SyncTextProxy(loop), StringIO(stdin)) as output:
+                try:
+                    value = eval(codeobj, namespace)
+                finally:
+                    output.close()
+                async for part in output:
+                    yield part
+                try:
+                    if codeobj.co_flags & inspect.CO_COROUTINE:
+                        return_value = await value
+                    else:
+                        return_value = value
+                except Exception:
+                    yield (OutputType.EXCEPTION, ExcInfo(*sys.exc_info()))
+                else:
+                    yield (OutputType.RETURN, return_value)
+        else:
+            exec(codeobj, namespace)
+            with self._redirect_io(SyncTextProxy(loop), StringIO(stdin)) as output:
+                task = asyncio.create_task(self._wait_task(namespace, output))
+                async for part in output:
+                    yield part
+                try:
+                    return_value = await task
+                except Exception:
+                    yield (OutputType.EXCEPTION, ExcInfo(*sys.exc_info()))
+                else:
+                    yield (OutputType.RETURN, return_value)
\ No newline at end of file
diff --git a/maubot.yaml b/maubot.yaml
index a18f155..b316d5d 100644
--- a/maubot.yaml
+++ b/maubot.yaml
@@ -1,6 +1,6 @@
 maubot: 0.1.0
 id: xyz.maubot.exec
-version: 0.1.0
+version: 0.2.0
 license: AGPL-3.0-or-later
 modules:
 - exec
diff --git a/mbcbuild.sh b/mbcbuild.sh
new file mode 100755
index 0000000..201a951
--- /dev/null
+++ b/mbcbuild.sh
@@ -0,0 +1 @@
+zip -9r exec-develop.mbp exec maubot.yaml base-config.yaml
-- 
GitLab