Skip to content

Commit e596dad

Browse files
committed
adding builder-tool
1 parent 936acb3 commit e596dad

10 files changed

Lines changed: 233 additions & 0 deletions

File tree

.github/workflows/OnRelease.yml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
name: On Release
2+
on:
3+
release:
4+
types: [published]
5+
6+
7+
jobs:
8+
build-builder-tool:
9+
runs-on: ubuntu-latest
10+
11+
steps:
12+
- uses: actions/checkout@v4
13+
14+
- name: setup Python 3.12
15+
uses: actions/setup-python@v5
16+
with:
17+
python-version: 3.12
18+
19+
- name: Update pip
20+
run: python -m pip install --upgrade pip
21+
22+
- name: Install dependencies
23+
run: cd builder-tool && pip install -r requirements.txt
24+
25+
- name: Build
26+
run: cd builder-tool && python pack.py --dist-dir dist -pv ${{ github.event.release.tag_name }} --debug
27+
28+
- name: Publish
29+
uses: AButler/upload-release-assets@v3.0
30+
with:
31+
files: "builder-tool/dist/*"
32+
repo-token: ${{ secrets.GITHUB_TOKEN }}

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
# temporary files
99
*.cache
1010
*.tmp
11+
temp/
1112

1213
# compiled files
1314
*py[cod]
2.86 KB
Binary file not shown.
2.57 KB
Binary file not shown.

builder-tool/pack.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
from src.main import BaseBuilder, Logger, PYTHON, NULL_TARGET #this file use the module to build itself
2+
import os
3+
import shutil
4+
5+
6+
class Builder(BaseBuilder):
7+
def Setup(self):
8+
Logger.debug('Copying sources')
9+
shutil.copytree('src', self.tempDir + '/src', ignore=shutil.ignore_patterns('*.pyc', '*.pyo', '__pycache__'))
10+
Logger.debug('Copying pyproject.toml')
11+
self.CopyAndReplaceByPackageVersion('pyproject.toml', self.tempDir + '/pyproject.toml')
12+
Logger.debug('Copying requirements.txt')
13+
shutil.copy('requirements.txt', self.tempDir + '/requirements.txt')
14+
Logger.debug('Copying readme.md')
15+
self.CopyAndReplaceByPackageVersion('readme.md', self.tempDir + '/readme.md')
16+
17+
def Build(self):
18+
command = f'{PYTHON} -m build --outdir {self.distDir} {self.tempDir} > {NULL_TARGET}'
19+
Logger.debug('Executing command: ' + command)
20+
os.system(command)
21+
22+
23+
BaseBuilder.execute()

builder-tool/pyproject.toml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
[build-system]
2+
requires = ["setuptools>=61.0"]
3+
build-backend = "setuptools.build_meta"
4+
5+
[project]
6+
name = "build-tool"
7+
version = "{version}"
8+
authors = [
9+
{ name="Antoine Buirey", email="antoine.buirey@gmail.com" }
10+
]
11+
description = "A simple build tool for projects"
12+
readme = "readme.md"
13+
requires-python = ">=3.10"
14+
classifiers = [
15+
"Programming Language :: Python :: 3",
16+
"License :: OSI Approved :: MIT License",
17+
"Operating System :: OS Independent",
18+
]

builder-tool/readme.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Builder Tool, for building, testing, publishing, and deploying projects easily.
2+
3+
Current version : {version}

builder-tool/requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
gamu_logger @ https://github.com/GamuNetwork/logger/releases/download/2.0.0-alpha.4/gamu_logger-2.0.0a4-py3-none-any.whl

builder-tool/src/__init__.py

Whitespace-only changes.

