Example #1
0
def version_setup_hook(config):
    """Creates a Python module called version.py which contains these variables:

    * ``__version__`` (the release version)
    * ``__svn_revision__`` (the SVN revision info as returned by the ``svnversion``
      command)
    * ``__svn_full_info__`` (as returned by the ``svn info`` command)
    * ``__setup_datetime__`` (the date and time that setup.py was last run).
    * ``__vdate__`` (the release date)

    These variables can be imported in the package's ``__init__.py`` for
    degugging purposes.  The version.py module will *only* be created in a
    package that imports from the version module in its ``__init__.py``.  It
    should be noted that this is generally preferable to writing these
    variables directly into ``__init__.py``, since this provides more control
    and is less likely to unexpectedly break things in ``__init__.py``.

    Config Usage::

        [global]
        setup-hooks = stsci.distutils.hooks.version_setup_hook

    You should write exactly this in your package's ``__init__.py``::

        from .version import *

    """

    if is_display_option(ignore=['--version']):
        return

    name = config['metadata'].get('name')
    version = config['metadata'].get('version', '0.0.0')
    vdate = config['metadata'].get('vdate', 'unspecified')
    package_dir = config.get('files', {}).get('packages_root', '')
    packages = config.get('files', {}).get('packages', '')

    packages = split_multiline(packages)

    _version_hook(__name__ + '.version_setup_hook', package_dir, packages,
                 name, version, vdate)
Example #2
0
def version_setup_hook(config):
    """Creates a Python module called version.py which contains these variables:

    * ``__version__`` (the release version)
    * ``__svn_revision__`` (the SVN revision info as returned by the ``svnversion``
      command)
    * ``__svn_full_info__`` (as returned by the ``svn info`` command)
    * ``__setup_datetime__`` (the date and time that setup.py was last run).
    * ``__vdate__`` (the release date)

    These variables can be imported in the package's ``__init__.py`` for
    degugging purposes.  The version.py module will *only* be created in a
    package that imports from the version module in its ``__init__.py``.  It
    should be noted that this is generally preferable to writing these
    variables directly into ``__init__.py``, since this provides more control
    and is less likely to unexpectedly break things in ``__init__.py``.

    Config Usage::

        [global]
        setup-hooks = stsci.distutils.hooks.version_setup_hook

    You should write exactly this in your package's ``__init__.py``::

        from .version import *

    """

    if is_display_option(ignore=['--version']):
        return

    name = config['metadata'].get('name')
    version = config['metadata'].get('version', '0.0.0')
    vdate = config['metadata'].get('vdate', 'unspecified')
    package_dir = config.get('files', {}).get('packages_root', '')
    packages = config.get('files', {}).get('packages', '')

    packages = split_multiline(packages)

    _version_hook(__name__ + '.version_setup_hook', package_dir, packages,
                  name, version, vdate)
