From 9f4648dae644f2fb9deb4c68859d6cdfd0bc0530 Mon Sep 17 00:00:00 2001 From: dusoleil Date: Thu, 23 Feb 2023 05:29:21 -0500 Subject: Dynamically source version in toml from git Instead of hard-coding the version into the pyproject.toml, we can dynamically source it at build time. Ideally, we want to use git describe as a single authority source on the version. The version is stored in sploit.__version__ and can be consumed during sploit runtime or during a build/package to populate the project's core metadata version in the toml file. hatchling provides a tool.hatch.version plugin that can read out the variable during a build/package. Because this variable is populated from a git command, if the source tree isn't in a git repo, it will fail. In this case, sploit will report a PEP 440 compliant fake version "0+unknown.version" to let the user know. Because a packaged distribution doesn't exist in a git repo, we want to bake in the version at build time into the package. hatchling provides a plugin to help with this, but it had some technical limitations that didn't quite work for our use case. Instead, I added a custom build hook which will take the version sourced from the package (and by proxy the git command), and overwrite the __init__.py with a hard-coded version in the __version__ variable. This means that built/packaged distributions of this project will have a fixed version hard-coded in rather than dynamically sourcing from git. The build hook operates just before the build executes. It seems that most build/packager front-ends (e.g. build, pip) will just run it in the current source tree rather than making a temp copy. This means that when we modify the __init__.py, it is modifying our git tree. Ideally, we want this to be restored at the end of the build. The build hook interface allows us to write a hook that happens after the build, but it won't run in the case of a crash or failed build. Instead, I added a custom solution to this using a member variable deconstructor. If the build ends in any way, the original contents of __init__.py are written back out. Signed-off-by: dusoleil Reviewed-by: Malfurious --- sploit/__init__.py | 2 ++ sploit/util.py | 20 ++++++++++++++++---- 2 files changed, 18 insertions(+), 4 deletions(-) (limited to 'sploit') diff --git a/sploit/__init__.py b/sploit/__init__.py index f5a82fc..5bac38f 100644 --- a/sploit/__init__.py +++ b/sploit/__init__.py @@ -8,3 +8,5 @@ from sploit import ( util, rev, ) + +__version__ = util.git_version() diff --git a/sploit/util.py b/sploit/util.py index c44ab78..3a2b842 100644 --- a/sploit/util.py +++ b/sploit/util.py @@ -1,14 +1,26 @@ +from os import path from subprocess import run -def run_cmd(cmd): - return run(cmd,capture_output=True).stdout.decode('utf-8').split('\n')[:-1] +def run_cmd(cmd,cwd=None): + return run(cmd,cwd=cwd,capture_output=True,text=True,check=True).stdout.split('\n')[:-1] __RUN_CACHE__ = {} -def run_cmd_cached(cmd): +def run_cmd_cached(cmd,cwd=None): key = ''.join(cmd) if key in __RUN_CACHE__: return __RUN_CACHE__[key] else: - result = run_cmd(cmd) + result = run_cmd(cmd,cwd) __RUN_CACHE__[key] = result return result + +#try to get the version through git +def git_version(): + try: + cwd = path.dirname(path.realpath(__file__)) + version = run_cmd(["git","describe","--always","--first-parent","--dirty"],cwd=cwd)[0] + #PEP440 compliance + version = version.replace('-','+',1).replace('-','.') + return version + except: + return "0+unknown.version" -- cgit v1.2.3