Hello community, here is the log from the commit of package osc for openSUSE:Factory checked in at 2018-08-20 16:23:02 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/osc (Old) and /work/SRC/openSUSE:Factory/.osc.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "osc" Mon Aug 20 16:23:02 2018 rev:127 rq:630510 version:0.163.0 Changes: -------- --- /work/SRC/openSUSE:Factory/osc/osc.changes 2018-06-29 22:37:15.169957426 +0200 +++ /work/SRC/openSUSE:Factory/.osc.new/osc.changes 2018-08-20 16:23:28.605166808 +0200 @@ -1,0 +2,15 @@ +Mon Aug 20 11:24:25 UTC 2018 - Adrian Schröter <adr...@suse.de> + +- 0.163.0 + * add sendsysrq command (requires OBS 2.10) + * add addcontainers command (requires OBS 2.10) + * enable statistics for local builds + * add new options to diff command: + --unexpand for local diffs only (bsc#1089025) + --meta for diffing meta files + * add support for podman/buildag engine (docker variation) + * support realname in .changes files + * fix DISTURL checkout for package containers using a multibuild flavor + * Disable ssl session resumption + +------------------------------------------------------------------- Old: ---- osc-0.162.1.tar.gz New: ---- osc-0.163.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ osc.spec ++++++ --- /var/tmp/diff_new_pack.aLmMct/_old 2018-08-20 16:23:29.137167563 +0200 +++ /var/tmp/diff_new_pack.aLmMct/_new 2018-08-20 16:23:29.141167568 +0200 @@ -16,12 +16,12 @@ # -%define version_unconverted 0.162.1 +%define version_unconverted 0.163.0 %define osc_plugin_dir %{_prefix}/lib/osc-plugins %define macros_file macros.osc Name: osc -Version: 0.162.1 +Version: 0.163.0 Release: 0 Summary: Open Build Service Commander License: GPL-2.0-or-later ++++++ PKGBUILD ++++++ --- /var/tmp/diff_new_pack.aLmMct/_old 2018-08-20 16:23:29.165167602 +0200 +++ /var/tmp/diff_new_pack.aLmMct/_new 2018-08-20 16:23:29.165167602 +0200 @@ -1,5 +1,5 @@ pkgname=osc -pkgver=0.162.1 +pkgver=0.163.0 pkgrel=0 pkgdesc="Open Build Service client" arch=('i686' 'x86_64') ++++++ _service ++++++ --- /var/tmp/diff_new_pack.aLmMct/_old 2018-08-20 16:23:29.181167625 +0200 +++ /var/tmp/diff_new_pack.aLmMct/_new 2018-08-20 16:23:29.181167625 +0200 @@ -1,7 +1,7 @@ <services> <service name="tar_scm" mode="disabled"> - <param name="version">0.162.1</param> - <param name="revision">0.162.1</param> + <param name="version">0.163.0</param> + <param name="revision">0.163.0</param> <param name="url">git://github.com/openSUSE/osc.git</param> <param name="scm">git</param> </service> ++++++ debian.changelog ++++++ --- /var/tmp/diff_new_pack.aLmMct/_old 2018-08-20 16:23:29.217167676 +0200 +++ /var/tmp/diff_new_pack.aLmMct/_new 2018-08-20 16:23:29.217167676 +0200 @@ -1,4 +1,4 @@ -osc (0.162.1) unstable; urgency=low +osc (0.163.0) unstable; urgency=low - Update to 0.161.1 -- Marco Strigl <marco.str...@suse.com> Thu, 26 Oct 2017 14:42:00 +0200 ++++++ osc-0.162.1.tar.gz -> osc-0.163.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/osc-0.162.1/NEWS new/osc-0.163.0/NEWS --- old/osc-0.162.1/NEWS 2017-12-05 14:29:03.000000000 +0100 +++ new/osc-0.163.0/NEWS 2018-08-20 13:19:29.000000000 +0200 @@ -1,3 +1,15 @@ +0.163 + - add sendsysrq command (requires OBS 2.10) + - add addcontainers command (requires OBS 2.10) + - enable statistics for local builds + - add new options to diff command: + --unexpand for local diffs only (bsc#1089025) + --meta for diffing meta files + - add support for podman/buildag engine (docker variation) + - support realname in .changes files + - fix DISTURL checkout for package containers using a multibuild flavor + - Disable ssl session resumption + 0.162.1 - Send sha256 hashes for tracked files if the wc is pulled/linkrepair diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/osc-0.162.1/dist/osc.complete new/osc-0.163.0/dist/osc.complete --- old/osc-0.162.1/dist/osc.complete 2017-12-05 14:29:03.000000000 +0100 +++ new/osc-0.163.0/dist/osc.complete 2018-08-20 13:19:29.000000000 +0200 @@ -87,14 +87,14 @@ lnkpkg="" apiurl="" alias="" -test -s ${PWD}/.osc/_project && read -t 1 oscprj < ${PWD}/.osc/_project -test -s ${PWD}/.osc/_package && read -t 1 oscpkg < ${PWD}/.osc/_package -if test -s ${PWD}/.osc/_files ; then - lnkprj=$(command sed -rn '/<linkinfo/{s@.*[[:blank:]]project="([^"]+)".*@\1@p;}' < ${PWD}/.osc/_files) - lnkpkg=$(command sed -rn '/<linkinfo/{s@.*[[:blank:]]package="([^"]+)".*@\1@p;}' < ${PWD}/.osc/_files) +test -s "${PWD}/.osc/_project" && read -t 1 oscprj < "${PWD}/.osc/_project" +test -s "${PWD}/.osc/_package" && read -t 1 oscpkg < "${PWD}/.osc/_package" +if test -s "${PWD}/.osc/_files" ; then + lnkprj=$(command sed -rn '/<linkinfo/{s@.*[[:blank:]]project="([^"]+)".*@\1@p;}' < "${PWD}/.osc/_files") + lnkpkg=$(command sed -rn '/<linkinfo/{s@.*[[:blank:]]package="([^"]+)".*@\1@p;}' < "${PWD}/.osc/_files") fi -if test -s ${PWD}/.osc/_apiurl -a -s ~/.oscrc ; then - read apiurl < ${PWD}/.osc/_apiurl +if test -s "${PWD}/.osc/_apiurl" -a -s ~/.oscrc ; then + read apiurl < "${PWD}/.osc/_apiurl" alias=$(sed -rn '\@^\['${apiurl}'@,\@=@{\@^aliases=@{s@[^=]+=([^,]+),.*@\1@p};}' < ~/.oscrc 2> /dev/null) fi if test "${cmdline[0]}" = isc ; then diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/osc-0.162.1/osc/build.py new/osc-0.163.0/osc/build.py --- old/osc-0.162.1/osc/build.py 2017-12-05 14:29:03.000000000 +0100 +++ new/osc-0.163.0/osc/build.py 2018-08-20 13:19:29.000000000 +0200 @@ -350,6 +350,11 @@ '-type', 'f'], stdout=subprocess.PIPE).stdout.read().strip() s_built = '' + elif buildtype == 'podman': + b_built = subprocess.Popen(['find', os.path.join(pacdir, 'DOCKER'), + '-type', 'f'], + stdout=subprocess.PIPE).stdout.read().strip() + s_built = '' elif buildtype == 'fissile': b_built = subprocess.Popen(['find', os.path.join(pacdir, 'FISSILE'), '-type', 'f'], @@ -473,6 +478,12 @@ d = p.obsoletes() if d: depfile.append('O:%s%s' % (id, ' '.join(d))) + d = p.recommends() + if d: + depfile.append('r:%s%s' % (id, ' '.join(d))) + d = p.supplements() + if d: + depfile.append('s:%s%s' % (id, ' '.join(d))) depfile.append('I:%s%s-%s 0-%s' % (id, p.name(), p.evr(), p.arch())) return depfile @@ -528,7 +539,7 @@ build_type = 'docker' if os.path.basename(build_descr) == 'fissile.yml': build_type = 'fissile' - if build_type not in ['spec', 'dsc', 'kiwi', 'arch', 'collax', 'livebuild', 'snapcraft', 'appimage', 'docker', 'fissile']: + if build_type not in ['spec', 'dsc', 'kiwi', 'arch', 'collax', 'livebuild', 'snapcraft', 'appimage', 'docker', 'podman', 'fissile']: raise oscerr.WrongArgs( 'Unknown build type: \'%s\'. Build description should end in .spec, .dsc, .kiwi, or .livebuild. Or being named PKGBUILD, build.collax, appimage.yml, snapcraft.yaml or Dockerfile' \ % build_type) @@ -536,6 +547,7 @@ raise oscerr.WrongArgs('Error: build description file named \'%s\' does not exist.' % build_descr) buildargs = [] + buildargs.append('--statistics') if not opts.userootforbuild: buildargs.append('--norootforbuild') if opts.clean: @@ -589,7 +601,7 @@ if opts.build_uid: build_uid = opts.build_uid if build_uid: - buildidre = re.compile('^[0-9]{1,5}:[0-9]{1,5}$') + buildidre = re.compile('^[0-9]+:[0-9]+$') if build_uid == 'caller': buildargs.append('--uid=%s:%s' % (os.getuid(), os.getgid())) elif buildidre.match(build_uid): @@ -978,7 +990,7 @@ buildargs.append('--oldpackages=%s' % old_pkg_dir) # Make packages from buildinfo available as repos for kiwi/docker/fissile - if build_type == 'kiwi' or build_type == 'docker' or build_type == 'fissile': + if build_type == 'kiwi' or build_type == 'docker' or build_type == 'podman' or build_type == 'fissile': if os.path.exists('repos'): shutil.rmtree('repos') if os.path.exists('containers'): @@ -1121,7 +1133,7 @@ print('Writing build configuration') - if build_type == 'kiwi' or build_type == 'docker' or build_type == 'fissile': + if build_type == 'kiwi' or build_type == 'docker' or build_type == 'podman'or build_type == 'fissile': rpmlist = [ '%s %s\n' % (i.name, i.fullfilename) for i in bi.deps if not i.noinstall ] else: rpmlist = [ '%s %s\n' % (i.name, i.fullfilename) for i in bi.deps ] @@ -1137,7 +1149,7 @@ rpmlist.append('preinstall: ' + ' '.join(bi.preinstall_list) + '\n') rpmlist.append('vminstall: ' + ' '.join(bi.vminstall_list) + '\n') rpmlist.append('runscripts: ' + ' '.join(bi.runscripts_list) + '\n') - if build_type != 'kiwi' and build_type != 'docker' and build_type != 'fissile': + if build_type != 'kiwi' and build_type != 'docker' and build_type != 'podman' and build_type != 'fissile': if bi.noinstall_list: rpmlist.append('noinstall: ' + ' '.join(bi.noinstall_list) + '\n') if bi.installonly_list: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/osc-0.162.1/osc/commandline.py new/osc-0.163.0/osc/commandline.py --- old/osc-0.162.1/osc/commandline.py 2017-12-05 14:29:03.000000000 +0100 +++ new/osc-0.163.0/osc/commandline.py 2018-08-20 13:19:29.000000000 +0200 @@ -384,7 +384,10 @@ if opts.verbose: for f in result[1]: - print("%9d %s %-40s" % (f.size, shorttime(f.mtime), f.name)) + if f.size is None and f.mtime is None: + print("%9s %12s %-40s" % ('unknown', 'unknown', f.name)) + else: + print("%9d %s %-40s" % (f.size, shorttime(f.mtime), f.name)) else: for f in result[1]: print(indent+f) @@ -446,6 +449,42 @@ return 1 + @cmdln.option('--extend-package-names', default=False, action="store_true", + help='Extend packages names with project name as suffix') + def do_addcontainers(self, subcmd, opts, *args): + """${cmd_name}: Add maintained containers for a give package + + The command adds all containers which are marked as maitained and contain + an rpm out of the specified source package. + + Examples: + osc addcontainers [PROJECT PACKAGE] + ${cmd_option_list} + """ + + args = slash_split(args) + apiurl = self.get_api_url() + localdir = os.getcwd() + project = package = None + if not args: + if is_package_dir(localdir): + project = store_read_project(localdir) + package = store_read_package(localdir) + elif len(args) == 2: + project = args[0] + package = args[1] + + if project == None or package == None: + raise oscerr.WrongArgs('Either specify project and package or call it from a package working copy') + + query = {'cmd': 'addcontainers'} + if opts.extend_package_names: + query['extend_package_names'] = '1' + + print("Add containers...") + url = makeurl(apiurl, ['source', project, package], query=query) + f = http_POST(url) + @cmdln.option('-s', '--skip-disabled', action='store_true', help='Skip disabled channels. Otherwise the source gets added, but not the repositories.') @cmdln.option('-e', '--enable-all', action='store_true', @@ -464,6 +503,7 @@ ${cmd_option_list} """ + args = slash_split(args) apiurl = self.get_api_url() localdir = os.getcwd() channel = None @@ -506,6 +546,7 @@ ${cmd_option_list} """ + args = slash_split(args) apiurl = self.get_api_url() localdir = os.getcwd() channel = None @@ -550,6 +591,7 @@ ${cmd_option_list} """ + args = slash_split(args) apiurl = self.get_api_url() project_dir = localdir = os.getcwd() patchinfo = 'patchinfo' @@ -2195,16 +2237,16 @@ project = None if len(args) > 0: project = args[0] + elif opts.project: + project = opts.project + if opts.package: + package = opts.package elif not opts.mine and not opts.user and not opts.group: try: project = store_read_project(os.curdir) package = store_read_package(os.curdir) except oscerr.NoWorkingCopy: pass - elif opts.project: - project = opts.project - if opts.package: - package = opts.package if len(args) > 1: package = args[1] @@ -3706,12 +3748,16 @@ 'the revision (rev1) on the server. ' 'If rev1 and rev2 are specified it will compare rev1 against rev2 ' '(NOTE: changes in your working copy are ignored in this case)') + @cmdln.option('-M', '--meta', action='store_true', + help='operate on meta files') @cmdln.option('-p', '--plain', action='store_true', help='output the diff in plain (not unified) diff format') @cmdln.option('-l', '--link', action='store_true', help='(osc linkdiff): compare against the base revision of the link') @cmdln.option('--missingok', action='store_true', help='do not fail if the source or target project/package does not exist on the server') + @cmdln.option('-u', '--unexpand', action='store_true', + help='Local changes only, ignore changes in linked package sources') def do_diff(self, subcmd, opts, *args): """${cmd_name}: Generates a diff @@ -3786,7 +3832,8 @@ diff += ''.join(i) else: diff += server_diff_noex(pac.apiurl, pac.prjname, pac.name, rev1, - pac.prjname, pac.name, rev2, not opts.plain, opts.missingok) + pac.prjname, pac.name, rev2, + not opts.plain, opts.missingok, opts.meta, not opts.unexpand) run_pager(diff) @@ -4288,11 +4335,10 @@ raise oscerr.WrongArgs('Incorrect number of arguments.\n\n' \ + self.get_cmd_help('checkout')) - # XXX: this too openSUSE-setup specific... - # FIXME: this should go into ~jw/patches/osc/osc.proj_pack_20101201.diff - # to be available to all subcommands via @cmdline.prep(proj_pack) + # A DISTURL can be found in build results to be able to relocate the source used to build + # obs://$OBS_INSTANCE/$PROJECT/$REPOSITORY/$XSRCMD5-$PACKAGE(:$FLAVOR) # obs://build.opensuse.org/openSUSE:11.3/standard/fc6c25e795a89503e99d59da5dc94a79-screen - m = re.match(r"obs://([^/]+)/(\S+)/([^/]+)/([A-Fa-f\d]+)\-(\S+)", args[0]) + m = re.match(r"obs://([^/]+)/(\S+)/([^/]+)/([A-Fa-f\d]+)\-([^:]*)(:\S+)?", args[0]) if m and len(args) == 1: apiurl = "https://" + m.group(1) project = project_dir = m.group(2) @@ -5702,9 +5748,9 @@ from .util import cpio print('Scanning the following dirs for local packages: %s' % ', '.join(opts.prefer_pkgs)) cpiodata = cpio.CpioWrite() - prefer_pkgs, cpio = get_prefer_pkgs(opts.prefer_pkgs, arch, - os.path.splitext(build_descr)[1], - cpiodata) + prefer_pkgs = get_prefer_pkgs(opts.prefer_pkgs, arch, + os.path.splitext(build_descr)[1], + cpiodata) cpiodata.add(os.path.basename(build_descr), build_descr_data) build_descr_data = cpiodata.get() @@ -6170,6 +6216,14 @@ if len(args) > 3: raise oscerr.WrongArgs('Too many arguments') + project = None + try: + project = store_read_project(os.curdir) + except oscerr.NoWorkingCopy: + pass + if project == opts.alternative_project: + opts.alternative_project = None + args = self.parse_repoarchdescr(args, opts.noinit or opts.offline, opts.alternative_project, False, opts.vm_type, opts.multibuild_package) # check for source services @@ -6449,45 +6503,59 @@ if suwrapper.startswith('su '): mntproc = [sucmd, '%s mount -n -tproc none %s/proc' % (suargs, buildroot)] mntsys = [sucmd, '%s mount -n -tsysfs none %s/sys' % (suargs, buildroot)] + mntdevpts = [sucmd, '%s mount -n -tdevpts -omode=0620,gid=5 none %s/dev/pts' % (suargs, buildroot)] umntproc = [sucmd, '%s umount %s/proc' % (suargs, buildroot)] umntsys = [sucmd, '%s umount %s/sys' % (suargs, buildroot)] + umntdevpts = [sucmd, '%s umount %s/devpts' % (suargs, buildroot)] cmd = [sucmd, '%s chroot "%s" su - %s' % (suargs, buildroot, user)] else: mntproc = [sucmd, 'mount', '-n', '-tproc' , 'none', '%s/proc' % buildroot] mntsys = [sucmd, 'mount', '-n', '-tsysfs' , 'none', '%s/sys' % buildroot] + mntdevpts = [sucmd, 'mount', '-n', '-tdevpts' , '-omode=0620,gid=5', 'none', '%s/dev/pts' % buildroot] umntproc = [sucmd, 'umount', '%s/proc' % buildroot] umntsys = [sucmd, 'umount', '%s/sys' % buildroot] + umntdevpts = [sucmd, 'umount', '%s/dev/pts' % buildroot] cmd = [sucmd, 'chroot', buildroot, 'su', '-', user] if suargs: mntproc[1:1] = suargs.split() + mntsys[1:1] = suargs.split() + mntdevpts[1:1] = suargs.split() umntproc[1:1] = suargs.split() + umntsys[1:1] = suargs.split() + umntdevpts[1:1] = suargs.split() cmd[1:1] = suargs.split() #signal handler for chroot procfs umount def umount_handle(signum = None, frame = None, ret=1): subprocess.call(umntproc) subprocess.call(umntsys) + subprocess.call(umntdevpts) sys.exit(ret) for sig in [signal.SIGTERM, signal.SIGINT, signal.SIGHUP, signal.SIGQUIT]: signal.signal(sig, umount_handle) print('mounting proc: %s' % ' '.join(mntproc)) print('mounting sys: %s' % ' '.join(mntsys)) + print('mounting devpts: %s' % ' '.join(mntdevpts)) mount_err = -1 proc_mount_err = subprocess.call(mntproc) sys_mount_err = subprocess.call(mntsys) + devpts_mount_err = subprocess.call(mntdevpts) if proc_mount_err > 0: print('There was an error mounting proc. Please check mountpoints in chroot') if sys_mount_err > 0: print('There was an error mounting sys. Please check mountpoints in chroot') + if devpts_mount_err > 0: + print('There was an error mounting devpts. Please check mountpoints in chroot') print('running: %s' % ' '.join(cmd)) retval = 0 try: retval = subprocess.call(cmd) finally: if ((not proc_mount_err or proc_mount_err == 32) and - (not sys_mount_err or sys_mount_err == 32)): - print('unmounting %s/proc and %s/sys ...' % (buildroot, buildroot)) + (not sys_mount_err or sys_mount_err == 32) and + (not devpts_mount_err or devpts_mount_err == 32)): + print('unmounting %s/proc and %s/sys and %s/dev/pts ...' % (buildroot, buildroot, buildroot)) umount_handle(ret=retval) @@ -6843,6 +6911,50 @@ print(p.info()) + @cmdln.option('-M', '--multibuild-package', action='append', + help='specify a specific multibuild flavor') + def do_sendsysrq(self, subcmd, opts, *args): + """${cmd_name}: trigger a sysrq in a running build + + This is only going to work when the build is running in a supported VM. + Also only a subset of sysrq are supported. Typical use case for debugging + are 9, t and w in this sequence. + + usage: + osc sendsysrq REPOSITORY ARCH SYSRQ + osc sendsysrq PROJECT PACKAGE REPOSITORY ARCH SYSRQ + ${cmd_option_list} + """ + args = slash_split(args) + + project = package = repo = arch = sysrq = None + apiurl = self.get_api_url() + + if len(args) < 4: + if is_package_dir(os.curdir): + project = store_read_project(os.curdir) + package = store_read_package(os.curdir) + apiurl = store_read_apiurl(os.curdir) + repo = args[0] + arch = args[1] + sysrq = args[2] + else: + raise oscerr.WrongArgs('Too few arguments.') + elif len(args) != 5: + raise oscerr.WrongArgs('Wrong number of arguments.') + else: + project = args[0] + package = args[1] + repo = args[2] + arch = args[3] + sysrq = args[4] + + packages = [package] + if opts.multibuild_package: + packages = ['%s:%s' % (package, flavor) for flavor in opts.multibuild_package] + for package in packages: + print(cmdbuild(apiurl, 'sendsysrq', project, package, arch, repo, None, sysrq)) + @cmdln.option('-a', '--arch', metavar='ARCH', help='Restart builds for a specific architecture') @cmdln.option('-M', '--multibuild-package', action='append', @@ -7076,7 +7188,7 @@ # Set binary target directory and create if not existing target_dir = os.path.normpath(opts.destdir) if not os.path.isdir(target_dir): - print('Creating %s' % target_dir) + print('Creating directory "%s"' % target_dir) os.makedirs(target_dir, 0o755) for arch in arches: @@ -7393,7 +7505,7 @@ usage: osc search \'search term\' <options> osc bse ... ('osc search --binary') - osc se 'perl(Foo::Bar)' ('osc --package perl-Foo-Bar') + osc se 'perl(Foo::Bar)' ('osc search --package perl-Foo-Bar') ${cmd_option_list} """ def build_xpath(attr, what, substr = False): @@ -7938,9 +8050,6 @@ repl = raw_input('\nUse this container? (y/n) ') if repl.lower() != 'y': searchresult = None - else: - print("Empty search result, you may want to search with other or all roles via -r ''") - return elif opts.user: searchresult = owner(apiurl, opts.user, "user", usefilter=filterroles, devel=None) elif opts.group: @@ -8678,18 +8787,36 @@ else: apiurl = self.get_api_url() - # set user's email if the mailaddr env variable is not set - if 'mailaddr' in os.environ: - pass - elif 'email' in conf.config['api_host_options'][apiurl]: - os.environ['mailaddr'] = conf.config['api_host_options'][apiurl]['email'] - else: + # try to set the env variables for the user's realname and email + # (the variables are used by the "vc" script) + tag2envs = {'realname': ['VC_REALNAME'], + 'email': ['VC_MAILADDR', 'mailaddr']} + tag2val = {} + missing_tags = [] + + for (tag, envs) in tag2envs.items(): + env_present = [env for env in envs if env in os.environ] + config_present = tag in conf.config['api_host_options'][apiurl] + if not env_present and not config_present: + missing_tags.append(tag) + elif config_present: + tag2val[tag] = conf.config['api_host_options'][apiurl][tag] + + if missing_tags: user = conf.get_apiurl_usr(apiurl) - data = get_user_data(apiurl, user, 'email') - if data: - os.environ['mailaddr'] = data[0] - else: - print('Try env mailaddr=...', file=sys.stderr) + data = get_user_data(apiurl, user, *missing_tags) + if data is not None: + for tag in missing_tags: + val = data.pop(0) + if val != '-': + tag2val[tag] = val + else: + msg = 'Try env %s=...' % tag2envs[tag][0] + print(msg, file=sys.stderr) + + for (tag, val) in tag2val.items(): + for env in tag2envs[tag]: + os.environ[env] = val if meego_style: if opts.message or opts.just_edit: @@ -8827,7 +8954,7 @@ Examples: osc revert <modified file(s)> - ose revert . + osc revert . Note: this only works for package working copies ${cmd_usage} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/osc-0.162.1/osc/conf.py new/osc-0.163.0/osc/conf.py --- old/osc-0.162.1/osc/conf.py 2017-12-05 14:29:03.000000000 +0100 +++ new/osc-0.163.0/osc/conf.py 2018-08-20 13:19:29.000000000 +0200 @@ -118,7 +118,7 @@ 'build-kernel': '', # optional for VM builds 'build-initrd': '', # optional for VM builds - 'build-jobs': _get_processors(), + 'build-jobs': str(_get_processors()), 'builtin_signature_check': '1', # by default use builtin check for verify pkgs 'icecream': '0', @@ -201,8 +201,9 @@ 'request_show_source_buildstatus', 'review_inherit_group', 'use_keyring', 'gnome_keyring', 'no_verify', 'builtin_signature_check', 'http_full_debug', 'include_request_from_project', 'local_service_run', 'buildlog_strip_time', 'no_preinstallimage', 'status_mtime_heuristic'] +integer_opts = ['build-jobs'] -api_host_options = ['user', 'pass', 'passx', 'aliases', 'http_headers', 'email', 'sslcertck', 'cafile', 'capath', 'trusted_prj'] +api_host_options = ['user', 'pass', 'passx', 'aliases', 'http_headers', 'realname', 'email', 'sslcertck', 'cafile', 'capath', 'trusted_prj'] new_conf_template = """ [general] @@ -361,6 +362,8 @@ pass = %(pass)s # set aliases for this apiurl # aliases = foo, bar +# real name used in .changes, unless the one from osc meta prj <user> will be used +# realname = # email used in .changes, unless the one from osc meta prj <user> will be used # email = # additional headers to pass to a request, e.g. for special authentication @@ -546,10 +549,10 @@ capath = i break if not cafile and not capath: - raise oscerr.OscIOError(None, 'No CA certificates found') + raise oscerr.OscIOError(None, 'No CA certificates found. (You may want to install ca-certificates-mozilla package)') ctx = oscssl.mySSLContext() if ctx.load_verify_locations(capath=capath, cafile=cafile) != 1: - raise oscerr.OscIOError(None, 'No CA certificates found') + raise oscerr.OscIOError(None, 'No CA certificates found. (You may want to install ca-certificates-mozilla package)') opener = m2urllib2.build_opener(ctx, oscssl.myHTTPSHandler(ssl_context=ctx, appname='osc'), HTTPCookieProcessor(cookiejar), authhandler, proxyhandler) else: handlers = [HTTPCookieProcessor(cookiejar), authhandler, proxyhandler] @@ -848,11 +851,14 @@ config = dict(cp.items('general', raw=1)) config['conffile'] = conffile - for i in boolean_opts: - try: - config[i] = cp.getboolean('general', i) - except ValueError as e: - raise oscerr.ConfigError('cannot parse \'%s\' setting: ' % i + str(e), conffile) + typed_opts = ((boolean_opts, cp.getboolean), (integer_opts, cp.getint)) + for opts, meth in typed_opts: + for opt in opts: + try: + config[opt] = meth('general', opt) + except ValueError as e: + msg = 'cannot parse \'%s\' setting: %s' % (opt, str(e)) + raise oscerr.ConfigError(msg, conffile) config['packagecachedir'] = os.path.expanduser(config['packagecachedir']) config['exclude_glob'] = config['exclude_glob'].split() @@ -970,7 +976,7 @@ 'pass': password, 'http_headers': http_headers} - optional = ('email', 'sslcertck', 'cafile', 'capath') + optional = ('realname', 'email', 'sslcertck', 'cafile', 'capath') for key in optional: if cp.has_option(url, key): if key == 'sslcertck': diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/osc-0.162.1/osc/core.py new/osc-0.163.0/osc/core.py --- old/osc-0.162.1/osc/core.py 2017-12-05 14:29:03.000000000 +0100 +++ new/osc-0.163.0/osc/core.py 2018-08-20 13:19:29.000000000 +0200 @@ -5,7 +5,7 @@ from __future__ import print_function -__version__ = '0.162.1' +__version__ = '0.163.0' # __store_version__ is to be incremented when the format of the working copy # "store" changes in an incompatible way. Please add any needed migration @@ -30,6 +30,7 @@ from urllib.request import pathname2url, install_opener, urlopen from urllib.request import Request as URLRequest from io import StringIO + from http.client import IncompleteRead except ImportError: #python 2.x from urlparse import urlsplit, urlunsplit, urlparse @@ -37,6 +38,7 @@ from urllib2 import HTTPError, install_opener, urlopen from urllib2 import Request as URLRequest from cStringIO import StringIO + from httplib import IncompleteRead try: @@ -288,6 +290,8 @@ for service in services: name = service.get('name') + if name is None: + error("invalid service definition. Attribute name missing.", service) if len(name) < 3 or '/' in name: error("invalid service name: %s" % name, service) mode = service.get('mode', '') @@ -1501,9 +1505,10 @@ print('Transmitting file data', end=' ') filelist = self.__generate_commitlist(todo_send) sfilelist = self.__send_commitlog(msg, filelist, validate=True) - if sfilelist.get('error') and sfilelist.findall('.//entry[@hash]'): + hash_entries = [e for e in sfilelist.findall('entry') if e.get('hash') is not None] + if sfilelist.get('error') and hash_entries: name2elem = dict([(e.get('name'), e) for e in filelist.findall('entry')]) - for entry in sfilelist.findall('.//entry[@hash]'): + for entry in hash_entries: filename = entry.get('name') fileelem = name2elem.get(filename) if filename not in sha256sums: @@ -4180,7 +4185,7 @@ except HTTPError as e: if e.hdrs.get('X-Opensuse-Errorcode') == "submit_request_rejected": print("WARNING:") - print("WARNING: Project does not accept submit request, request to open a NEW maintenance incident instead") + print("WARNING: Project does not accept submit request, a NEW maintenance incident request will be created instead") print("WARNING:") xpath = 'maintenance/maintains/@project = \'%s\' and attribute/@name = \'%s\'' % (dst_project, conf.config['maintenance_attribute']) res = search(apiurl, project_id=xpath) @@ -4841,7 +4846,8 @@ for cissue in collection: issue = {} for issue_detail in cissue.iter(): - issue[issue_detail.tag] = issue_detail.text.strip() + if issue_detail.text: + issue[issue_detail.tag] = issue_detail.text.strip() issue_list.append(issue) return issue_list @@ -5584,8 +5590,8 @@ for node in tree.findall('binary'): f = File(node.get('filename'), None, - int(node.get('size')), - int(node.get('mtime'))) + int(node.get('size') or 0) or None, + int(node.get('mtime') or 0) or None) l.append(f) return l @@ -5698,7 +5704,7 @@ if verbose and res['details'] != '': if res['code'] in ('unresolvable', 'expansion error'): lines = res['details'].split(',') - res['status'] += ': ' + '\n '.join(lines) + res['status'] += ': \n ' + '\n '.join(lines) else: res['status'] += ': %s' % res['details'] elif res['code'] in ('scheduled', ) and res['details']: @@ -5958,6 +5964,7 @@ return r + def streamfile(url, http_meth = http_GET, bufsize=8192, data=None, progress_obj=None, text=None): """ performs http_meth on url and read bufsize bytes from the response @@ -6021,6 +6028,11 @@ def print_buildlog(apiurl, prj, package, repository, arch, offset=0, strip_time=False, last=False): """prints out the buildlog on stdout""" + def print_data(data, strip_time=False): + if strip_time: + data = buildlog_strip_time(data) + sys.stdout.write(data.translate(all_bytes, remove_bytes)) + # to protect us against control characters import string all_bytes = string.maketrans('', '') @@ -6029,15 +6041,24 @@ query = {'nostream' : '1', 'start' : '%s' % offset} if last: query['last'] = 1 + retry_count = 0 while True: query['start'] = offset start_offset = offset u = makeurl(apiurl, ['build', prj, repository, arch, package, '_log'], query=query) - for data in streamfile(u, bufsize="line"): - offset += len(data) - if strip_time: - data = buildlog_strip_time(data) - sys.stdout.write(data.translate(all_bytes, remove_bytes)) + try: + for data in streamfile(u, bufsize="line"): + offset += len(data) + print_data(data, strip_time) + except IncompleteRead as e: + if retry_count >= 3: + raise e + retry_count += 1 + data = e.partial + if len(data): + offset += len(data) + print_data(data, strip_time) + continue if start_offset == offset: break @@ -6450,7 +6471,7 @@ return cmdbuild(apiurl, 'wipe', project, package, arch, repo, code) -def cmdbuild(apiurl, cmd, project, package=None, arch=None, repo=None, code=None): +def cmdbuild(apiurl, cmd, project, package=None, arch=None, repo=None, code=None, sysrq=None): query = { 'cmd': cmd } if package: query['package'] = package @@ -6460,6 +6481,8 @@ query['repository'] = repo if code: query['code'] = code + if sysrq: + query['sysrq'] = sysrq u = makeurl(apiurl, ['build', project], query) try: @@ -6474,6 +6497,8 @@ e.osc_msg += ' repository %s' % repo if code: e.osc_msg += ' code=%s' % code + if sysrq: + e.osc_msg += ' sysrq=%s' % code raise root = ET.parse(f).getroot() @@ -7350,7 +7375,11 @@ print('Aborting', file=sys.stderr) raise oscerr.UserAbort() elif repl == 'm': - comment = edit_text() + if tmpfile is not None: + tmpfile.seek(0) + comment = edit_message(footer=tmpfile.read()) + else: + comment = edit_text() create_comment(apiurl, 'request', comment, request.reqid) elif repl == 'b' and src_actions: print_source_buildstatus(src_actions) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/osc-0.162.1/osc/oscssl.py new/osc-0.163.0/osc/oscssl.py --- old/osc-0.162.1/osc/oscssl.py 2017-12-05 14:29:03.000000000 +0100 +++ new/osc-0.163.0/osc/oscssl.py 2018-08-20 13:19:29.000000000 +0200 @@ -174,7 +174,6 @@ class myHTTPSHandler(M2Crypto.m2urllib2.HTTPSHandler): handler_order = 499 - saved_session = None def __init__(self, *args, **kwargs): self.appname = kwargs.pop('appname', 'generic') @@ -204,8 +203,6 @@ selector = req.get_selector() # End our change h.set_debuglevel(self._debuglevel) - if self.saved_session: - h.set_session(self.saved_session) headers = dict(req.headers) headers.update(req.unredirected_hdrs) @@ -218,9 +215,6 @@ headers["Connection"] = "close" try: h.request(req.get_method(), selector, req.data, headers) - s = h.get_session() - if s: - self.saved_session = s r = h.getresponse() except socket.error as err: # XXX what error? err.filename = full_url diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/osc-0.162.1/osc/util/archquery.py new/osc-0.163.0/osc/util/archquery.py --- old/osc-0.162.1/osc/util/archquery.py 2017-12-05 14:29:03.000000000 +0100 +++ new/osc-0.163.0/osc/util/archquery.py 2018-08-20 13:19:29.000000000 +0200 @@ -95,6 +95,24 @@ def obsoletes(self): return self.fields['replaces'] if 'replaces' in self.fields else [] + def recommends(self): + # a .PKGINFO has no notion of "recommends" + return [] + + def suggests(self): + # libsolv treats an optdepend as a "suggests", hence we do the same + if 'optdepend' not in self.fields: + return [] + return [re.sub(':.*', '', entry) for entry in self.fields['optdepend']] + + def supplements(self): + # a .PKGINFO has no notion of "recommends" + return [] + + def enhances(self): + # a .PKGINFO has no notion of "enhances" + return [] + def canonname(self): pkgver = self.fields['pkgver'][0] if 'pkgver' in self.fields else None return self.name() + '-' + pkgver + '-' + self.arch() + '.' + self.pkgsuffix diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/osc-0.162.1/osc/util/debquery.py new/osc-0.163.0/osc/util/debquery.py --- old/osc-0.162.1/osc/util/debquery.py 2017-12-05 14:29:03.000000000 +0100 +++ new/osc-0.163.0/osc/util/debquery.py 2018-08-20 13:19:29.000000000 +0200 @@ -90,6 +90,9 @@ self.fields['pre_depends'] = [ i.strip() for i in re.split(',\s*', self.fields.get('pre_depends', '')) if i ] self.fields['conflicts'] = [ i.strip() for i in re.split(',\s*', self.fields.get('conflicts', '')) if i ] self.fields['breaks'] = [ i.strip() for i in re.split(',\s*', self.fields.get('breaks', '')) if i ] + self.fields['recommends'] = [ i.strip() for i in re.split(',\s*', self.fields.get('recommends', '')) if i ] + self.fields['suggests'] = [ i.strip() for i in re.split(',\s*', self.fields.get('suggests', '')) if i ] + self.fields['enhances'] = [ i.strip() for i in re.split(',\s*', self.fields.get('enhances', '')) if i ] if self_provides: # add self provides entry self.fields['provides'].append('%s (= %s)' % (self.name(), '-'.join(versrel))) @@ -137,6 +140,19 @@ def obsoletes(self): return [] + def recommends(self): + return self.fields['recommends'] + + def suggests(self): + return self.fields['suggests'] + + def supplements(self): + # a control file has no notion of "supplements" + return [] + + def enhances(self): + return self.fields['enhances'] + def gettag(self, num): return self.fields.get(num, None) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/osc-0.162.1/osc/util/packagequery.py new/osc-0.163.0/osc/util/packagequery.py --- old/osc-0.162.1/osc/util/packagequery.py 2017-12-05 14:29:03.000000000 +0100 +++ new/osc-0.163.0/osc/util/packagequery.py 2018-08-20 13:19:29.000000000 +0200 @@ -127,6 +127,18 @@ def obsoletes(self): raise NotImplementedError + def recommends(self): + raise NotImplementedError + + def suggests(self): + raise NotImplementedError + + def supplements(self): + raise NotImplementedError + + def enhances(self): + raise NotImplementedError + def gettag(self, tag): raise NotImplementedError diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/osc-0.162.1/osc/util/repodata.py new/osc-0.163.0/osc/util/repodata.py --- old/osc-0.162.1/osc/util/repodata.py 2017-12-05 14:29:03.000000000 +0100 +++ new/osc-0.163.0/osc/util/repodata.py 2018-08-20 13:19:29.000000000 +0200 @@ -154,6 +154,18 @@ def obsoletes(self): return self.__parseEntryCollection('obsoletes') + def recommends(self): + return self.__parseEntryCollection('recommends') + + def suggests(self): + return self.__parseEntryCollection('suggests') + + def supplements(self): + return self.__parseEntryCollection('supplements') + + def enhances(self): + return self.__parseEntryCollection('enhances') + def canonname(self): return osc.util.rpmquery.RpmQuery.filename(self.name(), None, self.version(), self.release(), self.arch()) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/osc-0.162.1/osc/util/rpmquery.py new/osc-0.163.0/osc/util/rpmquery.py --- old/osc-0.162.1/osc/util/rpmquery.py 2017-12-05 14:29:03.000000000 +0100 +++ new/osc-0.163.0/osc/util/rpmquery.py 2018-08-20 13:19:29.000000000 +0200 @@ -58,11 +58,18 @@ GREATER = 1 << 2 EQUAL = 1 << 3 + SENSE_STRONG = 1 << 27 + default_tags = (1000, 1001, 1002, 1003, 1004, 1022, 1005, 1020, 1047, 1112, 1113, # provides 1049, 1048, 1050, # requires 1054, 1053, 1055, # conflicts - 1090, 1114, 1115 # obsoletes + 1090, 1114, 1115, # obsoletes + 1156, 1158, 1157, # oldsuggests + 5046, 5047, 5048, # recommends + 5049, 5051, 5050, # suggests + 5052, 5053, 5054, # supplements + 5055, 5056, 5057 # enhances ) def __init__(self, fh): @@ -156,10 +163,10 @@ else: raise RpmHeaderError(self.__path, 'unsupported tag type \'%d\' (tag: \'%s\'' % (entry.type, entry.tag)) - def __reqprov(self, tag, flags, version): + def __reqprov(self, tag, flags, version, strong=None): pnames = self.header.gettag(tag) if not pnames: - return [] + return [] pnames = pnames.data pflags = self.header.gettag(flags).data pvers = self.header.gettag(version).data @@ -167,6 +174,14 @@ raise RpmError(self.__path, 'cannot get provides/requires, tags are missing') res = [] for name, flags, ver in zip(pnames, pflags, pvers): + if strong is not None: + # compat code for the obsolete RPMTAG_OLDSUGGESTSNAME tag + # strong == 1 => return only "recommends" + # strong == 0 => return only "suggests" + if strong == 1: + strong = self.SENSE_STRONG + if (flags & self.SENSE_STRONG) != strong: + continue # RPMSENSE_SENSEMASK = 15 (see rpmlib.h) but ignore RPMSENSE_SERIAL (= 1 << 0) therefore use 14 if flags & 14: name += ' ' @@ -236,6 +251,24 @@ def obsoletes(self): return self.__reqprov(1090, 1114, 1115) + def recommends(self): + recommends = self.__reqprov(5046, 5048, 5047) + if not recommends: + recommends = self.__reqprov(1156, 1158, 1157, 1) + return recommends + + def suggests(self): + suggests = self.__reqprov(5049, 5051, 5050) + if not suggests: + suggests = self.__reqprov(1156, 1158, 1157, 0) + return suggests + + def supplements(self): + return self.__reqprov(5052, 5054, 5053) + + def enhances(self): + return self.__reqprov(5055, 5057, 5506) + def is_src(self): # SOURCERPM = 1044 return self.gettag(1044) is None diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/osc-0.162.1/osc/util/safewriter.py new/osc-0.163.0/osc/util/safewriter.py --- old/osc-0.162.1/osc/util/safewriter.py 2017-12-05 14:29:03.000000000 +0100 +++ new/osc-0.163.0/osc/util/safewriter.py 2018-08-20 13:19:29.000000000 +0200 @@ -1,29 +1,23 @@ # be careful when debugging this code: # don't add print statements when setting sys.stdout = SafeWriter(sys.stdout)... -class SafeWriter: +class SafeWriter(object): """ Safely write an (unicode) str. In case of an "UnicodeEncodeError" the the str is encoded with the "encoding" encoding. All getattr, setattr calls are passed through to the "writer" instance. """ def __init__(self, writer, encoding='unicode_escape'): - self.__dict__['writer'] = writer - self.__dict__['encoding'] = encoding - - def __get_writer(self): - return self.__dict__['writer'] - - def __get_encoding(self): - return self.__dict__['encoding'] + self._writer = writer + self._encoding = encoding def write(self, s): try: - self.__get_writer().write(s) + self._writer.write(s) except UnicodeEncodeError as e: - self.__get_writer().write(s.encode(self.__get_encoding())) + self._writer.write(s.encode(self._encoding)) def __getattr__(self, name): - return getattr(self.__get_writer(), name) + return getattr(self._writer, name) def __setattr__(self, name, value): - setattr(self.__get_writer(), name, value) + super(SafeWriter, self).__setattr__(name, value) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/osc-0.162.1/osc_hotshot.py new/osc-0.163.0/osc_hotshot.py --- old/osc-0.162.1/osc_hotshot.py 2017-12-05 14:29:03.000000000 +0100 +++ new/osc-0.163.0/osc_hotshot.py 1970-01-01 01:00:00.000000000 +0100 @@ -1,32 +0,0 @@ -#!/usr/bin/env python - -import hotshot, hotshot.stats -import tempfile -import os, sys - -from osc import commandline - - -if __name__ == '__main__': - - (fd, filename) = tempfile.mkstemp(prefix = 'osc_profiledata_', dir = '/dev/shm') - f = os.fdopen(fd) - - try: - - prof = hotshot.Profile(filename) - - prof.runcall(commandline.main) - print 'run complete. analyzing.' - prof.close() - - stats = hotshot.stats.load(filename) - stats.strip_dirs() - stats.sort_stats('time', 'calls') - stats.print_stats(20) - - del stats - - finally: - f.close() - os.unlink(filename) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/osc-0.162.1/setup.py new/osc-0.163.0/setup.py --- old/osc-0.162.1/setup.py 2017-12-05 14:29:03.000000000 +0100 +++ new/osc-0.163.0/setup.py 2018-08-20 13:19:29.000000000 +0200 @@ -109,7 +109,7 @@ url = 'http://en.opensuse.org/openSUSE:OSC', download_url = 'https://github.com/openSUSE/osc', packages = ['osc', 'osc.util'], - scripts = ['osc_hotshot.py', 'osc-wrapper.py'], + scripts = ['osc-wrapper.py'], data_files = data_files, # Override certain command classes with our own ones ++++++ osc.dsc ++++++ --- /var/tmp/diff_new_pack.aLmMct/_old 2018-08-20 16:23:29.425167971 +0200 +++ /var/tmp/diff_new_pack.aLmMct/_new 2018-08-20 16:23:29.425167971 +0200 @@ -1,6 +1,6 @@ Format: 1.0 Source: osc -Version: 0.162.1 +Version: 0.163.0 Binary: osc Maintainer: Adrian Schroeter <adr...@suse.de> Architecture: any