Preserve picked patch name when possible
[stgit.git] / setup.py
blobc6296e3b25ec4f163a37b316299afc5f4d166152
1 #!/usr/bin/env python3
2 import io
3 import os
4 import sys
5 from importlib import import_module
6 from importlib.util import module_from_spec, spec_from_file_location
8 from setuptools import setup
9 from setuptools.command.build_py import build_py
10 from setuptools.command.sdist import sdist
13 # The goal is to get the version without doing a regular/full import of
14 # stgit. Executing the stgit._version module will obtain the version
15 # without importing anything else from the stgit package.
16 def _get_version():
17 spec = spec_from_file_location('version', os.path.join('stgit', '_version.py'))
18 module = module_from_spec(spec)
19 spec.loader.exec_module(module)
20 return module.__version__
23 version = _get_version()
26 def _write_version(base_dir):
27 _version_path = os.path.join(base_dir, 'stgit', '_version.py')
28 try:
29 # This could be a hard link, so try to delete it first.
30 os.remove(_version_path)
31 except OSError:
32 os.makedirs(os.path.join(base_dir, 'stgit'), exist_ok=True)
33 with open(_version_path, "w") as f:
34 f.write("# Generated by setup.py.\n\n__version__ = '{}'\n".format(version))
37 class _stgit_build_py(build_py):
38 def run(self):
39 super().run()
40 _write_version(self.build_lib)
43 class _stgit_sdist(sdist):
44 def make_release_tree(self, base_dir, files):
45 super().make_release_tree(base_dir, files)
46 _write_version(base_dir)
49 # Override setuptools build_py and sdist commands to rewrite the
50 # _version.py file into those commands' destination trees.
51 # N.B. the _version.py in the worktree is never overwritten.
52 cmdclass = dict(sdist=_stgit_sdist, build_py=_stgit_build_py)
55 # Carefully perform code generation. First check if generated code
56 # exists. Only write-out generated code if the content is different.
57 # This accommodates several setup.py contexts, including:
58 # - When running from an sdist where code is already generated
59 # - During pip installation where the stgit package is not in sys.path
60 # - In a git worktree where the generated code may change frequently
61 # - When running from a read-only directory/filesystem
62 def _maybe_generate_code():
63 base = os.path.abspath(os.path.dirname(__file__))
64 paths = dict(
65 cmds=os.path.join(base, 'stgit', 'commands', 'cmdlist.py'),
66 bash=os.path.join(base, 'completion', 'stgit.bash'),
67 fish=os.path.join(base, 'completion', 'stg.fish'),
70 existing_content = dict()
71 for k, path in paths.items():
72 if os.path.exists(path):
73 with open(path, 'r') as f:
74 existing_content[k] = f.read()
75 else:
76 existing_content[k] = None
78 sys.path.insert(0, base)
79 try:
80 try:
81 gen_funcs = dict(
82 cmds=import_module('stgit.commands').write_cmdlist_py,
83 bash=import_module('stgit.completion.bash').write_bash_completion,
84 fish=import_module('stgit.completion.fish').write_fish_completion,
86 except ImportError:
87 if all(existing_content.values()):
88 return # Okay, all generated content exists
89 else:
90 raise RuntimeError('Cannot perform code generation')
91 finally:
92 sys.path.pop(0)
94 for k, gen_func in gen_funcs.items():
95 with io.StringIO() as f:
96 gen_func(f)
97 new_content = f.getvalue()
98 if existing_content[k] != new_content:
99 with open(paths[k], 'w') as f:
100 f.write(new_content)
103 _maybe_generate_code()
106 def _long_description():
107 base = os.path.abspath(os.path.dirname(__file__))
108 parts = []
109 for fn in ['README.md', 'CHANGELOG.md']:
110 with open(os.path.join(base, fn)) as f:
111 parts.append(f.read())
112 return '\n\n'.join(parts)
115 setup(
116 name='stgit',
117 version=version,
118 license='GPLv2',
119 author='Catalin Marinas',
120 author_email='catalin.marinas@gmail.com',
121 maintainer='Peter Grayson',
122 maintainer_email='pete@jpgrayson.net',
123 url='http://stacked-git.github.io',
124 download_url='https://github.com/stacked-git/stgit.git',
125 description='Stacked Git',
126 long_description=_long_description(),
127 long_description_content_type='text/markdown',
128 python_requires='>=3.5',
129 zip_safe=False,
130 include_package_data=True,
131 entry_points=dict(console_scripts=['stg = stgit.main:main']),
132 cmdclass=cmdclass,
133 packages=[
134 'stgit',
135 'stgit.commands',
136 'stgit.completion',
137 'stgit.lib',
138 'stgit.lib.git',
140 classifiers=[
141 'Development Status :: 5 - Production/Stable',
142 'Environment :: Console',
143 'Intended Audience :: Developers',
144 'License :: OSI Approved :: GNU General Public License v2 (GPLv2)',
145 'Natural Language :: English',
146 'Operating System :: OS Independent',
147 'Programming Language :: Python',
148 'Programming Language :: Python :: 3',
149 'Programming Language :: Python :: 3.5',
150 'Programming Language :: Python :: 3.6',
151 'Programming Language :: Python :: 3.7',
152 'Programming Language :: Python :: 3.8',
153 'Programming Language :: Python :: 3.9',
154 'Programming Language :: Python :: 3.10',
155 'Programming Language :: Python :: Implementation :: CPython',
156 'Programming Language :: Python :: Implementation :: PyPy',
157 'Topic :: Software Development :: Version Control',