Skip to content
Snippets Groups Projects
update_feedstock.py 5.17 KiB
#!/usr/bin/env python

import hashlib
try:
  from urllib2 import urlopen
except ImportError:
  from urllib.request import urlopen
import requests
import json
try:
    from packaging.version import parse
except ImportError:
    from pip._vendor.packaging.version import parse
import re
import tempfile
import shutil
import os
import subprocess

URL_PATTERN = 'https://pypi.python.org/pypi/{package}/json'


def run_commands(*calls):
  """runs the given commands."""
  # get all calls
  for call in calls:
    print(' - ' + ' '.join(call))
    # execute call
    if subprocess.call(call):
      # call failed (has non-zero exit status)
      raise ValueError("Command '%s' failed; stopping" % ' '.join(call))


def get_version(package, url_pattern=URL_PATTERN):
  """Return version of package on pypi.python.org using json."""
  req = requests.get(url_pattern.format(package=package))
  version = parse('0')
  if req.status_code == requests.codes.ok:
    j = json.loads(req.text)
    if 'releases' in j:
      releases = j['releases']
      for release in releases:
        ver = parse(release)
        if not ver.is_prerelease:
          version = max(version, ver)
  return str(version)


def get_remote_md5_sum(url, max_file_size=100 * 1024 * 1024):
  remote = urlopen(url)
  hash = hashlib.md5()

  total_read = 0
  while True:
    data = remote.read(4096)
    total_read += 4096

    if not data or total_read > max_file_size:
      break
    hash.update(data)

  return hash.hexdigest()


def main(package, direct_push=False):
  stable_version = get_version(package)
  print('latest stable version for {} is {}'.format(package, stable_version))
  url = 'https://pypi.io/packages/source/{0}/{1}/{1}-{2}.zip'.format(
    package[0], package, stable_version)
  try:
    md5 = get_remote_md5_sum(url)
  except Exception:
      raise
  temp_dir = tempfile.mkdtemp()
  try:
    print("\nClonning the feedstock")
    feedstock = os.path.join(temp_dir, '{}-feedstock'.format(package))
    try:
      run_commands(
        ['git', 'clone',
         'git@github.com:conda-forge/{}-feedstock.git'.format(package),
         feedstock])
    except ValueError:
      print("\nThe feedstock does not exist on conda-forge. Exiting ...")
      raise
    os.chdir(feedstock)
    if not direct_push:
      run_commands(
        ['git', 'remote', 'add', 'bioidiap',
         'git@github.com:bioidiap/{}-feedstock.git'.format(package)],
        ['git', 'checkout', '-b', stable_version])
    # update meta.yaml
    with open('recipe/meta.yaml') as f:
      doc = f.read()
    if package == 'bob.math':
      build_number = '200'
    else:
      build_number = '0'
    doc = re.sub(r'\{\s?%\s?set\s?version\s?=\s?".*"\s?%\s?\}',
                 '{% set version = "' + str(stable_version) + '" %}',
                 doc, count=1)
    doc = re.sub(r'\s+number\:\s?[0-9]+', '\n  number: ' + build_number, doc,
                 count=1)
    doc = re.sub(r'\{\s?%\s?set\s?build_number\s?=\s?"[0-9]+"\s?%\s?\}',
                 '{% set build_number = "' + build_number + '" %}',
                 doc, count=1)
    doc = re.sub(r'\s+md5\:.*', '\n  md5: {}'.format(md5), doc, count=1)
    doc = re.sub(r'\s+url\:.*',
                 '\n  url: {}'.format(
                  url.replace(stable_version, '{{ version }}')),
                 doc, count=1)
    doc = re.sub(r'\s+home\:.*',
                 '\n  home: https://www.idiap.ch/software/bob/',
                 doc, count=1)

    if package == 'bob':
      requrl = 'https://gitlab.idiap.ch/bob/bob/raw/master/requirements.txt'
      remote = requests.get(requrl)
      req = remote.content.decode()
      req = '\n    - '.join(req.replace('== ', '==').strip().split('\n'))
      be_id = doc.find('bob.extension')
      te_id = doc.find('test:\n', be_id)
      template = '''{req}

  run:
    - python
    - {req}

'''.format(req=req)
      doc = doc[:be_id] + template + doc[te_id:]

    with open('recipe/meta.yaml', 'w') as f:
      f.write(doc)

    run_commands(['conda-smithy', 'rerender'],
                 ['git', '--no-pager', 'diff'],
                 ['git', 'add', '-A'])
    try:
      run_commands(['git', 'commit', '-am',
                    'Fix badges [skip ci]'])
                    # 'Update to version {}'.format(stable_version)])
    except ValueError:
      print('Feedstock is already uptodate, skipping.')
      return
    if direct_push:
      print(feedstock)
      try:
        answer = raw_input('Would you like to push directly to master?').lower()
      except Exception:
        answer = input('Would you like to push directly to master?').lower()
      if answer.startswith('y') or answer == '':
        run_commands(['git', 'push'])
        print('See the changes at:\n'
              'https://github.com/conda-forge/'
              '{}-feedstock/commits/master\n\n'.format(package))
    else:
      run_commands(['git', 'push', '--force', '--set-upstream',
                    'bioidiap', stable_version],
                   ['hub', 'pull-request', '-b', 'conda-forge:master',
                    '-h', 'bioidiap:{}'.format(stable_version),
                    '-m', 'Update to version {}'.format(stable_version)])
  finally:
    shutil.rmtree(temp_dir)


if __name__ == '__main__':
  import sys
  pkg = sys.argv[1]
  main(pkg)