Skip to content
Snippets Groups Projects
upload_or_check_nonexistence.py 4.85 KiB
Newer Older
  • Learn to ignore specific revisions
  • jlaura's avatar
    jlaura committed
    #!/usr/bin/env python
    from __future__ import print_function
    
    import argparse
    import hashlib
    import os
    import subprocess
    import sys
    
    from binstar_client.utils import get_binstar
    import binstar_client.errors
    import conda.config
    from conda_build.metadata import MetaData
    from conda_build.build import bldpkg_path
    
    
    def built_distribution_already_exists(cli, meta, owner):
        """
        Checks to see whether the built recipe (aka distribution) already
        exists on the owner/user's binstar account.
        """
        distro_name = '{}/{}.tar.bz2'.format(conda.config.subdir, meta.dist())
        fname = bldpkg_path(meta)
        try:
            dist_info = cli.distribution(owner, meta.name(), meta.version(),
                                         distro_name)
        except binstar_client.errors.NotFound:
            dist_info = {}
    
        exists = bool(dist_info)
        # Unfortunately, we cannot check the md5 quality of the built distribution, as
        # this will depend on fstat information such as modification date (because
        # distributions are tar files). Therefore we can only assume that the distribution
        # just built, and the one on anaconda.org are the same.
    #    if exists:
    #        md5_on_binstar = dist_info.get('md5')
    #        with open(fname, 'rb') as fh:
    #            md5_of_build = hashlib.md5(fh.read()).hexdigest()
    #
    #        if md5_on_binstar != md5_of_build:
    #            raise ValueError('This build ({}), and the build already on binstar '
    #                             '({}) are different.'.format(md5_of_build, md5_on_binstar))
        return exists
    
    
    def upload(cli, meta, owner, channels):
        try:
            with open('binstar.token', 'w') as fh:
                fh.write(cli.token)
            subprocess.check_call(['anaconda', '--quiet', '-t', 'binstar.token',
                                   'upload', bldpkg_path(meta),
                                   '--user={}'.format(owner),
                                   '--channel={}'.format(channels)],
                                  env=os.environ)
        finally:
            os.remove('binstar.token')
    
    
    def distribution_exists_on_channel(binstar_cli, meta, owner, channel='main'):
        """
        Determine whether a distribution exists on a specific channel.
        Note from @pelson: As far as I can see, there is no easy way to do this on binstar.
        """
        fname = '{}/{}.tar.bz2'.format(conda.config.subdir, meta.dist())
        distributions_on_channel = [dist['basename'] for dist in
                                    binstar_cli.show_channel(owner=owner, channel=channel)['files']]
        return fname in distributions_on_channel
    
    
    def add_distribution_to_channel(binstar_cli, meta, owner, channel='main'):
        """
        Add a(n already existing) distribution on binstar to another channel.
        Note - the addition is done based on name and version - no build strings etc.
        so if you have a foo-0.1-np18 and foo-0.1-np19 *both* will be added to the channel.
        """
        package_fname = '{}/{}.tar.bz2'.format(conda.config.subdir, meta.dist())
        binstar_cli.add_channel(channel, owner, meta.name(), meta.version())
    
    
    def main():
        token = os.environ.get('BINSTAR_KEY')
    
        description = ('Upload or check consistency of a built version of a '
                       'conda recipe with binstar. Note: The existence of the '
                       'BINSTAR_KEY environment variable determines '
                       'whether the upload should actually take place.')
        parser = argparse.ArgumentParser(description=description)
        parser.add_argument('recipe_dir', help='the conda recipe directory')
        parser.add_argument('owner', help='the binstar owner/user')
        parser.add_argument('--channel', help='the binstar channel', default='main')
        args = parser.parse_args()
        recipe_dir, owner, channel = args.recipe_dir, args.owner, args.channel
    
        cli = get_binstar(argparse.Namespace(token=token, site=None))
        meta = MetaData(recipe_dir)
        if meta.skip():
            print("No upload to take place - this configuration was skipped in build/skip.")
            return
        exists = built_distribution_already_exists(cli, meta, owner)
        if token:
            on_channel = distribution_exists_on_channel(cli, meta, owner, channel)
            if not exists:
                upload(cli, meta, owner, channel)
                print('Uploaded {}'.format(bldpkg_path(meta)))
            elif not on_channel:
                print('Adding distribution {} to {}\'s {} channel'
                      ''.format(bldpkg_path(meta), owner, channel))
                add_distribution_to_channel(cli, meta, owner, channel)
            else:
                print('Distribution {} already \nexists on {}\'s {} channel.'
                      ''.format(bldpkg_path(meta), owner, channel))
        else:
            print("No BINSTAR_KEY present, so no upload is taking place. "
                  "The distribution just built {} already available on {}'s "
                  "{} channel.".format('is' if exists else 'is not',
                                       owner, channel))
    
    if __name__ == '__main__':
        main()