Skip to content

Commit

Permalink
add auxlib to project root
Browse files Browse the repository at this point in the history
  • Loading branch information
kalefranz committed Mar 7, 2016
1 parent 29f01ce commit 94feda4
Show file tree
Hide file tree
Showing 4 changed files with 289 additions and 3 deletions.
26 changes: 26 additions & 0 deletions auxlib/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
"""auxiliary library to the python standard library"""
from __future__ import absolute_import, division, print_function
from logging import getLogger, NullHandler

# don't mess up logging for users
getLogger('auxlib').addHandler(NullHandler())

from .packaging import BuildPyCommand, SDistCommand, Tox, get_version # NOQA

__all__ = [
"__title__", "__version__", "__author__",
"__email__", "__license__", "__copyright__",
"__summary__", "__homepage__",
"BuildPyCommand", "SDistCommand", "Tox", "get_version",
]

__version__ = get_version(__file__, __package__)

__title__ = "auxlib"
__author__ = 'Kale Franz'
__email__ = '[email protected]'
__homepage__ = 'https://github.com/kalefranz/auxlib'
__license__ = "ISC"
__copyright__ = "(c) 2015 Kale Franz. All rights reserved."
__summary__ = __doc__
160 changes: 160 additions & 0 deletions auxlib/packaging.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
# -*- coding: utf-8 -*-
from __future__ import print_function, division, absolute_import
from logging import getLogger
from os import remove
from os.path import isdir, isfile, join
from re import match
try:
from setuptools.command.build_py import build_py
from setuptools.command.sdist import sdist
from setuptools.command.test import test as TestCommand
except ImportError:
from distutils.command.build_py import build_py
from distutils.command.sdist import sdist
TestCommand = object

from subprocess import CalledProcessError, check_call, check_output, call
import sys

from .path import absdirname, PackageFile

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(path):
try:
check_call(('git', 'diff', '--quiet'), cwd=path)
check_call(('git', 'diff', '--cached', '--quiet'), cwd=path)
return False
except CalledProcessError:
return True


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


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


def _get_version_from_git_tag(path):
"""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(path)
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(path):
dev = (m.group('dev') or b'0').decode('utf-8')
hash_ = (m.group('hash') or _get_git_hash(path)).decode('utf-8')
version += ".dev{dev}+{hash_}".format(dev=dev, hash_=hash_)
return version


def is_git_repo(path):
return call(('git', 'rev-parse'), cwd=path) == 0


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.
"""
# check for .version file
try:
version_from_pkg = _get_version_from_pkg_info(package)
return version_from_pkg.decode('UTF-8') if hasattr(version_from_pkg, 'decode') else version_from_pkg # NOQA
except IOError:
# no .version file found; fall back to git repo
here = absdirname(file)
if is_git_repo(here):
return _get_version_from_git_tag(here)

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


def write_version_into_init(target_dir, version):
target_init_file = join(target_dir, "__init__.py")
assert isfile(target_init_file), "File not found: {0}".format(target_init_file)
with open(target_init_file, 'r') as f:
init_lines = f.readlines()
for q in range(len(init_lines)):
if init_lines[q].startswith('__version__'):
init_lines[q] = '__version__ = "{0}"\n'.format(version)
elif init_lines[q].startswith(('from auxlib', 'import auxlib')):
init_lines[q] = None
print("UPDATING {0}".format(target_init_file))
remove(target_init_file)
with open(target_init_file, 'w') as f:
f.write(''.join(l for l in init_lines if l is not None))


def write_version_file(target_dir, version):
assert isdir(target_dir), "Directory not found: {0}".format(target_dir)
target_file = join(target_dir, ".version")
with open(target_file, 'w') as f:
f.write(version)


class BuildPyCommand(build_py):
def run(self):
build_py.run(self)
target_dir = join(self.build_lib, self.distribution.metadata.name)
write_version_into_init(target_dir, self.distribution.metadata.version)
write_version_file(target_dir, self.distribution.metadata.version)


class SDistCommand(sdist):
def make_release_tree(self, base_dir, files):
sdist.make_release_tree(self, base_dir, files)
target_dir = join(base_dir, self.distribution.metadata.name)
write_version_into_init(target_dir, self.distribution.metadata.version)
write_version_file(target_dir, self.distribution.metadata.version)


class Tox(TestCommand):
user_options = [('tox-args=', 'a', "Arguments to pass to tox")]

def initialize_options(self):
TestCommand.initialize_options(self)
self.tox_args = None

def finalize_options(self):
TestCommand.finalize_options(self)
self.test_args = []
self.test_suite = True

def run_tests(self):
# import here, cause outside the eggs aren't loaded
import tox
import shlex
args = self.tox_args
if args:
args = shlex.split(self.tox_args)
else:
args = ''
errno = tox.cmdline(args=args)
sys.exit(errno)
102 changes: 102 additions & 0 deletions auxlib/path.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# -*- coding: utf-8 -*-
from __future__ import print_function, division, absolute_import
from distutils.sysconfig import get_python_lib
from logging import getLogger
from os import chdir, getcwd
from os.path import (abspath, dirname, exists, expanduser, expandvars, isdir, isfile, join,
normpath, sep)
try:
import pkg_resources
except ImportError:
pkg_resources = None
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()


class ChangePath(object):

def __init__(self, path):
self.dirpath = dirname(path) if isfile(path) else path
if not isdir(self.dirpath):
raise IOError('File or directory not found: {0}'.format(path))

def __enter__(self):
self.cwd = getcwd()
chdir(self.dirpath)
return self

def __exit__(self, *args):
chdir(self.cwd)


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 is not None
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)))
4 changes: 1 addition & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@
import os
import sys

import auxlib # a build-time dependency only

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 @@ -29,6 +27,7 @@
here = os.path.abspath(os.path.dirname(__file__))
src_dir = os.path.join(here, "conda")
sys.path.insert(0, src_dir)
import auxlib # a build-time dependency only
import conda # NOQA


Expand All @@ -52,7 +51,6 @@
"Programming Language :: Python :: 2",
"Programming Language :: Python :: 2.7",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.3",
"Programming Language :: Python :: 3.4",
"Programming Language :: Python :: 3.5",
],
Expand Down

0 comments on commit 94feda4

Please sign in to comment.