Dark Mode

Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit d07e040

Browse files
committed
Use dev-shell
1 parent 7c2a1c2 commit d07e040

File tree

7 files changed

+679
-164
lines changed
  • .github/workflows
    • pythonapp.yml
  • .gitignore
  • README.creole
  • devshell.py
  • dragonpy
    • dev_shell.py
  • poetry.lock
  • pyproject.toml

7 files changed

+679
-164
lines changed

.github/workflows/pythonapp.yml

Lines changed: 17 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,15 @@ on:
1212

1313
jobs:
1414
test:
15-
runs-on: ubuntu-latest
15+
name: 'Python ${{ matrix.python-version }} on ${{ matrix.os }}'
16+
runs-on: ${{ matrix.os }}
17+
env:
18+
PYTHONUNBUFFERED: 1
1619
strategy:
17-
max-parallel: 4
20+
fail-fast: false
1821
matrix:
19-
python-version: ["3.9", "3.8"]
22+
python-version: ["3.10", "3.9", "3.8"]
23+
os: [ubuntu-latest, macOS-latest, windows-latest]
2024
steps:
2125
- uses: actions/checkout@v2
2226
with:
@@ -47,32 +51,23 @@ jobs:
4751
path: roms
4852
key: cache-roms
4953

50-
- name: 'Install package'
54+
- name: 'Bootstrap'
5155
run: |
52-
make install-poetry
53-
source $HOME/.poetry/env
54-
make install
56+
python3 devshell.py quit
5557
5658
- name: 'List installed packages'
5759
run: |
58-
source $HOME/.poetry/env
59-
poetry run pip freeze
60-
61-
- name: 'List all tox test environments'
62-
run: |
63-
source $HOME/.poetry/env
64-
make tox-listenvs
60+
python3 devshell.py list_venv_packages
6561
6662
- name: 'Run tests with Python v${{ matrix.python-version }}'
6763
run: |
68-
source $HOME/.poetry/env
69-
make pytest
70-
71-
# - name: 'Run linters'
72-
# if: matrix.python-version == '3.8'
73-
# run: |
74-
# source $HOME/.poetry/env
75-
# make lint
64+
python3 devshell.py pytest -vv
7665
7766
- name: 'Upload coverage report'
67+
if: matrix.os == 'ubuntu-latest'
7868
run: bash <(curl -s https://codecov.io/bash)
69+
70+
- name: 'Run linters'
71+
if: matrix.python-version == '3.8'
72+
run: |
73+
python3 devshell.py linting

.gitignore

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
.*
2+
3+
!.github
4+
!.gitignore
5+
16
*.rom
27
/roms/*
38

@@ -19,25 +24,17 @@ bin
1924
var
2025
sdist
2126
develop-eggs
22-
.installed.cfg
2327
lib
2428
lib64
2529

2630
# Installer logs
2731
pip-log.txt
2832

2933
# Unit test / coverage reports
30-
.coverage
3134
/htmlcov/*
32-
.tox
33-
nosetests.xml
3435

3536
# Translations
3637
*.mo
3738

38-
.project
39-
.pydevproject
40-
.idea/*
41-
.settings/*
4239
/publish.log
4340
/coverage.xml

README.creole

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,10 @@ pip install DragonPyEmulator
9393
{{{
9494
~$ git clone https://github.com/jedie/DragonPy.git
9595
~$ cd DragonPy/
96-
~/DragonPy$ make
96+
~/DragonPy$ ./devshell.py
97+
98+
WIP: remove old make file:
99+
97100
help List all commands
98101
install-poetry install or update poetry
99102
install install DragonPy via poetry

devshell.py

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
#!/usr/bin/env python3
2+
3+
"""
4+
developer shell
5+
~~~~~~~~~~~~~~~
6+
7+
Just call this file, and the magic happens ;)
8+
9+
This file is from: https://pypi.org/project/dev-shell/
10+
Source: https://github.com/jedie/dev-shell/blob/main/devshell.py
11+
12+
:copyleft: 2021 by Jens Diemer
13+
:license: GNU GPL v3 or above
14+
"""
15+
16+
import argparse
17+
import hashlib
18+
import signal
19+
import subprocess
20+
import sys
21+
import venv
22+
from pathlib import Path
23+
24+
25+
try:
26+
import ensurepip # noqa
27+
except ModuleNotFoundError as err:
28+
print(err)
29+
print('-' * 100)
30+
print('Error: Pip not available!')
31+
print('Hint: "apt-get install python3-venv"\n')
32+
raise
33+
34+
35+
assert sys.version_info >= (3, 7), 'Python version is too old!'
36+
37+
38+
if sys.platform == 'win32': # wtf
39+
# Files under Windows, e.g.: .../.venv/Scripts/python.exe
40+
BIN_NAME = 'Scripts'
41+
FILE_EXT = '.exe'
42+
else:
43+
# Files under Linux/Mac and all other than Windows, e.g.: .../.venv/bin/python
44+
BIN_NAME = 'bin'
45+
FILE_EXT = ''
46+
47+
BASE_PATH = Path(__file__).parent
48+
VENV_PATH = BASE_PATH / '.venv'
49+
BIN_PATH = VENV_PATH / BIN_NAME
50+
PYTHON_PATH = BIN_PATH / f'python{FILE_EXT}'
51+
PIP_PATH = BIN_PATH / f'pip{FILE_EXT}'
52+
POETRY_PATH = BIN_PATH / f'poetry{FILE_EXT}'
53+
54+
DEP_LOCK_PATH = BASE_PATH / 'poetry.lock'
55+
DEP_HASH_PATH = VENV_PATH / '.dep_hash'
56+
57+
# script file defined in pyproject.toml as [tool.poetry.scripts]
58+
# (Under Windows: ".exe" not added!)
59+
PROJECT_SHELL_SCRIPT = BIN_PATH / 'devshell'
60+
61+
62+
def get_dep_hash():
63+
""" Get SHA512 hash from poetry.lock content. """
64+
return hashlib.sha512(DEP_LOCK_PATH.read_bytes()).hexdigest()
65+
66+
67+
def store_dep_hash():
68+
""" Generate /.venv/.dep_hash """
69+
DEP_HASH_PATH.write_text(get_dep_hash())
70+
71+
72+
def venv_up2date():
73+
""" Is existing .venv is up-to-date? """
74+
if DEP_HASH_PATH.is_file():
75+
return DEP_HASH_PATH.read_text() == get_dep_hash()
76+
return False
77+
78+
79+
def verbose_check_call(*popen_args):
80+
popen_args = [str(arg) for arg in popen_args] # e.g.: Path() -> str for python 3.7
81+
print(f'\n+ {" ".join(popen_args)}\n')
82+
return subprocess.check_call(popen_args)
83+
84+
85+
def noop_signal_handler(signal_num, frame):
86+
"""
87+
Signal handler that does nothing: Used to ignore "Ctrl-C" signals
88+
"""
89+
pass
90+
91+
92+
def main(argv):
93+
if len(argv) == 2 and argv[1] in ('--update', '--help'):
94+
parser = argparse.ArgumentParser(
95+
prog=Path(__file__).name,
96+
description='Developer shell',
97+
epilog='...live long and prosper...'
98+
)
99+
parser.add_argument(
100+
'--update', default=False, action='store_true',
101+
help='Force create/upgrade virtual environment'
102+
)
103+
parser.add_argument(
104+
'command_args',
105+
nargs=argparse.ZERO_OR_MORE,
106+
help='arguments to pass to dev-setup shell/cli',
107+
)
108+
options = parser.parse_args(argv)
109+
force_update = options.update
110+
extra_args = argv[2:]
111+
else:
112+
force_update = False
113+
extra_args = argv[1:]
114+
115+
# Create virtual env in ".../.venv/":
116+
if not PYTHON_PATH.is_file() or force_update:
117+
print('Create virtual env here:', VENV_PATH.absolute())
118+
builder = venv.EnvBuilder(symlinks=True, upgrade=True, with_pip=True)
119+
builder.create(env_dir=VENV_PATH)
120+
121+
# install/update "pip" and "poetry":
122+
if not POETRY_PATH.is_file() or force_update:
123+
# Note: Under Windows pip.exe can't replace this own .exe file, so use the module way:
124+
verbose_check_call(PYTHON_PATH, '-m', 'pip', 'install', '-U', 'pip', 'setuptools')
125+
verbose_check_call(PIP_PATH, 'install', 'poetry')
126+
127+
if not DEP_LOCK_PATH.is_file():
128+
verbose_check_call(POETRY_PATH, 'update')
129+
130+
# install via poetry, if:
131+
# 1. .venv not exists
132+
# 2. "--update" used
133+
# 3. poetry.lock file was changed
134+
if not PROJECT_SHELL_SCRIPT.is_file() or force_update or not venv_up2date():
135+
verbose_check_call(POETRY_PATH, 'install')
136+
store_dep_hash()
137+
138+
# The cmd2 shell should not abort on Ctrl-C => ignore "Interrupt from keyboard" signal:
139+
signal.signal(signal.SIGINT, noop_signal_handler)
140+
141+
# Run project cmd shell via "setup.py" entrypoint:
142+
# (Call it via python, because Windows sucks calling the file direct)
143+
try:
144+
verbose_check_call(PYTHON_PATH, PROJECT_SHELL_SCRIPT, *extra_args)
145+
except subprocess.CalledProcessError as err:
146+
sys.exit(err.returncode)
147+
148+
149+
if __name__ == '__main__':
150+
main(sys.argv)

dragonpy/dev_shell.py

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import sys
2+
from pathlib import Path
3+
4+
import cmd2
5+
from creole.setup_utils import assert_rst_readme
6+
from dev_shell.base_cmd2_app import DevShellBaseApp
7+
from dev_shell.command_sets import DevShellBaseCommandSet
8+
from dev_shell.command_sets.dev_shell_commands import DevShellCommandSet as OriginDevShellCommandSet
9+
from dev_shell.command_sets.dev_shell_commands import run_linters
10+
from dev_shell.config import DevShellConfig
11+
from dev_shell.utils.subprocess_utils import verbose_check_call
12+
from poetry_publish.publish import poetry_publish
13+
14+
import dragonpy
15+
16+
17+
PACKAGE_ROOT = Path(dragonpy.__file__).parent.parent.parent
18+
19+
20+
@cmd2.with_default_category('DragonPy commands')
21+
class DragonPyCommandSet(DevShellBaseCommandSet):
22+
pass
23+
24+
25+
class DevShellCommandSet(OriginDevShellCommandSet):
26+
27+
# TODO:
28+
# pyupgrade --exit-zero-even-if-changed --py3-plus --py36-plus --py37-plus --py38-plus
29+
# `find . -name "*.py" -type f ! -path "./.tox/*" ! -path "./htmlcov/*" ! -path "*/volumes/*"
30+
31+
def do_publish(self, statement: cmd2.Statement):
32+
"""
33+
Publish "dev-shell" to PyPi
34+
"""
35+
# don't publish if README is not up-to-date:
36+
assert_rst_readme(package_root=PACKAGE_ROOT, filename='README.creole')
37+
38+
# don't publish if code style wrong:
39+
run_linters()
40+
41+
# don't publish if test fails:
42+
verbose_check_call('pytest', '-x')
43+
44+
poetry_publish(
45+
package_root=PACKAGE_ROOT,
46+
version=dragonpy.__version__,
47+
creole_readme=True, # don't publish if README.rst is not up-to-date
48+
)
49+
50+
51+
class DevShellApp(DevShellBaseApp):
52+
pass
53+
54+
55+
def get_devshell_app_kwargs():
56+
"""
57+
Generate the kwargs for the cmd2 App.
58+
(Separated because we needs the same kwargs in tests)
59+
"""
60+
config = DevShellConfig(package_module=dragonpy)
61+
62+
# initialize all CommandSet() with context:
63+
kwargs = dict(config=config)
64+
65+
app_kwargs = dict(
66+
config=config,
67+
command_sets=[
68+
DragonPyCommandSet(**kwargs),
69+
DevShellCommandSet(**kwargs),
70+
],
71+
)
72+
return app_kwargs
73+
74+
75+
def devshell_cmdloop():
76+
"""
77+
Entry point to start the "dev-shell" cmd2 app.
78+
Used in: [tool.poetry.scripts]
79+
"""
80+
c = DevShellApp(**get_devshell_app_kwargs())
81+
sys.exit(c.cmdloop())

0 commit comments

Comments
(0)