Browse code

initial commit

Joseph Weston authored on 22/02/2018 01:16:42
Showing 8 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1 @@
1
+miniver/_static_version.py export-subst
0 2
new file mode 100644
... ...
@@ -0,0 +1,5 @@
1
+*.egg-info
2
+build
3
+dist
4
+**/*/__pycache__
5
+*.pyc
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 74
new file mode 100644
... ...
@@ -0,0 +1,3 @@
1
+from . import version
2
+__version__ = version.version
3
+del version
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
+)