Example #3
0
def tag_svn_revision(config):
    """
    A setup_hook to add the SVN revision of the current working copy path to
    the package version string, but only if the version ends in .dev.

    For example, ``mypackage-1.0.dev`` becomes ``mypackage-1.0.dev1234``.  This
    is in accordance with the version string format standardized by PEP 386.

    This should be used as a replacement for the ``tag_svn_revision`` option to
    the egg_info command.  This hook is more compatible with
    packaging/distutils2, which does not include any VCS support.  This hook is
    also more flexible in that it turns the revision number on/off depending on
    the presence of ``.dev`` in the version string, so that it's not
    automatically added to the version in final releases.

    This hook does require the ``svnversion`` command to be available in order
    to work.  It does not examine the working copy metadata directly.


    Config Usage::

        [global]
        setup_hooks = stsci.distutils.hooks.tag_svn_revision

    You should write exactly this in your package's ``__init__.py``::

        from .version import *

    """

    if 'metadata' in config and 'version' in config['metadata']:
        metadata = config['metadata']
        version = metadata['version']

        # Don't add an svn revision unless the version ends with .dev
        if not version.endswith('.dev'):
            return

        # First try to get the revision by checking for it in an existing
        # .version module
        package_dir = config.get('files', {}).get('packages_root', '')
        packages = config.get('files', {}).get('packages', '')
        packages = split_multiline(packages)
        rev = None
        for package in packages:
            version_py = package_uses_version_py(package_dir, package)
            if not version_py:
                continue
            try:
                mod = __import__(package + '.version',
                                 fromlist='__svn_revision__')
            except ImportError:
                mod = None
            if mod is not None and hasattr(mod, '__svn_revision__'):
                rev = mod.__svn_revision__
                break

        # Cleanup
        for modname in list(sys.modules):
            if modname == package or modname.startswith(package + '.'):
                del sys.modules[modname]

        if rev is None:
            # A .version module didn't exist or was incomplete; try calling
            # svnversion directly
            rev = get_svn_version()

        if not rev:
            return
        if ':' in rev:
            rev, _ = rev.split(':', 1)
        while rev and rev[-1] not in string.digits:
            rev = rev[:-1]
        try:
            rev = int(rev)
        except (ValueError, TypeError):
            return

        metadata['version'] ='%s%d' % (version, rev)
Example #4
0
 def _load_commands(self, commands):
     commands = split_multiline(commands)
     if isinstance(commands, str):
         commands = [commands]
     for command in commands:
         set_command(command.strip())
Example #5
0
 def _load_compilers(self, compilers):
     compilers = split_multiline(compilers)
     if isinstance(compilers, str):
         compilers = [compilers]
     for compiler in compilers:
         set_compiler(compiler.strip())
Example #6
0
    def parse_config_files(self, filenames=None):
        if filenames is None:
            filenames = self.find_config_files()

        logger.debug("Distribution.parse_config_files():")

        parser = RawConfigParser()

        for filename in filenames:
            logger.debug("  reading %s", filename)
            parser.read(filename, encoding='utf-8')

            if os.path.split(filename)[-1] == 'setup.cfg':
                self._read_setup_cfg(parser, filename)

            for section in parser.sections():
                if section == 'global':
                    if parser.has_option('global', 'compilers'):
                        self._load_compilers(parser.get('global', 'compilers'))

                    if parser.has_option('global', 'commands'):
                        self._load_commands(parser.get('global', 'commands'))

                options = parser.options(section)
                opt_dict = self.dist.get_option_dict(section)

                for opt in options:
                    if opt == '__name__':
                        continue
                    val = parser.get(section, opt)
                    opt = opt.replace('-', '_')

                    if opt == 'sub_commands':
                        val = split_multiline(val)
                        if isinstance(val, str):
                            val = [val]

                    # Hooks use a suffix system to prevent being overriden
                    # by a config file processed later (i.e. a hook set in
                    # the user config file cannot be replaced by a hook
                    # set in a project config file, unless they have the
                    # same suffix).
                    if (opt.startswith("pre_hook.") or
                        opt.startswith("post_hook.")):
                        hook_type, alias = opt.split(".")
                        hook_dict = opt_dict.setdefault(
                            hook_type, (filename, {}))[1]
                        hook_dict[alias] = val
                    else:
                        opt_dict[opt] = filename, val

            # Make the RawConfigParser forget everything (so we retain
            # the original filenames that options come from)
            parser.__init__()

        # If there was a "global" section in the config file, use it
        # to set Distribution options.
        if 'global' in self.dist.command_options:
            for opt, (src, val) in self.dist.command_options['global'].items():
                alias = self.dist.negative_opt.get(opt)
                try:
                    if alias:
                        setattr(self.dist, alias, not strtobool(val))
                    elif opt == 'dry_run':  # FIXME ugh!
                        setattr(self.dist, opt, strtobool(val))
                    else:
                        setattr(self.dist, opt, val)
                except ValueError as msg:
                    raise PackagingOptionError(msg)
