From 367e1c3ccb07c6888ddcb3365d38719ed751d825 Mon Sep 17 00:00:00 2001 From: Roman Valls Guimera Date: Mon, 25 Aug 2014 14:16:13 +0200 Subject: [PATCH 1/6] Working install_requires version of setup.py --- setup.py | 160 ++----------------------------------------------------- 1 file changed, 3 insertions(+), 157 deletions(-) diff --git a/setup.py b/setup.py index 3d84120d0e..1898a124d2 100755 --- a/setup.py +++ b/setup.py @@ -114,137 +114,6 @@ def _add_append_key(in_dict, key, value): in_dict[key] = [in_dict[key]] in_dict[key].append(value) -# Dependency checks -def package_check(pkg_name, version=None, - optional=False, - checker=LooseVersion, - version_getter=None, - messages=None, - setuptools_args=None, - pypi_pkg_name=None - ): - ''' Check if package `pkg_name` is present and has good enough version - - Has two modes of operation. If `setuptools_args` is None (the default), - raise an error for missing non-optional dependencies and log warnings for - missing optional dependencies. If `setuptools_args` is a dict, then fill - ``install_requires`` key value with any missing non-optional dependencies, - and the ``extras_requires`` key value with optional dependencies. - - This allows us to work with and without setuptools. It also means we can - check for packages that have not been installed with setuptools to avoid - installing them again. - - Parameters - ---------- - pkg_name : str - name of package as imported into python - version : {None, str}, optional - minimum version of the package that we require. If None, we don't - check the version. Default is None - optional : bool or str, optional - If ``bool(optional)`` is False, raise error for absent package or wrong - version; otherwise warn. If ``setuptools_args`` is not None, and - ``bool(optional)`` is not False, then `optional` should be a string - giving the feature name for the ``extras_require`` argument to setup. - checker : callable, optional - callable with which to return comparable thing from version - string. Default is ``distutils.version.LooseVersion`` - version_getter : {None, callable}: - Callable that takes `pkg_name` as argument, and returns the - package version string - as in:: - - ``version = version_getter(pkg_name)`` - - If None, equivalent to:: - - mod = __import__(pkg_name); version = mod.__version__`` - messages : None or dict, optional - dictionary giving output messages - setuptools_args : None or dict - If None, raise errors / warnings for missing non-optional / optional - dependencies. If dict fill key values ``install_requires`` and - ``extras_require`` for non-optional and optional dependencies. - pypi_pkg_name : None or string - When the pypi package name differs from the installed module. This is the - case with the package python-dateutil which installs as dateutil. - ''' - setuptools_mode = not setuptools_args is None - optional_tf = bool(optional) - if version_getter is None: - def version_getter(pkg_name): - mod = __import__(pkg_name) - return mod.__version__ - if messages is None: - messages = {} - msgs = { - 'missing': 'Cannot import package "%s" - is it installed?', - 'missing opt': 'Missing optional package "%s"', - 'opt suffix' : '; you may get run-time errors', - 'version too old': 'You have version %s of package "%s"' - ' but we need version >= %s', } - msgs.update(messages) - status, have_version = _package_status(pkg_name, - version, - version_getter, - checker) - if pypi_pkg_name: - pkg_name = pypi_pkg_name - - if status == 'satisfied': - return - if not setuptools_mode: - if status == 'missing': - if not optional_tf: - raise RuntimeError(msgs['missing'] % pkg_name) - log.warn(msgs['missing opt'] % pkg_name + - msgs['opt suffix']) - return - elif status == 'no-version': - raise RuntimeError('Cannot find version for %s' % pkg_name) - assert status == 'low-version' - if not optional_tf: - raise RuntimeError(msgs['version too old'] % (have_version, - pkg_name, - version)) - log.warn(msgs['version too old'] % (have_version, - pkg_name, - version) - + msgs['opt suffix']) - return - # setuptools mode - if optional_tf and not isinstance(optional, string_types): - raise RuntimeError('Not-False optional arg should be string') - dependency = pkg_name - - if version: - dependency += '>=' + version - if optional_tf: - if not 'extras_require' in setuptools_args: - setuptools_args['extras_require'] = {} - _add_append_key(setuptools_args['extras_require'], - optional, - dependency) - return - _add_append_key(setuptools_args, 'install_requires', dependency) - return - - -def _package_status(pkg_name, version, version_getter, checker): - try: - __import__(pkg_name) - except ImportError: - return 'missing', None - if not version: - return 'satisfied', None - try: - have_version = version_getter(pkg_name) - except AttributeError: - return 'no-version', None - if checker(have_version) < checker(version): - return 'low-version', have_version - return 'satisfied', have_version - ## END - COPIED FROM NIBABEL from build_docs import cmdclass, INFO_VARS @@ -269,31 +138,6 @@ def configuration(parent_package='',top_path=None): config.add_subpackage('nipype', 'nipype') return config -# Prepare setuptools args -if 'setuptools' in sys.modules: - extra_setuptools_args = dict( - tests_require=['nose'], - test_suite='nose.collector', - zip_safe=False, - extras_require = dict( - doc='Sphinx>=0.3', - test='nose>=0.10.1'), - ) - pkg_chk = partial(package_check, setuptools_args = extra_setuptools_args) -else: - extra_setuptools_args = {} - pkg_chk = package_check - -# Hard and soft dependency checking -pkg_chk('networkx', INFO_VARS['NETWORKX_MIN_VERSION']) -pkg_chk('nibabel', INFO_VARS['NIBABEL_MIN_VERSION']) -pkg_chk('numpy', INFO_VARS['NUMPY_MIN_VERSION']) -pkg_chk('scipy', INFO_VARS['SCIPY_MIN_VERSION']) -pkg_chk('traits', INFO_VARS['TRAITS_MIN_VERSION']) -pkg_chk('nose', INFO_VARS['NOSE_MIN_VERSION']) -pkg_chk('dateutil', INFO_VARS['DATEUTIL_MIN_VERSION'], - pypi_pkg_name='python-dateutil') - ################################################################################ # Import the documentation building classes. @@ -324,8 +168,10 @@ def main(**extra_args): version=INFO_VARS['VERSION'], configuration=configuration, cmdclass=cmdclass, + install_requires=['networkx', 'nibabel', 'numpy', 'scipy', 'traits', + 'nose', 'dateutils'], scripts=glob('bin/*'), **extra_args) if __name__ == "__main__": - main(**extra_setuptools_args) + main() From 60d9a171825b832501d01e701275bfad26df2aab Mon Sep 17 00:00:00 2001 From: Roman Valls Guimera Date: Mon, 25 Aug 2014 15:56:32 +0200 Subject: [PATCH 2/6] import setuptools (supports install_requires) instead of distutils --- setup.py | 139 +------- setup_egg.py | 23 -- versioneer.py | 875 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 890 insertions(+), 147 deletions(-) delete mode 100755 setup_egg.py create mode 100644 versioneer.py diff --git a/setup.py b/setup.py index 1898a124d2..1c1c1ecac3 100755 --- a/setup.py +++ b/setup.py @@ -6,19 +6,13 @@ Nipype intends to create python interfaces to other neuroimaging packages and create an API for specifying a full analysis pipeline in python. - -Much of the machinery at the beginning of this file has been copied over from -nibabel denoted by ## START - COPIED FROM NIBABEL and a corresponding ## END - """ import sys from glob import glob import os - -## START - COPIED FROM NIBABEL -from os.path import join as pjoin -from functools import partial +from pip.req import parse_requirements +import versioneer PY3 = sys.version_info[0] >= 3 if PY3: @@ -34,125 +28,24 @@ # update it when the contents of directories change. if os.path.exists('MANIFEST'): os.remove('MANIFEST') -# For some commands, use setuptools. -if len(set(('develop', 'bdist_egg', 'bdist_rpm', 'bdist', 'bdist_dumb', - 'install_egg_info', 'egg_info', 'easy_install', 'bdist_wheel', - 'bdist_mpkg')).intersection(sys.argv)) > 0: - # setup_egg imports setuptools setup, thus monkeypatching distutils. - import setup_egg - -from distutils.core import setup - -from distutils.version import LooseVersion +from setuptools import setup, find_packages from distutils.command.build_py import build_py -from distutils import log - -def get_comrec_build(pkg_dir, build_cmd=build_py): - """ Return extended build command class for recording commit - - The extended command tries to run git to find the current commit, getting - the empty string if it fails. It then writes the commit hash into a file - in the `pkg_dir` path, named ``COMMIT_INFO.txt``. - - In due course this information can be used by the package after it is - installed, to tell you what commit it was installed from if known. - - To make use of this system, you need a package with a COMMIT_INFO.txt file - - e.g. ``myproject/COMMIT_INFO.txt`` - that might well look like this:: - - # This is an ini file that may contain information about the code state - [commit hash] - # The line below may contain a valid hash if it has been substituted - during 'git archive' archive_subst_hash=$Format:%h$ - # This line may be modified by the install process - install_hash= - - The COMMIT_INFO file above is also designed to be used with git substitution - - so you probably also want a ``.gitattributes`` file in the root directory - of your working tree that contains something like this:: - - myproject/COMMIT_INFO.txt export-subst - - That will cause the ``COMMIT_INFO.txt`` file to get filled in by ``git - archive`` - useful in case someone makes such an archive - for example with - via the github 'download source' button. - - Although all the above will work as is, you might consider having something - like a ``get_info()`` function in your package to display the commit - information at the terminal. See the ``pkg_info.py`` module in the nipy - package for an example. - """ - class MyBuildPy(build_cmd): - ''' Subclass to write commit data into installation tree ''' - def run(self): - build_cmd.run(self) - import subprocess - proc = subprocess.Popen('git rev-parse HEAD', - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - shell=True) - repo_commit, _ = proc.communicate() - # Fix for python 3 - repo_commit = str(repo_commit) - # We write the installation commit even if it's empty - cfg_parser = ConfigParser() - cfg_parser.read(pjoin(pkg_dir, 'COMMIT_INFO.txt')) - cfg_parser.set('commit hash', 'install_hash', repo_commit) - out_pth = pjoin(self.build_lib, pkg_dir, 'COMMIT_INFO.txt') - cfg_parser.write(open(out_pth, 'wt')) - return MyBuildPy - -def _add_append_key(in_dict, key, value): - """ Helper for appending dependencies to setuptools args """ - # If in_dict[key] does not exist, create it - # If in_dict[key] is a string, make it len 1 list of strings - # Append value to in_dict[key] list - if key not in in_dict: - in_dict[key] = [] - elif isinstance(in_dict[key], string_types): - in_dict[key] = [in_dict[key]] - in_dict[key].append(value) - -## END - COPIED FROM NIBABEL +# XXX: write COMMIT_INFO.txt with versioneer +versioneer.VCS = 'git' +versioneer.versionfile_source = 'src/nipype/_version.py' +versioneer.versionfile_build = 'nipype/_version.py' +versioneer.tag_prefix = '' # tags are like 1.2.0 +versioneer.parentdir_prefix = 'nipype-' # dirname like 'myproject-1.2.0' from build_docs import cmdclass, INFO_VARS -# Add custom commit-recording build command -cmdclass['build_py'] = get_comrec_build('nipype') - -def configuration(parent_package='',top_path=None): - from numpy.distutils.misc_util import Configuration - - config = Configuration(None, parent_package, top_path) - config.set_options(ignore_setup_xxx_py=True, - assume_default_configuration=True, - delegate_options_to_subpackages=True, - quiet=True) - # The quiet=True option will silence all of the name setting warnings: - # Ignoring attempt to set 'name' (from 'nipy.core' to - # 'nipy.core.image') - # Robert Kern recommends setting quiet=True on the numpy list, stating - # these messages are probably only used in debugging numpy distutils. - config.get_version('nipype/__init__.py') # sets config.version - config.add_subpackage('nipype', 'nipype') - return config - -################################################################################ -# Import the documentation building classes. - -try: - from build_docs import cmdclass -except ImportError: - """ Pass by the doc build gracefully if sphinx is not installed """ - print "Sphinx is not installed, docs cannot be built" - cmdclass = {} - +#XXX: Build docs too -################################################################################ +install_reqs = parse_requirements('requirements.txt') +reqs = [str(ir.req) for ir in install_reqs] def main(**extra_args): - from numpy.distutils.core import setup setup(name=INFO_VARS['NAME'], maintainer=INFO_VARS['MAINTAINER'], maintainer_email=INFO_VARS['MAINTAINER_EMAIL'], @@ -165,12 +58,10 @@ def main(**extra_args): author=INFO_VARS['AUTHOR'], author_email=INFO_VARS['AUTHOR_EMAIL'], platforms=INFO_VARS['PLATFORMS'], - version=INFO_VARS['VERSION'], - configuration=configuration, - cmdclass=cmdclass, - install_requires=['networkx', 'nibabel', 'numpy', 'scipy', 'traits', - 'nose', 'dateutils'], + version=versioneer.get_version(), + cmdclass=versioneer.get_cmdclass(), scripts=glob('bin/*'), + install_requires=reqs, **extra_args) if __name__ == "__main__": diff --git a/setup_egg.py b/setup_egg.py deleted file mode 100755 index 68ff5b15a1..0000000000 --- a/setup_egg.py +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env python -# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*- -# vi: set ft=python sts=4 ts=4 sw=4 et: -"""Wrapper to run setup.py using setuptools.""" - -from setuptools import setup - -################################################################################ -# Call the setup.py script, injecting the setuptools-specific arguments. - -extra_setuptools_args = dict( - tests_require=['nose'], - test_suite='nose.collector', - zip_safe=False, - ) - - -if __name__ == '__main__': - execfile('setup.py', dict(__name__='__main__', - extra_setuptools_args=extra_setuptools_args)) - - - diff --git a/versioneer.py b/versioneer.py new file mode 100644 index 0000000000..03193e8814 --- /dev/null +++ b/versioneer.py @@ -0,0 +1,875 @@ + +# Version: 0.11 + +""" +The Versioneer +============== + +* like a rocketeer, but for versions! +* https://github.com/warner/python-versioneer +* Brian Warner +* License: Public Domain +* Compatible With: python2.6, 2.7, 3.2, 3.3, 3.4, and pypy + +[![Build Status](https://travis-ci.org/warner/python-versioneer.png?branch=master)](https://travis-ci.org/warner/python-versioneer) + +This is a tool for managing a recorded version number in distutils-based +python projects. The goal is to remove the tedious and error-prone "update +the embedded version string" step from your release process. Making a new +release should be as easy as recording a new tag in your version-control +system, and maybe making new tarballs. + + +## Quick Install + +* `pip install versioneer` to somewhere to your $PATH +* run `versioneer-installer` in your source tree: this installs `versioneer.py` +* follow the instructions below (also in the `versioneer.py` docstring) + +## Version Identifiers + +Source trees come from a variety of places: + +* a version-control system checkout (mostly used by developers) +* a nightly tarball, produced by build automation +* a snapshot tarball, produced by a web-based VCS browser, like github's + "tarball from tag" feature +* a release tarball, produced by "setup.py sdist", distributed through PyPI + +Within each source tree, the version identifier (either a string or a number, +this tool is format-agnostic) can come from a variety of places: + +* ask the VCS tool itself, e.g. "git describe" (for checkouts), which knows + about recent "tags" and an absolute revision-id +* the name of the directory into which the tarball was unpacked +* an expanded VCS keyword ($Id$, etc) +* a `_version.py` created by some earlier build step + +For released software, the version identifier is closely related to a VCS +tag. Some projects use tag names that include more than just the version +string (e.g. "myproject-1.2" instead of just "1.2"), in which case the tool +needs to strip the tag prefix to extract the version identifier. For +unreleased software (between tags), the version identifier should provide +enough information to help developers recreate the same tree, while also +giving them an idea of roughly how old the tree is (after version 1.2, before +version 1.3). Many VCS systems can report a description that captures this, +for example 'git describe --tags --dirty --always' reports things like +"0.7-1-g574ab98-dirty" to indicate that the checkout is one revision past the +0.7 tag, has a unique revision id of "574ab98", and is "dirty" (it has +uncommitted changes. + +The version identifier is used for multiple purposes: + +* to allow the module to self-identify its version: `myproject.__version__` +* to choose a name and prefix for a 'setup.py sdist' tarball + +## Theory of Operation + +Versioneer works by adding a special `_version.py` file into your source +tree, where your `__init__.py` can import it. This `_version.py` knows how to +dynamically ask the VCS tool for version information at import time. However, +when you use "setup.py build" or "setup.py sdist", `_version.py` in the new +copy is replaced by a small static file that contains just the generated +version data. + +`_version.py` also contains `$Revision$` markers, and the installation +process marks `_version.py` to have this marker rewritten with a tag name +during the "git archive" command. As a result, generated tarballs will +contain enough information to get the proper version. + + +## Installation + +First, decide on values for the following configuration variables: + +* `VCS`: the version control system you use. Currently accepts "git". + +* `versionfile_source`: + + A project-relative pathname into which the generated version strings should + be written. This is usually a `_version.py` next to your project's main + `__init__.py` file. If your project uses `src/myproject/__init__.py`, this + should be `src/myproject/_version.py`. This file should be checked in to + your VCS as usual: the copy created below by `setup.py versioneer` will + include code that parses expanded VCS keywords in generated tarballs. The + 'build' and 'sdist' commands will replace it with a copy that has just the + calculated version string. + +* `versionfile_build`: + + Like `versionfile_source`, but relative to the build directory instead of + the source directory. These will differ when your setup.py uses + 'package_dir='. If you have `package_dir={'myproject': 'src/myproject'}`, + then you will probably have `versionfile_build='myproject/_version.py'` and + `versionfile_source='src/myproject/_version.py'`. + +* `tag_prefix`: + + a string, like 'PROJECTNAME-', which appears at the start of all VCS tags. + If your tags look like 'myproject-1.2.0', then you should use + tag_prefix='myproject-'. If you use unprefixed tags like '1.2.0', this + should be an empty string. + +* `parentdir_prefix`: + + a string, frequently the same as tag_prefix, which appears at the start of + all unpacked tarball filenames. If your tarball unpacks into + 'myproject-1.2.0', this should be 'myproject-'. + +This tool provides one script, named `versioneer-installer`. That script does +one thing: write a copy of `versioneer.py` into the current directory. + +To versioneer-enable your project: + +* 1: Run `versioneer-installer` to copy `versioneer.py` into the top of your + source tree. + +* 2: add the following lines to the top of your `setup.py`, with the + configuration values you decided earlier: + + import versioneer + versioneer.VCS = 'git' + versioneer.versionfile_source = 'src/myproject/_version.py' + versioneer.versionfile_build = 'myproject/_version.py' + versioneer.tag_prefix = '' # tags are like 1.2.0 + versioneer.parentdir_prefix = 'myproject-' # dirname like 'myproject-1.2.0' + +* 3: add the following arguments to the setup() call in your setup.py: + + version=versioneer.get_version(), + cmdclass=versioneer.get_cmdclass(), + +* 4: now run `setup.py versioneer`, which will create `_version.py`, and + will modify your `__init__.py` to define `__version__` (by calling a + function from `_version.py`). It will also modify your `MANIFEST.in` to + include both `versioneer.py` and the generated `_version.py` in sdist + tarballs. + +* 5: commit these changes to your VCS. To make sure you won't forget, + `setup.py versioneer` will mark everything it touched for addition. + +## Post-Installation Usage + +Once established, all uses of your tree from a VCS checkout should get the +current version string. All generated tarballs should include an embedded +version string (so users who unpack them will not need a VCS tool installed). + +If you distribute your project through PyPI, then the release process should +boil down to two steps: + +* 1: git tag 1.0 +* 2: python setup.py register sdist upload + +If you distribute it through github (i.e. users use github to generate +tarballs with `git archive`), the process is: + +* 1: git tag 1.0 +* 2: git push; git push --tags + +Currently, all version strings must be based upon a tag. Versioneer will +report "unknown" until your tree has at least one tag in its history. This +restriction will be fixed eventually (see issue #12). + +## Version-String Flavors + +Code which uses Versioneer can learn about its version string at runtime by +importing `_version` from your main `__init__.py` file and running the +`get_versions()` function. From the "outside" (e.g. in `setup.py`), you can +import the top-level `versioneer.py` and run `get_versions()`. + +Both functions return a dictionary with different keys for different flavors +of the version string: + +* `['version']`: condensed tag+distance+shortid+dirty identifier. For git, + this uses the output of `git describe --tags --dirty --always` but strips + the tag_prefix. For example "0.11-2-g1076c97-dirty" indicates that the tree + is like the "1076c97" commit but has uncommitted changes ("-dirty"), and + that this commit is two revisions ("-2-") beyond the "0.11" tag. For + released software (exactly equal to a known tag), the identifier will only + contain the stripped tag, e.g. "0.11". + +* `['full']`: detailed revision identifier. For Git, this is the full SHA1 + commit id, followed by "-dirty" if the tree contains uncommitted changes, + e.g. "1076c978a8d3cfc70f408fe5974aa6c092c949ac-dirty". + +Some variants are more useful than others. Including `full` in a bug report +should allow developers to reconstruct the exact code being tested (or +indicate the presence of local changes that should be shared with the +developers). `version` is suitable for display in an "about" box or a CLI +`--version` output: it can be easily compared against release notes and lists +of bugs fixed in various releases. + +In the future, this will also include a +[PEP-0440](http://legacy.python.org/dev/peps/pep-0440/) -compatible flavor +(e.g. `1.2.post0.dev123`). This loses a lot of information (and has no room +for a hash-based revision id), but is safe to use in a `setup.py` +"`version=`" argument. It also enables tools like *pip* to compare version +strings and evaluate compatibility constraint declarations. + +The `setup.py versioneer` command adds the following text to your +`__init__.py` to place a basic version in `YOURPROJECT.__version__`: + + from ._version import get_versions + __version = get_versions()['version'] + del get_versions + +## Updating Versioneer + +To upgrade your project to a new release of Versioneer, do the following: + +* install the new Versioneer (`pip install -U versioneer` or equivalent) +* re-run `versioneer-installer` in your source tree to replace your copy of + `versioneer.py` +* edit `setup.py`, if necessary, to include any new configuration settings + indicated by the release notes +* re-run `setup.py versioneer` to replace `SRC/_version.py` +* commit any changed files + +### Upgrading from 0.10 to 0.11 + +You must add a `versioneer.VCS = "git"` to your `setup.py` before re-running +`setup.py versioneer`. This will enable the use of additional version-control +systems (SVN, etc) in the future. + +## Future Directions + +This tool is designed to make it easily extended to other version-control +systems: all VCS-specific components are in separate directories like +src/git/ . The top-level `versioneer.py` script is assembled from these +components by running make-versioneer.py . In the future, make-versioneer.py +will take a VCS name as an argument, and will construct a version of +`versioneer.py` that is specific to the given VCS. It might also take the +configuration arguments that are currently provided manually during +installation by editing setup.py . Alternatively, it might go the other +direction and include code from all supported VCS systems, reducing the +number of intermediate scripts. + + +## License + +To make Versioneer easier to embed, all its code is hereby released into the +public domain. The `_version.py` that it creates is also in the public +domain. + +""" + +import os, sys, re, subprocess, errno +from distutils.core import Command +from distutils.command.sdist import sdist as _sdist +from distutils.command.build import build as _build + +# these configuration settings will be overridden by setup.py after it +# imports us +versionfile_source = None +versionfile_build = None +tag_prefix = None +parentdir_prefix = None +VCS = None + +# these dictionaries contain VCS-specific tools +LONG_VERSION_PY = {} + +def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False): + assert isinstance(commands, list) + p = None + for c in commands: + try: + # remember shell=False, so use git.cmd on windows, not just git + p = subprocess.Popen([c] + args, cwd=cwd, stdout=subprocess.PIPE, + stderr=(subprocess.PIPE if hide_stderr + else None)) + break + except EnvironmentError: + e = sys.exc_info()[1] + if e.errno == errno.ENOENT: + continue + if verbose: + print("unable to run %s" % args[0]) + print(e) + return None + else: + if verbose: + print("unable to find command, tried %s" % (commands,)) + return None + stdout = p.communicate()[0].strip() + if sys.version >= '3': + stdout = stdout.decode() + if p.returncode != 0: + if verbose: + print("unable to run %s (error)" % args[0]) + return None + return stdout + +LONG_VERSION_PY['git'] = ''' +# This file helps to compute a version number in source trees obtained from +# git-archive tarball (such as those provided by githubs download-from-tag +# feature). Distribution tarballs (built by setup.py sdist) and build +# directories (produced by setup.py build) will contain a much shorter file +# that just contains the computed version number. + +# This file is released into the public domain. Generated by +# versioneer-0.11 (https://github.com/warner/python-versioneer) + +# these strings will be replaced by git during git-archive +git_refnames = "%(DOLLAR)sFormat:%%d%(DOLLAR)s" +git_full = "%(DOLLAR)sFormat:%%H%(DOLLAR)s" + +# these strings are filled in when 'setup.py versioneer' creates _version.py +tag_prefix = "%(TAG_PREFIX)s" +parentdir_prefix = "%(PARENTDIR_PREFIX)s" +versionfile_source = "%(VERSIONFILE_SOURCE)s" + +import os, sys, re, subprocess, errno + +def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False): + assert isinstance(commands, list) + p = None + for c in commands: + try: + # remember shell=False, so use git.cmd on windows, not just git + p = subprocess.Popen([c] + args, cwd=cwd, stdout=subprocess.PIPE, + stderr=(subprocess.PIPE if hide_stderr + else None)) + break + except EnvironmentError: + e = sys.exc_info()[1] + if e.errno == errno.ENOENT: + continue + if verbose: + print("unable to run %%s" %% args[0]) + print(e) + return None + else: + if verbose: + print("unable to find command, tried %%s" %% (commands,)) + return None + stdout = p.communicate()[0].strip() + if sys.version >= '3': + stdout = stdout.decode() + if p.returncode != 0: + if verbose: + print("unable to run %%s (error)" %% args[0]) + return None + return stdout + + +def versions_from_parentdir(parentdir_prefix, root, verbose=False): + # Source tarballs conventionally unpack into a directory that includes + # both the project name and a version string. + dirname = os.path.basename(root) + if not dirname.startswith(parentdir_prefix): + if verbose: + print("guessing rootdir is '%%s', but '%%s' doesn't start with prefix '%%s'" %% + (root, dirname, parentdir_prefix)) + return None + return {"version": dirname[len(parentdir_prefix):], "full": ""} + +def git_get_keywords(versionfile_abs): + # the code embedded in _version.py can just fetch the value of these + # keywords. When used from setup.py, we don't want to import _version.py, + # so we do it with a regexp instead. This function is not used from + # _version.py. + keywords = {} + try: + f = open(versionfile_abs,"r") + for line in f.readlines(): + if line.strip().startswith("git_refnames ="): + mo = re.search(r'=\s*"(.*)"', line) + if mo: + keywords["refnames"] = mo.group(1) + if line.strip().startswith("git_full ="): + mo = re.search(r'=\s*"(.*)"', line) + if mo: + keywords["full"] = mo.group(1) + f.close() + except EnvironmentError: + pass + return keywords + +def git_versions_from_keywords(keywords, tag_prefix, verbose=False): + if not keywords: + return {} # keyword-finding function failed to find keywords + refnames = keywords["refnames"].strip() + if refnames.startswith("$Format"): + if verbose: + print("keywords are unexpanded, not using") + return {} # unexpanded, so not in an unpacked git-archive tarball + refs = set([r.strip() for r in refnames.strip("()").split(",")]) + # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of + # just "foo-1.0". If we see a "tag: " prefix, prefer those. + TAG = "tag: " + tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)]) + if not tags: + # Either we're using git < 1.8.3, or there really are no tags. We use + # a heuristic: assume all version tags have a digit. The old git %%d + # expansion behaves like git log --decorate=short and strips out the + # refs/heads/ and refs/tags/ prefixes that would let us distinguish + # between branches and tags. By ignoring refnames without digits, we + # filter out many common branch names like "release" and + # "stabilization", as well as "HEAD" and "master". + tags = set([r for r in refs if re.search(r'\d', r)]) + if verbose: + print("discarding '%%s', no digits" %% ",".join(refs-tags)) + if verbose: + print("likely tags: %%s" %% ",".join(sorted(tags))) + for ref in sorted(tags): + # sorting will prefer e.g. "2.0" over "2.0rc1" + if ref.startswith(tag_prefix): + r = ref[len(tag_prefix):] + if verbose: + print("picking %%s" %% r) + return { "version": r, + "full": keywords["full"].strip() } + # no suitable tags, so we use the full revision id + if verbose: + print("no suitable tags, using full revision id") + return { "version": keywords["full"].strip(), + "full": keywords["full"].strip() } + + +def git_versions_from_vcs(tag_prefix, root, verbose=False): + # this runs 'git' from the root of the source tree. This only gets called + # if the git-archive 'subst' keywords were *not* expanded, and + # _version.py hasn't already been rewritten with a short version string, + # meaning we're inside a checked out source tree. + + if not os.path.exists(os.path.join(root, ".git")): + if verbose: + print("no .git in %%s" %% root) + return {} + + GITS = ["git"] + if sys.platform == "win32": + GITS = ["git.cmd", "git.exe"] + stdout = run_command(GITS, ["describe", "--tags", "--dirty", "--always"], + cwd=root) + if stdout is None: + return {} + if not stdout.startswith(tag_prefix): + if verbose: + print("tag '%%s' doesn't start with prefix '%%s'" %% (stdout, tag_prefix)) + return {} + tag = stdout[len(tag_prefix):] + stdout = run_command(GITS, ["rev-parse", "HEAD"], cwd=root) + if stdout is None: + return {} + full = stdout.strip() + if tag.endswith("-dirty"): + full += "-dirty" + return {"version": tag, "full": full} + + +def get_versions(default={"version": "unknown", "full": ""}, verbose=False): + # I am in _version.py, which lives at ROOT/VERSIONFILE_SOURCE. If we have + # __file__, we can work backwards from there to the root. Some + # py2exe/bbfreeze/non-CPython implementations don't do __file__, in which + # case we can only use expanded keywords. + + keywords = { "refnames": git_refnames, "full": git_full } + ver = git_versions_from_keywords(keywords, tag_prefix, verbose) + if ver: + return ver + + try: + root = os.path.abspath(__file__) + # versionfile_source is the relative path from the top of the source + # tree (where the .git directory might live) to this file. Invert + # this to find the root from __file__. + for i in range(len(versionfile_source.split(os.sep))): + root = os.path.dirname(root) + except NameError: + return default + + return (git_versions_from_vcs(tag_prefix, root, verbose) + or versions_from_parentdir(parentdir_prefix, root, verbose) + or default) +''' + +def git_get_keywords(versionfile_abs): + # the code embedded in _version.py can just fetch the value of these + # keywords. When used from setup.py, we don't want to import _version.py, + # so we do it with a regexp instead. This function is not used from + # _version.py. + keywords = {} + try: + f = open(versionfile_abs,"r") + for line in f.readlines(): + if line.strip().startswith("git_refnames ="): + mo = re.search(r'=\s*"(.*)"', line) + if mo: + keywords["refnames"] = mo.group(1) + if line.strip().startswith("git_full ="): + mo = re.search(r'=\s*"(.*)"', line) + if mo: + keywords["full"] = mo.group(1) + f.close() + except EnvironmentError: + pass + return keywords + +def git_versions_from_keywords(keywords, tag_prefix, verbose=False): + if not keywords: + return {} # keyword-finding function failed to find keywords + refnames = keywords["refnames"].strip() + if refnames.startswith("$Format"): + if verbose: + print("keywords are unexpanded, not using") + return {} # unexpanded, so not in an unpacked git-archive tarball + refs = set([r.strip() for r in refnames.strip("()").split(",")]) + # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of + # just "foo-1.0". If we see a "tag: " prefix, prefer those. + TAG = "tag: " + tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)]) + if not tags: + # Either we're using git < 1.8.3, or there really are no tags. We use + # a heuristic: assume all version tags have a digit. The old git %d + # expansion behaves like git log --decorate=short and strips out the + # refs/heads/ and refs/tags/ prefixes that would let us distinguish + # between branches and tags. By ignoring refnames without digits, we + # filter out many common branch names like "release" and + # "stabilization", as well as "HEAD" and "master". + tags = set([r for r in refs if re.search(r'\d', r)]) + if verbose: + print("discarding '%s', no digits" % ",".join(refs-tags)) + if verbose: + print("likely tags: %s" % ",".join(sorted(tags))) + for ref in sorted(tags): + # sorting will prefer e.g. "2.0" over "2.0rc1" + if ref.startswith(tag_prefix): + r = ref[len(tag_prefix):] + if verbose: + print("picking %s" % r) + return { "version": r, + "full": keywords["full"].strip() } + # no suitable tags, so we use the full revision id + if verbose: + print("no suitable tags, using full revision id") + return { "version": keywords["full"].strip(), + "full": keywords["full"].strip() } + + +def git_versions_from_vcs(tag_prefix, root, verbose=False): + # this runs 'git' from the root of the source tree. This only gets called + # if the git-archive 'subst' keywords were *not* expanded, and + # _version.py hasn't already been rewritten with a short version string, + # meaning we're inside a checked out source tree. + + if not os.path.exists(os.path.join(root, ".git")): + if verbose: + print("no .git in %s" % root) + return {} + + GITS = ["git"] + if sys.platform == "win32": + GITS = ["git.cmd", "git.exe"] + stdout = run_command(GITS, ["describe", "--tags", "--dirty", "--always"], + cwd=root) + if stdout is None: + return {} + if not stdout.startswith(tag_prefix): + if verbose: + print("tag '%s' doesn't start with prefix '%s'" % (stdout, tag_prefix)) + return {} + tag = stdout[len(tag_prefix):] + stdout = run_command(GITS, ["rev-parse", "HEAD"], cwd=root) + if stdout is None: + return {} + full = stdout.strip() + if tag.endswith("-dirty"): + full += "-dirty" + return {"version": tag, "full": full} + + +def do_vcs_install(manifest_in, versionfile_source, ipy): + GITS = ["git"] + if sys.platform == "win32": + GITS = ["git.cmd", "git.exe"] + files = [manifest_in, versionfile_source, ipy] + try: + me = __file__ + if me.endswith(".pyc") or me.endswith(".pyo"): + me = os.path.splitext(me)[0] + ".py" + versioneer_file = os.path.relpath(me) + except NameError: + versioneer_file = "versioneer.py" + files.append(versioneer_file) + present = False + try: + f = open(".gitattributes", "r") + for line in f.readlines(): + if line.strip().startswith(versionfile_source): + if "export-subst" in line.strip().split()[1:]: + present = True + f.close() + except EnvironmentError: + pass + if not present: + f = open(".gitattributes", "a+") + f.write("%s export-subst\n" % versionfile_source) + f.close() + files.append(".gitattributes") + run_command(GITS, ["add", "--"] + files) + +def versions_from_parentdir(parentdir_prefix, root, verbose=False): + # Source tarballs conventionally unpack into a directory that includes + # both the project name and a version string. + dirname = os.path.basename(root) + if not dirname.startswith(parentdir_prefix): + if verbose: + print("guessing rootdir is '%s', but '%s' doesn't start with prefix '%s'" % + (root, dirname, parentdir_prefix)) + return None + return {"version": dirname[len(parentdir_prefix):], "full": ""} + +SHORT_VERSION_PY = """ +# This file was generated by 'versioneer.py' (0.11) from +# revision-control system data, or from the parent directory name of an +# unpacked source archive. Distribution tarballs contain a pre-generated copy +# of this file. + +version_version = '%(version)s' +version_full = '%(full)s' +def get_versions(default={}, verbose=False): + return {'version': version_version, 'full': version_full} + +""" + +DEFAULT = {"version": "unknown", "full": "unknown"} + +def versions_from_file(filename): + versions = {} + try: + with open(filename) as f: + for line in f.readlines(): + mo = re.match("version_version = '([^']+)'", line) + if mo: + versions["version"] = mo.group(1) + mo = re.match("version_full = '([^']+)'", line) + if mo: + versions["full"] = mo.group(1) + except EnvironmentError: + return {} + + return versions + +def write_to_version_file(filename, versions): + with open(filename, "w") as f: + f.write(SHORT_VERSION_PY % versions) + + print("set %s to '%s'" % (filename, versions["version"])) + + +def get_root(): + try: + return os.path.dirname(os.path.abspath(__file__)) + except NameError: + return os.path.dirname(os.path.abspath(sys.argv[0])) + +def vcs_function(vcs, suffix): + return getattr(sys.modules[__name__], '%s_%s' % (vcs, suffix), None) + +def get_versions(default=DEFAULT, verbose=False): + # returns dict with two keys: 'version' and 'full' + assert versionfile_source is not None, "please set versioneer.versionfile_source" + assert tag_prefix is not None, "please set versioneer.tag_prefix" + assert parentdir_prefix is not None, "please set versioneer.parentdir_prefix" + assert VCS is not None, "please set versioneer.VCS" + + # I am in versioneer.py, which must live at the top of the source tree, + # which we use to compute the root directory. py2exe/bbfreeze/non-CPython + # don't have __file__, in which case we fall back to sys.argv[0] (which + # ought to be the setup.py script). We prefer __file__ since that's more + # robust in cases where setup.py was invoked in some weird way (e.g. pip) + root = get_root() + versionfile_abs = os.path.join(root, versionfile_source) + + # extract version from first of _version.py, VCS command (e.g. 'git + # describe'), parentdir. This is meant to work for developers using a + # source checkout, for users of a tarball created by 'setup.py sdist', + # and for users of a tarball/zipball created by 'git archive' or github's + # download-from-tag feature or the equivalent in other VCSes. + + get_keywords_f = vcs_function(VCS, "get_keywords") + versions_from_keywords_f = vcs_function(VCS, "versions_from_keywords") + if get_keywords_f and versions_from_keywords_f: + vcs_keywords = get_keywords_f(versionfile_abs) + ver = versions_from_keywords_f(vcs_keywords, tag_prefix) + if ver: + if verbose: print("got version from expanded keyword %s" % ver) + return ver + + ver = versions_from_file(versionfile_abs) + if ver: + if verbose: print("got version from file %s %s" % (versionfile_abs,ver)) + return ver + + versions_from_vcs_f = vcs_function(VCS, "versions_from_vcs") + if versions_from_vcs_f: + ver = versions_from_vcs_f(tag_prefix, root, verbose) + if ver: + if verbose: print("got version from VCS %s" % ver) + return ver + + ver = versions_from_parentdir(parentdir_prefix, root, verbose) + if ver: + if verbose: print("got version from parentdir %s" % ver) + return ver + + if verbose: print("got version from default %s" % default) + return default + +def get_version(verbose=False): + return get_versions(verbose=verbose)["version"] + +class cmd_version(Command): + description = "report generated version string" + user_options = [] + boolean_options = [] + def initialize_options(self): + pass + def finalize_options(self): + pass + def run(self): + ver = get_version(verbose=True) + print("Version is currently: %s" % ver) + + +class cmd_build(_build): + def run(self): + versions = get_versions(verbose=True) + _build.run(self) + # now locate _version.py in the new build/ directory and replace it + # with an updated value + target_versionfile = os.path.join(self.build_lib, versionfile_build) + print("UPDATING %s" % target_versionfile) + os.unlink(target_versionfile) + with open(target_versionfile, "w") as f: + f.write(SHORT_VERSION_PY % versions) + +if 'cx_Freeze' in sys.modules: # cx_freeze enabled? + from cx_Freeze.dist import build_exe as _build_exe + + class cmd_build_exe(_build_exe): + def run(self): + versions = get_versions(verbose=True) + target_versionfile = versionfile_source + print("UPDATING %s" % target_versionfile) + os.unlink(target_versionfile) + with open(target_versionfile, "w") as f: + f.write(SHORT_VERSION_PY % versions) + + _build_exe.run(self) + os.unlink(target_versionfile) + with open(versionfile_source, "w") as f: + assert VCS is not None, "please set versioneer.VCS" + LONG = LONG_VERSION_PY[VCS] + f.write(LONG % {"DOLLAR": "$", + "TAG_PREFIX": tag_prefix, + "PARENTDIR_PREFIX": parentdir_prefix, + "VERSIONFILE_SOURCE": versionfile_source, + }) + +class cmd_sdist(_sdist): + def run(self): + versions = get_versions(verbose=True) + self._versioneer_generated_versions = versions + # unless we update this, the command will keep using the old version + self.distribution.metadata.version = versions["version"] + return _sdist.run(self) + + def make_release_tree(self, base_dir, files): + _sdist.make_release_tree(self, base_dir, files) + # now locate _version.py in the new base_dir directory (remembering + # that it may be a hardlink) and replace it with an updated value + target_versionfile = os.path.join(base_dir, versionfile_source) + print("UPDATING %s" % target_versionfile) + os.unlink(target_versionfile) + with open(target_versionfile, "w") as f: + f.write(SHORT_VERSION_PY % self._versioneer_generated_versions) + +INIT_PY_SNIPPET = """ +from ._version import get_versions +__version__ = get_versions()['version'] +del get_versions +""" + +class cmd_update_files(Command): + description = "install/upgrade Versioneer files: __init__.py SRC/_version.py" + user_options = [] + boolean_options = [] + def initialize_options(self): + pass + def finalize_options(self): + pass + def run(self): + print(" creating %s" % versionfile_source) + with open(versionfile_source, "w") as f: + assert VCS is not None, "please set versioneer.VCS" + LONG = LONG_VERSION_PY[VCS] + f.write(LONG % {"DOLLAR": "$", + "TAG_PREFIX": tag_prefix, + "PARENTDIR_PREFIX": parentdir_prefix, + "VERSIONFILE_SOURCE": versionfile_source, + }) + + ipy = os.path.join(os.path.dirname(versionfile_source), "__init__.py") + try: + with open(ipy, "r") as f: + old = f.read() + except EnvironmentError: + old = "" + if INIT_PY_SNIPPET not in old: + print(" appending to %s" % ipy) + with open(ipy, "a") as f: + f.write(INIT_PY_SNIPPET) + else: + print(" %s unmodified" % ipy) + + # Make sure both the top-level "versioneer.py" and versionfile_source + # (PKG/_version.py, used by runtime code) are in MANIFEST.in, so + # they'll be copied into source distributions. Pip won't be able to + # install the package without this. + manifest_in = os.path.join(get_root(), "MANIFEST.in") + simple_includes = set() + try: + with open(manifest_in, "r") as f: + for line in f: + if line.startswith("include "): + for include in line.split()[1:]: + simple_includes.add(include) + except EnvironmentError: + pass + # That doesn't cover everything MANIFEST.in can do + # (http://docs.python.org/2/distutils/sourcedist.html#commands), so + # it might give some false negatives. Appending redundant 'include' + # lines is safe, though. + if "versioneer.py" not in simple_includes: + print(" appending 'versioneer.py' to MANIFEST.in") + with open(manifest_in, "a") as f: + f.write("include versioneer.py\n") + else: + print(" 'versioneer.py' already in MANIFEST.in") + if versionfile_source not in simple_includes: + print(" appending versionfile_source ('%s') to MANIFEST.in" % + versionfile_source) + with open(manifest_in, "a") as f: + f.write("include %s\n" % versionfile_source) + else: + print(" versionfile_source already in MANIFEST.in") + + # Make VCS-specific changes. For git, this means creating/changing + # .gitattributes to mark _version.py for export-time keyword + # substitution. + do_vcs_install(manifest_in, versionfile_source, ipy) + +def get_cmdclass(): + cmds = {'version': cmd_version, + 'versioneer': cmd_update_files, + 'build': cmd_build, + 'sdist': cmd_sdist, + } + if 'cx_Freeze' in sys.modules: # cx_freeze enabled? + cmds['build_exe'] = cmd_build_exe + del cmds['build'] + + return cmds From 45fdfebb078a507f7eab44a6489e703e5711d66e Mon Sep 17 00:00:00 2001 From: Roman Valls Guimera Date: Mon, 25 Aug 2014 15:57:53 +0200 Subject: [PATCH 3/6] add version pyfile for versioneer --- nipype/_version.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 nipype/_version.py diff --git a/nipype/_version.py b/nipype/_version.py new file mode 100644 index 0000000000..e69de29bb2 From 9b5be460e0372d109a0ed0b17f28838bb742070e Mon Sep 17 00:00:00 2001 From: Roman Valls Guimera Date: Mon, 25 Aug 2014 16:40:13 +0200 Subject: [PATCH 4/6] Forgot to run last step for Mozilla python versioneer --- .gitattributes | 1 + MANIFEST.in | 2 + nipype/__init__.py | 4 + nipype/_version.py | 183 +++++++++++++++++++++++++++++++++++++++++++++ setup.py | 4 +- 5 files changed, 192 insertions(+), 2 deletions(-) diff --git a/.gitattributes b/.gitattributes index f600c7be69..e16177f50f 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,2 @@ nipype/COMMIT_INFO.txt export-subst +nipype/_version.py export-subst diff --git a/MANIFEST.in b/MANIFEST.in index 1447cfdacc..69d4c71b7b 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -12,3 +12,5 @@ include nipype/COMMIT_INFO.txt recursive-include doc * recursive-include matlabscripts * recursive-include tools * +include versioneer.py +include nipype/_version.py diff --git a/nipype/__init__.py b/nipype/__init__.py index a5183e022c..dad0440c2c 100644 --- a/nipype/__init__.py +++ b/nipype/__init__.py @@ -77,3 +77,7 @@ def _test_local_install(): from pipeline import Node, MapNode, JoinNode, Workflow from interfaces import (DataGrabber, DataSink, SelectFiles, IdentityInterface, Rename, Function, Select, Merge) + +from ._version import get_versions +__version__ = get_versions()['version'] +del get_versions diff --git a/nipype/_version.py b/nipype/_version.py index e69de29bb2..822c15ea3f 100644 --- a/nipype/_version.py +++ b/nipype/_version.py @@ -0,0 +1,183 @@ + +# This file helps to compute a version number in source trees obtained from +# git-archive tarball (such as those provided by githubs download-from-tag +# feature). Distribution tarballs (built by setup.py sdist) and build +# directories (produced by setup.py build) will contain a much shorter file +# that just contains the computed version number. + +# This file is released into the public domain. Generated by +# versioneer-0.11 (https://github.com/warner/python-versioneer) + +# these strings will be replaced by git during git-archive +git_refnames = "$Format:%d$" +git_full = "$Format:%H$" + +# these strings are filled in when 'setup.py versioneer' creates _version.py +tag_prefix = "" +parentdir_prefix = "nipype-" +versionfile_source = "nipype/_version.py" + +import os, sys, re, subprocess, errno + +def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False): + assert isinstance(commands, list) + p = None + for c in commands: + try: + # remember shell=False, so use git.cmd on windows, not just git + p = subprocess.Popen([c] + args, cwd=cwd, stdout=subprocess.PIPE, + stderr=(subprocess.PIPE if hide_stderr + else None)) + break + except EnvironmentError: + e = sys.exc_info()[1] + if e.errno == errno.ENOENT: + continue + if verbose: + print("unable to run %s" % args[0]) + print(e) + return None + else: + if verbose: + print("unable to find command, tried %s" % (commands,)) + return None + stdout = p.communicate()[0].strip() + if sys.version >= '3': + stdout = stdout.decode() + if p.returncode != 0: + if verbose: + print("unable to run %s (error)" % args[0]) + return None + return stdout + + +def versions_from_parentdir(parentdir_prefix, root, verbose=False): + # Source tarballs conventionally unpack into a directory that includes + # both the project name and a version string. + dirname = os.path.basename(root) + if not dirname.startswith(parentdir_prefix): + if verbose: + print("guessing rootdir is '%s', but '%s' doesn't start with prefix '%s'" % + (root, dirname, parentdir_prefix)) + return None + return {"version": dirname[len(parentdir_prefix):], "full": ""} + +def git_get_keywords(versionfile_abs): + # the code embedded in _version.py can just fetch the value of these + # keywords. When used from setup.py, we don't want to import _version.py, + # so we do it with a regexp instead. This function is not used from + # _version.py. + keywords = {} + try: + f = open(versionfile_abs,"r") + for line in f.readlines(): + if line.strip().startswith("git_refnames ="): + mo = re.search(r'=\s*"(.*)"', line) + if mo: + keywords["refnames"] = mo.group(1) + if line.strip().startswith("git_full ="): + mo = re.search(r'=\s*"(.*)"', line) + if mo: + keywords["full"] = mo.group(1) + f.close() + except EnvironmentError: + pass + return keywords + +def git_versions_from_keywords(keywords, tag_prefix, verbose=False): + if not keywords: + return {} # keyword-finding function failed to find keywords + refnames = keywords["refnames"].strip() + if refnames.startswith("$Format"): + if verbose: + print("keywords are unexpanded, not using") + return {} # unexpanded, so not in an unpacked git-archive tarball + refs = set([r.strip() for r in refnames.strip("()").split(",")]) + # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of + # just "foo-1.0". If we see a "tag: " prefix, prefer those. + TAG = "tag: " + tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)]) + if not tags: + # Either we're using git < 1.8.3, or there really are no tags. We use + # a heuristic: assume all version tags have a digit. The old git %d + # expansion behaves like git log --decorate=short and strips out the + # refs/heads/ and refs/tags/ prefixes that would let us distinguish + # between branches and tags. By ignoring refnames without digits, we + # filter out many common branch names like "release" and + # "stabilization", as well as "HEAD" and "master". + tags = set([r for r in refs if re.search(r'\d', r)]) + if verbose: + print("discarding '%s', no digits" % ",".join(refs-tags)) + if verbose: + print("likely tags: %s" % ",".join(sorted(tags))) + for ref in sorted(tags): + # sorting will prefer e.g. "2.0" over "2.0rc1" + if ref.startswith(tag_prefix): + r = ref[len(tag_prefix):] + if verbose: + print("picking %s" % r) + return { "version": r, + "full": keywords["full"].strip() } + # no suitable tags, so we use the full revision id + if verbose: + print("no suitable tags, using full revision id") + return { "version": keywords["full"].strip(), + "full": keywords["full"].strip() } + + +def git_versions_from_vcs(tag_prefix, root, verbose=False): + # this runs 'git' from the root of the source tree. This only gets called + # if the git-archive 'subst' keywords were *not* expanded, and + # _version.py hasn't already been rewritten with a short version string, + # meaning we're inside a checked out source tree. + + if not os.path.exists(os.path.join(root, ".git")): + if verbose: + print("no .git in %s" % root) + return {} + + GITS = ["git"] + if sys.platform == "win32": + GITS = ["git.cmd", "git.exe"] + stdout = run_command(GITS, ["describe", "--tags", "--dirty", "--always"], + cwd=root) + if stdout is None: + return {} + if not stdout.startswith(tag_prefix): + if verbose: + print("tag '%s' doesn't start with prefix '%s'" % (stdout, tag_prefix)) + return {} + tag = stdout[len(tag_prefix):] + stdout = run_command(GITS, ["rev-parse", "HEAD"], cwd=root) + if stdout is None: + return {} + full = stdout.strip() + if tag.endswith("-dirty"): + full += "-dirty" + return {"version": tag, "full": full} + + +def get_versions(default={"version": "unknown", "full": ""}, verbose=False): + # I am in _version.py, which lives at ROOT/VERSIONFILE_SOURCE. If we have + # __file__, we can work backwards from there to the root. Some + # py2exe/bbfreeze/non-CPython implementations don't do __file__, in which + # case we can only use expanded keywords. + + keywords = { "refnames": git_refnames, "full": git_full } + ver = git_versions_from_keywords(keywords, tag_prefix, verbose) + if ver: + return ver + + try: + root = os.path.abspath(__file__) + # versionfile_source is the relative path from the top of the source + # tree (where the .git directory might live) to this file. Invert + # this to find the root from __file__. + for i in range(len(versionfile_source.split(os.sep))): + root = os.path.dirname(root) + except NameError: + return default + + return (git_versions_from_vcs(tag_prefix, root, verbose) + or versions_from_parentdir(parentdir_prefix, root, verbose) + or default) diff --git a/setup.py b/setup.py index 1c1c1ecac3..cd62acaf64 100755 --- a/setup.py +++ b/setup.py @@ -33,8 +33,8 @@ # XXX: write COMMIT_INFO.txt with versioneer versioneer.VCS = 'git' -versioneer.versionfile_source = 'src/nipype/_version.py' -versioneer.versionfile_build = 'nipype/_version.py' +versioneer.versionfile_source = 'nipype/_version.py' +versioneer.versionfile_build = 'build/_version.py' versioneer.tag_prefix = '' # tags are like 1.2.0 versioneer.parentdir_prefix = 'nipype-' # dirname like 'myproject-1.2.0' From 50e712bc7b2a9bcf3a40df697d56aeb9e9d620ed Mon Sep 17 00:00:00 2001 From: Roman Valls Guimera Date: Mon, 25 Aug 2014 17:39:16 +0200 Subject: [PATCH 5/6] correct build path for versioneer --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index cd62acaf64..a7a98d1600 100755 --- a/setup.py +++ b/setup.py @@ -34,7 +34,7 @@ # XXX: write COMMIT_INFO.txt with versioneer versioneer.VCS = 'git' versioneer.versionfile_source = 'nipype/_version.py' -versioneer.versionfile_build = 'build/_version.py' +versioneer.versionfile_build = 'nipype/_version.py' versioneer.tag_prefix = '' # tags are like 1.2.0 versioneer.parentdir_prefix = 'nipype-' # dirname like 'myproject-1.2.0' From 4e9462e8a79001b5cd35e69dd2071f69087da2d3 Mon Sep 17 00:00:00 2001 From: Roman Valls Guimera Date: Mon, 25 Aug 2014 22:50:53 +0200 Subject: [PATCH 6/6] Figuring out how to handle build_docs within setup.py --- setup.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index a7a98d1600..22c792c1e6 100755 --- a/setup.py +++ b/setup.py @@ -31,16 +31,17 @@ from setuptools import setup, find_packages from distutils.command.build_py import build_py -# XXX: write COMMIT_INFO.txt with versioneer versioneer.VCS = 'git' versioneer.versionfile_source = 'nipype/_version.py' versioneer.versionfile_build = 'nipype/_version.py' versioneer.tag_prefix = '' # tags are like 1.2.0 versioneer.parentdir_prefix = 'nipype-' # dirname like 'myproject-1.2.0' -from build_docs import cmdclass, INFO_VARS +from build_docs import INFO_VARS +from build_docs import cmdclass as docs_class -#XXX: Build docs too +#XXX: Build docs too from setup.py? requires +# merging cmdclasses versioneer and build_docs install_reqs = parse_requirements('requirements.txt') reqs = [str(ir.req) for ir in install_reqs]