builder-tool/src/main.py

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
import argparse
2+
from gamuLogger import Logger, LEVELS
3+
4+
import os, sys, shutil
5+
6+
from tempfile import mkdtemp
7+
8+
class BaseBuilder:
9+
def __init__(self):
10+
if self.__class__ == BaseBuilder:
11+
raise Exception('BaseBuilder is an abstract class and cannot be instantiated')
12+
13+
self.argumentParser = argparse.ArgumentParser(description='Builder tool')
14+
15+
loggerOptions = self.argumentParser.add_argument_group('Logger options')
16+
loggerOptions.add_argument('--debug', action='store_true', help='Enable debug messages')
17+
18+
buildersOptions = self.argumentParser.add_argument_group('Builder options')
19+
buildersOptions.add_argument('--no-tests', action='store_true', help='Do not run tests')
20+
buildersOptions.add_argument('--no-docs', action='store_true', help='Do not generate documentation')
21+
buildersOptions.add_argument('--no-build', action='store_true', help='Do not build the package')
22+
buildersOptions.add_argument('--publish', action='store_true', help='Publish the package')
23+
buildersOptions.add_argument('--no-clean', action='store_true', help='Do not clean temporary files')
24+
buildersOptions.add_argument('--temp-dir', help='Temporary directory', type=str, default=mkdtemp())
25+
buildersOptions.add_argument('--dist-dir', help='Distribution directory', type=str, default='dist')
26+
buildersOptions.add_argument('-pv', '--package-version', help='Package version', type=str, default='0.0.0')
27+
28+
self.argumentParser.add_argument('--version', '-v', action='version', version='%(prog)s 1.0')
29+
30+
self.args = self.argumentParser.parse_args()
31+
32+
if self.args.debug:
33+
Logger.setLevel('stdout', LEVELS.DEBUG)
34+
35+
36+
Logger.debug('Using temporary directory: ' + os.path.abspath(self.args.temp_dir))
37+
Logger.debug('Using distribution directory: ' + os.path.abspath(self.args.dist_dir))
38+
39+
if os.path.exists(self.args.temp_dir):
40+
Logger.debug('Removing temp directory for cleaning')
41+
shutil.rmtree(self.args.temp_dir)
42+
43+
Logger.debug('Creating temp directory')
44+
os.makedirs(self.args.temp_dir)
45+
46+
@property
47+
def tempDir(self):
48+
return os.path.abspath(self.args.temp_dir)
49+
50+
@property
51+
def packageVersion(self):
52+
return self.args.package_version
53+
54+
@property
55+
def distDir(self):
56+
return os.path.abspath(self.args.dist_dir)
57+
58+
def CopyAndReplaceByPackageVersion(self, src, dst, versionString = "{version}"):
59+
with open(src, 'r') as file:
60+
content = file.read()
61+
content = content.replace(versionString, self.packageVersion)
62+
with open(dst, 'w') as file:
63+
file.write(content)
64+
65+
66+
67+
# These methods should be overriden by the child class
68+
def Setup(self):
69+
"""Copy required file to the temporary directory and replace the version string by the package version, install dependencies, etc."""
70+
Logger.warning('no setup configured')
71+
72+
def Tests(self):
73+
"""Run the tests for the package"""
74+
Logger.debug('no tests configured')
75+
76+
def Docs(self):
77+
"""Generate the documentation for the package"""
78+
Logger.debug('no docs configured')
79+
80+
def Build(self):
81+
"""Build the package"""
82+
Logger.warning('no build configured')
83+
84+
def Publish(self):
85+
"""Publish the package"""
86+
Logger.error('no publish configured')
87+
88+
89+
def __clean(self):
90+
shutil.rmtree(self.args.temp_dir)
91+
92+
93+
def __run(self):
94+
"""
95+
Order of execution:
96+
- Setup
97+
- Build
98+
- Tests
99+
- Docs
100+
- Publish
101+
- Clean
102+
103+
If any of this steps fails, the process should stop, and the clean method should be called
104+
"""
105+
106+
Logger.info('Running setup')
107+
self.Setup()
108+
Logger.debug('Setup finished')
109+
110+
if not self.args.no_build:
111+
Logger.info('Building package')
112+
self.Build()
113+
114+
if self.args.no_tests:
115+
Logger.warning('Skipping tests')
116+
else:
117+
Logger.info('Running tests')
118+
self.Tests()
119+
120+
if not self.args.no_docs:
121+
Logger.info('Generating documentation')
122+
self.Docs()
123+
124+
if self.args.publish:
125+
Logger.info('Publishing package')
126+
self.Publish()
127+
else:
128+
Logger.info('Package not published')
129+
130+
if self.args.no_clean:
131+
Logger.warning('Skipping cleaning')
132+
else:
133+
Logger.info('Cleaning temporary files')
134+
self.__clean()
135+
Logger.debug('Temporary files cleaned')
136+
137+
Logger.info('Process finished')
138+
139+
140+
@staticmethod
141+
def execute():
142+
subClasses = BaseBuilder.__subclasses__()
143+
if len(subClasses) == 0:
144+
Logger.critical('No builders found')
145+
sys.exit(1)
146+
elif len(subClasses) > 1:
147+
Logger.critical('Multiple builders found')
148+
sys.exit(1)
149+
subClasses[0]().__run()
150+
151+
152+
# some useful constants
153+
154+
PYTHON = sys.executable
155+
NULL_TARGET = '/dev/null' if os.name == 'posix' else 'nul'

0 commit comments

Comments
 (0)