diff --git a/osc/commandline.py b/osc/commandline.py index fb9d8e4f..1a84dc3e 100755 --- a/osc/commandline.py +++ b/osc/commandline.py @@ -2103,6 +2103,58 @@ Please submit there instead, or use --nodevelproject to force direct submission. print wipebinaries(conf.config['apiurl'], args[0], package, opts.arch, opts.repo, code) + @cmdln.option('-q', '--quiet', action='store_true', + help='do not show downloading progress') + @cmdln.option('-d', '--destdir', default='.', metavar='DIR', + help='destination directory') + def do_getbinaries(self, subcmd, opts, project, package, repository, architecture): + """${cmd_name}: Download binaries to a local directory + + This command does download packages directly from the api server. + Thus, it does directly access the packages that are used for building + others, even when they are "published" yet. + + ${cmd_usage} + ${cmd_option_list} + """ + + # Get package list + binaries = get_binarylist(conf.config['apiurl'], + project, repository, architecture, + package = package, verbose=True) + + if not os.path.isdir(opts.destdir): + print "Creating %s" % opts.destdir + os.makedirs(opts.destdir, 0755) + + if binaries == [ ]: + sys.exit('no binaries found. Either the package does not ' + 'exist, or no binaries have been built.') + + for binary in binaries: + + # skip source rpms + if binary.name.endswith('.src.rpm'): + continue + + target_filename = '%s/%s' % (opts.destdir, binary.name) + + if os.path.exists(target_filename): + st = os.stat(target_filename) + if st.st_mtime == binary.mtime and st.st_size == binary.size: + continue + + get_binary_file(conf.config['apiurl'], + project, + repository, architecture, + binary.name, + package = package, + target_filename = target_filename, + target_mtime = binary.mtime, + progress_meter = not opts.quiet) + + + @cmdln.option('--repos-baseurl', action='store_true', help='show base URLs of download repositories') @cmdln.option('-e', '--enable-exact', action='store_true', diff --git a/osc/core.py b/osc/core.py index bbc7b18f..f8970bb6 100755 --- a/osc/core.py +++ b/osc/core.py @@ -2048,9 +2048,13 @@ def get_source_file(apiurl, prj, package, filename, targetfilename=None, revisio def get_binary_file(apiurl, prj, repo, arch, - filename, targetfilename=None, - package=None, - progress_meter=False): + filename, + package = None, + target_filename = None, + target_mtime = None, + progress_meter = False): + + target_filename = target_filename or filename where = package or '_repository' u = makeurl(apiurl, ['build', prj, repo, arch, where, filename]) @@ -2064,26 +2068,35 @@ def get_binary_file(apiurl, prj, repo, arch, import tempfile (fd, tmpfilename) = tempfile.mkstemp(prefix = filename + '.', suffix = '.osc', dir = '/tmp') + os.chmod(tmpfilename, 0644) - o = os.fdopen(fd, 'w') + try: + o = os.fdopen(fd, 'w') + + downloaded = 0 + while 1: + #buf = f.read(BUFSIZE) + buf = f.read(16384) + if not buf: break + o.write(buf) + downloaded += len(buf) + if progress_meter: + completion = str(int((float(downloaded)/binsize)*100)) + sys.stdout.write('%s%*s%%]' % ('\b'*5, 3, completion)) + sys.stdout.flush() + o.close() - downloaded = 0 - while 1: - #buf = f.read(BUFSIZE) - buf = f.read(16384) - if not buf: break - o.write(buf) - downloaded += len(buf) if progress_meter: - completion = str(int((float(downloaded)/binsize)*100)) - sys.stdout.write('%s%*s%%]' % ('\b'*5, 3, completion)) - sys.stdout.flush() - o.close() + sys.stdout.write('\n') - if progress_meter: - sys.stdout.write('\n') + shutil.move(tmpfilename, target_filename) + if target_mtime: + os.utime(target_filename, (-1, target_mtime)) - shutil.move(tmpfilename, targetfilename or filename) + # make sure that the temp file is cleaned up when we are interrupted + finally: + try: os.unlink(tmpfilename) + except: pass def dgst(file): @@ -2542,13 +2555,22 @@ def get_repos_of_project(apiurl, prj): yield repo_line_templ % (node.get('name'), node2.text) -def get_binarylist(apiurl, prj, repo, arch, package=None): +def get_binarylist(apiurl, prj, repo, arch, package=None, verbose=False): what = package or '_repository' u = makeurl(apiurl, ['build', prj, repo, arch, what]) f = http_GET(u) tree = ET.parse(f) - r = [ node.get('filename') for node in tree.findall('binary')] - return r + if not verbose: + return [ node.get('filename') for node in tree.findall('binary')] + else: + l = [] + for node in tree.findall('binary'): + f = File(node.get('filename'), + None, + int(node.get('size')), + int(node.get('mtime'))) + l.append(f) + return l def get_binarylist_published(apiurl, prj, repo, arch):