Commit b195e724 authored by Stas Fomin's avatar Stas Fomin
Browse files

somehow working

parents
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# pyenv
.python-version
# celery beat schedule file
celerybeat-schedule
# SageMath parsed files
*.sage.py
# dotenv
.env
# virtualenv
.venv
venv/
ENV/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
# IDE settings
.vscode/
in
selected-packages.*
deps.txt
demo/*.sh
demo/*.iso
*.old
e
demo/out*
.vagrant
\ No newline at end of file
=======
History
=======
0.1.5 (2020-08-11)
------------------
* Adapt to new interface in "magic"
* Don't touch tmpfs to save memory to nuitka compilation
* --stage-pack-me
0.1.0 (2020-07-31)
------------------
* First release on PyPI.
* Actually couple of months testing in intranet.
MIT License
Copyright (c) 2020, Stas Fomin
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
===================
terrarium-assembler
===================
.. image:: https://img.shields.io/pypi/v/terrarium_assembler.svg
:target: https://pypi.python.org/pypi/terrarium_assembler
.. image:: https://img.shields.io/travis/belonesox/terrarium_assembler.svg
:target: https://travis-ci.com/belonesox/terrarium_assembler
.. image:: https://readthedocs.org/projects/terrarium-assembler/badge/?version=latest
:target: https://terrarium-assembler.readthedocs.io/en/latest/?badge=latest
:alt: Documentation Status
Generate Portable Linux Applications,
mostly using python packages and any system package,
that can be run on any Linux,
without Docker, Snap, Flathub, etc.
Just portable folder.
* Free software: MIT license
* Documentation: https://terrarium-assembler.readthedocs.io.
Features
--------
* TODO
Credits
-------
rem
rmdir /S /Q dist
C:\ta-buildroot\python-x86-3.7.9\python.exe setup.py sdist bdist_wheel
rem twine upload dist/*
#!/usr/bin/env python
"""The setup script."""
from setuptools import setup, find_packages
with open('README.rst') as readme_file:
readme = readme_file.read()
with open('HISTORY.rst') as history_file:
history = history_file.read()
requirements = [
'easydict',
'pytictoc',
# 'nuitka',
'file-magic',
'jinja2',
'packaging',
'wheel_filename',
]
test_requirements = ['pytest>=3', ]
setup(
author="Stas Fomin",
author_email='stas-fomin@yandex.ru',
python_requires='>=3.7',
classifiers=[
'Development Status :: 2 - Pre-Alpha',
'Intended Audience :: Developers',
'License :: OSI Approved :: MIT License',
'Natural Language :: English',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
],
description="Generate Portable Windows Applications",
entry_points={
'console_scripts': [
'terrarium_assembler_win=terrarium_assembler_win.cli:main',
],
},
install_requires=requirements,
license="MIT license",
long_description=readme + '\n\n' + history,
include_package_data=True,
keywords='terrarium_assembler',
name='terrarium_assembler_win',
packages=find_packages(include=['terrarium_assembler_win', 'terrarium_assembler_win.*']),
# test_suite='tests',
# tests_require=test_requirements,
url='https://github.com/belonesox/terrarium_assembler_win',
setup_requires=['setuptools-git-versioning'],
version_config=True,
zip_safe=False,
)
#!/usr/bin/env python
from terrarium_assembler_win.cli import main
main()
\ No newline at end of file
"""Top-level package for terrarium-assembler."""
__author__ = """Stas Fomin"""
__email__ = 'stas-fomin@yandex.ru'
__version__ = '0.1.0'
# from ..utils import *
# from ta import *
# from nuitka import *
# import pkgutil
# __all__ = []
# for loader, module_name, is_pkg in pkgutil.walk_packages(__path__):
# __all__.append(module_name)
# _module = loader.find_module(module_name).load_module(module_name)
# globals()[module_name] = _module
#import importlib
#import pkgutil
from .ta import *
from .nuitkaflags import *
from .utils import *
"""Console script for terrarium_assembler."""
import argparse
import sys
from .ta import TerrariumAssembler
def main():
ta = TerrariumAssembler()
ta.process()
pass
if __name__ == '__main__':
res = main()
sys.exit(0) # pragma: no cover
"""
All nuitka functions associated for TA
"""
import os
import sys
from setuptools import find_packages
from pkgutil import iter_modules
import dataclasses as dc
import importlib
import pathlib
import re
PACKAGES_DIRS = [
os.getcwd(),
'/opt/venvdm/lib64/python3.8/site-packages/',
'/opt/venvdm/src',
'/usr/lib/python3.8/site-packages/',
'/usr/lib64/python3.8/site-packages/',
]
def find_modules(path):
if not path:
return None
modules = set()
rootdir, base_package_name = os.path.split(path)
def add_modules4pkg(pkg):
modules.add(pkg)
pkgpath = path + '/' + pkg.replace('.', '/')
if sys.version_info.major == 2 or (sys.version_info.major == 3 and sys.version_info.minor < 6):
for _, name, ispkg in iter_modules([pkgpath]):
if not ispkg:
modules.add(pkg + '.' + name)
else:
for info in iter_modules([pkgpath]):
if not info.ispkg:
modules.add(pkg + '.' + info.name)
pass
for info in iter_modules([path]):
if not info.ispkg:
if info.name not in ['__main__', 'setup']:
modules.add(info.name)
for pkg in find_packages(path):
add_modules4pkg(pkg)
return modules
def dir4module(modname):
try:
mod = importlib.__import__(modname)
except:
return None
finally:
if modname in sys.modules:
del sys.modules[modname]
import gc
gc.collect()
return str(pathlib.Path(mod.__file__).resolve().parent)
def dir4mnode(target_):
module = target_.module
module_dir = None
if "folder" in target_:
module_dir = target_.folder
else:
module_dir = dir4module(module)
return module_dir
def flags4module(modname, module_dir, block_modules=None):
# modnames_ = [modname]
mods = sorted(find_modules(module_dir))
disabled_re = None
if block_modules:
disabled_re_str = '(' + '|'.join([s.replace('.', '\.') for s in block_modules]) + ')'
# print(disabled_re_str)
disabled_re = re.compile(disabled_re_str)
flags = []
for mod in mods:
beforename, lastname = os.path.splitext(modname + '.' + mod)
if not lastname[1:2].isdigit():
firstname = mod.split('.')[0]
if 'migrations' in mod.split('.'):
continue
if firstname not in ['tests'] and lastname[1:] not in ['tests']:
modname_ = mod
if modname != firstname:
modname_ = modname + '.' + mod
if disabled_re and disabled_re.match(modname_):
flags.append(' --nofollow-import-to ' + modname_ )
else:
flags.append(' --include-module ' + modname_ )
flags.append("--module %s" % module_dir)
return flags
@dc.dataclass
class NuitkaFlags:
'''
Just make observable flags for Nuitka compiler
'''
force_packages: list = None # force packages to include
force_modules: list = None # force modules to include
block_packages: list = None # disable packages
std_flags: list = ('show-progress', 'show-scons') # base flags
# def get_flags(self, out_dir, module=None, block_modules=None):
def get_flags(self, out_dir, target_):
'''
Get flags for Nuitka compiler
'''
block_modules = None
if block_modules in target_:
block_modules = target_.block_modules
flags = ("""
%s --output-dir="%s"
""" % (" --".join([''] + self.std_flags), out_dir)).strip().split("\n")
if self.force_packages:
for it_ in self.force_packages:
flags.append('--include-package=' + it_)
if self.force_modules:
for it_ in self.force_modules:
flags.append('--include-module=' + it_)
if self.block_packages:
for it_ in self.block_packages:
flags.append('--nofollow-import-to=' + it_)
if "module" in target_:
module_dir = dir4mnode(target_)
if not module_dir:
return ''
flags += flags4module(target_.module, module_dir, block_modules)
else:
flags.append('--standalone')
flags.append('--follow-imports')
if "modules" in target_:
for it_ in target_.modules:
flags.append('--nofollow-import-to=' + it_)
if 'force_modules' in target_:
for it_ in target_.force_modules:
flags.append('--include-module=' + it_)
return " ".join(flags)
if __name__ == '__main__':
print(dir4module('ansible'))
# flags4module
\ No newline at end of file
This diff is collapsed.
"""
Different (geeky) utils for TA
"""
import os
import subprocess
import shutil
import stat
import pathlib
from easydict import EasyDict as edict
# from jinja2 import Template, Undefined
from jinja2 import Environment, FileSystemLoader, Template, Undefined, DebugUndefined
# from elevate import elevate
def mkdir_p(path):
pathlib.Path(path).mkdir(parents=True, exist_ok=True)
pass
def folder_size(path, *, follow_symlinks=False):
'''
Counting size of a folder.
'''
try:
if not os.path.exists(path):
# Nonexistant folder has zero size.
return 0
it = list(os.scandir(path))
# with os.scandir(path) as it:
return sum(folder_size(entry, follow_symlinks=follow_symlinks) for entry in it)
except NotADirectoryError:
return os.stat(path, follow_symlinks=follow_symlinks).st_size
def wtf(f):
'''
For debugging purposes.
'''
for wtf_ in ['PYTEST', '/tests']:
if wtf_ in f:
return True
class NullUndefined(Undefined):
def __getattr__(self, key):
return ''
def yaml_load(filename, vars_=None):
'''
Load yaml file into edict. Hide edict deps.
'''
import yaml
fc = None
# with open(filename, 'r') as f:
dir_, filename_ = os.path.split(os.path.abspath(filename))
file_loader = FileSystemLoader(dir_)
env = Environment(loader=file_loader, undefined=DebugUndefined)
env.trim_blocks = True
env.lstrip_blocks = True
env.rstrip_blocks = True
template = env.get_template(filename_)
real_yaml = ''
try:
for try_ in range(5):
real_yaml = template.render(vars_)
ld = yaml.safe_load(real_yaml)
vars_ = {**vars_, **ld}
# for key in vars_:
# if key.endswith('_dir'):
# vars_[key] = vars_[key].replace('/', '@')
real_yaml = template.render(vars_)
fc = edict(yaml.safe_load(template.render(vars_)))
except Exception as ex_:
print(f'Error parsing {filename_} see "troubles.yml" ')
with open("troubles.yml", 'w', encoding='utf-8') as lf:
lf.write(real_yaml)
raise ex_
# for key in fc:
# if key.endswith('_dir'):
# fc[key] = fc[key].replace('/', '\\')
return fc
def rmdir(oldpath):
if os.path.exists(oldpath):
shutil.rmtree(oldpath, ignore_errors=True)
if os.path.exists(oldpath):
os.system('sudo rm -rf "%s"' % oldpath)
# elevate(graphical=False)
# shutil.rmtree(oldpath)
pass
def git2dir(git_url, git_branch, path_to_dir):
oldpath = path_to_dir + '.old'
newpath = path_to_dir + '.new'
rmdir(oldpath)
pdir = os.path.split(path_to_dir)[0]
os.chdir(pdir)
scmd = 'git --git-dir=/dev/null clone --single-branch --branch %(git_branch)s --depth=1 %(git_url)s %(newpath)s ' % vars()
rmdir(newpath)
os.system(scmd)
if os.path.exists(newpath):
if os.path.exists(path_to_dir):
rmdir(oldpath)
shutil.move(path_to_dir, oldpath)
print(newpath, "->", path_to_dir)
shutil.move(newpath, path_to_dir)
pass
def make_setup_if_not_exists():
'''
If python package without setup.py
(for example Poetry)
'''
if not os.path.exists('setup.py') and os.path.exists('setup.cfg'):
from poetry.masonry.builders.sdist import SdistBuilder
from poetry.factory import Factory
factory = Factory()
poetry = factory.create_poetry('.')
sdist_builder = SdistBuilder(poetry, None, None)
setuppy_blob = sdist_builder.build_setup()
with open('setup.py', 'wb') as unit:
unit.write(setuppy_blob)
unit.write(b'\n# This setup.py was autogenerated using poetry.\n')
pass
def giturl2folder(git_url):
_, fld_ = os.path.split(git_url)
fld_, _ = os.path.splitext(fld_)
return fld_
def expandpath(path):
return os.path.abspath(os.path.expanduser(os.path.expandvars(path)))
"""
Parse wheel filenames
``wheel-filename`` lets you verify `wheel
<https://www.python.org/dev/peps/pep-0427/>`_ filenames and parse them into
their component fields.
This package adheres strictly to the relevant PEPs, with the following
exceptions:
- Unlike other filename components, version components may contain the
characters ``!`` and ``+`` for full PEP 440 support.
- Version components may be any sequence of the relevant set of characters;
they are not verified for PEP 440 compliance.
- The ``.whl`` file extension is matched case-insensitively.
Visit <https://github.com/jwodder/wheel-filename> for more information.
"""