Skip to content

Commit c8929af

Browse files
committed
Initial commit
0 parents  commit c8929af

20 files changed

+207
-0
lines changed

.gitignore

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
*.log
2+
*.pot
3+
*.pyc
4+
*.sublime-*
5+
.idea/

MANIFEST.in

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
include tests.py
2+
graft test_data

README.rst

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
==============
2+
versionfromgit
3+
==============
4+
5+
6+
This package lets you use git tags to version python projects that don't use setup.py or other distutils. The idea is
7+
to only use a requirements file to pin dependancies as is common for django or other web applications that need to get
8+
'deployed' as opposed to 'installed'.
9+
10+
It doesn't write to any file to update the version so no changes need to be re-committed.
11+
12+
Usage
13+
=====
14+
15+
16+
``<package>/__init__.py``:
17+
18+
.. code-block:: python
19+
20+
from versionfromgit import versions_from_git
21+
22+
__version__ = versions_from_git(tag_prefix="v")['version']
23+
del versions_from_git

setup.py

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
'''Setup file for versionfromgit.'''
2+
from setuptools import setup
3+
from versionfromgit import __version__
4+
5+
setup(
6+
name='versionfromgit',
7+
version=__version__,
8+
packages=['versionfromgit'],
9+
description='Utility to version non-distutils python projects using git tags.',
10+
author='Dries Desmet',
11+
author_email='[email protected]',
12+
include_package_data=True,
13+
test_suite='tests',
14+
classifiers=[
15+
'Development Status :: 3 - Alpha',
16+
'Intended Audience :: Developers',
17+
'License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)',
18+
'Programming Language :: Python',
19+
'Programming Language :: Python :: 2.7',
20+
'Topic :: Software Development :: Build Tools',
21+
'Topic :: Software Development :: Version Control',
22+
],
23+
)
+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Initial Commit.

test_data/repo1/dot.git/HEAD

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ref: refs/heads/master

test_data/repo1/dot.git/config

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
[core]
2+
repositoryformatversion = 0
3+
filemode = true
4+
bare = false
5+
logallrefupdates = true

test_data/repo1/dot.git/description

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Unnamed repository; edit this file 'description' to name the repository.

test_data/repo1/dot.git/index

112 Bytes
Binary file not shown.

test_data/repo1/dot.git/info/exclude

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# git ls-files --others --exclude-from=.git/info/exclude
2+
# Lines that start with '#' are comments.
3+
# For a project mostly in C, the following would be a good set of
4+
# exclude patterns (uncomment them if you want to use them):
5+
# *.[oa]
6+
# *~

test_data/repo1/dot.git/logs/HEAD

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
0000000000000000000000000000000000000000 f6bc903b304e1049f8a3420ac6df8a241443dba6 Mike Bryant <[email protected]> 1392742529 +0000 commit (initial): Initial Commit.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
0000000000000000000000000000000000000000 f6bc903b304e1049f8a3420ac6df8a241443dba6 Mike Bryant <[email protected]> 1392742529 +0000 commit (initial): Initial Commit.
Binary file not shown.
Binary file not shown.

