Skip to content

Commit

Permalink
use auxlib for packaging
Browse files Browse the repository at this point in the history
  • Loading branch information
kalefranz committed Mar 1, 2016
1 parent b4142f4 commit a1fc225
Show file tree
Hide file tree
Showing 8 changed files with 245 additions and 24 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ MANIFEST
coverage.xml
.tox/
junit.xml
.version
4 changes: 2 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ install:

script:
- py.test --cov conda --cov-report xml tests
- radon cc --ignore "build,tests,ve,_vendor,progressbar" --no-assert -nb --total-average -s conda
- radon mi --ignore "build,tests,ve,_vendor,progressbar" -na -m -s conda
- radon cc --ignore "build,tests,ve,_vendor,auxlib,progressbar" --no-assert -nb --total-average -s conda
- radon mi --ignore "build,tests,ve,_vendor,auxlib,progressbar" -na -m -s conda
- flake8 --exit-zero --statistics
- "[[ $PY_VERSION = 3.5 ]] || ./tests/run-integration"

Expand Down
23 changes: 18 additions & 5 deletions conda/__init__.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,24 @@
# (c) 2012-2013 Continuum Analytics, Inc. / http://continuum.io
# (c) 2012-2016 Continuum Analytics, Inc. / http://continuum.io
# All Rights Reserved
#
# conda is distributed under the terms of the BSD 3-clause license.
# Consult LICENSE.txt or http://opensource.org/licenses/BSD-3-Clause.
"""OS-agnostic, system-level binary package manager."""
from __future__ import absolute_import, division, print_function

from __future__ import absolute_import
from .auxlib.packaging import get_version

from conda._version import get_versions
__version__ = get_versions()['version']
del get_versions
__all__ = [
"__name__", "__version__", "__author__",
"__email__", "__license__", "__copyright__",
"__summary__", "__url__",
]


__name__ = "conda"
__version__ = get_version(__file__, __package__)
__author__ = "Continuum Analytics, Inc."
__email__ = "[email protected]"
__license__ = "BSD"
__summary__ = __doc__
__url__ = "https://github.com/conda/conda"
5 changes: 5 additions & 0 deletions conda/auxlib/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import absolute_import, division, print_function
from logging import getLogger

log = getLogger(__name__)
111 changes: 111 additions & 0 deletions conda/auxlib/packaging.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# -*- coding: utf-8 -*-
from __future__ import print_function, division, absolute_import
from distutils.command.build_py import build_py
from distutils.command.sdist import sdist
from logging import getLogger
from os.path import basename, dirname, join, isdir
from re import match
from subprocess import CalledProcessError, check_call, check_output

from .path import absdirname, PackageFile, ROOT_PATH

log = getLogger(__name__)


def _get_version_from_pkg_info(package_name):
with PackageFile('.version', package_name) as fh:
return fh.read()


def _is_git_dirty():
try:
check_call(('git', 'diff', '--quiet'))
check_call(('git', 'diff', '--cached', '--quiet'))
return False
except CalledProcessError:
return True


def _get_most_recent_git_tag():
try:
return check_output(["git", "describe", "--tags"]).strip()
except CalledProcessError as e:
if e.returncode == 128:
return "0.0.0.0"
else:
raise # pragma: no cover


def _get_git_hash():
try:
return check_output(["git", "rev-parse", "HEAD"]).strip()[:7]
except CalledProcessError:
return 0


def _get_version_from_git_tag():
"""Return a PEP440-compliant version derived from the git status.
If that fails for any reason, return the first 7 chars of the changeset hash.
"""
tag = _get_most_recent_git_tag()
m = match(b"(?P<xyz>\d+\.\d+\.\d+)(?:-(?P<dev>\d+)-(?P<hash>.+))?", tag)
version = m.group('xyz').decode('utf-8')
if m.group('dev') or _is_git_dirty():
dev = (m.group('dev') or 0).decode('utf-8')
hash_ = (m.group('hash') or _get_git_hash()).decode('utf-8')
version += ".dev{dev}.{hash_}".format(dev=dev, hash_=hash_)
return version


def is_git_repo(path, package):
if path == ROOT_PATH or dirname(basename(path)) == package:
return False
else:
return isdir(join(path, '.git')) or is_git_repo(dirname(path), package)


def get_version(file, package):
"""Returns a version string for the current package, derived
either from git or from a .version file.
This function is expected to run in two contexts. In a development
context, where .git/ exists, the version is pulled from git tags.
Using the BuildPyCommand and SDistCommand classes for cmdclass in
setup.py will write a .version file into any dist.
In an installed context, the .version file written at dist build
time is the source of version information.
"""
here = absdirname(file)
if is_git_repo(here, package):
return _get_version_from_git_tag()

# fall back to .version file
version_from_pkg = _get_version_from_pkg_info(package)
if version_from_pkg:
return version_from_pkg.decode('utf-8')

raise RuntimeError("Could not get package version (no .git or .version file)")


class BuildPyCommand(build_py):
def run(self):
build_py.run(self)
# locate .version in the new build/ directory and replace it with an updated value
target_version_file = join(self.build_lib, self.distribution.metadata.name, ".version")
print("UPDATING {0}".format(target_version_file))
with open(target_version_file, 'w') as f:
f.write(self.distribution.metadata.version)


class SDistCommand(sdist):
def run(self):
return sdist.run(self)

