aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xblast.py192
1 files changed, 123 insertions, 69 deletions
diff --git a/blast.py b/blast.py
index b1da853..2315b92 100755
--- a/blast.py
+++ b/blast.py
@@ -4,14 +4,17 @@ import os
import yaml
import subprocess
import sys
+from glob import glob
from packaging.specifiers import SpecifierSet
from packaging.version import Version, InvalidVersion
USER_CONFIG = os.path.expanduser('~/.blast/config.yaml')
USER_CONFIG_EXISTS = os.path.exists(USER_CONFIG)
+VERSION_BAD_PATTERNS = ['release_', '_release', 'release-', '-release']
SPECIFIERS = ['~', '!', '<', '>', '=']
+
@contextlib.contextmanager
def use_directory(path):
prev = os.path.abspath(os.curdir)
@@ -30,7 +33,8 @@ class PyEnv:
def _cmd(self, *args, **kwargs):
if not args:
- raise ValueError('Expecting arguments to pass to pyenv. Got nothing.')
+ raise ValueError('Expecting arguments to pass to pyenv. '
+ 'Got nothing.')
command = []
proc = None
@@ -54,7 +58,9 @@ class PyEnv:
command = ' '.join(command) # convert to string
try:
- proc = subprocess.run(command, env=env, shell=shell, stdout=stdout, stderr=stderr, check=True, encoding='utf-8')
+ proc = subprocess.run(command, env=env, shell=shell,
+ stdout=stdout, stderr=stderr,
+ check=True, encoding='utf-8')
except subprocess.CalledProcessError as cpe:
if cpe.returncode:
print('Command (exit {}): {}'.format(cpe.returncode, command))
@@ -68,25 +74,28 @@ class PyEnv:
def create(self):
if os.environ.get('PYENV_ROOT'):
- if not os.path.exists(os.path.join(os.environ['PYENV_ROOT'], 'versions', self.version)):
- proc_inst = self._cmd('install', '-s', self.version, override=True)
+ if not os.path.exists(os.path.join(os.environ['PYENV_ROOT'],
+ 'versions', self.version)):
+ proc_inst = self._cmd('install', '-s',
+ self.version, override=True)
if proc_inst.stderr:
- if not 'already' in proc_inst.stderr:
+ if 'already' not in proc_inst.stderr:
print(proc_inst.stderr)
exit(1)
- if not os.path.exists(os.path.join(os.environ['PYENV_ROOT'], 'versions', self.venv)):
- proc_venv = self._cmd('virtualenv', self.version, self.venv, override=True)
+ if not os.path.exists(os.path.join(os.environ['PYENV_ROOT'],
+ 'versions', self.venv)):
+ self._cmd('virtualenv', self.version, self.venv, override=True)
else:
raise RuntimeError('PYENV_ROOT is not defined.')
exit(1)
-
def activate(self):
env = {}
command = 'eval "$(pyenv init -)" ' \
'&& eval "$(pyenv virtualenv-init -)" ' \
- '&& pyenv activate "{}" && pyenv rehash && printenv'.format(self.venv)
+ '&& pyenv activate "{}" ' \
+ '&& pyenv rehash && printenv'.format(self.venv)
proc = self._cmd(command,
shell=True, redirect=True)
@@ -101,15 +110,22 @@ class PyEnv:
class Git:
- def __init__(self, uri):
+ def __init__(self, uri, root='.'):
self.uri = uri
- self.base = os.path.abspath(os.path.basename(self.uri).replace('.git', ''))
- self.basepath = self.base
+ self.root = os.path.abspath(root)
+
+ if not os.path.exists(self.root):
+ print('Making {}'.format(self.root))
+ os.makedirs(self.root)
+
+ self.base = os.path.basename(self.uri).replace('.git', '')
+ self.basepath = os.path.abspath(os.path.join(self.root, self.base))
self._tags = []
def _cmd(self, *args, **kwargs):
if not args:
- raise ValueError('Expecting arguments to pass to Git. Got nothing.')
+ raise ValueError('Expecting arguments to pass to Git. '
+ 'Got nothing.')
command = ['git']
proc = None
@@ -118,7 +134,9 @@ class Git:
command.append(arg)
try:
- proc = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True, encoding='utf-8')
+ proc = subprocess.run(command, stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE, check=True,
+ encoding='utf-8')
except subprocess.CalledProcessError as cpe:
print('Command (exit {}): {}'.format(cpe.returncode, command))
print(cpe.stderr.strip())
@@ -136,7 +154,9 @@ class Git:
if os.path.exists(self.basepath):
return self.basepath
- self._cmd('clone', self.uri)
+ with use_directory(self.root):
+ self._cmd('clone', self.uri)
+
return self.basepath
def fetch(self, *args, **kwargs):
@@ -180,7 +200,6 @@ class Git:
def setuptools_inject():
- print("Injecting setuptools...")
with open('setup.py', 'r') as script:
orig = script.read().splitlines()
@@ -191,6 +210,15 @@ def setuptools_inject():
script.write(new)
+def normalize_tag(tag, bad_patterns):
+ # Normalize non-standard tagging conventions
+ if bad_patterns is not None:
+ for pattern in bad_patterns:
+ tag = tag.replace(pattern, '')
+
+ return tag
+
+
def eval_specifier(spec, tag, bad_patterns=None):
# Determine if specifiers are present in spec string
have_specifier = False
@@ -204,11 +232,7 @@ def eval_specifier(spec, tag, bad_patterns=None):
spec = '==' + spec
spec = SpecifierSet(spec)
-
- # Normalize non-standard tagging conventions
- if bad_patterns is not None:
- for pattern in bad_patterns:
- tag = tag.replace(pattern, '')
+ tag = normalize_tag(tag)
try:
tag = Version(tag)
@@ -219,6 +243,24 @@ def eval_specifier(spec, tag, bad_patterns=None):
return tag in spec
+def dist_exists(root, mode, bad_patterns, *hints):
+ ext = ''
+ if mode == 'sdist':
+ ext = '.tar.gz'
+ elif mode == 'bdist_wheel':
+ ext = '.whl'
+ else:
+ raise NotImplementedError('Mode "{}" is not implemented.'.format(mode))
+
+ pattern = normalize_tag('*'.join(hints), bad_patterns) + '*' + ext
+ paths = glob(os.path.join(root, pattern))
+
+ if paths:
+ return True
+
+ return False
+
+
if __name__ == '__main__':
# import argparse
# from pprint import pprint
@@ -240,54 +282,56 @@ if __name__ == '__main__':
requires:
- wheel
- version_latest: true
+ #version_latest: true
version_bad_patterns:
- 'release_'
- '_release'
- 'release-'
- '-release'
+ - 'v'
+ - 'V'
projects:
- #acstools:
- # requires:
- # - relic
+ acstools:
+ requires:
+ - relic
- #asdf:
- # requires: null
+ asdf:
+ requires: null
- #calcos:
- # requires: null
+ calcos:
+ requires: null
- #costools:
- # requires: null
+ costools:
+ requires: null
- #crds:
- # requires:
- # - astropy
- # - numpy
- # - requests
- # setuptools_inject: true
+ crds:
+ requires:
+ - astropy
+ - numpy
+ - requests
+ setuptools_inject: true
- #drizzle:
- # requires: null
+ drizzle:
+ requires: null
- #drizzlepac:
- # requires:
- # - astropy
- # - numpy
+ drizzlepac:
+ requires:
+ - astropy
+ - numpy
- #fitsblender:
- # requires: null
+ fitsblender:
+ requires: null
- #imexam:
- # requires: null
+ imexam:
+ requires: null
- #nictools:
- # requires: null
+ nictools:
+ requires: null
- #pysynphot:
- # requires: null
+ pysynphot:
+ requires: null
reftools:
requires: null
@@ -344,9 +388,13 @@ if __name__ == '__main__':
requires: null
""")
- upload_dir = os.path.abspath(os.path.join(os.curdir, 'upload'))
- if not os.path.exists(upload_dir):
- os.mkdir(upload_dir)
+ output_dir = os.path.abspath(os.path.join(os.curdir, 'upload'))
+
+ if config.get('output_dir'):
+ output_dir = os.path.abspath(config['output_dir'])
+
+ if not os.path.exists(output_dir):
+ os.mkdir(output_dir)
# Begin aliveness checks before we get too far
check_keys = ['global', 'host', 'organization', 'projects']
@@ -364,7 +412,6 @@ if __name__ == '__main__':
# Check structure of project dictionaries
for project, info in config['projects'].items():
- print(project, info)
if info is None and not info.get('requires'):
print('Error: {}: Missing `requires` list'.format(project), file=sys.stderr)
failed_requires = True
@@ -375,7 +422,7 @@ if __name__ == '__main__':
# Perform matrix tasks
for project, info in config['projects'].items():
url = '/'.join([config['host'], config['organization'], project])
- repo = Git(url)
+ repo = Git(url, root='src')
print('Repository: {}'.format(url))
print('Source directory: {}'.format(repo.basepath))
@@ -397,13 +444,13 @@ if __name__ == '__main__':
pyenv.activate()
# Upgrade PIP
- pyenv.run('pip', 'install', '--upgrade', 'pip', redirect=True)
+ pyenv.run('pip', 'install', '-q', '--upgrade', 'pip', redirect=True)
# Generic setup
if config.get('global'):
if config['global'].get('requires'):
for pkg in config['global']['requires']:
- pyenv.run('pip', 'install', pkg, redirect=True)
+ pyenv.run('pip', 'install', '-q', pkg, redirect=True)
if config['global'].get('version_latest'):
repo.reset('--hard')
@@ -415,15 +462,15 @@ if __name__ == '__main__':
if info.get('requires'):
for pkg in info['requires']:
- pyenv.run('pip', 'install', pkg)
+ pyenv.run('pip', 'install', '-q', pkg)
for tag in tags:
+ sanitize = VERSION_BAD_PATTERNS
if info.get('build_versions'):
spec = info['build_versions']
- sanitize = None
if config['global'].get('version_bad_patterns'):
- sanitize = config['global']['version_bad_patterns']
+ sanitize += config['global']['version_bad_patterns']
if info.get('version_bad_patterns'):
sanitize += info['version_bad_patterns']
@@ -438,15 +485,22 @@ if __name__ == '__main__':
repo.checkout(tag)
if info.get('setuptools_inject', False):
+ print('===> Overriding distutils with setuptools')
setuptools_inject()
- for build_command in ['sdist', 'bdist_egg', 'bdist_wheel']:
+ for build_command, build_args in [('sdist', []),
+ ('bdist_wheel', [])]:
print('===> {}::{}: {}: '.format(project, tag, build_command), end='')
- proc = pyenv.run('python', 'setup.py', build_command, '-d', upload_dir, redirect=True)
- if proc.stderr and proc.returncode:
- print("FAILED")
- print('#{}'.format('!' * 78))
- print(proc.stderr)
- print('#{}'.format('!' * 78))
+ if not dist_exists(output_dir, build_command, sanitize, project, tag):
+ proc = pyenv.run('python', 'setup.py',
+ build_command, '-d', output_dir,
+ *build_args, redirect=True)
+ if proc.stderr and proc.returncode:
+ print("FAILED")
+ print('#{}'.format('!' * 78))
+ print(proc.stderr)
+ print('#{}'.format('!' * 78))
+ elif not proc.returncode:
+ print("SUCCESS")
else:
- print("SUCCESS")
+ print("EXISTS")