test_data/repo1/dot.git/objects/f6/bc903b304e1049f8a3420ac6df8a241443dba6

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
x��K
2+
1D]��B�&"�+"� cf d��1G����h��t��������ǧƔ]T��^1E�H���Hk-�eb��O�;��?{ +�u:��h�3� ��&A��uq�K/�ױ#���<�
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
f6bc903b304e1049f8a3420ac6df8a241443dba6
+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
f6bc903b304e1049f8a3420ac6df8a241443dba6

test_data/repo1/mymodule/__init__.py

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
from versionfromgit import versions_from_git
2+
3+
__version__ = versions_from_git(tag_prefix="v")['version']
4+
del versions_from_git

tests.py

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
'''Tests for gitversion.'''
2+
# pylint: disable=C0103
3+
# pylint: disable=R0904
4+
5+
import contextlib
6+
import versionfromgit
7+
import os
8+
import shutil
9+
import tempfile
10+
import unittest
11+
import logging
12+
13+
LOGGER = logging.getLogger(__name__)
14+
15+
16+
class GitVersionCase(unittest.TestCase):
17+
18+
'''Test the correct versions are detected (and written, if applicable).'''
19+
20+
repos = {
21+
'repo1': {'versionstring': '0.1'},
22+
}
23+
24+
def setUp(self):
25+
26+
self.tempdir = tempfile.mkdtemp()
27+
LOGGER.debug("Created temporary directory %r", self.tempdir)
28+
self.testdir = os.path.join(self.tempdir, 'repo')
29+
self.gitdir = os.path.join(self.testdir, '.git')
30+
31+
def tearDown(self):
32+
33+
LOGGER.debug('Removing %r', self.tempdir)
34+
shutil.rmtree(self.tempdir)
35+
36+
37+
def test_git_describe(self):
38+
'''
39+
Tests that the version is determined correctly.
40+
'''
41+
42+
for repo in self.repos:
43+
LOGGER.debug('investigating %r', repo)

versionfromgit/__init__.py

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
"""
2+
This module offers a way of getting a version string using git and returns nothing if git isn't used.
3+
4+
I first thought of using setup.py to put the version string and the idea came from here:
5+
https://blog.mozilla.org/warner/2012/01/31/version-string-management-in-python-introducing-python-versioneer/
6+
7+
but then I reckoned using setup.py is cumbersome for python web applications to keep in sync.
8+
Also, setup.py should not contain explicit versions but mostly implicit version ranges.
9+
10+
Requirements.txt is a better fit to recreate an explicit environment. With that, I'm not using source distributions or
11+
other tarballs for deploying, but just use git to update a remote deployment fast.
12+
13+
Basically, this module is a stripped down version of Brian Warner's python-versioneer and assumes you only want to
14+
install using pip install -r requirements.txt. Distutils or similar simply won't work (but are broken anyway).
15+
16+
"""
17+
18+
__version__ = '0.1-alpha'
19+
20+
import sys
21+
import subprocess
22+
import errno
23+
24+
def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False):
25+
assert isinstance(commands, list)
26+
p = None
27+
for c in commands:
28+
try:
29+
# remember shell=False, so use git.cmd on windows, not just git
30+
p = subprocess.Popen([c] + args, cwd=cwd, stdout=subprocess.PIPE,
31+
stderr=(subprocess.PIPE if hide_stderr
32+
else None))
33+
break
34+
except EnvironmentError:
35+
e = sys.exc_info()[1]
36+
if e.errno == errno.ENOENT:
37+
continue
38+
if verbose:
39+
print("unable to run %s" % args[0])
40+
print(e)
41+
return None
42+
else:
43+
if verbose:
44+
print("unable to find command, tried %s" % (commands,))
45+
return None
46+
stdout = p.communicate()[0].strip()
47+
if sys.version >= '3':
48+
stdout = stdout.decode()
49+
if p.returncode != 0:
50+
if verbose:
51+
print("unable to run %s (error)" % args[0])
52+
return None
53+
return stdout
54+
55+
56+
def versions_from_git(tag_prefix="", verbose=False):
57+
"""
58+
Returns a dictionary with a version and a full version.
59+
60+
A 'version' is based on git describe and strips 'tag_prefix'.
61+
A 'full version' is simply the complete revision number with '-dirty' attached if we are in between commits.
62+
63+
@param tag_prefix: strip this tag_prefix to get version eg: for v0.1 return 0.1
64+
@param verbose:
65+
@return: {'version': version, 'full': fullversion}
66+
"""
67+
68+
GITS = ["git"]
69+
if sys.platform == "win32":
70+
GITS = ["git.cmd", "git.exe"]
71+
stdout = run_command(GITS, ["describe", "--tags", "--dirty", "--always"])
72+
if stdout is None:
73+
return {}
74+
if not stdout.startswith(tag_prefix):
75+
# simply don't strip the prefix
76+
if verbose:
77+
print("tag '%s' doesn't start with prefix '%s'" % (stdout, tag_prefix))
78+
tag = stdout
79+
else:
80+
tag = stdout[len(tag_prefix):]
81+
stdout = run_command(GITS, ["rev-parse", "HEAD"])
82+
if stdout is None:
83+
return {}
84+
full = stdout.strip()
85+
if tag.endswith("-dirty"):
86+
full += "-dirty"
87+
return {"version": tag, "full": full}

0 commit comments

Comments
 (0)