def make_release_tree(self, base_dir, files):
sdist.make_release_tree(self, base_dir, files)
target_version_file = join(base_dir, self.distribution.metadata.name, ".version")
print("UPDATING {0}".format(target_version_file))
with open(target_version_file, 'w') as f:
f.write(self.distribution.metadata.version)
81 changes: 81 additions & 0 deletions conda/auxlib/path.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# -*- coding: utf-8 -*-
from __future__ import print_function, division, absolute_import
from distutils.sysconfig import get_python_lib
from logging import getLogger
import pkg_resources
from os.path import (abspath, dirname, exists, expanduser, expandvars, join, normpath, sep)
import sys


log = getLogger(__name__)


ROOT_PATH = abspath(sep)


def site_packages_paths():
if hasattr(sys, 'real_prefix'):
# in a virtualenv
log.debug('searching virtualenv')
return [p for p in sys.path if p.endswith('site-packages')]
else:
# not in a virtualenv
log.debug('searching outside virtualenv') # pragma: no cover
return get_python_lib() # pragma: no cover


class PackageFile(object):

def __init__(self, file_path, package_name):
self.file_path = file_path
self.package_name = package_name

def __enter__(self):
self.file_handle = open_package_file(self.file_path, self.package_name)
return self.file_handle

def __exit__(self, *args):
self.file_handle.close()


def open_package_file(file_path, package_name):
file_path = expand(file_path)

# look for file at relative path
if exists(file_path):
log.info("found real file {0}".format(file_path))
return open(file_path)

# look for file in package resources
if package_name and pkg_resources.resource_exists(package_name, file_path):
log.info("found package resource file {0} for package {1}".format(file_path, package_name))
return pkg_resources.resource_stream(package_name, file_path)

# look for file in site-packages
package_path = find_file_in_site_packages(file_path, package_name)
if package_path:
return open(package_path) # pragma: no cover

msg = "file for module [{0}] cannot be found at path {1}".format(package_name, file_path)
log.error(msg)
raise IOError(msg)


def find_file_in_site_packages(file_path, package_name):
package_path = package_name.replace('.', '/')
for site_packages_path in site_packages_paths():
test_path = join(site_packages_path, package_path, file_path)
if exists(test_path):
log.info("found site-package file {0} for package {1}".format(file_path, package_name))
return test_path
else:
log.error("No file found at {0}.".format(test_path))
return None


def expand(path):
return normpath(expanduser(expandvars(path)))


def absdirname(path):
return abspath(expanduser(dirname(path)))
5 changes: 3 additions & 2 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,16 @@ markers =
[pep8]
max-line-length = 99
ignore = E121,E123,E126,E133,E226,E241,E242,E704
exclude = build/*,.tox/*,tests/*,ve/*,*/_vendor/*,conda/progressbar/*
exclude = build/*,.tox/*,tests/*,ve/*,*/_vendor/*,conda/auxlib/*,conda/progressbar/*


[flake8]
max-line-length = 99
ignore = E121,E123,E126,E133,E226,E241,E242,E704
exclude = build/*,.tox/*,tests/*,ve/*,*/_vendor/*,conda/progressbar/*
exclude = build/*,.tox/*,tests/*,ve/*,*/_vendor/*,conda/auxlib/*,conda/progressbar/*


[coverage:run]
omit =
conda/auxlib/*
conda/progressbar/*
39 changes: 24 additions & 15 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@
import os
import sys

import versioneer

if not (sys.version_info[:2] == (2, 7) or sys.version_info[:2] >= (3, 3)):
sys.exit("conda is only meant for Python 2.7 or 3.3 and up. "
"current version: %d.%d" % sys.version_info[:2])
Expand All @@ -24,20 +22,28 @@
is in error, run CONDA_DEFAULT_ENV='' python setup.py.
""")

versioneer.versionfile_source = 'conda/_version.py'
versioneer.versionfile_build = 'conda/_version.py'
versioneer.tag_prefix = '' # tags are like 1.2.0
versioneer.parentdir_prefix = 'conda-' # dirname like 'myproject-1.2.0'
# When executing the setup.py, we need to be able to import ourselves, this
# means that we need to add the src directory to the sys.path.
here = os.path.abspath(os.path.dirname(__file__))
src_dir = os.path.join(here, "conda")
sys.path.insert(0, src_dir)
import conda # NOQA
from conda.auxlib.packaging import BuildPyCommand, SDistCommand # NOQA


with open(os.path.join(here, "README.rst")) as f:
long_description = f.read()


setup(
name="conda",
version=versioneer.get_version(),
cmdclass=versioneer.get_cmdclass(),
author="Continuum Analytics, Inc.",
author_email="[email protected]",
url="https://github.com/conda/conda",
license="BSD",
name=conda.__name__,
version=conda.__version__,
author=conda.__author__,
author_email=conda.__email__,
url=conda.__url__,
license=conda.__license__,
description=conda.__summary__,
long_description=long_description,
classifiers=[
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Developers",
Expand All @@ -49,13 +55,16 @@
"Programming Language :: Python :: 3.4",
"Programming Language :: Python :: 3.5",
],
description="OS-agnostic, system-level binary package manager.",
long_description=open('README.rst').read(),
packages=[
'conda',
'conda.auxlib'
'conda.cli',
'conda.progressbar'
],
cmdclass={
'build_py': BuildPyCommand,
'sdist': SDistCommand,
},
install_requires=['pycosat >=0.6.1', 'pyyaml', 'requests'],
entry_points={
'console_scripts': [
Expand Down

0 comments on commit a1fc225

Please sign in to comment.