def __init__(self, bs, worker_config, args): Worker.__init__(self, bs, worker_config, args) self.client = docker.Client(version=os.environ.get('DOCKER_VERSION'), **kwargs_from_env(assert_hostname=False)) log.info('Connecting to docker daemon ...') try: image = args.image if ':' in image: self.image, self.tag = image.split(':', 1) else: self.image, self.tag = image, None images = self.client.images(self.image) except ConnectionError as err: raise errors.BinstarError( "Docker client could not connect to daemon (is docker installed?)\n" "You may need to set your DOCKER_HOST environment variable") if not images: raise errors.BinstarError( "You do not have the docker image '{image}'\n" "You may need to run:\n\n\tdocker pull {image}s\n".format( image=args.image)) if self.args.allow_user_images: log.warn("Allowing users to specify docker images")
def main(args): bs = get_binstar(args, cls=BinstarBuildAPI) if args.queue is None: username = queue_name = None elif args.queue.count('/') == 1: username, queue_name = args.queue.split('/', 1) elif args.queue.count('/') == 2: _, username, queue_name = args.queue.split('/', 2) elif args.queue.count('-') == 2: _, username, queue_name = args.queue.split('-', 2) else: raise errors.UserError( "Build queue must be of the form build-USERNAME-QUEUENAME or USERNAME/QUEUENAME" ) if args.create: if queue_name is None: raise errors.BinstarError("Must specify a queue name to create") if not is_valid_name(queue_name): raise errors.BinstarError( 'Invalid name for ' 'queue: {}. Must start' ' with a letter and contain' ' only numbers, letters, -, and _'.format(queue_name)) bs.add_build_queue(username, queue_name) print("Created queue %s" % queue_name) return if queue_name: queue = bs.build_queue(username, queue_name) if args.remove: if queue.get('workers'): prompt = ('This build queue still has workers attached. ' 'Are you sure you want to remove it') if not bool_input(prompt, False): print("Not removing queue") return bs.remove_build_queue(username, queue_name) print("Removed queue %s" % queue_name) return if args.remove_worker: bs.remove_worker(username, queue_name, args.remove_worker) print("Removed worker %s from queue %s" % (args.remove_worker, queue_name)) return if queue_name: print() show_queue(queue) else: show_queues(bs, username)
def get_package_name(args, package_attrs, filename, package_type): if args.package: if 'name' in package_attrs and package_attrs['name'].lower() != args.package.lower(): msg = 'Package name on the command line " %s" does not match the package name in the file "%s"' raise errors.BinstarError(msg % (args.package.lower(), package_attrs['name'].lower())) package_name = args.package else: if 'name' not in package_attrs: raise errors.BinstarError("Could not detect package name for package type %s, please use the --package option" % (package_type,)) package_name = package_attrs['name'] return package_name
def add_package(aserver_api, args, username, package_name, package_attrs, package_type): try: return aserver_api.package(username, package_name) except errors.NotFound: if not args.auto_register: message = ( 'Anaconda repository package %s/%s does not exist. ' 'Please run "anaconda package --create" to create this package namespace in the cloud.' % (username, package_name) ) logger.error(message) raise errors.UserError(message) else: if args.summary: summary = args.summary else: if 'summary' not in package_attrs: message = "Could not detect package summary for package type %s, please use the --summary option" % (package_type,) logger.error(message) raise errors.BinstarError(message) summary = package_attrs['summary'] public = not args.private return aserver_api.add_package( username, package_name, summary, package_attrs.get('license'), public=public, attrs=package_attrs, license_url=package_attrs.get('license_url'), license_family=package_attrs.get('license_family'), package_type=package_type, )
def register(cls, bs, username, queue, platform, hostname, dist, name=None): ''' Register the worker with anaconda server ''' for worker in cls.registered_workers(bs): if name in (worker.name, worker.worker_id): raise errors.BinstarError('Cannot have duplicate worker ' '--name or id: {}'.format(name)) worker_id = bs.register_worker(username, queue, platform, hostname, dist, name=name) log.info('Registered worker with worker_id:\t{}'.format(worker_id)) if name is None: name = worker_id return WorkerConfiguration(name, worker_id, username, queue, platform, hostname, dist)
def add_package(aserver_api, args, username, package_name, package_attrs, package_type): try: aserver_api.package(username, package_name) except errors.NotFound: if not args.auto_register: raise errors.UserError( 'Anaconda Cloud package %s/%s does not exist. ' 'Please run "anaconda package --create" to create this package namespace in the cloud.' % (username, package_name)) else: if args.summary: summary = args.summary else: if 'summary' not in package_attrs: raise errors.BinstarError( "Could not detect package summary for package type %s, please use the --summary option" % (package_type, )) summary = package_attrs['summary'] aserver_api.add_package(username, package_name, summary, package_attrs.get('license'), public=True, attrs=package_attrs)
def register_func(cls, *args, **kwargs): name = kwargs.get('name') if name in registered: raise errors.BinstarError( 'already registered {}'.format(registered)) registered[name] = True args2 = [name] + list(args) return WorkerConfiguration(*args2)
def get_version(args, release_attrs, package_type): if args.version: version = args.version else: if 'version' not in release_attrs: raise errors.BinstarError("Could not detect package version for package type %s, please use the --version option" % (package_type,)) version = release_attrs['version'] return version
def load(cls, worker_name, bs): 'Load a worker config from a worker_id' for worker in cls.registered_workers(bs): if worker_name == worker.worker_id or worker_name == worker.name: if worker.hostname == cls.HOSTNAME: return worker raise errors.BinstarError('Worker with id ' '{} not found'.format(worker_name))
def job_loop(self): """ An iterator that will yield job_data objects when one is available. Also handles journaling of jobs """ bs = self.bs worker_idle = False while 1: try: job_data = bs.pop_build_job(self.config.username, self.config.queue, self.worker_id) except errors.NotFound: self.write_status(False, "worker not found") if self.args.show_traceback: raise else: msg = ("This worker can no longer " "pop items off the build queue. " "Did someone remove it manually?") raise errors.BinstarError(msg) except requests.ConnectionError as err: log.error("Trouble connecting to binstar at '{0}' ".format( bs.domain)) log.error("Could not retrieve work items") job_data = {} self.write_status(False, "Trouble connecting to binstar") except errors.ServerError as err: log.exception(err) log.error( "There server '{0}' returned an error response ".format( bs.domain)) log.error("Could not retrieve work items") self.write_status(False, "Server error") job_data = {} else: self.write_status(True) if job_data.get('job') is None: if not worker_idle: idle_msg = 'Worker is waiting for the next job' log.info(idle_msg) worker_idle = True time.sleep(self.SLEEP_TIME) continue worker_idle = False yield job_data if self.args.one: break
def load(cls, worker_name, bs, warn=False): 'Load a worker config from a worker_id' for worker in cls.registered_workers(bs): if worker_name in (worker.worker_id, worker.name): return worker raise errors.BinstarError('Worker with id ' '{} not found'.format(worker_name))
def submit_build(binstar, args): path = abspath(args.path) log.info('Getting build product: %s' % abspath(args.path)) with open(join(path, '.binstar.yml')) as cfg: build_matrix = list(yaml.load_all(cfg)) builds = list(serialize_builds(build_matrix)) if args.platform: log.info("Only selecting builds on platform %s" % args.platform) builds = [b for b in builds if b['platform'] == args.platform] if not builds: msg = "No build instructions found" if args.platform: msg += " for platform %s" % args.platform raise errors.BinstarError(msg) log.info('Submitting %i sub builds' % len(builds)) for i, build in enumerate(builds): log.info(' %i)' % i + ' %(platform)-10s %(engine)-15s %(env)-15s' % build) if not args.dry_run: if args.git_url: log.info("Submitting the following repo for package creation: %s" % args.git_url) else: with mktemp() as tmp: log.info("Archiving build directory for upload ...") with tarfile.open(tmp, mode='w|bz2') as tf: exclude = ExcludeGit(path, use_git_ignore=not args.dont_git_ignore) tf.add(path, '.', exclude=exclude) log.info("Created archive (%i files); Uploading to binstar" % exclude.num_included) queue_tags = [] if args.buildhost: queue_tags.append('hostname:%s' % args.buildhost) if args.dist: queue_tags.append('dist:%s' % args.dist) with open(tmp, mode='rb') as fd: build = binstar.submit_for_build(args.package.user, args.package.name, fd, builds, channels=args.channels, queue=args.queue, queue_tags=queue_tags, test_only=args.test_only, callback=upload_print_callback(args)) print_build_results(args, build) else: log.info('Build not submitted (dry-run)')
def __init__(self, bs, args): Worker.__init__(self, bs, args) self.client = docker.Client(base_url=os.environ.get('DOCKER_HOST')) log.info('Connecting to docker daemon ...') try: images = self.client.images(args.image) except ConnectionError as err: raise errors.BinstarError( "Docker client could not connect to daemon (is docker installed?)\n" "You may need to set your DOCKER_HOST environment variable") if not images: raise errors.BinstarError( "You do not have the docker image '%(image)s'\n" "You may need to run:\n\n\tdocker pull %(image)s\n" % dict(image=args.image)) if self.args.allow_user_images: log.warn("Allowing users to specify docker images")
def main(args): aserver_api = get_server_api(args.token, args.site) aserver_api.check_server() if args.user: username = args.user else: user = aserver_api.user() username = user['login'] uploaded_packages = [] uploaded_projects = [] # Flatten file list because of 'windows_glob' function files = [f for fglob in args.files for f in fglob] if args.all: files += get_convert_files(files) for filename in files: if not exists(filename): message = 'file %s does not exist' % (filename) logger.error(message) raise errors.BinstarError(message) package_type = determine_package_type(filename, args) if package_type == 'project': uploaded_projects.append(upload_project(filename, args, username)) else: if package_type == 'ipynb' and not args.mode == 'force': try: nbformat.read(open(filename), nbformat.NO_CONVERT) except Exception as error: logger.error("Invalid notebook file '%s': %s", filename, error) logger.info("Use --force to upload the file anyways") continue package_info = upload_package(filename, package_type=package_type, aserver_api=aserver_api, username=username, args=args) if package_info: uploaded_packages.append(package_info) for package, upload_info in uploaded_packages: package_url = upload_info.get( 'url', 'https://anaconda.org/%s/%s' % (username, package)) logger.info("{} located at:\n{}\n".format( verbose_package_type(package_type), package_url)) for project_name, url in uploaded_projects: logger.info("Project {} uploaded to {}.\n".format(project_name, url))
def determine_package_type(filename, args): """ return the file type from the inspected package or from the -t/--package-type argument """ if args.package_type: package_type = args.package_type else: log.info('detecting package type ...') sys.stdout.flush() package_type = detect_package_type(filename) if package_type is None: raise errors.BinstarError('Could not detect package type of file %r please specify package type with option --package-type' % filename) log.info(package_type) return package_type
def main(args): binstar = get_binstar(args) print("main upload!") if args.dest and '/' in args.dest: username = args.dest.split('/', 1)[0] else: user = binstar.user() username = user['login'] if args.dest: package_name = args.dest.rsplit('/', 1)[-1] else: package_name = os.path.basename(args.datafile).split('.')[0] if not exists(args.datafile): raise errors.BinstarError('file %s does not exist' % args.datafile) package_type = 'data' ensure_package(binstar, username, package_name, args.summary) ensure_version(binstar, username, package_name, args.version) ensure_unique(binstar, username, package_name, args.version, os.path.basename(args.datafile), force=False) with open(args.datafile) as fd: upload_info = binstar.upload(username, package_name, args.version, os.path.basename(args.datafile), fd, package_type, args.description, attrs={'data_type': 'download'}, channels=['main'], callback=upload_print_callback(args)) log.info("\n\nUpload(s) Complete\n") package_url = upload_info.get( 'url', 'https://anaconda.org/%s/%s' % (username, package_name)) log.info("Package located at:\n%s\n" % package_url)
def _real_upload_project(project, args, username): from anaconda_project import project_ops print("Uploading project: {}".format(project.name)) status = project_ops.upload(project, site=args.site, username=username, token=args.token, log_level=args.log_level) for log in status.logs: print(log) if not status: for error in status.errors: print(error, file=sys.stderr) print(status.status_description, file=sys.stderr) raise errors.BinstarError(status.status_description) else: print(status.status_description) return [project.name, status.url]
def upload_project(project_path, args, username): try: from anaconda_project import project_ops except ImportError: raise errors.BinstarError("To upload projects such as {}, install the anaconda-project package.".format(project_path)) from anaconda_project import project if os.path.exists(project_path) and not os.path.isdir(project_path): # make the single file into a temporary project directory with (_TmpDir(prefix="anaconda_upload_")) as dirname: shutil.copy(project_path, dirname) basename_no_extension = os.path.splitext(os.path.basename(project_path))[0] project = project_ops.create(dirname, name=basename_no_extension) return _real_upload_project(project, args, username) else: project = project.Project(directory_path=project_path) return _real_upload_project(project, args, username)
def deregister(self, bs, as_json=False): 'Deregister the worker from anaconda server' try: removed_worker = bs.remove_worker(self.username, self.queue, self.worker_id) if not removed_worker: raise errors.BinstarError('Failed to remove_worker with argument of ' + \ 'worker_id\t{}\tqueue\t{}'.format(self.worker_id, self.queue)) log.info('Deregistered worker with worker-id {}'.format(self.worker_id)) except Exception: log.info('Failed on anaconda build deregister.\n') self.print_registered_workers(bs) log.info('deregister failed with error:\n') raise
def running(self): 'Flag this worker id as running' if self.is_running(): msg = "This worker appears to already be running with pid {}".format(self.pid) raise errors.BinstarError(msg) dst = '{}.{}'.format(self.filename, os.getpid()) try: with open(dst, 'w') as out: out.write('') except (OSError, AttributeError): log.warning("Could not link the pid to a pidfile") try: yield finally: if os.path.isfile(dst): os.unlink(dst)
def validate_worker_name(cls, bs, name): workers_by_name = {} for worker in cls.registered_workers(bs): if not worker.name in workers_by_name: workers_by_name[worker.name] = [worker] else: workers_by_name[worker.name].append(worker) workers = workers_by_name.get(name, []) if len(workers) > 1: msg = '' for worker in workers: worker.name = name msg += '{name}, id:{worker_id}, hostname:{hostname}, queue:{username}/{queue}\n'.format( **worker.to_dict()) raise errors.BinstarError('Cannot anaconda worker run {}' ' (the name is ambiguous). Use' ' one of the worker id\'s below' ' instead.\n\n' + msg)
def upload(self, force=False): """ Uploads a notebook :param force: True/False :returns {} """ self.package and self.release try: return self.aserver_api.upload(self.username, self.project, self.version, self.name, self.content_io(), "ipynb") except errors.Conflict: if force: self.remove() return self.upload() else: msg = "Conflict: {}/{} already exist".format( self.project, self.version) raise errors.BinstarError(msg)
def upload(self, force=False): """ Uploads a notebook :param force: True/False :returns {} """ self.package and self.release try: return self.binstar.upload(self.username, self.project, self.version, basename(self.filepath), open(self.filepath, 'rb'), self.filepath.split('.')[-1]) except errors.Conflict: if force: self.remove() return self.upload() else: msg = "Conflict: {} already exist in {}/{}".format( self.filepath, self.project, self.version) raise errors.BinstarError(msg)
def determine_package_type(filename, args): """ return the file type from the inspected package or from the -t/--package-type argument """ if args.package_type: package_type = args.package_type else: logger.info('Detecting file type...') package_type = detect_package_type(filename) if package_type is None: message = 'Could not detect package type of file %r please specify package type with option --package-type' % filename logger.error(message) raise errors.BinstarError(message) logger.info('File type is "%s"', package_type) return package_type
def interactive_get_token(args, fail_if_already_exists=True): bs = get_server_api(args.token, args.site, args.log_level) config = get_config(remote_site=args.site) url = config.get('url', 'https://api.anaconda.org') parsed_url = urlparse(url) token = None hostname = getattr(args, 'hostname', platform.node()) if getattr(args, 'login_username', None): username = args.login_username else: username = input('Username: '******'binstar_client:' site = args.site or config.get('default_site') if site and site != 'binstar': # For testing with binstar alpha site auth_name += '%s:' % site auth_name += '%s@%s' % (getpass.getuser(), hostname) password = getattr(args, 'login_password', None) for _ in range(3): try: sys.stderr.write("%s's " % username) if password is None: password = getpass.getpass(stream=sys.stderr) token = bs.authenticate( username, password, auth_name, url, created_with=' '.join(sys.argv), fail_if_already_exists=fail_if_already_exists, hostname=hostname) break except errors.Unauthorized: log.error( 'Invalid Username password combination, please try again') password = None continue except errors.BinstarError as err: if fail_if_already_exists is True and err.args[1] == 400: log.warn('It appears you are already logged in from host %s' % socket.gethostname()) log.warn( 'Logging in again will remove the previous token. ' ' (This could cause troubles with virtual machines with the same hostname)' ) log.warn('Otherwise you can login again and specify a ' 'different hostname with "--hostname"') if bool_input("Would you like to continue"): fail_if_already_exists = False continue else: raise if token is None: if parsed_url.netloc.startswith('api.anaconda.org'): netloc = 'anaconda.org' else: netloc = parsed_url.netloc hostparts = (parsed_url.scheme, netloc) msg = ('Sorry. Please try again ' + \ '(go to %s://%s/account/forgot_password ' % hostparts + \ 'to reset your password)') raise errors.BinstarError(msg) return token
def interactive_get_token(args, fail_if_already_exists=True): bs = get_server_api(args.token, args.site, args.log_level) config = get_config(remote_site=args.site) token = None # This function could be called from a totally different CLI, so we don't # know if the attribute hostname exists. hostname = getattr(args, 'hostname', platform.node()) site = args.site or config.get('default_site') url = config.get('url', 'https://api.anaconda.org') auth_name = 'binstar_client:' if site and site != 'binstar': # For testing with binstar alpha site auth_name += '%s:' % site auth_name += '%s@%s' % (getpass.getuser(), hostname) bs.check_server() auth_type = bs.authentication_type() if auth_type == 'kerberos': token = try_replace_token( bs.krb_authenticate, application=auth_name, application_url=url, created_with=' '.join(sys.argv), fail_if_already_exists=fail_if_already_exists, hostname=hostname, ) if token is None: raise errors.BinstarError( 'Unable to authenticate via Kerberos. Try refreshing your ' 'authentication using `kinit`') else: if getattr(args, 'login_username', None): username = args.login_username else: username = input('Username: '******'login_password', None) for _ in range(3): try: sys.stderr.write("%s's " % username) if password is None: password = getpass.getpass(stream=sys.stderr) token = try_replace_token( bs.authenticate, username=username, password=password, application=auth_name, application_url=url, created_with=' '.join(sys.argv), fail_if_already_exists=fail_if_already_exists, hostname=hostname, ) break except errors.Unauthorized: log.error( 'Invalid Username password combination, please try again') password = None continue if token is None: parsed_url = urlparse(url) if parsed_url.netloc.startswith('api.anaconda.org'): netloc = 'anaconda.org' else: netloc = parsed_url.netloc hostparts = (parsed_url.scheme, netloc) msg = ('Sorry. Please try again ' + \ '(go to %s://%s/account/forgot_password ' % hostparts + \ 'to reset your password)') raise errors.BinstarError(msg) return token
def main(args): config = get_config(site=args.site) aserver_api = get_server_api(token=args.token, site=args.site, config=config) aserver_api.check_server() validate_username = True if args.user: username = args.user elif 'upload_user' in config: username = config['upload_user'] else: validate_username = False user = aserver_api.user() username = user['login'] logger.info('Using "%s" as upload username', username) if validate_username: try: aserver_api.user(username) except errors.NotFound: message = 'User "{}" does not exist'.format(username) logger.error(message) raise errors.BinstarError(message) uploaded_packages = [] uploaded_projects = [] # Flatten file list because of 'windows_glob' function files = [f for fglob in args.files for f in fglob] if args.all: files += get_convert_files(files) for filename in files: if not exists(filename): message = 'File "{}" does not exist'.format(filename) logger.error(message) raise errors.BinstarError(message) else: logger.info("Processing '%s'", filename) package_type = determine_package_type(filename, args) if package_type == 'project': uploaded_projects.append(upload_project(filename, args, username)) else: if package_type == 'ipynb' and not args.mode == 'force': try: nbformat.read(open(filename), nbformat.NO_CONVERT) except Exception as error: logger.error("Invalid notebook file '%s': %s", filename, error) logger.info("Use --force to upload the file anyways") continue package_info = upload_package(filename, package_type=package_type, aserver_api=aserver_api, username=username, args=args) if package_info is not None and len(package_info) == 2: _package, _upload_info = package_info if _upload_info: uploaded_packages.append(package_info) for package, upload_info in uploaded_packages: package_url = upload_info.get( 'url', 'https://anaconda.org/%s/%s' % (username, package)) logger.info("{} located at:\n{}\n".format( verbose_package_type(package_type), package_url)) for project_name, url in uploaded_projects: logger.info("Project {} uploaded to {}.\n".format(project_name, url))
def main(args): aserver_api = get_binstar(args) if args.user: username = args.user else: user = aserver_api.user() username = user['login'] uploaded_packages = [] # Flatten file list because of 'windows_glob' function files = [f for fglob in args.files for f in fglob] for filename in files: if not exists(filename): raise errors.BinstarError('file %s does not exist' % (filename)) package_type = determine_package_type(filename, args) log.info('extracting package attributes for upload ...') sys.stdout.flush() try: package_attrs, release_attrs, file_attrs = get_attrs(package_type, filename, parser_args=args) except Exception: if args.show_traceback: raise raise errors.BinstarError('Trouble reading metadata from %r. Is this a valid %s package' % (filename, package_type)) if args.build_id: file_attrs['attrs']['binstar_build'] = args.build_id log.info('done') package_name = get_package_name(args, package_attrs, filename, package_type) version = get_version(args, release_attrs, package_type) add_package(aserver_api, args, username, package_name, package_attrs, package_type) add_release(aserver_api, args, username, package_name, version, release_attrs) binstar_package_type = file_attrs.pop('binstar_package_type', package_type) with open(filename, 'rb') as fd: log.info('\nUploading file %s/%s/%s/%s ... ' % (username, package_name, version, file_attrs['basename'])) sys.stdout.flush() if remove_existing_file(aserver_api, args, username, package_name, version, file_attrs): continue try: upload_info = aserver_api.upload(username, package_name, version, file_attrs['basename'], fd, binstar_package_type, args.description, dependencies=file_attrs.get('dependencies'), attrs=file_attrs['attrs'], channels=args.channels, callback=upload_print_callback(args)) except errors.Conflict: full_name = '%s/%s/%s/%s' % (username, package_name, version, file_attrs['basename']) log.info('Distribution already exists. Please use the -i/--interactive or --force options or `anaconda remove %s`' % full_name) raise uploaded_packages.append([package_name, upload_info]) log.info("\n\nUpload(s) Complete\n") for package, upload_info in uploaded_packages: package_url = upload_info.get('url', 'https://anaconda.org/%s/%s' % (username, package)) log.info("Package located at:\n%s\n" % package_url)
def check_output(args, cwd='.', raise_=True): try: return _check_output(args, cwd=cwd, env=os.environ).decode() except Exception as e: if raise_: raise errors.BinstarError('Failed on {}'.format(args))
def upload_package(filename, package_type, aserver_api, username, args): logger.info('Extracting {} attributes for upload'.format( verbose_package_type(package_type))) try: package_attrs, release_attrs, file_attrs = get_attrs(package_type, filename, parser_args=args) except Exception: message = 'Trouble reading metadata from {}. Is this a valid {} package?'.format( filename, verbose_package_type(package_type)) logger.error(message) if args.show_traceback: raise raise errors.BinstarError(message) if args.build_id: file_attrs['attrs']['binstar_build'] = args.build_id package_name = get_package_name(args, package_attrs, filename, package_type) version = get_version(args, release_attrs, package_type) logger.info('Creating package "%s"', package_name) package = add_package(aserver_api, args, username, package_name, package_attrs, package_type) package_types = package.get('package_types', []) if package_types and package_type not in package_types: message = 'You already have a {} named \'{}\'. Use a different name for this {}.'.format( verbose_package_type(package_types[0] if package_types else ''), package_name, verbose_package_type(package_type), ) logger.error(message) raise errors.BinstarError(message) logger.info('Creating release "%s"', version) add_release(aserver_api, args, username, package_name, version, release_attrs) binstar_package_type = file_attrs.pop('binstar_package_type', package_type) with open(filename, 'rb') as fd: logger.info('Uploading file "%s/%s/%s/%s"', username, package_name, version, file_attrs['basename']) if remove_existing_file(aserver_api, args, username, package_name, version, file_attrs): return None try: upload_info = aserver_api.upload( username, package_name, version, file_attrs['basename'], fd, binstar_package_type, args.description, dependencies=file_attrs.get('dependencies'), attrs=file_attrs['attrs'], channels=args.labels, callback=upload_print_callback(args)) except errors.Conflict: logger.info( 'Distribution already exists. Please use the -i/--interactive or --force options or `anaconda ' 'remove %s/%s/%s/%s', username, package_name, version, file_attrs['basename']) raise logger.info("Upload complete") return [package_name, upload_info]