Example #7
0
    def _read_setup_cfg(self, parser, cfg_filename):
        cfg_directory = os.path.dirname(os.path.abspath(cfg_filename))
        content = {}
        for section in parser.sections():
            content[section] = dict(parser.items(section))

        # global setup hooks are called first
        if 'global' in content:
            if 'setup_hooks' in content['global']:
                setup_hooks = split_multiline(content['global']['setup_hooks'])

                # add project directory to sys.path, to allow hooks to be
                # distributed with the project
                sys.path.insert(0, cfg_directory)
                try:
                    for line in setup_hooks:
                        try:
                            hook = resolve_name(line)
                        except ImportError as e:
                            logger.warning('cannot find setup hook: %s',
                                           e.args[0])
                        else:
                            self.setup_hooks.append(hook)
                    self.run_hooks(content)
                finally:
                    sys.path.pop(0)

        metadata = self.dist.metadata

        # setting the metadata values
        if 'metadata' in content:
            for key, value in content['metadata'].items():
                key = key.replace('_', '-')
                if metadata.is_multi_field(key):
                    value = split_multiline(value)

                if key == 'project-url':
                    value = [(label.strip(), url.strip())
                             for label, url in
                             [v.split(',') for v in value]]

                if key == 'description-file':
                    if 'description' in content['metadata']:
                        msg = ("description and description-file' are "
                               "mutually exclusive")
                        raise PackagingOptionError(msg)

                    filenames = value.split()

                    # concatenate all files
                    value = []
                    for filename in filenames:
                        # will raise if file not found
                        with open(filename) as description_file:
                            value.append(description_file.read().strip())
                        # add filename as a required file
                        if filename not in metadata.requires_files:
                            metadata.requires_files.append(filename)
                    value = '\n'.join(value).strip()
                    key = 'description'

                if metadata.is_metadata_field(key):
                    metadata[key] = self._convert_metadata(key, value)

        if 'files' in content:
            files = content['files']
            self.dist.package_dir = files.pop('packages_root', None)

            files = dict((key, split_multiline(value)) for key, value in
                         files.items())

            self.dist.packages = []

            packages = files.get('packages', [])
            if isinstance(packages, str):
                packages = [packages]

            for package in packages:
                if ':' in package:
                    dir_, package = package.split(':')
                    self.dist.package_dir[package] = dir_
                self.dist.packages.append(package)

            self.dist.py_modules = files.get('modules', [])
            if isinstance(self.dist.py_modules, str):
                self.dist.py_modules = [self.dist.py_modules]
            self.dist.scripts = files.get('scripts', [])
            if isinstance(self.dist.scripts, str):
                self.dist.scripts = [self.dist.scripts]

            self.dist.package_data = {}
            # bookkeeping for the loop below
            firstline = True
            prev = None

            for line in files.get('package_data', []):
                if '=' in line:
                    # package name -- file globs or specs
                    key, value = line.split('=')
                    prev = self.dist.package_data[key.strip()] = value.split()
                elif firstline:
                    # invalid continuation on the first line
                    raise PackagingOptionError(
                        'malformed package_data first line: %r (misses "=")' %
                        line)
                else:
                    # continuation, add to last seen package name
                    prev.extend(line.split())

                firstline = False

            self.dist.data_files = []
            for data in files.get('data_files', []):
                data = data.split('=')
                if len(data) != 2:
                    continue
                key, value = data
                values = [v.strip() for v in value.split(',')]
                self.dist.data_files.append((key, values))

            # manifest template
            self.dist.extra_files = files.get('extra_files', [])

            resources = []
            for rule in files.get('resources', []):
                glob, destination = rule.split('=', 1)
                rich_glob = glob.strip().split(' ', 1)
                if len(rich_glob) == 2:
                    prefix, suffix = rich_glob
                else:
                    assert len(rich_glob) == 1
                    prefix = ''
                    suffix = glob
                if destination == '<exclude>':
                    destination = None
                resources.append(
                    (prefix.strip(), suffix.strip(), destination.strip()))
                self.dist.data_files = get_resources_dests(
                    cfg_directory, resources)

        ext_modules = self.dist.ext_modules
        for section_key in content:
            # no str.partition in 2.4 :(
            labels = section_key.split(':')
            if len(labels) == 2 and labels[0] == 'extension':
                values_dct = content[section_key]
                if 'name' in values_dct:
                    raise PackagingOptionError(
                        'extension name should be given as [extension: name], '
                        'not as key')
                name = labels[1].strip()
                _check_name(name, self.dist.packages)
                ext_modules.append(Extension(
                    name,
                    _pop_values(values_dct, 'sources'),
                    _pop_values(values_dct, 'include_dirs'),
                    _pop_values(values_dct, 'define_macros'),
                    _pop_values(values_dct, 'undef_macros'),
                    _pop_values(values_dct, 'library_dirs'),
                    _pop_values(values_dct, 'libraries'),
                    _pop_values(values_dct, 'runtime_library_dirs'),
                    _pop_values(values_dct, 'extra_objects'),
                    _pop_values(values_dct, 'extra_compile_args'),
                    _pop_values(values_dct, 'extra_link_args'),
                    _pop_values(values_dct, 'export_symbols'),
                    _pop_values(values_dct, 'swig_opts'),
                    _pop_values(values_dct, 'depends'),
                    values_dct.pop('language', None),
                    values_dct.pop('optional', None),
                    **values_dct))
