0 | 6 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,116 @@ |
1 |
+CC0 1.0 Universal |
|
2 |
+ |
|
3 |
+Statement of Purpose |
|
4 |
+ |
|
5 |
+The laws of most jurisdictions throughout the world automatically confer |
|
6 |
+exclusive Copyright and Related Rights (defined below) upon the creator and |
|
7 |
+subsequent owner(s) (each and all, an "owner") of an original work of |
|
8 |
+authorship and/or a database (each, a "Work"). |
|
9 |
+ |
|
10 |
+Certain owners wish to permanently relinquish those rights to a Work for the |
|
11 |
+purpose of contributing to a commons of creative, cultural and scientific |
|
12 |
+works ("Commons") that the public can reliably and without fear of later |
|
13 |
+claims of infringement build upon, modify, incorporate in other works, reuse |
|
14 |
+and redistribute as freely as possible in any form whatsoever and for any |
|
15 |
+purposes, including without limitation commercial purposes. These owners may |
|
16 |
+contribute to the Commons to promote the ideal of a free culture and the |
|
17 |
+further production of creative, cultural and scientific works, or to gain |
|
18 |
+reputation or greater distribution for their Work in part through the use and |
|
19 |
+efforts of others. |
|
20 |
+ |
|
21 |
+For these and/or other purposes and motivations, and without any expectation |
|
22 |
+of additional consideration or compensation, the person associating CC0 with a |
|
23 |
+Work (the "Affirmer"), to the extent that he or she is an owner of Copyright |
|
24 |
+and Related Rights in the Work, voluntarily elects to apply CC0 to the Work |
|
25 |
+and publicly distribute the Work under its terms, with knowledge of his or her |
|
26 |
+Copyright and Related Rights in the Work and the meaning and intended legal |
|
27 |
+effect of CC0 on those rights. |
|
28 |
+ |
|
29 |
+1. Copyright and Related Rights. A Work made available under CC0 may be |
|
30 |
+protected by copyright and related or neighboring rights ("Copyright and |
|
31 |
+Related Rights"). Copyright and Related Rights include, but are not limited |
|
32 |
+to, the following: |
|
33 |
+ |
|
34 |
+ i. the right to reproduce, adapt, distribute, perform, display, communicate, |
|
35 |
+ and translate a Work; |
|
36 |
+ |
|
37 |
+ ii. moral rights retained by the original author(s) and/or performer(s); |
|
38 |
+ |
|
39 |
+ iii. publicity and privacy rights pertaining to a person's image or likeness |
|
40 |
+ depicted in a Work; |
|
41 |
+ |
|
42 |
+ iv. rights protecting against unfair competition in regards to a Work, |
|
43 |
+ subject to the limitations in paragraph 4(a), below; |
|
44 |
+ |
|
45 |
+ v. rights protecting the extraction, dissemination, use and reuse of data in |
|
46 |
+ a Work; |
|
47 |
+ |
|
48 |
+ vi. database rights (such as those arising under Directive 96/9/EC of the |
|
49 |
+ European Parliament and of the Council of 11 March 1996 on the legal |
|
50 |
+ protection of databases, and under any national implementation thereof, |
|
51 |
+ including any amended or successor version of such directive); and |
|
52 |
+ |
|
53 |
+ vii. other similar, equivalent or corresponding rights throughout the world |
|
54 |
+ based on applicable law or treaty, and any national implementations thereof. |
|
55 |
+ |
|
56 |
+2. Waiver. To the greatest extent permitted by, but not in contravention of, |
|
57 |
+applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and |
|
58 |
+unconditionally waives, abandons, and surrenders all of Affirmer's Copyright |
|
59 |
+and Related Rights and associated claims and causes of action, whether now |
|
60 |
+known or unknown (including existing as well as future claims and causes of |
|
61 |
+action), in the Work (i) in all territories worldwide, (ii) for the maximum |
|
62 |
+duration provided by applicable law or treaty (including future time |
|
63 |
+extensions), (iii) in any current or future medium and for any number of |
|
64 |
+copies, and (iv) for any purpose whatsoever, including without limitation |
|
65 |
+commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes |
|
66 |
+the Waiver for the benefit of each member of the public at large and to the |
|
67 |
+detriment of Affirmer's heirs and successors, fully intending that such Waiver |
|
68 |
+shall not be subject to revocation, rescission, cancellation, termination, or |
|
69 |
+any other legal or equitable action to disrupt the quiet enjoyment of the Work |
|
70 |
+by the public as contemplated by Affirmer's express Statement of Purpose. |
|
71 |
+ |
|
72 |
+3. Public License Fallback. Should any part of the Waiver for any reason be |
|
73 |
+judged legally invalid or ineffective under applicable law, then the Waiver |
|
74 |
+shall be preserved to the maximum extent permitted taking into account |
|
75 |
+Affirmer's express Statement of Purpose. In addition, to the extent the Waiver |
|
76 |
+is so judged Affirmer hereby grants to each affected person a royalty-free, |
|
77 |
+non transferable, non sublicensable, non exclusive, irrevocable and |
|
78 |
+unconditional license to exercise Affirmer's Copyright and Related Rights in |
|
79 |
+the Work (i) in all territories worldwide, (ii) for the maximum duration |
|
80 |
+provided by applicable law or treaty (including future time extensions), (iii) |
|
81 |
+in any current or future medium and for any number of copies, and (iv) for any |
|
82 |
+purpose whatsoever, including without limitation commercial, advertising or |
|
83 |
+promotional purposes (the "License"). The License shall be deemed effective as |
|
84 |
+of the date CC0 was applied by Affirmer to the Work. Should any part of the |
|
85 |
+License for any reason be judged legally invalid or ineffective under |
|
86 |
+applicable law, such partial invalidity or ineffectiveness shall not |
|
87 |
+invalidate the remainder of the License, and in such case Affirmer hereby |
|
88 |
+affirms that he or she will not (i) exercise any of his or her remaining |
|
89 |
+Copyright and Related Rights in the Work or (ii) assert any associated claims |
|
90 |
+and causes of action with respect to the Work, in either case contrary to |
|
91 |
+Affirmer's express Statement of Purpose. |
|
92 |
+ |
|
93 |
+4. Limitations and Disclaimers. |
|
94 |
+ |
|
95 |
+ a. No trademark or patent rights held by Affirmer are waived, abandoned, |
|
96 |
+ surrendered, licensed or otherwise affected by this document. |
|
97 |
+ |
|
98 |
+ b. Affirmer offers the Work as-is and makes no representations or warranties |
|
99 |
+ of any kind concerning the Work, express, implied, statutory or otherwise, |
|
100 |
+ including without limitation warranties of title, merchantability, fitness |
|
101 |
+ for a particular purpose, non infringement, or the absence of latent or |
|
102 |
+ other defects, accuracy, or the present or absence of errors, whether or not |
|
103 |
+ discoverable, all to the greatest extent permissible under applicable law. |
|
104 |
+ |
|
105 |
+ c. Affirmer disclaims responsibility for clearing rights of other persons |
|
106 |
+ that may apply to the Work or any use thereof, including without limitation |
|
107 |
+ any person's Copyright and Related Rights in the Work. Further, Affirmer |
|
108 |
+ disclaims responsibility for obtaining any necessary consents, permissions |
|
109 |
+ or other rights required for any use of the Work. |
|
110 |
+ |
|
111 |
+ d. Affirmer understands and acknowledges that Creative Commons is not a |
|
112 |
+ party to this document and has no duty or obligation with respect to this |
|
113 |
+ CC0 or use of the Work. |
|
114 |
+ |
|
115 |
+For more information, please see |
|
116 |
+<http://creativecommons.org/publicdomain/zero/1.0/> |
0 | 117 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,73 @@ |
1 |
+# Miniver |
|
2 |
+[![License: CC0-1.0][cc0_badge]][cc0] |
|
3 |
+ |
|
4 |
+**Like [versioneer][versioneer], but smaller** |
|
5 |
+ |
|
6 |
+Miniver is a **min**imal **ver**sioning tool that serves the same purpose |
|
7 |
+as [Versioneer][versioneer], except that it is not designed to be |
|
8 |
+cross platform, and only works with Git. |
|
9 |
+ |
|
10 |
+#### Why would I use this? |
|
11 |
+If you are developing a Python package inside a Git repository and |
|
12 |
+want to get the version directly from Git tags, rather than hard-coding |
|
13 |
+version strings everywhere. |
|
14 |
+ |
|
15 |
+This is the same problem that Versioneer solves, but Miniver is less |
|
16 |
+than 200 lines of code, whereas Versioneer is over 2000. The tradeoff |
|
17 |
+is that Miniver only works with Git, and has not been tested across |
|
18 |
+different platforms and Python versions (yet). |
|
19 |
+ |
|
20 |
+ |
|
21 |
+[versioneer]: https://github.com/warner/python-versioneer |
|
22 |
+[cc0_badge]: https://licensebuttons.net/l/zero/1.0/88x31.png |
|
23 |
+[cc0]: http://creativecommons.org/publicdomain/zero/1.0/ |
|
24 |
+ |
|
25 |
+## Usage |
|
26 |
+Copy the contents of the `miniver` directory (in this repository) into your |
|
27 |
+project's main package directory. |
|
28 |
+ |
|
29 |
+Then copy the following snippets into the appropriate files: |
|
30 |
+ |
|
31 |
+```python |
|
32 |
+# Your package's __init__.py |
|
33 |
+from . import version |
|
34 |
+__version__ = version.version |
|
35 |
+del version |
|
36 |
+``` |
|
37 |
+ |
|
38 |
+```python |
|
39 |
+# Your project's setup.py |
|
40 |
+ |
|
41 |
+# Loads version.py module without importing the whole package. |
|
42 |
+def get_version_and_cmdclass(package_name): |
|
43 |
+ import os |
|
44 |
+ from importlib.util import module_from_spec, spec_from_file_location |
|
45 |
+ spec = spec_from_file_location('version', |
|
46 |
+ os.path.join(package_name, 'miniver.py')) |
|
47 |
+ module = module_from_spec(spec) |
|
48 |
+ spec.loader.exec_module(module) |
|
49 |
+ return module.version, module.cmdclass |
|
50 |
+ |
|
51 |
+ |
|
52 |
+version, cmdclass = get_version_and_cmdclass('my_package') |
|
53 |
+ |
|
54 |
+setup( |
|
55 |
+ name='my_package', |
|
56 |
+ version=version, |
|
57 |
+ cmdclass=cmdclass, |
|
58 |
+) |
|
59 |
+``` |
|
60 |
+ |
|
61 |
+``` |
|
62 |
+# Your project's .gitattributes |
|
63 |
+my_package/_static_version.py export-subst |
|
64 |
+``` |
|
65 |
+ |
|
66 |
+replacing `'my_package'` in the above with the name of your package |
|
67 |
+(this should be the same as the name of the directory into |
|
68 |
+which you copied the contents of `miniver`). |
|
69 |
+ |
|
70 |
+That's it! |
|
71 |
+ |
|
72 |
+## License |
|
73 |
+Miniver is in the public domain under a CC0 license. |
0 | 4 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,9 @@ |
1 |
+# This file will be overwritten by setup.py when a source or binary |
|
2 |
+# distribution is made. The magic value "__use_git__" is interpreted by |
|
3 |
+# version.py. |
|
4 |
+ |
|
5 |
+version = "__use_git__" |
|
6 |
+ |
|
7 |
+# These values are only set if the distribution was created with 'git archive' |
|
8 |
+refnames = "$Format:%D$" |
|
9 |
+git_hash = "$Format:%h$" |
0 | 10 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,166 @@ |
1 |
+from collections import namedtuple |
|
2 |
+import os |
|
3 |
+import subprocess |
|
4 |
+import sys |
|
5 |
+ |
|
6 |
+from distutils.command.build import build as build_orig |
|
7 |
+from setuptools.command.sdist import sdist as sdist_orig |
|
8 |
+ |
|
9 |
+Version = namedtuple('Version', ('release', 'dev', 'labels')) |
|
10 |
+ |
|
11 |
+# No public API |
|
12 |
+__all__ = [] |
|
13 |
+ |
|
14 |
+package_root = os.path.dirname(os.path.realpath(__file__)) |
|
15 |
+package_name = os.path.basename(package_root) |
|
16 |
+distr_root = os.path.dirname(package_root) |
|
17 |
+ |
|
18 |
+STATIC_VERSION_FILE = '_static_version.py' |
|
19 |
+ |
|
20 |
+ |
|
21 |
+def get_version(version_file=STATIC_VERSION_FILE): |
|
22 |
+ version_info = {} |
|
23 |
+ with open(os.path.join(package_root, version_file), 'rb') as f: |
|
24 |
+ exec(f.read(), {}, version_info) |
|
25 |
+ version = version_info['version'] |
|
26 |
+ version_is_from_git = (version == "__use_git__") |
|
27 |
+ if version_is_from_git: |
|
28 |
+ version = get_version_from_git() |
|
29 |
+ if not version: |
|
30 |
+ version = get_version_from_git_archive(version_info) |
|
31 |
+ if not version: |
|
32 |
+ version = Version("unknown", None, None) |
|
33 |
+ return semver_format(version) |
|
34 |
+ else: |
|
35 |
+ return version |
|
36 |
+ |
|
37 |
+ |
|
38 |
+def semver_format(version_info): |
|
39 |
+ release, dev, labels = version_info |
|
40 |
+ |
|
41 |
+ version_parts = [release] |
|
42 |
+ if dev: |
|
43 |
+ if release.endswith('-dev'): |
|
44 |
+ version_parts.append(dev) |
|
45 |
+ elif release.contains('-'): |
|
46 |
+ version_parts.append('.dev{}'.format(dev)) |
|
47 |
+ else: |
|
48 |
+ version_parts.append('-dev{}'.format(dev)) |
|
49 |
+ |
|
50 |
+ if labels: |
|
51 |
+ version_parts.append('+') |
|
52 |
+ version_parts.append(".".join(labels)) |
|
53 |
+ |
|
54 |
+ return "".join(version_parts) |
|
55 |
+ |
|
56 |
+ |
|
57 |
+def get_version_from_git(): |
|
58 |
+ try: |
|
59 |
+ p = subprocess.Popen(['git', 'rev-parse', '--show-toplevel'], |
|
60 |
+ cwd=distr_root, |
|
61 |
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
|
62 |
+ except OSError: |
|
63 |
+ return |
|
64 |
+ if p.wait() != 0: |
|
65 |
+ return |
|
66 |
+ if not os.path.samefile(p.communicate()[0].decode().rstrip('\n'), |
|
67 |
+ distr_root): |
|
68 |
+ # The top-level directory of the current Git repository is not the same |
|
69 |
+ # as the root directory of the Kwant distribution: do not extract the |
|
70 |
+ # version from Git. |
|
71 |
+ return |
|
72 |
+ |
|
73 |
+ # git describe --first-parent does not take into account tags from branches |
|
74 |
+ # that were merged-in. |
|
75 |
+ for opts in [['--first-parent'], []]: |
|
76 |
+ try: |
|
77 |
+ p = subprocess.Popen(['git', 'describe', '--long'] + opts, |
|
78 |
+ cwd=distr_root, |
|
79 |
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
|
80 |
+ except OSError: |
|
81 |
+ return |
|
82 |
+ if p.wait() == 0: |
|
83 |
+ break |
|
84 |
+ else: |
|
85 |
+ return |
|
86 |
+ description = p.communicate()[0].decode().strip('v').rstrip('\n') |
|
87 |
+ |
|
88 |
+ release, dev, git = description.rsplit('-', 2) |
|
89 |
+ labels = [] |
|
90 |
+ if dev == "0": |
|
91 |
+ dev = None |
|
92 |
+ else: |
|
93 |
+ labels.append(git) |
|
94 |
+ |
|
95 |
+ try: |
|
96 |
+ p = subprocess.Popen(['git', 'diff', '--quiet'], cwd=distr_root) |
|
97 |
+ except OSError: |
|
98 |
+ labels.append('confused') # This should never happen. |
|
99 |
+ else: |
|
100 |
+ if p.wait() == 1: |
|
101 |
+ labels.append('dirty') |
|
102 |
+ |
|
103 |
+ return Version(release, dev, labels) |
|
104 |
+ |
|
105 |
+ |
|
106 |
+# TODO: change this logic when there is a git pretty-format |
|
107 |
+# that gives the same output as 'git describe'. |
|
108 |
+# Currently we can only tell the tag the current commit is |
|
109 |
+# pointing to, or its hash (with no version info) |
|
110 |
+# if it is not tagged. |
|
111 |
+def get_version_from_git_archive(version_info): |
|
112 |
+ try: |
|
113 |
+ refnames = version_info['refnames'] |
|
114 |
+ git_hash = version_info['git_hash'] |
|
115 |
+ except KeyError: |
|
116 |
+ # These fields are not present if we are running from an sdist. |
|
117 |
+ # Execution should never reach here, though |
|
118 |
+ return None |
|
119 |
+ |
|
120 |
+ if git_hash.startswith('$Format') or refnames.startswith('$Format'): |
|
121 |
+ # variables not expanded during 'git archive' |
|
122 |
+ return None |
|
123 |
+ |
|
124 |
+ VTAG = 'tag: v' |
|
125 |
+ refs = set(r.strip() for r in refnames.split(",")) |
|
126 |
+ version_tags = set(r[len(VTAG):] for r in refs if r.startswith(VTAG)) |
|
127 |
+ if version_tags: |
|
128 |
+ release, *_ = sorted(version_tags) # prefer e.g. "2.0" over "2.0rc1" |
|
129 |
+ return Version(release, dev=None, labels=None) |
|
130 |
+ else: |
|
131 |
+ return Version('unknown', dev=None, labels=[f'g{git_hash}']) |
|
132 |
+ |
|
133 |
+ |
|
134 |
+version = get_version() |
|
135 |
+ |
|
136 |
+# The following section defines a module global 'cmdclass', |
|
137 |
+# which can be used from setup.py. The 'package_name' and |
|
138 |
+# 'version' module globals are used (but not modified). |
|
139 |
+ |
|
140 |
+def _write_version(fname): |
|
141 |
+ # This could be a hard link, so try to delete it first. Is there any way |
|
142 |
+ # to do this atomically together with opening? |
|
143 |
+ try: |
|
144 |
+ os.remove(fname) |
|
145 |
+ except OSError: |
|
146 |
+ pass |
|
147 |
+ with open(fname, 'w') as f: |
|
148 |
+ f.write("# This file has been created by setup.py.\n" |
|
149 |
+ "version = '{}'\n".format(version)) |
|
150 |
+ |
|
151 |
+ |
|
152 |
+class _build(build_orig): |
|
153 |
+ def run(self): |
|
154 |
+ super().run() |
|
155 |
+ _write_version(os.path.join(self.build_lib, package_name, |
|
156 |
+ STATIC_VERSION_FILE)) |
|
157 |
+ |
|
158 |
+ |
|
159 |
+class _sdist(sdist_orig): |
|
160 |
+ def make_release_tree(self, base_dir, files): |
|
161 |
+ super().make_release_tree(base_dir, files) |
|
162 |
+ _write_version(os.path.join(base_dir, package_name, |
|
163 |
+ STATIC_VERSION_FILE)) |
|
164 |
+ |
|
165 |
+ |
|
166 |
+cmdclass = dict(sdist=_sdist, build=_build) |
0 | 167 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,37 @@ |
1 |
+# -*- coding: utf-8 -*- |
|
2 |
+ |
|
3 |
+from setuptools import setup, find_packages |
|
4 |
+import sys |
|
5 |
+ |
|
6 |
+ |
|
7 |
+# Loads version.py module without importing the whole package. |
|
8 |
+def get_version_and_cmdclass(package_name): |
|
9 |
+ import os |
|
10 |
+ from importlib.util import module_from_spec, spec_from_file_location |
|
11 |
+ spec = spec_from_file_location('version', |
|
12 |
+ os.path.join(package_name, 'version.py')) |
|
13 |
+ module = module_from_spec(spec) |
|
14 |
+ spec.loader.exec_module(module) |
|
15 |
+ return module.version, module.cmdclass |
|
16 |
+ |
|
17 |
+ |
|
18 |
+version, cmdclass = get_version_and_cmdclass('miniver') |
|
19 |
+ |
|
20 |
+ |
|
21 |
+setup( |
|
22 |
+ name='miniver', |
|
23 |
+ description='minimal versioning tool', |
|
24 |
+ version=version, |
|
25 |
+ url='https://github.com/jbweston/miniver', |
|
26 |
+ author='Joseph Weston', |
|
27 |
+ license='CC0', |
|
28 |
+ classifiers=[ |
|
29 |
+ 'Development Status :: 4 - Beta', |
|
30 |
+ 'License :: CC0 1.0 Universal (CC0 1.0) Public Domain Dedication', |
|
31 |
+ 'Topic :: Software Development :: Version Control :: Git', |
|
32 |
+ 'Intended Audience :: Developers', |
|
33 |
+ 'Programming Language :: Python', |
|
34 |
+ ], |
|
35 |
+ packages=find_packages('.'), |
|
36 |
+ cmdclass=cmdclass, |
|
37 |
+) |