Mailinglist Archive: opensuse-buildservice (251 mails)

< Previous Next >
[opensuse-buildservice] osc pdiff plugin
  • From: Vincent Untz <vuntz@xxxxxxxxxxxx>
  • Date: Fri, 10 Sep 2010 17:58:33 +0200
  • Message-id: <20100910155833.GE27509@xxxxxxxxx>
Hi,

I got tired of typing long rdiff commands for packages that are known to
be links/branches, so I wrote a pdiff (parent diff) plugin.

pdiff simply works this way:

+ look if PRJ/PKG is a link/branch, and if it is, it gets the parent
from the link/branch data.

+ if it's not a link/branch, it tries to guess what would be a good
parent. Currently, it just guesses by looking at the project name
(for home:vuntz:branches:* names).

If you call it from a project checkout or a package checkout, you can
skip some arguments (it will take the project, or the project and
package information from the checkout).

So you can just do "osc pdiff" in a checkout instead of a long rdiff
command, or something like "osc pdiff GNOME:Factory gnome-panel" to
do a diff between gnome-panel in GNOME:Factory and openSUSE:Factory.

Feedback welcome.

I'm unsure where we should ship plugins like this one. Does it make
sense to include them in osc? Or should I just create a osc-plugin-pdiff
package and submit it to openSUSE:Tools?

Vincent

--
Les gens heureux ne sont pas pressés.
# vim: set ts=4 sw=4 et: coding=UTF-8

#
# Copyright (c) 2010, Novell, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# * Neither the name of the <ORGANIZATION> nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
#
# (Licensed under the simplified BSD license)
#
# Authors: Vincent Untz <vuntz@xxxxxxxxxxxx>
#


class OscPdiffError(Exception):
def __init__(self, value):
self.msg = value

def __str__(self):
return repr(self.msg)


def _pdiff_raise_non_existing_package(self, project, package, msg = None):
raise oscerr.PackageMissing(project, package, msg or '%s/%s does not
exist.' % (project, package))


def _pdiff_package_exists(self, apiurl, project, package):
try:
show_package_meta(apiurl, project, package)
return True
except urllib2.HTTPError, e:
if e.code != 404:
print >>sys.stderr, 'Cannot check that %s/%s exists: %s' %
(project, package, e)
return False


def _pdiff_guess_parent(self, apiurl, project, package, check_exists_first =
False):
# Make sure the parent exists
if check_exists_first and not self._pdiff_package_exists(apiurl, project,
package):
self._pdiff_raise_non_existing_package(project, package)

if project.startswith('home:'):
guess = project[len('home:'):]
# remove user name
pos = guess.find(':')
if pos > 0:
guess = guess[guess.find(':') + 1:]
if guess.startswith('branches:'):
guess = guess[len('branches:'):]
return (guess, package)

return (None, None)


def _pdiff_get_parent_from_link(self, apiurl, project, package):
link_url = makeurl(apiurl, ['source', project, package, '_link'])

try:
file = http_GET(link_url)
root = ET.parse(file).getroot()
except urllib2.HTTPError, e:
return (None, None)
except SyntaxError, e:
print >>sys.stderr, 'Cannot parse %s/%s/_link: %s' % (project, package,
e)
return (None, None)

parent_project = root.get('project')
parent_package = root.get('package') or package

if parent_project is None:
return (None, None)

return (parent_project, parent_package)


def _pdiff_get_exists_and_parent(self, apiurl, project, package):
link_url = makeurl(apiurl, ['public', 'source', project, package])
try:
file = http_GET(link_url)
root = ET.parse(file).getroot()
except urllib2.HTTPError, e:
if e.code != 404:
print >>sys.stderr, 'Cannot get list of files for %s/%s: %s' %
(project, package, e)
return (None, None, None)
except SyntaxError, e:
print >>sys.stderr, 'Cannot parse list of files for %s/%s: %s' %
(project, package, e)
return (None, None, None)

link_node = root.find('linkinfo')
if link_node is None:
return (True, None, None)

parent_project = link_node.get('project')
parent_package = link_node.get('package') or package

if parent_project is None:
raise oscerr.APIError('%s/%s is a link with no parent?' % (project,
package))

return (True, parent_project, parent_package)


@cmdln.option('-p', '--plain', action='store_true',
dest='plain',
help='output the diff in plain (not unified) diff format')
@cmdln.option('-n', '--nomissingok', action='store_true',
dest='nomissingok',
help='fail if the parent package does not exist on the server')
def do_pdiff(self, subcmd, opts, *args):
"""${cmd_name}: Quick alias to diff the content of a package with its
parent.

Usage:
osc pdiff [--plain|-p] [--nomissing-ok|-n]
osc pdiff [--plain|-p] [--nomissing-ok|-n] PKG
osc pdiff [--plain|-p] [--nomissing-ok|-n] PRJ PKG

${cmd_option_list}
"""

apiurl = conf.config['apiurl']

unified = not opts.plain
noparentok = not opts.nomissingok

if len(args) > 2:
raise oscerr.WrongArgs('Too many arguments.')

if len(args) == 0:
if not is_package_dir(os.getcwd()):
raise oscerr.WrongArgs('Current directory is not a checked out
package. Please specify a project and a package.')
project = store_read_project(os.curdir)
package = store_read_package(os.curdir)
elif len(args) == 1:
if not is_project_dir(os.getcwd()):
raise oscerr.WrongArgs('Current directory is not a checked out
project. Please specify a project and a package.')
project = store_read_project(os.curdir)
package = args[0]
elif len(args) == 2:
project = args[0]
package = args[1]
else:
raise RuntimeError('Internal error: bad check for arguments.')

## Find parent package

# Old way, that does one more request to api
#(parent_project, parent_package) =
self._pdiff_get_parent_from_link(apiurl, project, package)
#if not parent_project:
# (parent_project, parent_package) = self._pdiff_guess_parent(apiurl,
project, package, check_exists_first = True)
# if parent_project and parent_package:
# print 'Guessed that %s/%s is the parent package.' %
(parent_project, parent_package)

# New way
(exists, parent_project, parent_package) =
self._pdiff_get_exists_and_parent (apiurl, project, package)
if not exists:
self._pdiff_raise_non_existing_package(project, package)
if not parent_project:
(parent_project, parent_package) = self._pdiff_guess_parent(apiurl,
project, package, check_exists_first = False)
if parent_project and parent_package:
print 'Guessed that %s/%s is the parent package.' %
(parent_project, parent_package)

if not parent_project or not parent_package:
print >>sys.stderr, 'Cannot find a parent for %s/%s to diff against.' %
(project, package)
return

if not noparentok and not self._pdiff_package_exists(apiurl,
parent_project, parent_package):
self._pdiff_raise_non_existing_package(parent_project, parent_package,
msg = 'Parent for %s/%s (%s/%s) does not exist.' % (project, package,
parent_project, parent_package))

rdiff = server_diff(apiurl, parent_project, parent_package, None, project,
package, None, unified = unified, missingok = noparentok)

if len(rdiff) > 0:
run_pager(rdiff)
< Previous Next >