diff --git a/.github/workflows/nuitka.yml b/.github/workflows/nuitka.yml
index 20159e81..0fdf414e 100644
--- a/.github/workflows/nuitka.yml
+++ b/.github/workflows/nuitka.yml
@@ -21,11 +21,11 @@ jobs:
- name: Set up Visual Studio environment
if: success()
uses: seanmiddleditch/gha-setup-vsdevenv@master
- - name: Set up Python 3.9.4 (x64)
+ - name: Set up Python 3.10.4 (x64)
if: success()
uses: actions/setup-python@v2
with:
- python-version: 3.9.4
+ python-version: 3.10.4
architecture: x64
- name: Create virtual environment
if: success()
diff --git a/build.py b/build.py
index 5c92b353..82d09261 100644
--- a/build.py
+++ b/build.py
@@ -7,6 +7,8 @@
import sys
import zipfile
+from pyro.Comparators import endswith
+
class Application:
logging.basicConfig(level=logging.INFO, format='%(asctime)s [%(levelname).4s] %(message)s')
@@ -24,25 +26,38 @@ def __init__(self, args: argparse.Namespace) -> None:
self.root_tools_path: str = os.path.join(self.root_path, 'tools')
self.dist_tools_path: str = os.path.join(self.dist_path, 'tools')
+ self.site_path: str = os.path.join(self.dist_path, 'site')
+ self.zip_path: str = os.path.join(self.root_path, 'bin', f'{self.package_name}.zip')
+
+ self.dist_glob_pattern: str = os.path.join(self.dist_path, r'**\*')
+
+ self.icon_path: str = os.path.join(self.root_path, 'fire.ico')
+
+ pyro_version: str = '1.0.0.0'
+
self.nuitka_args: list = [
'python', '-m', 'nuitka',
'--standalone', 'pyro',
'--include-package=pyro',
- '--experimental=use_pefile',
- '--python-flag=nosite',
- f'--python-for-scons={sys.executable}',
'--assume-yes-for-downloads',
'--plugin-enable=multiprocessing',
- '--show-progress',
- '--plugin-enable=pkg-resources'
+ '--plugin-enable=pkg-resources',
+ '--msvc=14.3',
+ '--disable-ccache',
+ '--windows-company-name=fireundubh',
+ f'--windows-product-name={self.package_name.capitalize()}',
+ f'--windows-file-version={pyro_version}',
+ f'--windows-product-version={pyro_version}',
+ '--windows-file-description=https://github.com/fireundubh/pyro',
+ '--windows-icon-from-ico=fire.ico'
]
def __setattr__(self, key: str, value: object) -> None:
# sanitize paths
- if isinstance(value, str) and key.endswith('path'):
+ if isinstance(value, str) and endswith(key, 'path', ignorecase=True):
value = os.path.normpath(value)
# normpath converts empty paths to os.curdir which we don't want
- if value == '.':
+ if value == os.curdir:
value = ''
super(Application, self).__setattr__(key, value)
@@ -57,6 +72,7 @@ def _clean_dist_folder(self) -> None:
'python37.dll',
'python38.dll',
'python39.dll',
+ 'python310.dll',
'_elementpath.pyd',
'_hashlib.pyd',
'_multiprocessing.pyd',
@@ -69,7 +85,7 @@ def _clean_dist_folder(self) -> None:
'unicodedata.pyd'
)
- for f in glob.iglob(os.path.join(self.dist_path, r'**\*'), recursive=True):
+ for f in glob.iglob(self.dist_glob_pattern, recursive=True):
if not os.path.isfile(f):
continue
@@ -80,7 +96,7 @@ def _clean_dist_folder(self) -> None:
Application.log.warning(f'Deleting: "{f}"')
os.remove(f)
- for f in glob.iglob(os.path.join(self.dist_path, r'**\*'), recursive=True):
+ for f in glob.iglob(self.dist_glob_pattern, recursive=True):
if not os.path.isdir(f):
continue
@@ -88,25 +104,21 @@ def _clean_dist_folder(self) -> None:
Application.log.warning(f'Deleting empty folder: "{f}"')
shutil.rmtree(f, ignore_errors=True)
- site_dir: str = os.path.join(self.dist_path, 'site')
- if os.path.exists(site_dir):
- shutil.rmtree(site_dir, ignore_errors=True)
+ if os.path.exists(self.site_path):
+ shutil.rmtree(self.site_path, ignore_errors=True)
- def _build_zip_archive(self) -> str:
- zip_path: str = os.path.join(self.root_path, 'bin', f'{self.package_name}.zip')
- os.makedirs(os.path.dirname(zip_path), exist_ok=True)
+ def _build_zip_archive(self) -> None:
+ os.makedirs(os.path.dirname(self.zip_path), exist_ok=True)
- files: list = [f for f in glob.glob(os.path.join(self.dist_path, r'**\*'), recursive=True)
+ files: list = [f for f in glob.glob(self.dist_glob_pattern, recursive=True)
if os.path.isfile(f)]
- with zipfile.ZipFile(zip_path, 'w') as z:
+ with zipfile.ZipFile(self.zip_path, 'w') as z:
for f in files:
z.write(f, os.path.join(self.package_name, os.path.relpath(f, self.dist_path)),
compress_type=zipfile.ZIP_STORED)
Application.log.info(f'Added file to archive: {f}')
- return zip_path
-
@staticmethod
def exec_process(cmd: list, env: dict) -> int:
try:
@@ -126,7 +138,7 @@ def run(self) -> int:
sys.exit(1)
if self.vcvars64_path:
- if not os.path.exists(self.vcvars64_path) or not self.vcvars64_path.endswith('.bat'):
+ if not os.path.exists(self.vcvars64_path) or not endswith(self.vcvars64_path, '.bat', ignorecase=True):
Application.log.error('Cannot build Pyro with MSVC compiler because VsDevCmd path is invalid')
sys.exit(1)
@@ -193,9 +205,9 @@ def run(self) -> int:
if not self.no_zip:
Application.log.info('Building archive...')
- zip_created: str = self._build_zip_archive()
+ self._build_zip_archive()
- Application.log.info(f'Wrote archive: "{zip_created}"')
+ Application.log.info(f'Wrote archive: "{self.zip_path}"')
Application.log.info('Build complete.')
diff --git a/fire.ico b/fire.ico
new file mode 100644
index 00000000..2f8c4e44
Binary files /dev/null and b/fire.ico differ
diff --git a/pyro/Application.py b/pyro/Application.py
index 58116bf3..c11593d6 100644
--- a/pyro/Application.py
+++ b/pyro/Application.py
@@ -4,7 +4,11 @@
import sys
from pyro.Enums.Event import (BuildEvent,
- ImportEvent)
+ ImportEvent,
+ CompileEvent,
+ AnonymizeEvent,
+ PackageEvent,
+ ZipEvent)
from pyro.BuildFacade import BuildFacade
from pyro.Comparators import startswith
from pyro.PapyrusProject import PapyrusProject
@@ -145,11 +149,23 @@ def run(self) -> int:
ppj.try_run_event(BuildEvent.PRE)
if build.scripts_count > 0:
+ if ppj.use_pre_compile_event:
+ ppj.try_run_event(CompileEvent.PRE)
+
build.try_compile()
+ if ppj.use_post_compile_event:
+ ppj.try_run_event(CompileEvent.POST)
+
if ppj.options.anonymize:
if build.compile_data.failed_count == 0 or ppj.options.ignore_errors:
+ if ppj.use_pre_anonymize_event:
+ ppj.try_run_event(AnonymizeEvent.PRE)
+
build.try_anonymize()
+
+ if ppj.use_post_anonymize_event:
+ ppj.try_run_event(AnonymizeEvent.POST)
else:
Application.log.error(f'Cannot anonymize scripts because {build.compile_data.failed_count} scripts failed to compile')
sys.exit(build.compile_data.failed_count)
@@ -158,7 +174,13 @@ def run(self) -> int:
if ppj.options.package:
if build.compile_data.failed_count == 0 or ppj.options.ignore_errors:
+ if ppj.use_pre_package_event:
+ ppj.try_run_event(PackageEvent.PRE)
+
build.try_pack()
+
+ if ppj.use_post_package_event:
+ ppj.try_run_event(PackageEvent.POST)
else:
Application.log.error(f'Cannot create Packages because {build.compile_data.failed_count} scripts failed to compile')
sys.exit(build.compile_data.failed_count)
@@ -167,7 +189,13 @@ def run(self) -> int:
if ppj.options.zip:
if build.compile_data.failed_count == 0 or ppj.options.ignore_errors:
+ if ppj.use_pre_zip_event:
+ ppj.try_run_event(ZipEvent.PRE)
+
build.try_zip()
+
+ if ppj.use_post_zip_event:
+ ppj.try_run_event(ZipEvent.POST)
else:
Application.log.error(f'Cannot create ZipFile because {build.compile_data.failed_count} scripts failed to compile')
sys.exit(build.compile_data.failed_count)
diff --git a/pyro/Constants.py b/pyro/Constants.py
index ee967a14..e972e042 100644
--- a/pyro/Constants.py
+++ b/pyro/Constants.py
@@ -53,8 +53,16 @@ class XmlTagName(Constant):
PAPYRUS_PROJECT: str = 'PapyrusProject'
POST_BUILD_EVENT: str = 'PostBuildEvent'
POST_IMPORT_EVENT: str = 'PostImportEvent'
+ POST_COMPILE_EVENT: str = 'PostCompileEvent'
+ POST_ANONYMIZE_EVENT: str = 'PostAnonymizeEvent'
+ POST_PACKAGE_EVENT: str = 'PostPackageEvent'
+ POST_ZIP_EVENT: str = 'PostZipEvent'
PRE_BUILD_EVENT: str = 'PreBuildEvent'
PRE_IMPORT_EVENT: str = 'PreImportEvent'
+ PRE_COMPILE_EVENT: str = 'PreCompileEvent'
+ PRE_ANONYMIZE_EVENT: str = 'PreAnonymizeEvent'
+ PRE_PACKAGE_EVENT: str = 'PrePackageEvent'
+ PRE_ZIP_EVENT: str = 'PreZipEvent'
SCRIPTS: str = 'Scripts'
VARIABLES: str = 'Variables'
ZIP_FILE: str = 'ZipFile'
diff --git a/pyro/Enums/Event.py b/pyro/Enums/Event.py
index 42f558bb..1c7bf8e2 100644
--- a/pyro/Enums/Event.py
+++ b/pyro/Enums/Event.py
@@ -12,4 +12,24 @@ class ImportEvent(Enum):
POST = 1
-Event = Union[BuildEvent, ImportEvent]
+class CompileEvent(Enum):
+ PRE = 0
+ POST = 1
+
+
+class AnonymizeEvent(Enum):
+ PRE = 0
+ POST = 1
+
+
+class PackageEvent(Enum):
+ PRE = 0
+ POST = 1
+
+
+class ZipEvent(Enum):
+ PRE = 0
+ POST = 1
+
+
+Event = Union[BuildEvent, ImportEvent, CompileEvent, AnonymizeEvent, PackageEvent, ZipEvent]
diff --git a/pyro/PapyrusProject.py b/pyro/PapyrusProject.py
index 2ecaadc5..6511175a 100644
--- a/pyro/PapyrusProject.py
+++ b/pyro/PapyrusProject.py
@@ -12,7 +12,11 @@
from pyro.Enums.Event import (Event,
BuildEvent,
- ImportEvent)
+ ImportEvent,
+ CompileEvent,
+ AnonymizeEvent,
+ PackageEvent,
+ ZipEvent)
from pyro.CommandArguments import CommandArguments
from pyro.Comparators import (endswith,
is_folder_node,
@@ -45,6 +49,16 @@ class PapyrusProject(ProjectBase):
zip_files_node: etree.ElementBase = None
pre_build_node: etree.ElementBase = None
post_build_node: etree.ElementBase = None
+ pre_import_node: etree.ElementBase = None
+ post_import_node: etree.ElementBase = None
+ pre_compile_node: etree.ElementBase = None
+ post_compile_node: etree.ElementBase = None
+ pre_anonymize_node: etree.ElementBase = None
+ post_anonymize_node: etree.ElementBase = None
+ pre_package_node: etree.ElementBase = None
+ post_package_node: etree.ElementBase = None
+ pre_zip_node: etree.ElementBase = None
+ post_zip_node: etree.ElementBase = None
remote: RemoteBase = None
remote_schemas: tuple = ('https:', 'http:')
@@ -132,6 +146,30 @@ def bool_attr(element: etree.Element, attr_name: str) -> bool:
self.post_import_node = self.ppj_root.find(XmlTagName.POST_IMPORT_EVENT)
self.use_post_import_event = bool_attr(self.post_import_node, XmlAttributeName.USE_IN_BUILD)
+ self.pre_compile_node = self.ppj_root.find(XmlTagName.PRE_COMPILE_EVENT)
+ self.use_pre_compile_event = bool_attr(self.pre_compile_node, XmlAttributeName.USE_IN_BUILD)
+
+ self.post_compile_node = self.ppj_root.find(XmlTagName.POST_COMPILE_EVENT)
+ self.use_post_compile_event = bool_attr(self.post_compile_node, XmlAttributeName.USE_IN_BUILD)
+
+ self.pre_anonymize_node = self.ppj_root.find(XmlTagName.PRE_ANONYMIZE_EVENT)
+ self.use_pre_anonymize_event = bool_attr(self.pre_anonymize_node, XmlAttributeName.USE_IN_BUILD)
+
+ self.post_anonymize_node = self.ppj_root.find(XmlTagName.POST_ANONYMIZE_EVENT)
+ self.use_post_anonymize_event = bool_attr(self.post_anonymize_node, XmlAttributeName.USE_IN_BUILD)
+
+ self.pre_package_node = self.ppj_root.find(XmlTagName.PRE_PACKAGE_EVENT)
+ self.use_pre_package_event = bool_attr(self.pre_package_node, XmlAttributeName.USE_IN_BUILD)
+
+ self.post_package_node = self.ppj_root.find(XmlTagName.POST_PACKAGE_EVENT)
+ self.use_post_package_event = bool_attr(self.post_package_node, XmlAttributeName.USE_IN_BUILD)
+
+ self.pre_zip_node = self.ppj_root.find(XmlTagName.PRE_ZIP_EVENT)
+ self.use_pre_zip_event = bool_attr(self.pre_zip_node, XmlAttributeName.USE_IN_BUILD)
+
+ self.post_zip_node = self.ppj_root.find(XmlTagName.POST_ZIP_EVENT)
+ self.use_post_zip_event = bool_attr(self.post_zip_node, XmlAttributeName.USE_IN_BUILD)
+
if self.options.package and self.packages_node is not None:
if not self.options.package_path:
self.options.package_path = self.packages_node.get(XmlAttributeName.OUTPUT)
@@ -758,5 +796,21 @@ def try_run_event(self, event: Event) -> None:
ProcessManager.run_event(self.pre_build_node, self.project_path)
elif event == BuildEvent.POST:
ProcessManager.run_event(self.post_build_node, self.project_path)
+ elif event == CompileEvent.PRE:
+ ProcessManager.run_event(self.pre_compile_node, self.project_path)
+ elif event == CompileEvent.POST:
+ ProcessManager.run_event(self.post_compile_node, self.project_path)
+ elif event == AnonymizeEvent.PRE:
+ ProcessManager.run_event(self.pre_anonymize_node, self.project_path)
+ elif event == AnonymizeEvent.POST:
+ ProcessManager.run_event(self.post_anonymize_node, self.project_path)
+ elif event == PackageEvent.PRE:
+ ProcessManager.run_event(self.pre_package_node, self.project_path)
+ elif event == PackageEvent.POST:
+ ProcessManager.run_event(self.post_package_node, self.project_path)
+ elif event == ZipEvent.PRE:
+ ProcessManager.run_event(self.pre_zip_node, self.project_path)
+ elif event == ZipEvent.POST:
+ ProcessManager.run_event(self.post_zip_node, self.project_path)
else:
raise NotImplementedError
diff --git a/pyro/PapyrusProject.xsd b/pyro/PapyrusProject.xsd
index 3b123853..10e33bce 100644
--- a/pyro/PapyrusProject.xsd
+++ b/pyro/PapyrusProject.xsd
@@ -22,6 +22,14 @@
+
+
+
+
+
+
+
+
diff --git a/requirements.txt b/requirements.txt
index f2069d16..50e04468 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -2,3 +2,4 @@ lxml
nuitka
psutil
wcmatch
+ordered-set