Example #8
0
def tag_svn_revision(config):
    """
    A setup_hook to add the SVN revision of the current working copy path to
    the package version string, but only if the version ends in .dev.

    For example, ``mypackage-1.0.dev`` becomes ``mypackage-1.0.dev1234``.  This
    is in accordance with the version string format standardized by PEP 386.

    This should be used as a replacement for the ``tag_svn_revision`` option to
    the egg_info command.  This hook is more compatible with
    packaging/distutils2, which does not include any VCS support.  This hook is
    also more flexible in that it turns the revision number on/off depending on
    the presence of ``.dev`` in the version string, so that it's not
    automatically added to the version in final releases.

    This hook does require the ``svnversion`` command to be available in order
    to work.  It does not examine the working copy metadata directly.


    Config Usage::

        [global]
        setup_hooks = stsci.distutils.hooks.tag_svn_revision

    You should write exactly this in your package's ``__init__.py``::

        from .version import *

    """

    if 'metadata' in config and 'version' in config['metadata']:
        metadata = config['metadata']
        version = metadata['version']

        # Don't add an svn revision unless the version ends with .dev
        if not version.endswith('.dev'):
            return

        # First try to get the revision by checking for it in an existing
        # .version module
        package_dir = config.get('files', {}).get('packages_root', '')
        packages = config.get('files', {}).get('packages', '')
        packages = split_multiline(packages)
        rev = None
        for package in packages:
            version_py = package_uses_version_py(package_dir, package)
            if not version_py:
                continue
            try:
                mod = __import__(package + '.version',
                                 fromlist='__svn_revision__')
            except ImportError:
                mod = None
            if mod is not None and hasattr(mod, '__svn_revision__'):
                rev = mod.__svn_revision__
                break

        # Cleanup
        for modname in list(sys.modules):
            if modname == package or modname.startswith(package + '.'):
                del sys.modules[modname]

        if rev is None:
            # A .version module didn't exist or was incomplete; try calling
            # svnversion directly
            rev = get_svn_version()

        if not rev:
            return
        if ':' in rev:
            rev, _ = rev.split(':', 1)
        while rev and rev[-1] not in string.digits:
            rev = rev[:-1]
        try:
            rev = int(rev)
        except (ValueError, TypeError):
            return

        metadata['version'] = '%s%d' % (version, rev)