diff options
author | Richard Maw <richard.maw@codethink.co.uk> | 2013-01-24 15:49:10 +0000 |
---|---|---|
committer | Richard Maw <richard.maw@codethink.co.uk> | 2013-01-28 13:04:26 +0000 |
commit | 6d50cfe8df892b10dd5c1312e013d8e228648bc7 (patch) | |
tree | ea62bcff16e3e423835d4ad8776526ec68214574 /setup.py | |
parent | 0a6ab406c667d8b542ee6008349423a83896297b (diff) | |
download | morph-6d50cfe8df892b10dd5c1312e013d8e228648bc7.tar.gz |
Make morph get its version from git.
When morph is built, it writes various version information from git
into morphlib.
When morphlib is loaded it attempts to read this version information.
if it cannot be found then it checks whether morphlib is being run from
inside a git checkout, if it is then it reads the information that way.
If it isn't in a git checkout then it raises an exception as builds made
in such a fashion are not reproducible.
The git version information retained is:
1. The output of git describe
This is a relatively human-friendly way of knowing a version and
gives a reasonably short output string.
This will end with `-unreproducible` if there were uncommitted changes.
2. The commit sha1, so the exact part of Morph's history can be found
3. The tree sha1, so if the branch has been rebased rather than
merged such that the commit is lost, you may still be able to find
it, though it requires a git-wizard to check it out
4. The branch of morph, so that it's easier to see if the
Further possible changes to increase reproducibility include:
1. Not allowing `python setup.py build` if there are uncommitted changes
2. Failing to run with uncommitted changes (recommended against since it
will just annoy developers who are making changes to morph, and make
them commit just to shut it up, then destroy the history later)
Requiring an extra flag to build in this case may work better.
3. Reading the uncommitted changes into a tree object and including
that would allow it to be recovered if the tree was later committed.
4. Checking whether the commit has been pushed upstream as well.
Too annoying to work.
Diffstat (limited to 'setup.py')
-rw-r--r-- | setup.py | 53 |
1 files changed, 48 insertions, 5 deletions
@@ -1,4 +1,4 @@ -# Copyright (C) 2011, 2012 Codethink Limited +# Copyright (C) 2011, 2012, 2013 Codethink Limited # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -23,23 +23,58 @@ from distutils.command.build import build from distutils.command.clean import clean import glob import os +import os.path import shutil import subprocess +import cliapp + import morphlib -class GenerateManpage(build): +class GenerateResources(build): def run(self): + if not self.dry_run: + self.generate_manpages() + self.generate_version() build.run(self) - print 'building manpages' + + def generate_manpages(self): + self.announce('building manpages') for x in ['morph']: with open('%s.1' % x, 'w') as f: subprocess.check_call(['python', x, '--generate-manpage=%s.1.in' % x, '--output=%s.1' % x], stdout=f) + def generate_version(self): + target_dir = os.path.join(self.build_lib, 'morphlib') + + self.mkpath(target_dir) + + def save_git_info(filename, *args): + path = os.path.join(target_dir, filename) + command = ['git'] + list(args) + + self.announce('generating %s with %s' % + (path, ' '.join(command))) + + with open(os.path.join(target_dir, filename), 'w') as f: + p = subprocess.Popen(command, + cwd=os.path.dirname(__file__), + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + o = p.communicate() + if p.returncode: + raise subprocess.CalledProcessError(p.returncode, command) + f.write(o[0].strip()) + + save_git_info('version', 'describe', '--always', + '--dirty=-unreproducible') + save_git_info('commit', 'rev-parse', 'HEAD^{commit}') + save_git_info('tree', 'rev-parse', 'HEAD^{tree}') + save_git_info('ref', 'rev-parse', '--symbolic-full-name', 'HEAD') class Clean(clean): @@ -104,10 +139,18 @@ FIXME url='http://www.baserock.org/', scripts=['morph'], packages=['morphlib'], - package_data={'morphlib': ['plugins/*_plugin.py']}, + package_data={ + 'morphlib': [ + 'plugins/*_plugin.py', + 'version', + 'commit', + 'tree', + 'ref', + ] + }, data_files=[('share/man/man1', glob.glob('*.[1-8]'))], cmdclass={ - 'build': GenerateManpage, + 'build': GenerateResources, 'check': Check, 'clean': Clean, }) |