+0.152
+ - add support searching for groups via "group:" prefix
+ - show possible used incident projects on "maintained" command
+ OBS 2.7 only:
+ - support buildtime source services
+ - support maintenance_incident requests with acceptinfo data
+ - support maintenance_release requests with acceptinfo data
+
+0.151
+ - fixed shell command injection via crafted _service files (CVE-2015-0778)
+ - fix times when data comes from OBS backend
+ - support updateing the link in target package for submit requests
+ - various minor bugfixes
+
+0.150
+ - support local builds using builenv (for same build environment as a former build)
+ - add "osc api --edit" option to be able to edit some meta files directly
+ - follow the request order of the api (sorting according to priorization)
+ - add mr --release-project option for kgraft updates
+ - add support for makeoriginolder in request
+
0.149
- removed "--diff" option from the "createrequest" command
- introduced new "vc-cmd" config option, which is used to specify the path
osc -- opensuse-commander with svn like handling
+
Patches can be submitted via
* mail to opensuse-buildservice@opensuse.org
* Bugzilla: https://bugzilla.novell.com/enter_bug.cgi?product=openSUSE.org&component=BuildService
RPM packages are here (rpm-md repository):
http://download.opensuse.org/repositories/openSUSE:/Tools/
-To install from svn, do
+To install from git, do
python setup.py build
python setup.py install
osc (0.153.0-2) unstable; urgency=low
- Update to 0.153.0
- -- shuai fu <shuai01.fu@samsung.com> Fri, 20 May 2016 10:00:00 +0200
+ -- Adrian Schroeter <adrian@suse.de> Wed, 18 May 2016 10:00:00 +0200
osc (0.151.0-2) unstable; urgency=low
- Update to 0.151.0
- -- shuai fu <shuai01.fu@samsung.com> Wed, 28 Feb 2016 10:00:00 +0200
+ -- Adrian Schroeter <adrian@suse.de> Wed, 28 Jun 2012 10:00:00 +0200
osc (0.139.0-1) unstable; urgency=low
- Update to 0.139.0
test -z "$BASH_VERSION" && return
complete -o default _nullcommand >/dev/null 2>&1 || return
complete -r _nullcommand >/dev/null 2>&1 || return
-COMP_WORDBREAKS="${COMP_WORDBREAKS//:}"
test -s /usr/share/osc/complete && complete -o default -C /usr/share/osc/complete osc
test -s /usr/lib64/osc/complete && complete -o default -C /usr/lib64/osc/complete osc
test -s /usr/lib/osc/complete && complete -o default -C /usr/lib/osc/complete osc
#
# usage with bash
#
-# COMP_WORDBREAKS="${COMP_WORDBREAKS//:}"
# complete -C osc.complete osc
#
# Author: Werner Fink <werner@suse.de>
let colon=0
else
COMMAND_LINE="${COMP_LINE:0:$COMP_POINT}"
-# let colon=1
let colon=0
+ case "$COMP_WORDBREAKS" in
+ *:*) let colon=1
+ esac
[[ $COMMAND_LINE =~ \\: ]] && COMMAND_LINE="${COMMAND_LINE//\\:/:}"
fi
IFS="${IFS}="
cmdline=($COMMAND_LINE)
IFS="$OIFS"
-test "${cmdline[0]}" != "osc" && exit 1
+case "${cmdline[0]}" in
+iosc|isc|osc) ;;
+*) exit 1
+esac
let last=${#COMMAND_LINE}
let last--
oscpkg=""
lnkprj=""
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)
fi
+if test -s ${PWD}/.osc/_apiurl ; 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
+ alias=internal
+fi
+
+projects=~/.osc.projects
+command=osc
-if test -s ~/.osc.projects ; then
- typeset -i ctime=$(command date -d "$(command stat -c '%z' ~/.osc.projects)" +'%s')
+case "${cmdline[1]}" in
+-A|--apiurl)
+ if test -n "${cmdline[2]}" -a -s ~/.oscrc ; then
+ hints=($(sed -rn '/^(aliases=|\[http)/{s/,/ /g;s/(aliases=|\[|\])//gp}' < ~/.oscrc 2> /dev/null))
+ for h in ${hints[@]} ; do
+ case "$h" in
+ http*)
+ tmp=$(sed -rn '\@^\['${h}'@,\@=@{\@^aliases=@{s@[^=]+=([^,]+),.*@\1@p};}' < ~/.oscrc 2> /dev/null)
+ if test "${cmdline[2]}" = "$h" ; then
+ alias=$tmp
+ break
+ fi
+ ;;
+ *)
+ if test "${cmdline[2]}" = "$h" ; then
+ alias=$h
+ break
+ fi
+ esac
+ done
+ fi
+esac
+
+if test -n "$alias" ; then
+ projects="${projects}.${alias}"
+ command="$command -A $alias"
+fi
+
+if test -s "${projects}" ; then
+ typeset -i ctime=$(command date -d "$(command stat -c '%z' ${projects})" +'%s')
typeset -i now=$(command date -d now +'%s')
if ((now - ctime > 86400)) ; then
- if tmp=$(mktemp ~/.osc.projects.XXXXXX) ; then
- command osc ls / >| $tmp
- mv -uf $tmp ~/.osc.projects
+ if tmp=$(mktemp ${projects}.XXXXXX) ; then
+ command ${command} ls / >| $tmp
+ mv -uf $tmp ${projects}
fi
fi
else
- command osc ls / >| ~/.osc.projects
+ command ${command} ls / >| "${projects}"
fi
projects ()
local -a list
local -a argv
local -i argc=0
- local arg
+ local arg cur
for arg; do
if test $arg == "--" ; then
let argc++
argv[argc++]=$arg
done
shift $argc
- if test -n "$1" ; then
- list=($(command grep -E "^$1" ~/.osc.projects))
+ cur="$1"
+ if test -n "${cur}" ; then
+ list=($(command grep -E "^${cur}" ${projects}))
else
- list=($(command cat ~/.osc.projects))
+ list=($(command cat ${projects}))
fi
if ((colon)) ; then
- builtin compgen -W "${list[*]}" "$1"|sed -r 's@([^\\]):@\1\\:@g'
+ local colon_word
+ colon_word=${cur%${cur##*:}}
+ builtin compgen -W "${list[*]}" -- "${cur}" | sed -r "s@^${colon_word}@@g"
else
- builtin compgen -W "${list[*]}" -- ${1+"$@"}
+ builtin compgen -W "${list[*]}" -- "${cur}"
fi
}
local -a list
local -a argv
local -i argc=0
- local arg
+ local arg cur
for arg; do
if test $arg == "--" ; then
let argc++
argv[argc++]=$arg
done
shift $argc
- if test -n "$1" ; then
- list=($(command osc ls ${argv[@]}|command grep -E "^$1"))
+ cur="$1"
+ if test -n "${cur}" ; then
+ list=($(command ${command} ls ${argv[@]}|command grep -E "^${cur}"))
else
- list=($(command osc ls ${argv[@]}))
+ list=($(command ${command} ls ${argv[@]}))
fi
- builtin compgen -W "${list[*]}" -- ${1+"$@"}
+ builtin compgen -W "${list[*]}" -- "${cur}"
}
repositories ()
done
shift $argc
if test -n "$1" ; then
- list=($(command osc meta prj ${argv[@]}|\
+ list=($(command ${command} meta prj ${argv[@]}|\
command sed -rn '/<repository/{s@^\s*<.*name="([^"]*)".*@\1@p}'|\
command sort -u|command grep -E "^$1"))
else
- list=($(command osc meta prj ${argv[@]}|\
+ list=($(command ${command} meta prj ${argv[@]}|\
command sed -rn '/<repository/{s@^\s*<.*name="([^"]*)".*@\1@p}'|\
command sort -u))
fi
done
shift $argc
if test -n "$1" ; then
- list=($(command osc meta prj ${argv[@]}|\
+ list=($(command ${command} meta prj ${argv[@]}|\
command sed -rn '/<arch>/{s@^\s*<arch>(.*)</arch>@\1@p}'|\
command sort -u|command grep -E "^$1"))
else
- list=($(command osc meta prj ${argv[@]}|\
+ list=($(command ${command} meta prj ${argv[@]}|\
command sed -rn '/<arch>/{s@^\s*<arch>(.*)</arch>@\1@p}'|\
command sort -u))
fi
users ()
{
- if test -s ~/.osc.projects ; then
- command sed -rn "/^home:$1/{ s/^home:([^:]*):.*/\1/p}" ~/.osc.projects|command sort -u
+ if test -s ${projects} ; then
+ command sed -rn "/^home:$1/{ s/^home:([^:]*):.*/\1/p}" ${projects}|command sort -u
elif test -s ~/.oscrc; then
command sed -rn '/^(user=)/{s/(user=)//p}' ~/.oscrc|command sort -u
else
fi
;;
build)
- opts=(--help --oldpackages --disable-cpio-bulk-download --download-api-only --release --baselibs
+ opts=(--help --oldpackages --disable-cpio-bulk-download --release --baselibs
--disable-debuginfo --debuginfo --alternative-project --vm-type --linksources
--local-package --build-uid --userootforbuild --define --without --with
--ccache --icecream --jobs --root --extra-pkgs --keep-pkgs --prefer-pkgs
done
fi
if ((count == 2)) ; then
- specs=($(command ls *.spec 2>/dev/null))
- images=($(command ls *.kiwi 2>/dev/null))
- builtin compgen -W "${opts[*]} ${specs[*]} ${images[*]}" -- "${cmdline[count]}"
+ specs=($(command ls *.spec))
+ builtin compgen -W "${opts[*]} ${specs[*]}" -- "${cmdline[count]}"
fi
;;
branch|getpac|bco|branchco)
import locale
import sys
+import os
from osc import commandline, babysitter
#reload, neither setdefaultencoding are in python3
pass
+# avoid buffering output on pipes (bnc#930137)
+# Basically, a "print('foo')" call is translated to a corresponding
+# fwrite call that writes to the stdout stream (cf. string_print
+# (Objects/stringobject.c) and builtin_print (Python/bltinmodule.c));
+# If no pipe is used, stdout is a tty/refers to a terminal =>
+# the stream is line buffered (see _IO_file_doallocate (libio/filedoalloc.c)).
+# If a pipe is used, stdout does not refer to a terminal anymore =>
+# the stream is fully buffered by default (see _IO_file_doallocate).
+# The following fdopen call makes stdout line buffered again (at least on
+# systems that support setvbuf - if setvbuf is not supported, the stream
+# remains fully buffered (see PyFile_SetBufSize (Objects/fileobject.c))).
+if not os.isatty(sys.stdout.fileno()):
+ sys.stdout = os.fdopen(sys.stdout.fileno(), sys.stdout.mode, 1)
+
osccli = commandline.Osc()
r = babysitter.run(osccli)
--- /dev/null
+# fish completion for git
+# vim: smartindent:expandtab:ts=2:sw=2
+
+function __fish_osc_needs_command
+ set cmd (commandline -opc)
+ if contains "$cmd" 'osc' 'osc help'
+ return 0
+ end
+ return 1
+end
+
+function __fish_osc_using_command
+ set cmd (commandline -opc)
+ if [ (count $cmd) -gt 1 ]
+ for arg in $argv
+ if [ $arg = $cmd[2] ]
+ return 0
+ end
+ end
+ end
+ return 1
+end
+
+# general options
+complete -f -c osc -n 'not __fish_osc_needs_command' -s A -l apiurl -d 'specify URL to access API server at or an alias'
+complete -f -c osc -n 'not __fish_osc_needs_command' -s c -l config -d 'specify alternate configuration file'
+complete -f -c osc -n 'not __fish_osc_needs_command' -s d -l debug -d 'print info useful for debugging'
+complete -f -c osc -n 'not __fish_osc_needs_command' -l debugger -d 'jump into the debugger before executing anything'
+complete -f -c osc -n 'not __fish_osc_needs_command' -s h -l help -d 'show this help message and exit'
+complete -f -c osc -n 'not __fish_osc_needs_command' -s H -l http-debug -d 'debug HTTP traffic (filters some headers)'
+complete -f -c osc -n 'not __fish_osc_needs_command' -l http-full-debug -d 'debug HTTP traffic (filters no headers)'
+complete -f -c osc -n 'not __fish_osc_needs_command' -l no-gnome-keyring -d 'disable usage of GNOME Keyring'
+complete -f -c osc -n 'not __fish_osc_needs_command' -l no-keyring -d 'disable usage of desktop keyring system'
+complete -f -c osc -n 'not __fish_osc_needs_command' -l post-mortem -d 'jump into the debugger in case of errors'
+complete -f -c osc -n 'not __fish_osc_needs_command' -s q -l quiet -d 'be quiet, not verbose'
+complete -f -c osc -n 'not __fish_osc_needs_command' -s t -l traceback -d 'print call trace in case of errors'
+complete -f -c osc -n 'not __fish_osc_needs_command' -s v -l verbose -d 'increase verbosity'
+complete -f -c osc -n 'not __fish_osc_needs_command' -l version -d 'show program\'s version number and exit'
+
+# osc commands
+complete -f -c osc -n '__fish_osc_needs_command' -a 'add' -d 'Mark files to be added upon the next commit'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'addremove ar' -d 'Adds new files, removes disappeared files'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'aggregatepac' -d '"Aggregate" a package to another package'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'api' -d 'Issue an arbitrary request to the API'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'branch bco branchco getpac' -d 'Branch a package'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'chroot' -d 'into the buildchroot'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'clean' -d 'removes all untracked files from the package working ...'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'commit checkin ci' -d 'Upload content to the repository server'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'config' -d 'get/set a config option'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'copypac' -d 'Copy a package'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'createincident' -d 'Create a maintenance incident'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'createrequest creq' -d 'create multiple requests with a single command'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'delete del remove rm' -d 'Mark files or package directories to be deleted upon ...'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'deleterequest deletereq dr dropreq droprequest' -d 'Request to delete (or "drop") a package or project'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'dependson whatdependson' -d 'Show the build dependencies'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'detachbranch' -d 'replace a link with its expanded sources'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'develproject bsdevelproject dp' -d 'print the devel project / package of a package'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'diff di ldiff linkdiff' -d 'Generates a diff'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'distributions dists' -d 'Shows all available distributions'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'getbinaries' -d 'Download binaries to a local directory'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'help ? h' -d 'give detailed help on a specific sub-command'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'importsrcpkg' -d 'Import a new package from a src.rpm'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'info' -d 'Print information about a working copy'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'init' -d 'Initialize a directory as working copy'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'jobhistory jobhist' -d 'Shows the job history of a project'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'linkpac' -d '"Link" a package to another package'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'linktobranch' -d 'Convert a package containing a classic link with patc...'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'list LL lL ll ls' -d 'List sources or binaries on the server'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'localbuildlog lbl' -d 'Shows the build log of a local buildchroot'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'log' -d 'Shows the commit log of a package'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'maintainer bugowner' -d 'Show maintainers according to server side configuration'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'maintenancerequest mr' -d 'Create a request for starting a maintenance incident.'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'man' -d 'generates a man page'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'mbranch maintained sm' -d 'Search or banch multiple instances of a package'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'meta' -d 'Show meta information, or edit it'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'mkpac' -d 'Create a new package under version control'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'mv' -d 'Move SOURCE file to DEST and keep it under version co...'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'my' -d 'show waiting work, packages, projects or requests inv...'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'patchinfo' -d 'Generate and edit a patchinfo file.'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'pdiff' -d 'Quick alias to diff the content of a package with its...'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'prdiff projdiff projectdiff' -d 'Server-side diff of two projects'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'prjresults pr' -d 'Shows project-wide build results'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'pull' -d 'merge the changes of the link target into your workin...'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'rdelete' -d 'Delete a project or packages on the server.'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'rdiff' -d 'Server-side "pretty" diff of two packages'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'rebuild rebuildpac' -d 'Trigger package rebuilds'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'release' -d 'Release sources and binaries'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'releaserequest' -d 'Create a request for releasing a maintenance update.'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'remotebuildlog rbl rblt rbuildlog rbuildlogtail remotebuildlogtail' -d 'Shows the build log of a package'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'repairlink' -d 'Repair a broken source link'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'repairwc' -d 'try to repair an inconsistent working copy'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'repositories platforms repos' -d 'shows repositories configured for a project. It skips...'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'repourls' -d 'Shows URLs of .repo files'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'request review rq' -d 'Show or modify requests and reviews'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'requestmaintainership reqbs reqbugownership reqmaintainership reqms requestbugownership' -d 'requests to add user as maintainer or bugowner'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'resolved' -d 'Remove "conflicted" state on working copy files'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'restartbuild abortbuild' -d 'Restart the build of a certain project or package'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'results r' -d 'Shows the build results of a package or project'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'revert' -d 'Restore changed files or the entire working copy.'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'rremove' -d 'Remove source files from selected package'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'search bse se' -d 'Search for a project and/or package.'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'service' -d 'Handle source services'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'setdevelproject sdp' -d 'Set the devel project / package of a package'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'setlinkrev' -d 'Updates a revision number in a source link.'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'signkey' -d 'Manage Project Signing Key'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'status st' -d 'Show status of files in working copy'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'submitrequest sr submitpac submitreq' -d 'Create request to submit source into another Project'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'token' -d 'Show and manage authentication token'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'triggerreason tr' -d 'Show reason why a package got triggered to build'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'undelete' -d 'Restores a deleted project or package on the server.'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'unlock' -d 'Unlocks a project or package'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'update up' -d 'Update a working copy'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'updatepacmetafromspec metafromspec updatepkgmetafromspec' -d 'Update package meta information from a specfile'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'vc' -d 'Edit the changes file'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'whois user who' -d 'Show fullname and email of a buildservice user'
+complete -f -c osc -n '__fish_osc_needs_command' -a 'wipebinaries' -d 'Delete all binary packages of a certain project/package'
'armv5tel': [ 'armv4l', 'armv5el', 'armv5tel' ],
's390x': ['s390' ],
'ppc64': [ 'ppc', 'ppc64', 'ppc64p7', 'ppc64le' ],
- 'ppc64le': [ 'ppc64le' ],
+ 'ppc64le': [ 'ppc64le', 'ppc64' ],
'i586': [ 'i386' ],
'i686': [ 'i586', 'i386' ],
'x86_64': ['i686', 'i586', 'i386' ],
self.mp = {}
for i in ['binary', 'package',
- 'epoch', 'version', 'release',
+ 'epoch', 'version', 'release', 'hdrmd5',
'project', 'repository',
'preinstall', 'vminstall', 'noinstall', 'installonly', 'runscripts',
]:
self.mp['apiurl'] = apiurl
if pacsuffix == 'deb':
- filename = debquery.DebQuery.filename(self.mp['name'], self.mp['epoch'], self.mp['version'], self.mp['release'], self.mp['arch'])
+ canonname = debquery.DebQuery.filename(self.mp['name'], self.mp['epoch'], self.mp['version'], self.mp['release'], self.mp['arch'])
elif pacsuffix == 'arch':
- filename = archquery.ArchQuery.filename(self.mp['name'], self.mp['epoch'], self.mp['version'], self.mp['release'], self.mp['arch'])
+ canonname = archquery.ArchQuery.filename(self.mp['name'], self.mp['epoch'], self.mp['version'], self.mp['release'], self.mp['arch'])
else:
- filename = rpmquery.RpmQuery.filename(self.mp['name'], self.mp['epoch'], self.mp['version'], self.mp['release'], self.mp['arch'])
+ canonname = rpmquery.RpmQuery.filename(self.mp['name'], self.mp['epoch'], self.mp['version'], self.mp['release'], self.mp['arch'])
- self.mp['filename'] = node.get('binary') or filename
+ self.mp['canonname'] = canonname
+ # maybe we should rename filename key to binary
+ self.mp['filename'] = node.get('binary') or canonname
if self.mp['repopackage'] == '_repository':
self.mp['repofilename'] = self.mp['name']
else:
# or if-modified-since, so the caching is simply name-based (on the assumption
# that the filename is suitable as identifier)
self.localdir = '%s/%s/%s/%s' % (cachedir, self.project, self.repository, self.arch)
- self.fullfilename = os.path.join(self.localdir, self.filename)
+ self.fullfilename = os.path.join(self.localdir, self.canonname)
self.url_local = 'file://%s' % self.fullfilename
# first, add the local URL
return repositoryDirectory
-def get_prefer_pkgs(dirs, wanted_arch, type):
+def get_prefer_pkgs(dirs, wanted_arch, type, cpio):
import glob
- from .util import repodata, packagequery, cpio
+ from .util import repodata, packagequery
paths = []
repositories = []
packageQueries.add(packageQuery)
for path in paths:
- if path.endswith('src.rpm'):
+ if path.endswith('.src.rpm') or path.endswith('.nosrc.rpm'):
+ continue
+ if path.endswith('.patch.rpm') or path.endswith('.delta.rpm'):
continue
if path.find('-debuginfo-') > 0:
continue
for name, packageQuery in packageQueries.items())
depfile = create_deps(packageQueries.values())
- cpio = cpio.CpioWrite()
cpio.add('deps', '\n'.join(depfile))
- return prefer_pkgs, cpio
+ return prefer_pkgs
def create_deps(pkgqs):
"""
- creates a list of requires/provides which corresponds to build's internal
+ creates a list of dependencies which corresponds to build's internal
dependency file format
"""
depfile = []
for p in pkgqs:
id = '%s.%s-0/0/0: ' % (p.name(), p.arch())
- depfile.append('R:%s%s' % (id, ' '.join(p.requires())))
depfile.append('P:%s%s' % (id, ' '.join(p.provides())))
+ depfile.append('R:%s%s' % (id, ' '.join(p.requires())))
+ d = p.conflicts()
+ if d:
+ depfile.append('C:%s%s' % (id, ' '.join(d)))
+ d = p.obsoletes()
+ if d:
+ depfile.append('O:%s%s' % (id, ' '.join(d)))
+ depfile.append('I:%s%s-%s 0-%s' % (id, p.name(), p.evr(), p.arch()))
return depfile
build_root = opts.root
if opts.target:
buildargs.append('--target=%s' % opts.target)
+ if opts.threads:
+ buildargs.append('--threads=%s' % opts.threads)
if opts.jobs:
buildargs.append('--jobs=%s' % opts.jobs)
elif config['build-jobs'] > 1:
s += "%%define %s\n" % i
build_descr_data = s + build_descr_data
+ cpiodata = None
+ servicefile = os.path.join(os.path.dirname(build_descr), "_service")
+ if not os.path.isfile(servicefile):
+ servicefile = os.path.join(os.path.dirname(build_descr), "_service")
+ if not os.path.isfile(servicefile):
+ servicefile = None
+ else:
+ print('Using local _service file')
+ buildenvfile = os.path.join(os.path.dirname(build_descr), "_buildenv." + repo + "." + arch)
+ if not os.path.isfile(buildenvfile):
+ buildenvfile = os.path.join(os.path.dirname(build_descr), "_buildenv")
+ if not os.path.isfile(buildenvfile):
+ buildenvfile = None
+ else:
+ print('Using local buildenv file: %s' % os.path.basename(buildenvfile))
+ if buildenvfile or servicefile:
+ from .util import cpio
+ if not cpiodata:
+ cpiodata = cpio.CpioWrite()
+
if opts.prefer_pkgs:
print('Scanning the following dirs for local packages: %s' % ', '.join(opts.prefer_pkgs))
- prefer_pkgs, cpio = get_prefer_pkgs(opts.prefer_pkgs, arch, build_type)
- cpio.add(os.path.basename(build_descr), build_descr_data)
- build_descr_data = cpio.get()
+ from .util import cpio
+ if not cpiodata:
+ cpiodata = cpio.CpioWrite()
+ prefer_pkgs = get_prefer_pkgs(opts.prefer_pkgs, arch, build_type, cpiodata)
+
+ if cpiodata:
+ cpiodata.add(os.path.basename(build_descr), build_descr_data)
+ # buildenv must come last for compatibility reasons...
+ if buildenvfile:
+ cpiodata.add("buildenv", open(buildenvfile).read())
+ if servicefile:
+ cpiodata.add("_service", open(servicefile).read())
+ build_descr_data = cpiodata.get()
# special handling for overlay and rsync-src/dest
specialcmdopts = []
enable_cpio = not opts.disable_cpio_bulk_download,
cookiejar=cookiejar)
- # implicitly trust the project we are building for
- check_trusted_projects(apiurl, [ i for i in bi.projects.keys() if not i == prj ])
+ if not opts.trust_all_projects:
+ # implicitly trust the project we are building for
+ check_trusted_projects(apiurl, [ i for i in bi.projects.keys() if not i == prj ])
# now update the package cache
fetcher.run(bi)
""" temporary directory that removes itself"""
def __init__(self, *args, **kwargs):
self.name = mkdtemp(*args, **kwargs)
+ _rmtree = staticmethod(shutil.rmtree)
def cleanup(self):
- shutil.rmtree(self.name)
+ self._rmtree(self.name)
def __del__(self):
self.cleanup()
def __exit__(self):
else:
print('WARNING: unknown packages get not verified, they can compromise your system !')
+ for i in bi.deps:
+ if i.hdrmd5:
+ from .util import packagequery
+ hdrmd5 = packagequery.PackageQuery.queryhdrmd5(i.fullfilename)
+ if not hdrmd5:
+ print("Error: cannot get hdrmd5 for %s" % i.fullfilename)
+ sys.exit(1)
+ if hdrmd5 != i.hdrmd5:
+ print("Error: hdrmd5 mismatch for %s: %s != %s" % (i.fullfilename, hdrmd5, i.hdrmd5))
+ sys.exit(1)
+
print('Writing build configuration')
if build_type == 'kiwi':
my_build_swap = build_root + '/swap'
vm_options = [ '--vm-type=%s' % vm_type ]
- if vm_type != 'lxc' and vm_type != 'emulator':
+ if vm_type != 'lxc':
vm_options += [ '--vm-disk=' + my_build_device ]
vm_options += [ '--vm-swap=' + my_build_swap ]
vm_options += [ '--logfile=%s/.build.log' % build_root ]
if os.access(build_root, os.W_OK) and os.access('/dev/kvm', os.W_OK):
# so let's hope there's also an fstab entry
need_root = False
+ if config['build-kernel']:
+ vm_options += [ '--vm-kernel=' + config['build-kernel'] ]
+ if config['build-initrd']:
+ vm_options += [ '--vm-initrd=' + config['build-initrd'] ]
+
build_root += '/.mount'
if config['build-memory']:
"""
self.cmdlooping = True
self.preloop()
- if intro is None:
- intro = self.intro
- if intro:
- intro_str = self._str(intro)
- self.stdout.write(intro_str+'\n')
- self.stop = False
- retval = None
- while not self.stop:
- if self.cmdqueue:
- argv = self.cmdqueue.pop(0)
- assert isinstance(argv, (list, tuple)), \
- "item on 'cmdqueue' is not a sequence: %r" % argv
- else:
- if self.use_rawinput:
- try:
- try:
- #python 2.x
- line = raw_input(self._prompt_str)
- except NameError:
- line = input(self._prompt_str)
- except EOFError:
- line = 'EOF'
+ if self.use_rawinput and self.completekey:
+ try:
+ import readline
+ self.old_completer = readline.get_completer()
+ readline.set_completer(self.complete)
+ readline.parse_and_bind(self.completekey+": complete")
+ except ImportError:
+ pass
+ try:
+ if intro is None:
+ intro = self.intro
+ if intro:
+ intro_str = self._str(intro)
+ self.stdout.write(intro_str+'\n')
+ self.stop = False
+ retval = None
+ while not self.stop:
+ if self.cmdqueue:
+ argv = self.cmdqueue.pop(0)
+ assert isinstance(argv, (list, tuple)), \
+ "item on 'cmdqueue' is not a sequence: %r" % argv
else:
- self.stdout.write(self._prompt_str)
- self.stdout.flush()
- line = self.stdin.readline()
- if not len(line):
- line = 'EOF'
+ if self.use_rawinput:
+ try:
+ try:
+ #python 2.x
+ line = raw_input(self._prompt_str)
+ except NameError:
+ line = input(self._prompt_str)
+ except EOFError:
+ line = 'EOF'
else:
- line = line[:-1] # chop '\n'
- argv = line2argv(line)
- try:
- argv = self.precmd(argv)
- retval = self.onecmd(argv)
- self.postcmd(argv)
- except:
- if not self.cmdexc(argv):
- raise
- retval = 1
- self.lastretval = retval
- self.postloop()
+ self.stdout.write(self._prompt_str)
+ self.stdout.flush()
+ line = self.stdin.readline()
+ if not len(line):
+ line = 'EOF'
+ else:
+ line = line[:-1] # chop '\n'
+ argv = line2argv(line)
+ try:
+ argv = self.precmd(argv)
+ retval = self.onecmd(argv)
+ self.postcmd(argv)
+ except:
+ if not self.cmdexc(argv):
+ raise
+ retval = 1
+ self.lastretval = retval
+ self.postloop()
+ finally:
+ if self.use_rawinput and self.completekey:
+ try:
+ import readline
+ readline.set_completer(self.old_completer)
+ except ImportError:
+ pass
self.cmdlooping = False
return retval
* http://en.opensuse.org/openSUSE:Build_Service_Tutorial
* http://en.opensuse.org/openSUSE:OSC
.PP
-You can modify osc commands, or roll you own, via the plugin API:
+You can modify osc commands, or roll your own, via the plugin API:
* http://en.opensuse.org/openSUSE:OSC_plugins
.SH AUTHOR
osc was written by several authors. This man page is automatically generated.
* http://en.opensuse.org/openSUSE:Build_Service_Tutorial
* http://en.opensuse.org/openSUSE:OSC
- You can modify osc commands, or roll you own, via the plugin API:
+ You can modify osc commands, or roll your own, via the plugin API:
* http://en.opensuse.org/openSUSE:OSC_plugins
"""
name = 'osc'
osc meta prj PRJ
osc meta pkg PRJ PKG
osc meta pkg PRJ PKG -e
- osc meta attribute PRJ [PKG [SUBPACKAGE]] [--attribute ATTRIBUTE] [--create|--delete|--set [value_list]]
Usage:
- osc meta <prj|pkg|prjconf|user|pattern|attribute> ARGS...
- osc meta <prj|pkg|prjconf|user|pattern|attribute> -e|--edit ARGS...
- osc meta <prj|pkg|prjconf|user|pattern|attribute> -F|--file ARGS...
+ osc meta <prj|pkg|prjconf|user|pattern> ARGS...
+ osc meta <prj|pkg|prjconf|user|pattern> -e|--edit ARGS...
+ osc meta <prj|pkg|prjconf|user|pattern> -F|--file ARGS...
osc meta pattern --delete PRJ PATTERN
+ osc meta attribute PRJ [PKG [SUBPACKAGE]] [--attribute ATTRIBUTE] [--create|--delete|--set [value_list]]
${cmd_option_list}
"""
help='never remove source package on accept, but update its content')
@cmdln.option('--no-update', action='store_true',
help='never touch source package on accept (will break source links)')
+ @cmdln.option('--update-link', action='store_true',
+ help='This transfers the source including the _link file.')
@cmdln.option('-d', '--diff', action='store_true',
help='show diff only instead of creating the actual request')
@cmdln.option('--yes', action='store_true',
sr_ids = []
# for single request
actionxml = ""
- options_block = ""
+ options_block = "<options>"
if src_update:
- options_block = """<options><sourceupdate>%s</sourceupdate></options> """ % (src_update)
+ options_block += """<sourceupdate>%s</sourceupdate>""" % (src_update)
+ if opts.update_link:
+ options_block + """<updatelink>true</updatelink></options> """
+ options_block += "</options>"
# loop via all packages for checking their state
for p in meta_get_packagelist(apiurl, project):
result = create_submit_request(apiurl,
src_project, src_package,
dst_project, dst_package,
- opts.message, orev=rev, src_update=src_update)
+ opts.message, orev=rev,
+ src_update=src_update, dst_updatelink=opts.update_link)
if supersede_existing:
for req in reqs:
change_request_state(apiurl, req.reqid, 'superseded',
@cmdln.option('-m', '--message', metavar='TEXT',
help='specify message TEXT')
- @cmdln.option('-r', '--repository', metavar='TEXT',
- help='specify message TEXT')
- @cmdln.option('--accept-in-hours', metavar='TEXT',
- help='specify message time when request shall get accepted automatically. Only works with write permissions in target.')
+ @cmdln.option('-r', '--repository', metavar='REPOSITORY',
+ help='specify repository')
+ @cmdln.option('--accept-in-hours', metavar='HOURS',
+ help='specify time when request shall get accepted automatically. Only works with write permissions in target.')
@cmdln.alias("dr")
@cmdln.alias("dropreq")
@cmdln.alias("droprequest")
print('No results')
return
- results.sort(reverse=True)
+ # we must not sort the results here, since the api is doing it already "the right way"
days = opts.days or conf.config['request_list_days']
since = ''
try:
except HTTPError as e:
# for OBS 2.0 and before
sr_actions = r.get_actions('submit')
- if not sr_actions:
- raise oscerr.WrongOptions('\'--diff\' not possible (request has no \'submit\' actions)')
+ if not r.get_actions('submit') and not r.get_actions('maintenance_incident') and not r.get_actions('maintenance_release'):
+ raise oscerr.WrongOptions('\'--diff\' not possible (request has no supported actions)')
for action in sr_actions:
diff += 'old: %s/%s\nnew: %s/%s\n' % (action.src_project, action.src_package,
action.tgt_project, action.tgt_package)
help='Use this attribute to find default maintenance project (default is OBS:MaintenanceProject)')
@cmdln.option('-m', '--message', metavar='TEXT',
help='specify message TEXT')
+ @cmdln.option('--release-project', metavar='RELEASEPROJECT',
+ help='Specify the release project')
@cmdln.option('--no-cleanup', action='store_true',
help='do not remove source project on accept')
@cmdln.option('--cleanup', action='store_true',
osc maintenancerequest [ SOURCEPROJECT [ SOURCEPACKAGES RELEASEPROJECT ] ]
${cmd_option_list}
"""
+ #FIXME: the follow syntax would make more sense and would obsolete the --release-project parameter
+ # but is incompatible with the current one
+ # osc maintenancerequest [ SOURCEPROJECT [ RELEASEPROJECT [ SOURCEPACKAGES ] ]
args = slash_split(args)
apiurl = self.get_api_url()
if source_project.startswith(default_branch):
opt_sourceupdate = 'cleanup'
+ if opts.release_project:
+ release_project = opts.release_project
+
if opts.incident_project:
target_project = opts.incident_project
else:
if opts.dryrun:
for r in result.findall('package'):
- print("%s/%s"%(r.get('project'), r.get('package')))
+ line="%s/%s"%(r.get('project'), r.get('package'))
+ for d in r.findall('devel'):
+ line+=" using sources from %s/%s"%(d.get('project'), d.get('package'))
+ print(line)
return
apiopt = ''
delete_project(apiurl, prj, opts.force, msg)
+ def do_lock(self, subcmd, opts, project, package=None):
+ """${cmd_name}: Locks a project or package.
+
+ usage:
+ osc lock PROJECT [PACKAGE]
+
+ ${cmd_option_list}
+ """
+ apiurl = self.get_api_url()
+ kind = 'prj'
+ path_args = (project,)
+ if package is not None:
+ kind = 'pkg'
+ path_args = (project, package)
+ meta = meta_exists(kind, path_args, create_new=False, apiurl=apiurl)
+ root = ET.fromstring(''.join(meta))
+ if root.find('lock') is not None:
+ print('Already locked', file=sys.stderr)
+ sys.exit(1)
+ # alternatively, we could also use the set_flag api call
+ # instead of manually manipulating the xml
+ lock = ET.SubElement(root, 'lock')
+ ET.SubElement(lock, 'enable')
+ meta = ET.tostring(root)
+ edit_meta(kind, path_args=path_args, data=meta)
+
+
@cmdln.option('-m', '--message', metavar='TEXT',
help='specify log message TEXT')
def do_unlock(self, subcmd, opts, *args):
else:
raise oscerr.WrongArgs('Wrong number of arguments')
- # XXX: API should somehow tell that
- url_tmpl = 'http://download.opensuse.org/repositories/%s/%s/%s.repo'
+ root = ET.fromstring(''.join(show_configuration(apiurl)))
+ elm = root.find('download_url')
+ if elm is None or not elm.text:
+ raise oscerr.APIError('download_url configuration element expected')
+
+ url_tmpl = elm.text + '/%s/%s/%s.repo'
repos = get_repositories_of_project(apiurl, project)
for repo in repos:
print(url_tmpl % (project.replace(':', ':/'), repo, project))
'M' Modified
'?' item is not under version control
'!' item is missing (removed by non-osc command) or incomplete
+ 'S' item is skipped (item exceeds a file size limit or is _service:* file)
+ 'F' Frozen (use "osc pull" to merge conflicts) (package-only state)
examples:
osc st
# state is != ' '
lines.append(statfrmt(st, os.path.normpath(os.path.join(prj.dir, pac))))
continue
- if st == ' ' and opts.verbose or st != ' ':
+ if p.isfrozen():
+ lines.append(statfrmt('F', os.path.normpath(os.path.join(prj.dir, pac))))
+ elif st == ' ' and opts.verbose or st != ' ':
lines.append(statfrmt(st, os.path.normpath(os.path.join(prj.dir, pac))))
states = p.get_status(opts.show_excluded, *excl_states)
for st, filename in sorted(states, lambda x, y: cmp(x[1], y[1])):
pacs = findpacs(args)
for p in pacs:
- p.todo = list(set(p.filenamelist + p.filenamelist_unvers + p.to_be_added))
- for filename in p.todo:
- if os.path.isdir(filename):
+ todo = list(set(p.filenamelist + p.filenamelist_unvers + p.to_be_added))
+ for filename in todo:
+ abs_filename = os.path.join(p.absdir, filename)
+ if os.path.isdir(abs_filename):
continue
# ignore foo.rXX, foo.mine for files which are in 'C' state
if os.path.splitext(filename)[0] in p.in_conflict:
if state == '?':
# TODO: should ignore typical backup files suffix ~ or .orig
p.addfile(filename)
+ elif state == 'D' and os.path.isfile(abs_filename):
+ # if the "deleted" file exists in the wc, track it again
+ p.addfile(filename)
elif state == '!':
p.delete_file(filename)
print(statfrmt('D', getTransActPath(os.path.join(p.dir, filename))))
repo_names = sorted(set([r.name for r in repositories]))
if not arg_repository and repositories:
+ # XXX: we should avoid hardcoding repository names
# Use a default value from config, but just even if it's available
- # unless try standard, or openSUSE_Factory
+ # unless try standard, or openSUSE_Factory, or openSUSE_Tumbleweed
arg_repository = repositories[-1].name
- for repository in (conf.config['build_repository'], 'standard', 'openSUSE_Factory'):
+ for repository in (conf.config['build_repository'], 'standard', 'openSUSE_Factory', 'openSUSE_Tumbleweed'):
if repository in repo_names:
arg_repository = repository
break
help='Build in specified directory')
@cmdln.option('-j', '--jobs', metavar='N',
help='Compile with N jobs')
+ @cmdln.option('-t', '--threads', metavar='N',
+ help='Compile with N threads')
@cmdln.option('--icecream', metavar='N',
help='use N parallel build jobs with icecream')
@cmdln.option('--ccache', action='store_true',
help=SUPPRESS_HELP)
@cmdln.option('--host', metavar='HOST',
help='perform the build on a remote server - user@server:~/remote/directory')
+ @cmdln.option('--trust-all-projects', action='store_true',
+ help='trust packages from all projects')
def do_build(self, subcmd, opts, *args):
"""${cmd_name}: Build a package on your local machine
if not os.path.isdir(d):
raise oscerr.WrongOptions('Preferred package location \'%s\' is not a directory' % d)
- if opts.noinit and opts.offline:
- raise oscerr.WrongOptions('--noinit and --offline are mutually exclusive')
-
if opts.offline and opts.preload:
raise oscerr.WrongOptions('--offline and --preload are mutually exclusive')
help='specify the used build target project')
@cmdln.option('--noinit', '--no-init', action='store_true',
help='do not guess/verify specified repository')
- @cmdln.option('-r', '--root', action='store_true',
+ @cmdln.option('-r', '--login-as-root', action='store_true',
help='login as root instead of abuild')
+ @cmdln.option('--root', metavar='ROOT',
+ help='Path to the buildroot')
@cmdln.option('-o', '--offline', action='store_true',
help='Use cached data without contacting the api server')
def do_chroot(self, subcmd, opts, *args):
- """${cmd_name}: chroot into the buildchroot
+ """${cmd_name}: opens a shell inside of the build root
- chroot into the buildchroot for the given repository, arch and build description
- (NOTE: this command does not work if "build-type" is set in the config)
+ chroot into the build root for the given repository, arch and build description
+ (NOTE: this command does not work if a VM is used)
usage:
osc chroot [OPTS] REPOSITORY ARCH BUILD_DESCR
"""
if len(args) > 3:
raise oscerr.WrongArgs('Too many arguments')
- if conf.config['build-type']:
+ if conf.config['build-type'] and conf.config['build-type'] != "lxc":
print('Not implemented for VMs', file=sys.stderr)
sys.exit(1)
user = 'abuild'
- if opts.root:
+ if opts.login_as_root:
user = 'root'
- repository, arch, descr = self.parse_repoarchdescr(args, opts.noinit or opts.offline, opts.alternative_project)
- project = opts.alternative_project or store_read_project('.')
- if opts.local_package:
- package = os.path.splitext(descr)[0]
- else:
- package = store_read_package('.')
- apihost = urlsplit(self.get_api_url())[1]
- buildroot = os.environ.get('OSC_BUILD_ROOT', conf.config['build-root']) \
- % {'repo': repository, 'arch': arch, 'project': project, 'package': package, 'apihost': apihost}
+ buildroot = opts.root
+ if buildroot is None:
+ repository, arch, descr = self.parse_repoarchdescr(args, opts.noinit or opts.offline, opts.alternative_project)
+ project = opts.alternative_project or store_read_project('.')
+ if opts.local_package:
+ package = os.path.splitext(descr)[0]
+ else:
+ package = store_read_package('.')
+ apihost = urlsplit(self.get_api_url())[1]
+ if buildroot is None:
+ buildroot = os.environ.get('OSC_BUILD_ROOT', conf.config['build-root']) \
+ % {'repo': repository, 'arch': arch, 'project': project, 'package': package, 'apihost': apihost}
if not os.path.isdir(buildroot):
raise oscerr.OscIOError(None, '\'%s\' is not a directory' % buildroot)
${cmd_option_list}
"""
+ args = slash_split(args)
+
if len(args) < 2 and is_package_dir('.'):
self.print_repos()
@cmdln.option('-V', '--version', action='store_true',
help='show package version, revision, and srcmd5. CAUTION: This is slow and unreliable')
@cmdln.option('-i', '--involved', action='store_true',
- help='show projects/packages where given person (or myself) is involved as bugowner or maintainer')
+ help='show projects/packages where given person (or myself) is involved as bugowner or maintainer [[{group|person}/]<name>] default: person')
@cmdln.option('-b', '--bugowner', action='store_true',
help='as -i, but only bugowner')
@cmdln.option('-m', '--maintainer', action='store_true',
# role filter
role_filter = ''
if opts.bugowner or opts.maintainer or opts.involved:
- xpath = xpath_join(xpath, 'person/@userid = \'%s\'' % search_term, inner=True)
- role_filter = '%s (%s)' % (search_term, 'person')
+ tmp = search_term.split(':')
+ if len(tmp) > 1:
+ search_type, search_term = [tmp[0], tmp[1]]
+ else:
+ search_type = 'person'
+ search_dict = { 'person' : 'userid',
+ 'group' : 'groupid' }
+ try:
+ search_id = search_dict[ search_type ]
+ except KeyError:
+ search_type, search_id = [ 'person', 'userid' ]
+ xpath = xpath_join(xpath, '%s/@%s = \'%s\'' % (search_type, search_id, search_term), inner=True)
+ role_filter = '%s (%s)' % (search_term, search_type)
role_filter_xpath = xpath
if opts.bugowner and not opts.maintainer:
- xpath = xpath_join(xpath, 'person/@role=\'bugowner\'', op='and')
+ xpath = xpath_join(xpath, '%s/@role=\'bugowner\'' % search_type, op='and')
role_filter = 'bugowner'
elif not opts.bugowner and opts.maintainer:
- xpath = xpath_join(xpath, 'person/@role=\'maintainer\'', op='and')
+ xpath = xpath_join(xpath, '%s/@role=\'maintainer\'' % search_type, op='and')
role_filter = 'maintainer'
if opts.limit_to_attribute:
xpath = xpath_join(xpath, 'attribute/@name=\'%s\'' % opts.limit_to_attribute, op='and')
@cmdln.option('-X', '-m', '--method', default='GET', metavar='HTTP_METHOD',
help='specify HTTP method to use (GET|PUT|DELETE|POST)')
+ @cmdln.option('-e', '--edit', default=None, action='store_true',
+ help='GET, edit and PUT the location')
@cmdln.option('-d', '--data', default=None, metavar='STRING',
help='specify string data for e.g. POST')
@cmdln.option('-T', '-f', '--file', default=None, metavar='FILE',
Examples:
osc api /source/home:user
osc api -X PUT -T /etc/fstab source/home:user/test5/myfstab
+ osc api -e /configuration
${cmd_usage}
${cmd_option_list}
data=opts.data,
file=opts.file,
headers=opts.headers)
-
out = r.read()
- sys.stdout.write(out)
+ if opts.edit:
+ text = edit_text(out)
+ r = http_request("PUT",
+ url,
+ data=text,
+ headers=opts.headers)
+ out = r.read()
+
+ sys.stdout.write(out)
@cmdln.option('-b', '--bugowner-only', action='store_true',
'build-vmdisk-rootsize': '', # optional for VM builds
'build-vmdisk-swapsize': '', # optional for VM builds
'build-vmdisk-filesystem': '', # optional for VM builds
+ 'build-kernel': '', # optional for VM builds
+ 'build-initrd': '', # optional for VM builds
'build-jobs': _get_processors(),
'builtin_signature_check': '1', # by default use builtin check for verify pkgs
# e.g. /var/tmp/FILE.swap
#build-swap = /var/tmp/FILE.swap
+# build-kernel is the boot kernel used for VM builds
+#build-kernel = /boot/vmlinuz
+
+# build-initrd is the boot initrd used for VM builds
+#build-initrd = /boot/initrd
+
# build-memory is the amount of memory used in the VM
# value in MB - e.g. 512
#build-memory = 512
# workaround for http://bugs.python.org/issue9639
authhandler_class = HTTPBasicAuthHandler
- if sys.version_info >= (2, 6, 6) and sys.version_info < (2, 7, 99) \
+ if sys.version_info >= (2, 6, 6) and sys.version_info < (2, 7, 1) \
and not 'reset_retry_count' in dir(HTTPBasicAuthHandler):
print('warning: your urllib2 version seems to be broken. ' \
'Using a workaround for http://bugs.python.org/issue9639', file=sys.stderr)
return None
authhandler_class = OscHTTPBasicAuthHandler
- elif sys.version_info >= (2, 6, 6) and sys.version_info < (2, 7, 99):
+ elif sys.version_info >= (2, 6, 6) and sys.version_info < (2, 7, 1):
class OscHTTPBasicAuthHandler(HTTPBasicAuthHandler):
def http_error_404(self, *args):
self.reset_retry_count()
<enable />
</build>
<debuginfo>
- <disable />
+ <enable />
</debuginfo>
<!-- remove this comment to enable one or more build targets
<arch>x86_64</arch>
<arch>i586</arch>
</repository>
- <repository name="openSUSE_11.2">
- <path project="openSUSE:11.2" repository="standard"/>
+ <repository name="openSUSE_13.2">
+ <path project="openSUSE:13.2" repository="standard"/>
<arch>x86_64</arch>
<arch>i586</arch>
</repository>
- <repository name="openSUSE_11.1">
- <path project="openSUSE:11.1" repository="standard"/>
+ <repository name="openSUSE_13.1">
+ <path project="openSUSE:13.1" repository="standard"/>
<arch>x86_64</arch>
<arch>i586</arch>
</repository>
- <repository name="Fedora_12">
- <path project="Fedora:12" repository="standard" />
+ <repository name="Fedora_21">
+ <path project="Fedora:21" repository="standard" />
<arch>x86_64</arch>
<arch>i586</arch>
</repository>
- <repository name="SLE_11">
- <path project="SUSE:SLE-11" repository="standard" />
+ <repository name="SLE_12">
+ <path project="SUSE:SLE-12:GA" repository="standard" />
<arch>x86_64</arch>
<arch>i586</arch>
</repository>
for service in services:
name = service.get('name')
+ if len(name) < 3 or '/' in name:
+ raise oscerr.APIError("invalid service name")
mode = service.get('mode', None)
data = { 'name' : name, 'mode' : '' }
if mode:
data['mode'] = mode
try:
+ command = [ name ]
for param in service.findall('param'):
option = param.get('name', None)
value = ""
if param.text:
value = param.text
- name += " --" + option + " '" + value + "'"
- data['command'] = name
+ command.append("--"+option)
+ command.append(value)
+ data['command'] = command
self.services.append(data)
except:
msg = 'invalid service format:\n%s' % ET.tostring(serviceinfo_node, encoding=ET_ENCODING)
allservices = self.services or []
if singleservice and not singleservice in allservices:
# set array to the manual specified singleservice, if it is not part of _service file
- data = { 'name' : singleservice, 'command' : singleservice, 'mode' : '' }
+ data = { 'name' : singleservice, 'command' : [ singleservice ], 'mode' : '' }
allservices = [data]
# set environment when using OBS 2.3 or later
for service in allservices:
if singleservice and service['name'] != singleservice:
continue
+ if service['mode'] == "buildtime":
+ continue
if service['mode'] == "serveronly" and callmode != "disabled":
continue
if service['mode'] == "disabled" and callmode != "disabled":
continue
if service['mode'] != "trylocal" and service['mode'] != "localonly" and callmode == "trylocal":
continue
- call = service['command']
temp_dir = None
try:
temp_dir = tempfile.mkdtemp()
- name = call.split(None, 1)[0]
- if not os.path.exists("/usr/lib/obs/service/"+name):
- raise oscerr.PackageNotInstalled("obs-service-"+name)
- cmd = "/usr/lib/obs/service/" + call + " --outdir " + temp_dir
- if conf.config['verbose'] > 1 or verbose:
- print("Run source service:", cmd)
- r = run_external(cmd, shell=True)
+ cmd = service['command']
+ if not os.path.exists("/usr/lib/obs/service/"+cmd[0]):
+ raise oscerr.PackageNotInstalled("obs-service-%s"%cmd[0])
+ cmd[0] = "/usr/lib/obs/service/"+cmd[0]
+ cmd = cmd + [ "--outdir", temp_dir ]
+ if conf.config['verbose'] > 1 or verbose or conf.config['debug']:
+ print("Run source service:", ' '.join(cmd))
+ r = run_external(*cmd)
if r != 0:
- print("Aborting: service call failed: " + cmd)
+ print("Aborting: service call failed: ", ' '.join(cmd))
# FIXME: addDownloadUrlService calls si.execute after
# updating _services.
return r
for filename in os.listdir(temp_dir):
shutil.move( os.path.join(temp_dir, filename), os.path.join(dir, filename) )
else:
+ name = service['name']
for filename in os.listdir(temp_dir):
shutil.move( os.path.join(temp_dir, filename), os.path.join(dir, "_service:"+name+":"+filename) )
finally:
def mark_frozen(self):
store_write_string(self.absdir, '_frozenlink', '')
print()
- print("The link in this package is currently broken. Checking")
+ print("The link in this package (\"%s\") is currently broken. Checking" % self.name)
print("out the last working version instead; please use 'osc pull'")
print("to merge the conflicts.")
print()
class RequestHistory(AbstractState):
"""Represents a history element of a request"""
+ re_name = re.compile(r'^Request (?:got )?([^\s]+)$')
+
def __init__(self, history_node):
AbstractState.__init__(self, history_node.tag)
self.who = history_node.get('who')
if not history_node.find('comment') is None and \
history_node.find('comment').text:
self.comment = history_node.find('comment').text.strip()
+ self.name = self._parse_name(history_node)
+
+ def _parse_name(self, history_node):
+ name = history_node.get('name', None)
+ if name is not None:
+ # OBS 2.5 and before
+ return name
+ mo = self.re_name.search(self.description)
+ if mo is not None:
+ return mo.group(1)
+ return self.description
def get_node_attrs(self):
return ('who', 'when')
# allowed types + the corresponding (allowed) attributes
type_args = {'submit': ('src_project', 'src_package', 'src_rev', 'tgt_project', 'tgt_package', 'opt_sourceupdate',
'acceptinfo_rev', 'acceptinfo_srcmd5', 'acceptinfo_xsrcmd5', 'acceptinfo_osrcmd5',
- 'acceptinfo_oxsrcmd5', 'opt_updatelink'),
+ 'acceptinfo_oxsrcmd5', 'opt_updatelink', 'opt_makeoriginolder'),
'add_role': ('tgt_project', 'tgt_package', 'person_name', 'person_role', 'group_name', 'group_role'),
'set_bugowner': ('tgt_project', 'tgt_package', 'person_name', 'group_name'),
'maintenance_release': ('src_project', 'src_package', 'src_rev', 'tgt_project', 'tgt_package', 'person_name',
+ 'acceptinfo_rev', 'acceptinfo_srcmd5', 'acceptinfo_xsrcmd5', 'acceptinfo_osrcmd5',
+ 'acceptinfo_oxsrcmd5', 'acceptinfo_oproject', 'acceptinfo_opackage'),
+ 'maintenance_incident': ('src_project', 'src_package', 'src_rev', 'tgt_project', 'tgt_package', 'tgt_releaseproject', 'person_name', 'opt_sourceupdate', 'opt_makeoriginolder',
'acceptinfo_rev', 'acceptinfo_srcmd5', 'acceptinfo_xsrcmd5', 'acceptinfo_osrcmd5',
'acceptinfo_oxsrcmd5'),
- 'maintenance_incident': ('src_project', 'src_package', 'src_rev', 'tgt_project', 'tgt_releaseproject', 'person_name', 'opt_sourceupdate'),
'delete': ('tgt_project', 'tgt_package', 'tgt_repository'),
'change_devel': ('src_project', 'src_package', 'tgt_project', 'tgt_package'),
'group': ('grouped_id', )}
if action.src_package == action.tgt_package:
tgt_package = ''
d['target'] = prj_pkg_join(action.tgt_project, tgt_package)
+ if action.opt_makeoriginolder:
+ d['target'] = d['target'] + ' ***make origin older***'
+ if action.opt_updatelink:
+ d['target'] = d['target'] + ' ***update link***'
elif action.type == 'add_role':
roles = []
if action.person_name and action.person_role:
"""
import time
- if time.localtime()[0] == time.localtime(t)[0]:
+ if time.gmtime()[0] == time.gmtime(t)[0]:
# same year
- return time.strftime('%b %d %H:%M', time.localtime(t))
+ return time.strftime('%b %d %H:%M %Z', time.gmtime(t))
else:
- return time.strftime('%b %d %Y', time.localtime(t))
+ return time.strftime('%b %d %Y', time.gmtime(t))
def is_project_dir(d):
e.osc_msg = 'show_pattern_meta: Error getting pattern \'%s\' for project \'%s\'' % (pattern, prj)
raise
+def show_configuration(apiurl):
+ u = makeurl(apiurl, ['public', 'configuration'])
+ f = http_GET(u)
+ return f.readlines()
+
class metafile:
"""metafile that can be manipulated and is stored back after manipulation."""
return os.stat(filename).st_mtime != orig_mtime
def edit_message(footer='', template='', templatelen=30):
- import tempfile
delim = '--This line, and those below, will be ignored--\n'
data = ''
if template != '':
if lines[templatelen:]:
footer = '%s\n\n%s' % ('\n'.join(lines[templatelen:]), footer)
data += '\n' + delim + '\n' + footer
+ return edit_text(data, delim, suffix='.diff', template=template)
+
+def edit_text(data='', delim=None, suffix='.txt', template=''):
+ import tempfile
try:
- (fd, filename) = tempfile.mkstemp(prefix='osc-commitmsg', suffix='.diff')
+ (fd, filename) = tempfile.mkstemp(prefix='osc-editor', suffix=suffix)
os.close(fd)
mtime = os.stat(filename).st_mtime
while True:
file_changed = _edit_message_open_editor(filename, data, mtime)
- msg = open(filename).read().split(delim)[0].rstrip()
+ msg = open(filename).read()
+ if delim:
+ msg = msg.split(delim)[0].rstrip()
if msg and file_changed:
break
else:
reason = 'Log message not specified'
- if template and template == msg:
+ if template == msg:
reason = 'Default log message was not changed. Press \'c\' to continue.'
ri = raw_input('%s\na)bort, c)ontinue, e)dit: ' % reason)
if ri in 'aA':
r.create(apiurl, addrevision=True)
return r
-# This creates an old style submit request for server api 1.0
def create_submit_request(apiurl,
src_project, src_package=None,
dst_project=None, dst_package=None,
- message="", orev=None, src_update=None):
+ message="", orev=None, src_update=None, dst_updatelink=None):
import cgi
options_block = ""
package = ""
if src_package:
package = """package="%s" """ % (src_package)
+ options_block = "<options>"
if src_update:
- options_block = """<options><sourceupdate>%s</sourceupdate></options> """ % (src_update)
+ options_block += """<sourceupdate>%s</sourceupdate>""" % (src_update)
+ if dst_updatelink:
+ options_block += """<updatelink>true</updatelink>"""
+ options_block += "</options>"
+
# Yes, this kind of xml construction is horrible
targetxml = ""
targetxml = """<target project="%s" %s /> """ % ( dst_project, packagexml )
# XXX: keep the old template for now in order to work with old obs instances
xml = """\
-<request type="submit">
- <submit>
+<request>
+ <action type="submit">
<source project="%s" %s rev="%s"/>
%s
%s
- </submit>
+ </action>
<state name="new"/>
<description>%s</description>
</request>
print("WARNING:")
print("WARNING: Project does not accept submit request, request to open a NEW maintenance incident instead")
print("WARNING:")
- xpath = 'attribute/@name = \'%s\'' % conf.config['maintenance_attribute']
+ xpath = 'maintenance/maintains/@project = \'%s\' and attribute/@name = \'%s\'' % (dst_project, conf.config['maintenance_attribute'])
res = search(apiurl, project_id=xpath)
root = res['project_id']
project = root.find('project')
+ if project is None:
+ print("WARNING: This project is not maintained in the maintenance project specified by '%s', looking elsewhere" % conf.config['maintenance_attribute'])
+ xpath = 'maintenance/maintains/@project = \'%s\'' % dst_project
+ res = search(apiurl, project_id=xpath)
+ root = res['project_id']
+ project = root.find('project')
if project is None:
raise oscerr.APIError("Server did not define a default maintenance project, can't submit.")
tproject = project.get('name')
r = create_maintenance_request(apiurl, src_project, [src_package], tproject, dst_project, src_update, message)
+ r = r.reqid
else:
raise
['request', reqid], query=query)
f = http_POST(u, data=message)
- r = f.read()
- if r.startswith('<status code="'):
- r = r.split('<status code="')[1]
- r = r.split('" />')[0]
-
- return r
+ root = ET.parse(f).getroot()
+ return root.get('code', 'unknown')
def change_request_state_template(req, newstate):
if not len(req.actions):
def __str__(self):
return self.repo_line_templ % (self.name, self.arch)
+ def __repr__(self):
+ return 'Repo(%s %s)' % (self.name, self.arch)
+
@staticmethod
def fromfile(filename):
if not os.path.exists(filename):
# to protect us against control characters
import string
all_bytes = string.maketrans('', '')
- remove_bytes = all_bytes[:9] + all_bytes[11:32] # accept tabs and newlines
+ remove_bytes = all_bytes[:8] + all_bytes[14:32] # accept tabs and newlines
query = {'nostream' : '1', 'start' : '%s' % offset}
if last:
r = []
for node in root.findall('entry'):
- rev = int(node.get('rev'))
+ rev = node.get('rev')
srcmd5 = node.get('srcmd5')
versrel = node.get('versrel')
bcnt = int(node.get('bcnt'))
- t = time.localtime(int(node.get('time')))
- t = time.strftime('%Y-%m-%d %H:%M:%S', t)
+ t = time.gmtime(int(node.get('time')))
+ t = time.strftime('%Y-%m-%d %H:%M:%S %Z', t)
if format == 'csv':
- r.append('%s|%s|%d|%s.%d' % (t, srcmd5, rev, versrel, bcnt))
+ r.append('%s|%s|%s|%s.%d' % (t, srcmd5, rev, versrel, bcnt))
else:
- r.append('%s %s %6d %s.%d' % (t, srcmd5, rev, versrel, bcnt))
+ bversrel='%s.%d' % (versrel, bcnt)
+ r.append('%s %s %s %s' % (t, srcmd5, bversrel.ljust(16)[:16], rev))
if format == 'text':
- r.insert(0, 'time srcmd5 rev vers-rel.bcnt')
+ r.insert(0, 'time srcmd5 vers-rel.bcnt rev')
return r
reason = "unknown"
code = node.get('code')
rt = int(node.get('readytime'))
- readyt = time.localtime(rt)
- readyt = time.strftime('%Y-%m-%d %H:%M:%S', readyt)
+ readyt = time.gmtime(rt)
+ readyt = time.strftime('%Y-%m-%d %H:%M:%S %Z', readyt)
st = int(node.get('starttime'))
et = int(node.get('endtime'))
- endtime = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(et))
+ endtime = time.strftime('%Y-%m-%d %H:%M:%S %Z', time.gmtime(et))
waittm = time.gmtime(et-st)
if waittm.tm_mday > 1:
waitbuild = "%1dd %2dh %2dm %2ds" % (waittm.tm_mday-1, waittm.tm_hour, waittm.tm_min, waittm.tm_sec)
requestid = node.find('requestid').text.encode(locale.getpreferredencoding(), 'replace')
except:
requestid = ""
- t = time.localtime(int(node.find('time').text))
- t = time.strftime('%Y-%m-%d %H:%M:%S', t)
+ t = time.gmtime(int(node.find('time').text))
+ t = time.strftime('%Y-%m-%d %H:%M:%S %Z', t)
if format == 'csv':
s = '%s|%s|%s|%s|%s|%s|%s' % (rev, user, t, srcmd5, version,
fullfilename = os.path.join(destdir, canonname)
if pac_obj is not None:
- pac_obj.filename = canonname
+ pac_obj.canonname = canonname
pac_obj.fullfilename = fullfilename
shutil.move(tmpfile, fullfilename)
os.chmod(fullfilename, 0o644)
i.makeurls(self.cachedir, self.urllist)
if os.path.exists(i.fullfilename):
cached += 1
+ if i.hdrmd5:
+ from .util import packagequery
+ hdrmd5 = packagequery.PackageQuery.queryhdrmd5(i.fullfilename)
+ if not hdrmd5 or hdrmd5 != i.hdrmd5:
+ os.unlink(i.fullfilename)
+ cached -= 1
miss = 0
needed = all - cached
if all:
'--offline not possible.' %
i.fullfilename)
self.dirSetup(i)
+ if i.hdrmd5 and self.enable_cpio:
+ self.__add_cpio(i)
+ done += 1
+ continue
try:
# if there isn't a progress bar, there is no output at all
if not self.progress_obj:
class ArchError(packagequery.PackageError):
pass
-class ArchQuery(packagequery.PackageQuery):
+class ArchQuery(packagequery.PackageQuery, packagequery.PackageQueryResult):
def __init__(self, fh):
self.__file = fh
self.__path = os.path.abspath(fh.name)
if self_provides:
prv = '%s = %s' % (self.name(), self.fields['pkgver'][0])
self.fields.setdefault('provides', []).append(prv)
+ return self
def vercmp(self, archq):
res = cmp(int(self.epoch()), int(archq.epoch()))
def requires(self):
return self.fields['depend'] if 'depend' in self.fields else []
+ def conflicts(self):
+ return self.fields['conflict'] if 'conflict' in self.fields else []
+
+ def obsoletes(self):
+ return self.fields['replaces'] if 'replaces' in self.fields else []
+
def canonname(self):
pkgver = self.fields['pkgver'][0] if 'pkgver' in self.fields else None
return self.name() + '-' + pkgver + '-' + self.arch() + '.' + self.pkgsuffix
+ def gettag(self, tag):
+ # implement me, if needed
+ return None
+
@staticmethod
def query(filename, all_tags = False, *extra_tags):
f = open(filename, 'rb')
class DebError(packagequery.PackageError):
pass
-class DebQuery(packagequery.PackageQuery):
+class DebQuery(packagequery.PackageQuery, packagequery.PackageQueryResult):
default_tags = ('package', 'version', 'release', 'epoch', 'architecture', 'description',
- 'provides', 'depends', 'pre_depends')
+ 'provides', 'depends', 'pre_depends', 'conflicts', 'breaks')
def __init__(self, fh):
self.__file = fh
except KeyError:
raise DebError(self.__path, 'missing \'control\' file in control.tar.gz')
self.__parse_control(control, all_tags, self_provides, *extra_tags)
+ return self
def __parse_control(self, control, all_tags=False, self_provides=True, *extra_tags):
data = control.readline().strip()
self.fields['provides'] = [ i.strip() for i in re.split(',\s*', self.fields.get('provides', '')) if i ]
self.fields['depends'] = [ i.strip() for i in re.split(',\s*', self.fields.get('depends', '')) if i ]
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 ]
if self_provides:
# add self provides entry
- self.fields['provides'].append('%s = %s' % (self.name(), '-'.join(versrel)))
+ self.fields['provides'].append('%s (= %s)' % (self.name(), '-'.join(versrel)))
def vercmp(self, debq):
res = cmp(int(self.epoch()), int(debq.epoch()))
return self.fields['provides']
def requires(self):
- return self.fields['depends']
+ return self.fields['depends'] + self.fields['pre_depends']
+
+ def conflicts(self):
+ return self.fields['conflicts'] + self.fields['breaks']
+
+ def obsoletes(self):
+ return []
def gettag(self, num):
return self.fields.get(num, None)
class PackageQuery:
"""abstract base class for all package types"""
def read(self, all_tags = False, *extra_tags):
+ """Returns a PackageQueryResult instance"""
raise NotImplementedError
+ # Hmmm... this should be a module function (inherting this stuff
+ # does not make much sense) (the same is true for the queryhdrmd5 method)
+ @staticmethod
+ def query(filename, all_tags=False, extra_rpmtags=(), extra_debtags=(), self_provides=True):
+ f = open(filename, 'rb')
+ magic = f.read(7)
+ f.seek(0)
+ extra_tags = ()
+ pkgquery = None
+ if magic[:4] == '\xed\xab\xee\xdb':
+ from . import rpmquery
+ pkgquery = rpmquery.RpmQuery(f)
+ extra_tags = extra_rpmtags
+ elif magic == '!<arch>':
+ from . import debquery
+ pkgquery = debquery.DebQuery(f)
+ extra_tags = extra_debtags
+ elif magic[:5] == '<?xml':
+ f.close()
+ return None
+ elif magic[:5] == '\375\067zXZ' or magic[:2] == '\037\213':
+ from . import archquery
+ pkgquery = archquery.ArchQuery(f)
+ else:
+ raise PackageError(filename, 'unsupported package type. magic: \'%s\'' % magic)
+ pkgqueryresult = pkgquery.read(all_tags, self_provides, *extra_tags)
+ f.close()
+ return pkgqueryresult
+
+ @staticmethod
+ def queryhdrmd5(filename):
+ f = open(filename, 'rb')
+ magic = f.read(7)
+ f.seek(0)
+ if magic[:4] == '\xed\xab\xee\xdb':
+ from . import rpmquery
+ f.close()
+ return rpmquery.RpmQuery.queryhdrmd5(filename)
+ return None
+
+
+class PackageQueryResult:
+ """abstract base class that represents the result of a package query"""
def name(self):
raise NotImplementedError
def requires(self):
raise NotImplementedError
- def gettag(self):
+ def conflicts(self):
+ raise NotImplementedError
+
+ def obsoletes(self):
+ raise NotImplementedError
+
+ def gettag(self, tag):
raise NotImplementedError
def vercmp(self, pkgquery):
def canonname(self):
raise NotImplementedError
- @staticmethod
- def query(filename, all_tags=False, extra_rpmtags=(), extra_debtags=(), self_provides=True):
- f = open(filename, 'rb')
- magic = f.read(7)
- f.seek(0)
- extra_tags = ()
- pkgquery = None
- if magic[:4] == '\xed\xab\xee\xdb':
- from . import rpmquery
- pkgquery = rpmquery.RpmQuery(f)
- extra_tags = extra_rpmtags
- elif magic == '!<arch>':
- from . import debquery
- pkgquery = debquery.DebQuery(f)
- extra_tags = extra_debtags
- elif magic[:5] == '<?xml':
- f.close()
- return None
- elif magic[:5] == '\375\067zXZ' or magic[:2] == '\037\213':
- from . import archquery
- pkgquery = archquery.ArchQuery(f)
- else:
- raise PackageError(filename, 'unsupported package type. magic: \'%s\'' % magic)
- pkgquery.read(all_tags, self_provides, *extra_tags)
- f.close()
- return pkgquery
+ def evr(self):
+ evr = self.version() + "-" + self.release()
+ epoch = self.epoch()
+ if epoch is not None and epoch != 0:
+ evr = epoch + ":" + evr
+ return evr
if __name__ == '__main__':
import sys
# project modules
import osc.util.rpmquery
+import osc.util.packagequery
def namespace(name):
return "{http://linux.duke.edu/metadata/%s}" % name
@param directory path to a repository directory (parent directory of
repodata directory)
- @return list of RepoDataQuery instances
+ @return list of RepoDataQueryResult instances
@raise IOError if repomd.xml contains no primary location
"""
path = primaryPath(directory)
packageQueries = []
for packageElement in root:
- packageQuery = RepoDataQuery(directory, packageElement)
+ packageQuery = RepoDataQueryResult(directory, packageElement)
packageQueries.append(packageQuery)
return packageQueries
-class RepoDataQuery(object):
- """PackageQuery that reads in data from the repodata directory files."""
+class RepoDataQueryResult(osc.util.packagequery.PackageQueryResult):
+ """PackageQueryResult that reads in data from the repodata directory files."""
def __init__(self, directory, element):
- """Creates a RepoDataQuery from the a package Element under a metadata
+ """Creates a RepoDataQueryResult from the a package Element under a metadata
Element in a primary.xml file.
@param directory repository directory path. Used to convert relative
def requires(self):
return self.__parseEntryCollection("requires")
+ def conflicts(self):
+ return self.__parseEntryCollection('conflicts')
+
+ def obsoletes(self):
+ return self.__parseEntryCollection('obsoletes')
+
+ def canonname(self):
+ return osc.util.rpmquery.RpmQuery.filename(self.name(), None,
+ self.version(), self.release(), self.arch())
+
+ def gettag(self, tag):
+ # implement me, if needed
+ return None
+
def vercmp(self, other):
res = osc.util.rpmquery.RpmQuery.rpmvercmp(str(self.epoch()), str(other.epoch()))
if res != 0:
self.count = count
self.data = None
-class RpmQuery(packagequery.PackageQuery):
+class RpmQuery(packagequery.PackageQuery, packagequery.PackageQueryResult):
LEAD_SIZE = 96
LEAD_MAGIC = 0xedabeedb
HEADER_MAGIC = 0x8eade801
default_tags = (1000, 1001, 1002, 1003, 1004, 1022, 1005, 1020,
1047, 1112, 1113, # provides
- 1049, 1048, 1050 # requires
+ 1049, 1048, 1050, # requires
+ 1054, 1053, 1055, # conflicts
+ 1090, 1114, 1115 # obsoletes
)
def __init__(self, fh):
self.filename_suffix = 'rpm'
self.header = None
- def read(self, all_tags=False, self_provides=True, *extra_tags):
+ def read(self, all_tags=False, self_provides=True, *extra_tags, **extra_kw):
# self_provides is unused because a rpm always has a self provides
self.__read_lead()
data = self.__file.read(RpmHeaderEntry.ENTRY_SIZE)
size = il * RpmHeaderEntry.ENTRY_SIZE + dl
# data is 8 byte aligned
pad = (size + 7) & ~7
- self.__file.read(pad)
- data = self.__file.read(RpmHeaderEntry.ENTRY_SIZE)
+ querysig = extra_kw.get('querysig')
+ if not querysig:
+ self.__file.read(pad)
+ data = self.__file.read(RpmHeaderEntry.ENTRY_SIZE)
hdrmgc, reserved, il, dl = struct.unpack('!I3i', data)
self.header = RpmHeader(pad, dl)
if self.HEADER_MAGIC != hdrmgc:
try: # this may fail for -debug* packages
self.__read_data(i, data)
except: pass
+ return self
def __read_lead(self):
data = self.__file.read(self.LEAD_SIZE)
entry.data = struct.unpack('!%dh' % entry.count, data[off:off + 2 * entry.count])
elif entry.type == 4:
entry.data = struct.unpack('!%di' % entry.count, data[off:off + 4 * entry.count])
- elif entry.type == 6 or entry.type == 7:
- # XXX: what to do with binary data? for now treat it as a string
+ elif entry.type == 6:
entry.data = unpack_string(data[off:])
+ elif entry.type == 7:
+ entry.data = data[off:off + entry.count]
elif entry.type == 8 or entry.type == 9:
cnt = entry.count
entry.data = []
raise RpmHeaderError(self.__path, 'unsupported tag type \'%d\' (tag: \'%s\'' % (entry.type, entry.tag))
def __reqprov(self, tag, flags, version):
- pnames = self.header.gettag(tag).data
+ pnames = self.header.gettag(tag)
+ if not pnames:
+ return []
+ pnames = pnames.data
pflags = self.header.gettag(flags).data
pvers = self.header.gettag(version).data
if not (pnames and pflags and pvers):
def requires(self):
return self.__reqprov(1049, 1048, 1050)
+ def conflicts(self):
+ return self.__reqprov(1054, 1053, 1055)
+
+ def obsoletes(self):
+ return self.__reqprov(1090, 1114, 1115)
+
def is_src(self):
# SOURCERPM = 1044
return self.gettag(1044) is None
f.close()
return rpmq
+ @staticmethod
+ def queryhdrmd5(filename):
+ f = open(filename, 'rb')
+ rpmq = RpmQuery(f)
+ rpmq.read(1004, querysig=True)
+ f.close()
+ entry = rpmq.gettag(1004)
+ if entry is None:
+ return None
+ return ''.join([ "%02x" % x for x in struct.unpack('16B', entry.data) ])
+
@staticmethod
def rpmvercmp(ver1, ver2):
"""
print('\n'.join(rpmq.provides()))
print('##########')
print('\n'.join(rpmq.requires()))
+ print('##########')
+ print(RpmQuery.queryhdrmd5(sys.argv[1]))
Name: osc
Summary: OpenSUSE Build Service Commander
Version: 0.153.0
-Release: 1.3
+Release: 1.5
Group: Development/Tools/Other
License: GPL v2 or later
Url: http://www.gitorious.org/opensuse/osc
--- /dev/null
+[general]
+# URL to access API server, e.g. https://api.opensuse.org
+# you also need a section [https://api.opensuse.org] with the credentials
+apiurl = http://localhost
+# Downloaded packages are cached here. Must be writable by you.
+#packagecachedir = /var/tmp/osbuild-packagecache
+# Wrapper to call build as root (sudo, su -, ...)
+#su-wrapper = su -c
+# rootdir to setup the chroot environment
+# can contain %(repo)s, %(arch)s, %(project)s and %(package)s for replacement, e.g.
+# /srv/oscbuild/%(repo)s-%(arch)s or
+# /srv/oscbuild/%(repo)s-%(arch)s-%(project)s-%(package)s
+#build-root = /var/tmp/build-root
+# compile with N jobs (default: "getconf _NPROCESSORS_ONLN")
+#build-jobs = N
+# build-type to use - values can be (depending on the capabilities of the 'build' script)
+# empty - chroot build
+# kvm - kvm VM build (needs build-device, build-swap, build-memory)
+# xen - xen VM build (needs build-device, build-swap, build-memory)
+# experimental:
+# qemu - qemu VM build
+# lxc - lxc build
+#build-type =
+# build-device is the disk-image file to use as root for VM builds
+# e.g. /var/tmp/FILE.root
+#build-device = /var/tmp/FILE.root
+# build-swap is the disk-image to use as swap for VM builds
+# e.g. /var/tmp/FILE.swap
+#build-swap = /var/tmp/FILE.swap
+# build-memory is the amount of memory used in the VM
+# value in MB - e.g. 512
+#build-memory = 512
+# build-vmdisk-rootsize is the size of the disk-image used as root in a VM build
+# values in MB - e.g. 4096
+#build-vmdisk-rootsize = 4096
+# build-vmdisk-swapsize is the size of the disk-image used as swap in a VM build
+# values in MB - e.g. 1024
+#build-vmdisk-swapsize = 1024
+# Numeric uid:gid to assign to the "abuild" user in the build-root
+# or "caller" to use the current users uid:gid
+# This is convenient when sharing the buildroot with ordinary userids
+# on the host.
+# This should not be 0
+# build-uid =
+# extra packages to install when building packages locally (osc build)
+# this corresponds to osc build's -x option and can be overridden with that
+# -x '' can also be given on the command line to override this setting, or
+# you can have an empty setting here.
+#extra-pkgs = vim gdb strace
+# build platform is used if the platform argument is omitted to osc build
+#build_repository = openSUSE_Factory
+# default project for getpac or bco
+#getpac_default_project = openSUSE:Factory
+# alternate filesystem layout: have multiple subdirs, where colons were.
+#checkout_no_colon = 0
+# local files to ignore with status, addremove, ....
+#exclude_glob = .osc CVS .svn .* _linkerror *~ #*# *.orig *.bak *.changes.*
+# keep passwords in plaintext. If you see this comment, your osc
+# already uses the encrypted password, and only keeps them in plain text
+# for backwards compatibility. Default will change to 0 in future releases.
+# You can remove the plaintext password without harm, if you do not need
+# backwards compatibility.
+#plaintext_passwd = 1
+# limit the age of requests shown with 'osc req list'.
+# this is a default only, can be overridden by 'osc req list -D NNN'
+# Use 0 for unlimted.
+#request_list_days = 0
+# show info useful for debugging
+#debug = 1
+# show HTTP traffic useful for debugging
+#http_debug = 1
+# Skip signature verification of packages used for build.
+#no_verify = 1
+# jump into the debugger in case of errors
+#post_mortem = 1
+# print call traces in case of errors
+#traceback = 1
+# use KDE/Gnome/MacOS/Windows keyring for credentials if available
+#use_keyring = 1
+# check for unversioned/removed files before commit
+#check_filelist = 1
+# check for pending requests after executing an action (e.g. checkout, update, commit)
+#check_for_request_on_action = 0
+# what to do with the source package if the submitrequest has been accepted. If
+# nothing is specified the API default is used
+#submitrequest_on_accept_action = cleanup|update|noupdate
+#review requests interactively (default: off)
+#request_show_review = 1
+# Directory with executables to validate sources, esp before committing
+#source_validator_directory = /usr/lib/osc/source_validators
+
+[http://localhost]
+user=Admin
+pass=opensuse
+# set aliases for this apiurl
+# aliases = foo, bar
+# 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
+#http_headers = Host: foofoobar,
+# User: mumblegack
+# Force using of keyring for this API
+#keyring = 1
--- /dev/null
+http://localhost
--- /dev/null
+<project name="osctest" />
--- /dev/null
+http://localhost
--- /dev/null
+<directory name="simple" rev="1" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="1">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+</directory>
\ No newline at end of file
--- /dev/null
+simple
\ No newline at end of file
--- /dev/null
+osctest
\ No newline at end of file
--- /dev/null
+This is a simple test.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change but
+is modified.
--- /dev/null
+[general]
+# URL to access API server, e.g. https://api.opensuse.org
+# you also need a section [https://api.opensuse.org] with the credentials
+apiurl = http://localhost
+# Downloaded packages are cached here. Must be writable by you.
+#packagecachedir = /var/tmp/osbuild-packagecache
+# Wrapper to call build as root (sudo, su -, ...)
+#su-wrapper = su -c
+# rootdir to setup the chroot environment
+# can contain %(repo)s, %(arch)s, %(project)s and %(package)s for replacement, e.g.
+# /srv/oscbuild/%(repo)s-%(arch)s or
+# /srv/oscbuild/%(repo)s-%(arch)s-%(project)s-%(package)s
+#build-root = /var/tmp/build-root
+# compile with N jobs (default: "getconf _NPROCESSORS_ONLN")
+#build-jobs = N
+# build-type to use - values can be (depending on the capabilities of the 'build' script)
+# empty - chroot build
+# kvm - kvm VM build (needs build-device, build-swap, build-memory)
+# xen - xen VM build (needs build-device, build-swap, build-memory)
+# experimental:
+# qemu - qemu VM build
+# lxc - lxc build
+#build-type =
+# build-device is the disk-image file to use as root for VM builds
+# e.g. /var/tmp/FILE.root
+#build-device = /var/tmp/FILE.root
+# build-swap is the disk-image to use as swap for VM builds
+# e.g. /var/tmp/FILE.swap
+#build-swap = /var/tmp/FILE.swap
+# build-memory is the amount of memory used in the VM
+# value in MB - e.g. 512
+#build-memory = 512
+# build-vmdisk-rootsize is the size of the disk-image used as root in a VM build
+# values in MB - e.g. 4096
+#build-vmdisk-rootsize = 4096
+# build-vmdisk-swapsize is the size of the disk-image used as swap in a VM build
+# values in MB - e.g. 1024
+#build-vmdisk-swapsize = 1024
+# Numeric uid:gid to assign to the "abuild" user in the build-root
+# or "caller" to use the current users uid:gid
+# This is convenient when sharing the buildroot with ordinary userids
+# on the host.
+# This should not be 0
+# build-uid =
+# extra packages to install when building packages locally (osc build)
+# this corresponds to osc build's -x option and can be overridden with that
+# -x '' can also be given on the command line to override this setting, or
+# you can have an empty setting here.
+#extra-pkgs = vim gdb strace
+# build platform is used if the platform argument is omitted to osc build
+#build_repository = openSUSE_Factory
+# default project for getpac or bco
+#getpac_default_project = openSUSE:Factory
+# alternate filesystem layout: have multiple subdirs, where colons were.
+#checkout_no_colon = 0
+# local files to ignore with status, addremove, ....
+#exclude_glob = .osc CVS .svn .* _linkerror *~ #*# *.orig *.bak *.changes.*
+# keep passwords in plaintext. If you see this comment, your osc
+# already uses the encrypted password, and only keeps them in plain text
+# for backwards compatibility. Default will change to 0 in future releases.
+# You can remove the plaintext password without harm, if you do not need
+# backwards compatibility.
+#plaintext_passwd = 1
+# limit the age of requests shown with 'osc req list'.
+# this is a default only, can be overridden by 'osc req list -D NNN'
+# Use 0 for unlimted.
+#request_list_days = 0
+# show info useful for debugging
+#debug = 1
+# show HTTP traffic useful for debugging
+#http_debug = 1
+# Skip signature verification of packages used for build.
+#no_verify = 1
+# jump into the debugger in case of errors
+#post_mortem = 1
+# print call traces in case of errors
+#traceback = 1
+# use KDE/Gnome/MacOS/Windows keyring for credentials if available
+#use_keyring = 1
+# check for unversioned/removed files before commit
+#check_filelist = 1
+# check for pending requests after executing an action (e.g. checkout, update, commit)
+#check_for_request_on_action = 0
+# what to do with the source package if the submitrequest has been accepted. If
+# nothing is specified the API default is used
+#submitrequest_on_accept_action = cleanup|update|noupdate
+#review requests interactively (default: off)
+#request_show_review = 1
+# Directory with executables to validate sources, esp before committing
+#source_validator_directory = /usr/lib/osc/source_validators
+
+[http://localhost]
+user=Admin
+pass=opensuse
+# set aliases for this apiurl
+# aliases = foo, bar
+# 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
+#http_headers = Host: foofoobar,
+# User: mumblegack
+# Force using of keyring for this API
+#keyring = 1
--- /dev/null
+http://localhost
--- /dev/null
+<project name="osctest" />
--- /dev/null
+http://localhost
--- /dev/null
+<directory name="add" rev="1" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="1">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+</directory>
--- /dev/null
+<package name="add" project="osctest">
+ <title>Title example</title>
+ <description>Description example</description>
+</package>
--- /dev/null
+osctest
\ No newline at end of file
--- /dev/null
+This is a simple test.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change.
--- /dev/null
+added file
--- /dev/null
+This is a simple test.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change.
--- /dev/null
+http://localhost
--- /dev/null
+<directory name="added_missing" rev="1" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="1">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="foo" size="23" skipped="True" />
+</directory>
--- /dev/null
+<package name="added_missing" project="osctest">
+ <title>Title example</title>
+ <description>Description example</description>
+</package>
--- /dev/null
+added_missing
--- /dev/null
+osctest
\ No newline at end of file
--- /dev/null
+http://localhost
--- /dev/null
+<directory name="allstates" rev="1" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="1">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="676513fde5797c3785164942c97dfec1" mtime="1283506309" name="missing" size="8" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+ <entry md5="d8e8fca2dc0f896fd7cb4cb0031ba249" mtime="1283505591" name="test" size="5" />
+ <entry md5="ffffffffffffffffffffffffffffffff" mtime="1111111111" name="skipped" size="100" skipped="true" />
+</directory>
--- /dev/null
+<package name="allstates" project="osctest">
+ <title>Title example</title>
+ <description>Description example</description>
+</package>
--- /dev/null
+osctest
\ No newline at end of file
--- /dev/null
+add
+missing
--- /dev/null
+This is a simple test.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change.
--- /dev/null
+added file
--- /dev/null
+This file did change.
--- /dev/null
+http://localhost
--- /dev/null
+<directory name="unix" rev="9afa23b484de05e28364b18de7bb1432" srcmd5="9afa23b484de05e28364b18de7bb1432">
+ <linkinfo baserev="b63634ab40861fdb8b44e5f4f459c621" lsrcmd5="cd21541fe2442d3d324a6d6103752913" package="unique" project="btest" srcmd5="b63634ab40861fdb8b44e5f4f459c621" />
+ <entry md5="75d884cf1d235180faec5acb63063972" mtime="1283525196" name="simple" size="21" />
+</directory>
--- /dev/null
+<package name="branch" project="osctest">
+ <title>Title example</title>
+ <description>Description example</description>
+ <person role="maintainer" userid="Admin"/>
+</package>
--- /dev/null
+imple modified file.
--- /dev/null
+<directory name="branch" rev="5" srcmd5="1d4bbfa2655ab3982074226e16e1e5ff" vrev="5">
+ <linkinfo baserev="b63634ab40861fdb8b44e5f4f459c621" lsrcmd5="1d4bbfa2655ab3982074226e16e1e5ff" package="bar" project="foo" srcmd5="b63634ab40861fdb8b44e5f4f459c621" xsrcmd5="87ea02aede261b0267aabaa97c756e7a" />
+ <entry md5="542f96b49b64095104d8a9e9dd313a9c" mtime="1283521153" name="_link" size="130" />
+ <entry md5="75da7f7167c22b2b02c6879366d78ad1" mtime="1283525027" name="simple" size="22" />
+</directory>
--- /dev/null
+<directory name="branch" rev="87ea02aede261b0267aabaa97c756e7a" srcmd5="87ea02aede261b0267aabaa97c756e7a">
+ <linkinfo baserev="b63634ab40861fdb8b44e5f4f459c621" lsrcmd5="1d4bbfa2655ab3982074226e16e1e5ff" package="bar" project="foo" srcmd5="b63634ab40861fdb8b44e5f4f459c621" />
+ <entry md5="75da7f7167c22b2b02c6879366d78ad1" mtime="1283525027" name="simple" size="22" />
+</directory>
--- /dev/null
+<directory name="branch" rev="6" srcmd5="cd21541fe2442d3d324a6d6103752913" vrev="6">
+ <linkinfo baserev="b63634ab40861fdb8b44e5f4f459c621" lsrcmd5="cd21541fe2442d3d324a6d6103752913" package="bar" project="foo" srcmd5="b63634ab40861fdb8b44e5f4f459c621" xsrcmd5="9afa23b484de05e28364b18de7bb1432" />
+ <entry md5="542f96b49b64095104d8a9e9dd313a9c" mtime="1283521153" name="_link" size="130" skipped="true" />
+ <entry md5="75d884cf1d235180faec5acb63063972" mtime="1283525196" name="simple" size="21" />
+</directory>
--- /dev/null
+simple modified file.
--- /dev/null
+http://localhost
--- /dev/null
+<directory name="conflict" rev="1" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="1">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282130148" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282130148" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282130148" name="nochange" size="25" />
+</directory>
\ No newline at end of file
--- /dev/null
+<package name="conflict" project="osctest">
+ <title>Title example</title>
+ <description>Description example</description>
+</package>
--- /dev/null
+conflict
\ No newline at end of file
--- /dev/null
+osctest
\ No newline at end of file
--- /dev/null
+This is a simple test.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change.
--- /dev/null
+This is a simple test.
--- /dev/null
+Is it possible
+to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change.
--- /dev/null
+http://localhost
--- /dev/null
+<directory name="delete" rev="1" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="1">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+</directory>
--- /dev/null
+<package name="delete" project="osctest">
+ <title>Title example</title>
+ <description>Description example</description>
+</package>
--- /dev/null
+osctest
\ No newline at end of file
--- /dev/null
+This is a simple test.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change.
--- /dev/null
+This is a simple test.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+http://localhost
--- /dev/null
+<directory name="multiple" rev="1" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="1">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+ <entry md5="d8e8fca2dc0f896fd7cb4cb0031ba249" mtime="1283505591" name="test" size="5" />
+</directory>
--- /dev/null
+<package name="multiple" project="osctest">
+ <title>Title example</title>
+ <description>Description example</description>
+</package>
--- /dev/null
+osctest
\ No newline at end of file
--- /dev/null
+foo
+merge
--- /dev/null
+This is a simple test.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change.
--- /dev/null
+added file
--- /dev/null
+This file did change.
--- /dev/null
+http://localhost
--- /dev/null
+<directory name="nochanges" rev="1" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="1">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="foo" size="23" skipped="True" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+</directory>
--- /dev/null
+<package name="nochanges" project="osctest">
+ <title>Title example</title>
+ <description>Description example</description>
+</package>
--- /dev/null
+osctest
\ No newline at end of file
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change.
--- /dev/null
+This file didn't change.
--- /dev/null
+http://localhost
--- /dev/null
+<directory name="simple" rev="1" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="1">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+</directory>
--- /dev/null
+<package name="simple" project="osctest">
+ <title>Title example</title>
+ <description>Description example</description>
+</package>
--- /dev/null
+simple
\ No newline at end of file
--- /dev/null
+osctest
\ No newline at end of file
--- /dev/null
+This is a simple test.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change.
--- /dev/null
+This is a simple test.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change but
+is modified.
--- /dev/null
+<directory name="added_missing" rev="2" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="2">
+ <entry md5="14758f1afd44c09b7992073ccf00b43d" mtime="1292622742" name="bar" size="7" />
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282130148" name="foo" size="23" />
+</directory>
--- /dev/null
+<directory name="added_missing" rev="1" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="1">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282130148" name="foo" size="23" />
+</directory>
--- /dev/null
+<directory><entry md5="14758f1afd44c09b7992073ccf00b43d" name="bar" /><entry md5="0d62ceea6020d75154078a20d8c9f9ba" name="foo" /></directory>
\ No newline at end of file
--- /dev/null
+<directory error="missing" name="added_missing">
+ <entry md5="14758f1afd44c09b7992073ccf00b43d" name="bar" />
+</directory>
--- /dev/null
+<directory name="simple" rev="2" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="2">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+ <entry md5="b423d194c75e59ee4d8d2e07ba24323d" mtime="1111111111" name="add" size="11" />
+</directory>
--- /dev/null
+<directory name="simple" rev="1" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="1">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+</directory>
--- /dev/null
+<directory><entry md5="b423d194c75e59ee4d8d2e07ba24323d" name="add" /><entry md5="0d62ceea6020d75154078a20d8c9f9ba" name="foo" /><entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" name="merge" /><entry md5="7efa70f68983fad1cf487f69dedf93e9" name="nochange" /></directory>
\ No newline at end of file
--- /dev/null
+<directory error="missing" name="add">
+ <entry md5="b423d194c75e59ee4d8d2e07ba24323d" name="add" />
+</directory>
--- /dev/null
+<directory name="allstates" rev="2" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="2">
+ <entry md5="b423d194c75e59ee4d8d2e07ba24323d" mtime="3333333333" name="add" size="11" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="d908d26cac8092d475f40a5179ca6347" mtime="4444444444" name="missing" size="9" />
+ <entry md5="2abd19de6a38ff2890af64f453df96b1" mtime="2222222222" name="nochange" size="22" />
+ <entry md5="d8e8fca2dc0f896fd7cb4cb0031ba249" mtime="1283505591" name="test" size="5" />
+ <entry md5="ffffffffffffffffffffffffffffffff" mtime="1111111111" name="skipped" size="100" />
+</directory>
--- /dev/null
+<directory name="allstates" rev="2" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="2">
+ <entry md5="b423d194c75e59ee4d8d2e07ba24323d" mtime="3333333333" name="add" size="11" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="d908d26cac8092d475f40a5179ca6347" mtime="4444444444" name="missing" size="9" />
+ <entry md5="2abd19de6a38ff2890af64f453df96b1" mtime="2222222222" name="nochange" size="22" />
+ <entry md5="d8e8fca2dc0f896fd7cb4cb0031ba249" mtime="1283505591" name="test" size="5" />
+ <entry md5="ffffffffffffffffffffffffffffffff" mtime="1111111111" name="skipped" size="100" skipped="true" />
+</directory>
--- /dev/null
+<directory name="allstates" rev="1" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="1">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="676513fde5797c3785164942c97dfec1" mtime="1283506309" name="missing" size="8" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+ <entry md5="d8e8fca2dc0f896fd7cb4cb0031ba249" mtime="1283505591" name="test" size="5" />
+ <entry md5="ffffffffffffffffffffffffffffffff" mtime="1111111111" name="skipped" size="100" />
+</directory>
--- /dev/null
+<directory><entry md5="b423d194c75e59ee4d8d2e07ba24323d" name="add" /><entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" name="merge" /><entry md5="d908d26cac8092d475f40a5179ca6347" name="missing" /><entry md5="2abd19de6a38ff2890af64f453df96b1" name="nochange" /><entry md5="ffffffffffffffffffffffffffffffff" name="skipped" /><entry md5="d8e8fca2dc0f896fd7cb4cb0031ba249" name="test" /></directory>
\ No newline at end of file
--- /dev/null
+<directory error="missing" name="allstates">
+ <entry md5="b423d194c75e59ee4d8d2e07ba24323d" name="add" />
+ <entry md5="d908d26cac8092d475f40a5179ca6347" name="missing" />
+ <entry md5="2abd19de6a38ff2890af64f453df96b1" name="nochange" />
+</directory>
--- /dev/null
+<directory name="conflict" rev="1" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="1">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282130148" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282130148" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282130148" name="nochange" size="25" />
+</directory>
\ No newline at end of file
--- /dev/null
+<directory name="simple" rev="2" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="2">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+</directory>
--- /dev/null
+<directory name="simple" rev="1" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="1">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+</directory>
--- /dev/null
+<directory><entry md5="0d62ceea6020d75154078a20d8c9f9ba" name="foo" /><entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" name="merge" /></directory>
\ No newline at end of file
--- /dev/null
+<directory name="branch" rev="7" srcmd5="1d4bbfa2655ab3982074226e16e1e5ff" vrev="7">
+ <linkinfo baserev="b63634ab40861fdb8b44e5f4f459c621" lsrcmd5="1d4bbfa2655ab3982074226e16e1e5ff" package="bar" project="foo" srcmd5="b63634ab40861fdb8b44e5f4f459c621" xsrcmd5="87ea02aede261b0267aabaa97c756e7a" />
+ <entry md5="542f96b49b64095104d8a9e9dd313a9c" mtime="1283521153" name="_link" size="130" />
+ <entry md5="75da7f7167c22b2b02c6879366d78ad1" mtime="1283525027" name="simple" size="22" />
+</directory>
--- /dev/null
+<directory name="branch" rev="87ea02aede261b0267aabaa97c756e7a" srcmd5="87ea02aede261b0267aabaa97c756e7a">
+ <linkinfo baserev="b63634ab40861fdb8b44e5f4f459c621" lsrcmd5="1d4bbfa2655ab3982074226e16e1e5ff" package="bar" project="foo" srcmd5="b63634ab40861fdb8b44e5f4f459c621" />
+ <entry md5="75da7f7167c22b2b02c6879366d78ad1" mtime="1283525027" name="simple" size="22" />
+</directory>
--- /dev/null
+<directory name="branch" rev="6" srcmd5="cd21541fe2442d3d324a6d6103752913" vrev="6">
+ <linkinfo baserev="b63634ab40861fdb8b44e5f4f459c621" lsrcmd5="cd21541fe2442d3d324a6d6103752913" package="bar" project="foo" srcmd5="b63634ab40861fdb8b44e5f4f459c621" xsrcmd5="9afa23b484de05e28364b18de7bb1432" />
+ <entry md5="542f96b49b64095104d8a9e9dd313a9c" mtime="1283521153" name="_link" size="130" skipped="true" />
+ <entry md5="75d884cf1d235180faec5acb63063972" mtime="1283525196" name="simple" size="21" />
+</directory>
--- /dev/null
+<directory><entry md5="75da7f7167c22b2b02c6879366d78ad1" name="simple" /></directory>
\ No newline at end of file
--- /dev/null
+<directory error="missing" name="branch">
+ <entry md5="75da7f7167c22b2b02c6879366d78ad1" name="simple" />
+</directory>
--- /dev/null
+<directory><entry md5="0d62ceea6020d75154078a20d8c9f9ba" name="foo" /><entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" name="merge" /><entry md5="382588b92f5976de693f44c4d6df27b7" name="nochange" /></directory>
\ No newline at end of file
--- /dev/null
+<directory name="simple" rev="2" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="2">
+ <entry md5="b423d194c75e59ee4d8d2e07ba24323d" mtime="1111111111" name="add" size="11" />
+ <entry md5="ea467af882b32a275fe62eb05aba6ee1" mtime="0000000000" name="add2" size="5" />
+ <entry md5="2abd19de6a38ff2890af64f453df96b1" mtime="2222222222" name="nochange" size="22" />
+ <entry md5="d8e8fca2dc0f896fd7cb4cb0031ba249" mtime="1283505591" name="test" size="5" />
+</directory>
--- /dev/null
+<directory name="simple" rev="1" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="1">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+ <entry md5="d8e8fca2dc0f896fd7cb4cb0031ba249" mtime="1283505591" name="test" size="5" />
+</directory>
--- /dev/null
+<directory><entry md5="b423d194c75e59ee4d8d2e07ba24323d" name="add" /><entry md5="ea467af882b32a275fe62eb05aba6ee1" name="add2" /><entry md5="2abd19de6a38ff2890af64f453df96b1" name="nochange" /><entry md5="d8e8fca2dc0f896fd7cb4cb0031ba249" name="test" /></directory>
\ No newline at end of file
--- /dev/null
+<directory error="missing" name="add">
+ <entry md5="2abd19de6a38ff2890af64f453df96b1" name="nochange" />
+ <entry md5="b423d194c75e59ee4d8d2e07ba24323d" name="add" />
+ <entry md5="ea467af882b32a275fe62eb05aba6ee1" name="add2" />
+</directory>
--- /dev/null
+<directory name="conflict" rev="1" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="1">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282130148" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282130148" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282130148" name="nochange" size="25" />
+</directory>
\ No newline at end of file
--- /dev/null
+<directory name="simple" rev="2" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="2">
+ <entry md5="b423d194c75e59ee4d8d2e07ba24323d" mtime="1111111111" name="add" size="11" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="2abd19de6a38ff2890af64f453df96b1" mtime="2222222222" name="nochange" size="22" />
+ <entry md5="d8e8fca2dc0f896fd7cb4cb0031ba249" mtime="1283505591" name="test" size="5" />
+</directory>
--- /dev/null
+<directory name="simple" rev="1" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="1">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+ <entry md5="d8e8fca2dc0f896fd7cb4cb0031ba249" mtime="1283505591" name="test" size="5" />
+</directory>
--- /dev/null
+<directory><entry md5="b423d194c75e59ee4d8d2e07ba24323d" name="add" /><entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" name="merge" /><entry md5="2abd19de6a38ff2890af64f453df96b1" name="nochange" /><entry md5="d8e8fca2dc0f896fd7cb4cb0031ba249" name="test" /></directory>
\ No newline at end of file
--- /dev/null
+<directory error="missing" name="partial">
+ <entry md5="b423d194c75e59ee4d8d2e07ba24323d" name="add" />
+ <entry md5="2abd19de6a38ff2890af64f453df96b1" name="nochange" />
+</directory>
--- /dev/null
+<directory name="simple" rev="2" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="2">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="382588b92f5976de693f44c4d6df27b7" mtime="1282047303" name="nochange" size="41" />
+</directory>
--- /dev/null
+<directory name="simple" rev="1" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="1">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+</directory>
--- /dev/null
+<directory><entry md5="0d62ceea6020d75154078a20d8c9f9ba" name="foo" /><entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" name="merge" /><entry md5="382588b92f5976de693f44c4d6df27b7" name="nochange" /></directory>
\ No newline at end of file
--- /dev/null
+<directory error="missing" name="simple">
+ <entry md5="c4eaea5dcaff13418e38e7fea151dd49" name="nochange" />
+</directory>
--- /dev/null
+import unittest
+import osc.core
+import shutil
+import tempfile
+import os
+import sys
+from xml.etree import cElementTree as ET
+EXPECTED_REQUESTS = []
+
+if sys.version_info[0:2] in ((2, 6), (2, 7)):
+ bytes = lambda x, *args: x
+
+try:
+ #python 2.x
+ from cStringIO import StringIO
+ from urllib2 import HTTPHandler, addinfourl, build_opener
+ from urlparse import urlparse, parse_qs
+except ImportError:
+ from io import StringIO
+ from urllib.request import HTTPHandler, addinfourl, build_opener
+ from urllib.parse import urlparse, parse_qs
+
+def urlcompare(url, *args):
+ """compare all components of url except query string - it is converted to
+ dict, therefor different ordering does not makes url's different, as well
+ as quoting of a query string"""
+
+ components = urlparse(url)
+ query_args = parse_qs(components.query)
+ components = components._replace(query=None)
+
+ if not args:
+ return False
+
+ for url in args:
+ components2 = urlparse(url)
+ query_args2 = parse_qs(components2.query)
+ components2 = components2._replace(query=None)
+
+ if components != components2 or \
+ query_args != query_args2:
+ return False
+
+ return True
+
+class RequestWrongOrder(Exception):
+ """raised if an unexpected request is issued to urllib2"""
+ def __init__(self, url, exp_url, method, exp_method):
+ Exception.__init__(self)
+ self.url = url
+ self.exp_url = exp_url
+ self.method = method
+ self.exp_method = exp_method
+
+ def __str__(self):
+ return '%s, %s, %s, %s' % (self.url, self.exp_url, self.method, self.exp_method)
+
+class RequestDataMismatch(Exception):
+ """raised if POSTed or PUTed data doesn't match with the expected data"""
+ def __init__(self, url, got, exp):
+ self.url = url
+ self.got = got
+ self.exp = exp
+
+ def __str__(self):
+ return '%s, %s, %s' % (self.url, self.got, self.exp)
+
+class MyHTTPHandler(HTTPHandler):
+ def __init__(self, exp_requests, fixtures_dir):
+ HTTPHandler.__init__(self)
+ self.__exp_requests = exp_requests
+ self.__fixtures_dir = fixtures_dir
+
+ def http_open(self, req):
+ r = self.__exp_requests.pop(0)
+ if not urlcompare(req.get_full_url(), r[1]) or req.get_method() != r[0]:
+ raise RequestWrongOrder(req.get_full_url(), r[1], req.get_method(), r[0])
+ if req.get_method() in ('GET', 'DELETE'):
+ return self.__mock_GET(r[1], **r[2])
+ elif req.get_method() in ('PUT', 'POST'):
+ return self.__mock_PUT(req, **r[2])
+
+ def __mock_GET(self, fullurl, **kwargs):
+ return self.__get_response(fullurl, **kwargs)
+
+ def __mock_PUT(self, req, **kwargs):
+ exp = kwargs.get('exp', None)
+ if exp is not None and 'expfile' in kwargs:
+ raise RuntimeError('either specify exp or expfile')
+ elif 'expfile' in kwargs:
+ exp = open(os.path.join(self.__fixtures_dir, kwargs['expfile']), 'r').read()
+ elif exp is None:
+ raise RuntimeError('exp or expfile required')
+ if exp is not None:
+ if req.get_data() != bytes(exp, "utf-8"):
+ raise RequestDataMismatch(req.get_full_url(), repr(req.get_data()), repr(exp))
+ return self.__get_response(req.get_full_url(), **kwargs)
+
+ def __get_response(self, url, **kwargs):
+ f = None
+ if 'exception' in kwargs:
+ raise kwargs['exception']
+ if 'text' not in kwargs and 'file' in kwargs:
+ f = StringIO(open(os.path.join(self.__fixtures_dir, kwargs['file']), 'r').read())
+ elif 'text' in kwargs and 'file' not in kwargs:
+ f = StringIO(kwargs['text'])
+ else:
+ raise RuntimeError('either specify text or file')
+ resp = addinfourl(f, {}, url)
+ resp.code = kwargs.get('code', 200)
+ resp.msg = ''
+ return resp
+
+def urldecorator(method, fullurl, **kwargs):
+ def decorate(test_method):
+ def wrapped_test_method(*args):
+ addExpectedRequest(method, fullurl, **kwargs)
+ test_method(*args)
+ # "rename" method otherwise we cannot specify a TestCaseClass.testName
+ # cmdline arg when using unittest.main()
+ wrapped_test_method.__name__ = test_method.__name__
+ return wrapped_test_method
+ return decorate
+
+def GET(fullurl, **kwargs):
+ return urldecorator('GET', fullurl, **kwargs)
+
+def PUT(fullurl, **kwargs):
+ return urldecorator('PUT', fullurl, **kwargs)
+
+def POST(fullurl, **kwargs):
+ return urldecorator('POST', fullurl, **kwargs)
+
+def DELETE(fullurl, **kwargs):
+ return urldecorator('DELETE', fullurl, **kwargs)
+
+def addExpectedRequest(method, url, **kwargs):
+ global EXPECTED_REQUESTS
+ EXPECTED_REQUESTS.append((method, url, kwargs))
+
+class OscTestCase(unittest.TestCase):
+ def setUp(self, copytree=True):
+ oscrc = os.path.join(self._get_fixtures_dir(), 'oscrc')
+ osc.core.conf.get_config(override_conffile=oscrc,
+ override_no_keyring=True, override_no_gnome_keyring=True)
+ os.environ['OSC_CONFIG'] = oscrc
+
+ self.tmpdir = tempfile.mkdtemp(prefix='osc_test')
+ if copytree:
+ shutil.copytree(os.path.join(self._get_fixtures_dir(), 'osctest'), os.path.join(self.tmpdir, 'osctest'))
+ global EXPECTED_REQUESTS
+ EXPECTED_REQUESTS = []
+ osc.core.conf._build_opener = lambda u: build_opener(MyHTTPHandler(EXPECTED_REQUESTS, self._get_fixtures_dir()))
+ self.stdout = sys.stdout
+ sys.stdout = StringIO()
+
+ def tearDown(self):
+ self.assertTrue(len(EXPECTED_REQUESTS) == 0)
+ sys.stdout = self.stdout
+ try:
+ shutil.rmtree(self.tmpdir)
+ except:
+ pass
+
+ def _get_fixtures_dir(self):
+ raise NotImplementedError('subclasses should implement this method')
+
+ def _change_to_pkg(self, name):
+ os.chdir(os.path.join(self.tmpdir, 'osctest', name))
+
+ def _check_list(self, fname, exp):
+ fname = os.path.join('.osc', fname)
+ self.assertTrue(os.path.exists(fname))
+ self.assertEqual(open(fname, 'r').read(), exp)
+
+ def _check_addlist(self, exp):
+ self._check_list('_to_be_added', exp)
+
+ def _check_deletelist(self, exp):
+ self._check_list('_to_be_deleted', exp)
+
+ def _check_conflictlist(self, exp):
+ self._check_list('_in_conflict', exp)
+
+ def _check_status(self, p, fname, exp):
+ self.assertEqual(p.status(fname), exp)
+
+ def _check_digests(self, fname, *skipfiles):
+ fname = os.path.join(self._get_fixtures_dir(), fname)
+ self.assertEqual(open(os.path.join('.osc', '_files'), 'r').read(), open(fname, 'r').read())
+ root = ET.parse(fname).getroot()
+ for i in root.findall('entry'):
+ if i.get('name') in skipfiles:
+ continue
+ self.assertTrue(os.path.exists(os.path.join('.osc', i.get('name'))))
+ self.assertEqual(osc.core.dgst(os.path.join('.osc', i.get('name'))), i.get('md5'))
+
+ def assertEqualMultiline(self, got, exp):
+ if (got + exp).find('\n') == -1:
+ self.assertEqual(got, exp)
+ else:
+ start_delim = "\n" + (" 8< ".join(["-----"] * 8)) + "\n"
+ end_delim = "\n" + (" >8 ".join(["-----"] * 8)) + "\n\n"
+ self.assertEqual(got, exp,
+ "got:" + start_delim + got + end_delim +
+ "expected:" + start_delim + exp + end_delim)
--- /dev/null
+[general]
+# URL to access API server, e.g. https://api.opensuse.org
+# you also need a section [https://api.opensuse.org] with the credentials
+apiurl = http://localhost
+# Downloaded packages are cached here. Must be writable by you.
+#packagecachedir = /var/tmp/osbuild-packagecache
+# Wrapper to call build as root (sudo, su -, ...)
+#su-wrapper = su -c
+# rootdir to setup the chroot environment
+# can contain %(repo)s, %(arch)s, %(project)s and %(package)s for replacement, e.g.
+# /srv/oscbuild/%(repo)s-%(arch)s or
+# /srv/oscbuild/%(repo)s-%(arch)s-%(project)s-%(package)s
+#build-root = /var/tmp/build-root
+# compile with N jobs (default: "getconf _NPROCESSORS_ONLN")
+#build-jobs = N
+# build-type to use - values can be (depending on the capabilities of the 'build' script)
+# empty - chroot build
+# kvm - kvm VM build (needs build-device, build-swap, build-memory)
+# xen - xen VM build (needs build-device, build-swap, build-memory)
+# experimental:
+# qemu - qemu VM build
+# lxc - lxc build
+#build-type =
+# build-device is the disk-image file to use as root for VM builds
+# e.g. /var/tmp/FILE.root
+#build-device = /var/tmp/FILE.root
+# build-swap is the disk-image to use as swap for VM builds
+# e.g. /var/tmp/FILE.swap
+#build-swap = /var/tmp/FILE.swap
+# build-memory is the amount of memory used in the VM
+# value in MB - e.g. 512
+#build-memory = 512
+# build-vmdisk-rootsize is the size of the disk-image used as root in a VM build
+# values in MB - e.g. 4096
+#build-vmdisk-rootsize = 4096
+# build-vmdisk-swapsize is the size of the disk-image used as swap in a VM build
+# values in MB - e.g. 1024
+#build-vmdisk-swapsize = 1024
+# Numeric uid:gid to assign to the "abuild" user in the build-root
+# or "caller" to use the current users uid:gid
+# This is convenient when sharing the buildroot with ordinary userids
+# on the host.
+# This should not be 0
+# build-uid =
+# extra packages to install when building packages locally (osc build)
+# this corresponds to osc build's -x option and can be overridden with that
+# -x '' can also be given on the command line to override this setting, or
+# you can have an empty setting here.
+#extra-pkgs = vim gdb strace
+# build platform is used if the platform argument is omitted to osc build
+#build_repository = openSUSE_Factory
+# default project for getpac or bco
+#getpac_default_project = openSUSE:Factory
+# alternate filesystem layout: have multiple subdirs, where colons were.
+#checkout_no_colon = 0
+# local files to ignore with status, addremove, ....
+#exclude_glob = .osc CVS .svn .* _linkerror *~ #*# *.orig *.bak *.changes.*
+# keep passwords in plaintext. If you see this comment, your osc
+# already uses the encrypted password, and only keeps them in plain text
+# for backwards compatibility. Default will change to 0 in future releases.
+# You can remove the plaintext password without harm, if you do not need
+# backwards compatibility.
+#plaintext_passwd = 1
+# limit the age of requests shown with 'osc req list'.
+# this is a default only, can be overridden by 'osc req list -D NNN'
+# Use 0 for unlimted.
+#request_list_days = 0
+# show info useful for debugging
+#debug = 1
+# show HTTP traffic useful for debugging
+#http_debug = 1
+# Skip signature verification of packages used for build.
+#no_verify = 1
+# jump into the debugger in case of errors
+#post_mortem = 1
+# print call traces in case of errors
+#traceback = 1
+# use KDE/Gnome/MacOS/Windows keyring for credentials if available
+#use_keyring = 1
+# check for unversioned/removed files before commit
+#check_filelist = 1
+# check for pending requests after executing an action (e.g. checkout, update, commit)
+#check_for_request_on_action = 0
+# what to do with the source package if the submitrequest has been accepted. If
+# nothing is specified the API default is used
+#submitrequest_on_accept_action = cleanup|update|noupdate
+#review requests interactively (default: off)
+#request_show_review = 1
+# Directory with executables to validate sources, esp before committing
+#source_validator_directory = /usr/lib/osc/source_validators
+
+[http://localhost]
+user=Admin
+pass=opensuse
+# set aliases for this apiurl
+# aliases = foo, bar
+# 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
+#http_headers = Host: foofoobar,
+# User: mumblegack
+# Force using of keyring for this API
+#keyring = 1
--- /dev/null
+[general]
+# URL to access API server, e.g. https://api.opensuse.org
+# you also need a section [https://api.opensuse.org] with the credentials
+apiurl = http://localhost
+# Downloaded packages are cached here. Must be writable by you.
+#packagecachedir = /var/tmp/osbuild-packagecache
+# Wrapper to call build as root (sudo, su -, ...)
+#su-wrapper = su -c
+# rootdir to setup the chroot environment
+# can contain %(repo)s, %(arch)s, %(project)s and %(package)s for replacement, e.g.
+# /srv/oscbuild/%(repo)s-%(arch)s or
+# /srv/oscbuild/%(repo)s-%(arch)s-%(project)s-%(package)s
+#build-root = /var/tmp/build-root
+# compile with N jobs (default: "getconf _NPROCESSORS_ONLN")
+#build-jobs = N
+# build-type to use - values can be (depending on the capabilities of the 'build' script)
+# empty - chroot build
+# kvm - kvm VM build (needs build-device, build-swap, build-memory)
+# xen - xen VM build (needs build-device, build-swap, build-memory)
+# experimental:
+# qemu - qemu VM build
+# lxc - lxc build
+#build-type =
+# build-device is the disk-image file to use as root for VM builds
+# e.g. /var/tmp/FILE.root
+#build-device = /var/tmp/FILE.root
+# build-swap is the disk-image to use as swap for VM builds
+# e.g. /var/tmp/FILE.swap
+#build-swap = /var/tmp/FILE.swap
+# build-memory is the amount of memory used in the VM
+# value in MB - e.g. 512
+#build-memory = 512
+# build-vmdisk-rootsize is the size of the disk-image used as root in a VM build
+# values in MB - e.g. 4096
+#build-vmdisk-rootsize = 4096
+# build-vmdisk-swapsize is the size of the disk-image used as swap in a VM build
+# values in MB - e.g. 1024
+#build-vmdisk-swapsize = 1024
+# Numeric uid:gid to assign to the "abuild" user in the build-root
+# or "caller" to use the current users uid:gid
+# This is convenient when sharing the buildroot with ordinary userids
+# on the host.
+# This should not be 0
+# build-uid =
+# extra packages to install when building packages locally (osc build)
+# this corresponds to osc build's -x option and can be overridden with that
+# -x '' can also be given on the command line to override this setting, or
+# you can have an empty setting here.
+#extra-pkgs = vim gdb strace
+# build platform is used if the platform argument is omitted to osc build
+#build_repository = openSUSE_Factory
+# default project for getpac or bco
+#getpac_default_project = openSUSE:Factory
+# alternate filesystem layout: have multiple subdirs, where colons were.
+#checkout_no_colon = 0
+# local files to ignore with status, addremove, ....
+#exclude_glob = .osc CVS .svn .* _linkerror *~ #*# *.orig *.bak *.changes.*
+# keep passwords in plaintext. If you see this comment, your osc
+# already uses the encrypted password, and only keeps them in plain text
+# for backwards compatibility. Default will change to 0 in future releases.
+# You can remove the plaintext password without harm, if you do not need
+# backwards compatibility.
+#plaintext_passwd = 1
+# limit the age of requests shown with 'osc req list'.
+# this is a default only, can be overridden by 'osc req list -D NNN'
+# Use 0 for unlimted.
+#request_list_days = 0
+# show info useful for debugging
+#debug = 1
+# show HTTP traffic useful for debugging
+#http_debug = 1
+# Skip signature verification of packages used for build.
+#no_verify = 1
+# jump into the debugger in case of errors
+#post_mortem = 1
+# print call traces in case of errors
+#traceback = 1
+# use KDE/Gnome/MacOS/Windows keyring for credentials if available
+#use_keyring = 1
+# check for unversioned/removed files before commit
+#check_filelist = 1
+# check for pending requests after executing an action (e.g. checkout, update, commit)
+#check_for_request_on_action = 0
+# what to do with the source package if the submitrequest has been accepted. If
+# nothing is specified the API default is used
+#submitrequest_on_accept_action = cleanup|update|noupdate
+#review requests interactively (default: off)
+#request_show_review = 1
+# Directory with executables to validate sources, esp before committing
+#source_validator_directory = /usr/lib/osc/source_validators
+
+[http://localhost]
+user=Admin
+pass=opensuse
+# set aliases for this apiurl
+# aliases = foo, bar
+# 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
+#http_headers = Host: foofoobar,
+# User: mumblegack
+# Force using of keyring for this API
+#keyring = 1
--- /dev/null
+http://localhost
--- /dev/null
+<project name="osctest" />
--- /dev/null
+http://localhost
--- /dev/null
+<directory name="simple" rev="1" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="1">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+</directory>
\ No newline at end of file
--- /dev/null
+simple
\ No newline at end of file
--- /dev/null
+osctest
\ No newline at end of file
--- /dev/null
+This is a simple test.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change but
+is modified.
--- /dev/null
+http://localhost
--- /dev/null
+<directory name="conflict" rev="2" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="2">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+</directory>
--- /dev/null
+simple
\ No newline at end of file
--- /dev/null
+osctest
\ No newline at end of file
--- /dev/null
+This is a simple test.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change.
--- /dev/null
+<<<<<<< foo.mine
+This is no test.
+=======
+This is a simple test.
+>>>>>>> foo.r2
--- /dev/null
+This is no test.
--- /dev/null
+This is a simple test.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change but
+is modified.
--- /dev/null
+http://localhost
--- /dev/null
+<directory name="simple" rev="1" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="1">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+</directory>
\ No newline at end of file
--- /dev/null
+simple
\ No newline at end of file
--- /dev/null
+osctest
\ No newline at end of file
--- /dev/null
+This is a simple test.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change but
+is modified.
--- /dev/null
+http://localhost
--- /dev/null
+<directory name="simple" rev="1" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="1">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+</directory>
\ No newline at end of file
--- /dev/null
+simple
\ No newline at end of file
--- /dev/null
+osctest
\ No newline at end of file
--- /dev/null
+toadd1
+merge
--- /dev/null
+This is a simple test.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change.
--- /dev/null
+This is a simple test.
--- /dev/null
+This file didn't change but
+is modified.
--- /dev/null
+http://localhost
--- /dev/null
+<directory name="simple" rev="1" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="1">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+ <entry md5="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" mtime="123456789" name="skipped" size="225" skipped="true" />
+ <entry md5="bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" mtime="012345678" name="skipped_exists" size="22" skipped="true" />
+</directory>
--- /dev/null
+simple
\ No newline at end of file
--- /dev/null
+osctest
\ No newline at end of file
--- /dev/null
+This is a simple test.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change.
--- /dev/null
+This is a simple test.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change but
+is modified.
--- /dev/null
+[general]
+# URL to access API server, e.g. https://api.opensuse.org
+# you also need a section [https://api.opensuse.org] with the credentials
+apiurl = http://localhost
+# Downloaded packages are cached here. Must be writable by you.
+#packagecachedir = /var/tmp/osbuild-packagecache
+# Wrapper to call build as root (sudo, su -, ...)
+#su-wrapper = su -c
+# rootdir to setup the chroot environment
+# can contain %(repo)s, %(arch)s, %(project)s and %(package)s for replacement, e.g.
+# /srv/oscbuild/%(repo)s-%(arch)s or
+# /srv/oscbuild/%(repo)s-%(arch)s-%(project)s-%(package)s
+#build-root = /var/tmp/build-root
+# compile with N jobs (default: "getconf _NPROCESSORS_ONLN")
+#build-jobs = N
+# build-type to use - values can be (depending on the capabilities of the 'build' script)
+# empty - chroot build
+# kvm - kvm VM build (needs build-device, build-swap, build-memory)
+# xen - xen VM build (needs build-device, build-swap, build-memory)
+# experimental:
+# qemu - qemu VM build
+# lxc - lxc build
+#build-type =
+# build-device is the disk-image file to use as root for VM builds
+# e.g. /var/tmp/FILE.root
+#build-device = /var/tmp/FILE.root
+# build-swap is the disk-image to use as swap for VM builds
+# e.g. /var/tmp/FILE.swap
+#build-swap = /var/tmp/FILE.swap
+# build-memory is the amount of memory used in the VM
+# value in MB - e.g. 512
+#build-memory = 512
+# build-vmdisk-rootsize is the size of the disk-image used as root in a VM build
+# values in MB - e.g. 4096
+#build-vmdisk-rootsize = 4096
+# build-vmdisk-swapsize is the size of the disk-image used as swap in a VM build
+# values in MB - e.g. 1024
+#build-vmdisk-swapsize = 1024
+# Numeric uid:gid to assign to the "abuild" user in the build-root
+# or "caller" to use the current users uid:gid
+# This is convenient when sharing the buildroot with ordinary userids
+# on the host.
+# This should not be 0
+# build-uid =
+# extra packages to install when building packages locally (osc build)
+# this corresponds to osc build's -x option and can be overridden with that
+# -x '' can also be given on the command line to override this setting, or
+# you can have an empty setting here.
+#extra-pkgs = vim gdb strace
+# build platform is used if the platform argument is omitted to osc build
+#build_repository = openSUSE_Factory
+# default project for getpac or bco
+#getpac_default_project = openSUSE:Factory
+# alternate filesystem layout: have multiple subdirs, where colons were.
+#checkout_no_colon = 0
+# local files to ignore with status, addremove, ....
+#exclude_glob = .osc CVS .svn .* _linkerror *~ #*# *.orig *.bak *.changes.*
+# keep passwords in plaintext. If you see this comment, your osc
+# already uses the encrypted password, and only keeps them in plain text
+# for backwards compatibility. Default will change to 0 in future releases.
+# You can remove the plaintext password without harm, if you do not need
+# backwards compatibility.
+#plaintext_passwd = 1
+# limit the age of requests shown with 'osc req list'.
+# this is a default only, can be overridden by 'osc req list -D NNN'
+# Use 0 for unlimted.
+#request_list_days = 0
+# show info useful for debugging
+#debug = 1
+# show HTTP traffic useful for debugging
+#http_debug = 1
+# Skip signature verification of packages used for build.
+#no_verify = 1
+# jump into the debugger in case of errors
+#post_mortem = 1
+# print call traces in case of errors
+#traceback = 1
+# use KDE/Gnome/MacOS/Windows keyring for credentials if available
+#use_keyring = 1
+# check for unversioned/removed files before commit
+#check_filelist = 1
+# check for pending requests after executing an action (e.g. checkout, update, commit)
+#check_for_request_on_action = 0
+# what to do with the source package if the submitrequest has been accepted. If
+# nothing is specified the API default is used
+#submitrequest_on_accept_action = cleanup|update|noupdate
+#review requests interactively (default: off)
+#request_show_review = 1
+# Directory with executables to validate sources, esp before committing
+#source_validator_directory = /usr/lib/osc/source_validators
+
+[http://localhost]
+user=Admin
+pass=opensuse
+# set aliases for this apiurl
+# aliases = foo, bar
+# 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
+#http_headers = Host: foofoobar,
+# User: mumblegack
+# Force using of keyring for this API
+#keyring = 1
--- /dev/null
+http://localhost
--- /dev/null
+<project name="osctest" />
--- /dev/null
+http://localhost
--- /dev/null
+<directory name="binary" rev="2" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="2">
+ <entry md5="8f618462e00017108b4146a29e074bdf" mtime="1111111111" name="binary" size="18" />
+ <entry md5="ee813c93cb5730dce38976695634482f" mtime="1111111111" name="binary_deleted" size="26" />
+</directory>
--- /dev/null
+binary_added
--- /dev/null
+binary_deleted
--- /dev/null
+http://localhost
--- /dev/null
+<directory name="simple" rev="1" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="1">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+</directory>
\ No newline at end of file
--- /dev/null
+remote_localdelete
--- /dev/null
+osctest
\ No newline at end of file
--- /dev/null
+This is a simple test.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change.
--- /dev/null
+This is a simple test.
--- /dev/null
+This file didn't change.
--- /dev/null
+http://localhost
--- /dev/null
+<directory name="simple" rev="1" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="1">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+ <entry md5="b1b642cdbacf9956104f8565e297ed00" mtime="1283246089" name="binary" size="27" />
+</directory>
--- /dev/null
+remote_localmodified
--- /dev/null
+osctest
\ No newline at end of file
--- /dev/null
+This is a simple test.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change.
--- /dev/null
+This is a simple test.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change.
+oh it does
--- /dev/null
+http://localhost
--- /dev/null
+<directory name="simple" rev="1" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="1">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+</directory>
\ No newline at end of file
--- /dev/null
+remote_simple
--- /dev/null
+osctest
\ No newline at end of file
--- /dev/null
+This is a simple test.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change.
--- /dev/null
+This is a simple test.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change.
--- /dev/null
+http://localhost
--- /dev/null
+<directory name="simple" rev="1" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="1">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+</directory>
\ No newline at end of file
--- /dev/null
+remote_simple_noadd
--- /dev/null
+osctest
\ No newline at end of file
--- /dev/null
+This is a simple test.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change.
--- /dev/null
+This is a simple test.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change.
--- /dev/null
+http://localhost
--- /dev/null
+<directory name="replaced" rev="2" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="2">
+ <entry md5="81be947db54c2e225dc8eacce64d8a4a" mtime="1282731457" name="replaced" size="17" />
+</directory>
--- /dev/null
+osctest
\ No newline at end of file
--- /dev/null
+yet another file
--- /dev/null
+foo replaced
--- /dev/null
+http://localhost
--- /dev/null
+<directory name="simple" rev="2" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="2">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+ <entry md5="eb9c2bf0eb63f3a7bc0ea37ef18aeba5" mtime="1282730880" name="somefile" size="13" />
+ <entry md5="81be947db54c2e225dc8eacce64d8a4a" mtime="1282731457" name="replaced" size="17" />
+ <entry md5="676513fde5797c3785164942c97dfec1" mtime="1282731738" name="missing" size="8" />
+ <entry md5="ffffffffffffffffffffffffffffffff" mtime="1111111111" name="skipped" size="12" skipped="true" />
+</directory>
--- /dev/null
+simple
\ No newline at end of file
--- /dev/null
+osctest
\ No newline at end of file
--- /dev/null
+toadd1
+replaced
+addedmissing
--- /dev/null
+This is a simple test.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change.
--- /dev/null
+yet another file
--- /dev/null
+some content
--- /dev/null
+<<<<<<< foo.mine
+This is no test.
+=======
+This is a simple test.
+>>>>>>> foo.r2
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change but
+is modified.
--- /dev/null
+foo replaced
--- /dev/null
+<directory name="simple" rev="3" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="3">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+</directory>
--- /dev/null
+<directory name="simple" rev="3" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="3">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+ <entry md5="136a96e1470ec7424bc8ae47612977db" mtime="1282914026" name="foobar" size="14" />
+ <entry md5="9b55c93ffec5ef8850c84882de7ef6b5" mtime="1283242538" name="binary" size="7" />
+</directory>
--- /dev/null
+foobar
+barfoo
--- /dev/null
+<directory name="simple" rev="3" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="3">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="foo" size="23" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+</directory>
--- /dev/null
+<directory name="simple" rev="3" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="3">
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+</directory>
--- /dev/null
+<directory name="simple" rev="3" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="3">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="foo" size="23" />
+ <entry md5="daafe513479072c5a942928d1850a939" mtime="1282908295" name="merge" size="35" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+</directory>
--- /dev/null
+Is it
+possible to
+merge this file?
--- /dev/null
+<directory name="simple" rev="3" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="3">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+</directory>
--- /dev/null
+<directory name="simple" rev="3" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="3">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+ <entry md5="b1b642cdbacf9956104f8565e297ed00" mtime="1283246089" name="binary" size="27" />
+</directory>
--- /dev/null
+This file didn't change.
--- /dev/null
+[general]
+# URL to access API server, e.g. https://api.opensuse.org
+# you also need a section [https://api.opensuse.org] with the credentials
+apiurl = http://localhost
+# Downloaded packages are cached here. Must be writable by you.
+#packagecachedir = /var/tmp/osbuild-packagecache
+# Wrapper to call build as root (sudo, su -, ...)
+#su-wrapper = su -c
+# rootdir to setup the chroot environment
+# can contain %(repo)s, %(arch)s, %(project)s and %(package)s for replacement, e.g.
+# /srv/oscbuild/%(repo)s-%(arch)s or
+# /srv/oscbuild/%(repo)s-%(arch)s-%(project)s-%(package)s
+#build-root = /var/tmp/build-root
+# compile with N jobs (default: "getconf _NPROCESSORS_ONLN")
+#build-jobs = N
+# build-type to use - values can be (depending on the capabilities of the 'build' script)
+# empty - chroot build
+# kvm - kvm VM build (needs build-device, build-swap, build-memory)
+# xen - xen VM build (needs build-device, build-swap, build-memory)
+# experimental:
+# qemu - qemu VM build
+# lxc - lxc build
+#build-type =
+# build-device is the disk-image file to use as root for VM builds
+# e.g. /var/tmp/FILE.root
+#build-device = /var/tmp/FILE.root
+# build-swap is the disk-image to use as swap for VM builds
+# e.g. /var/tmp/FILE.swap
+#build-swap = /var/tmp/FILE.swap
+# build-memory is the amount of memory used in the VM
+# value in MB - e.g. 512
+#build-memory = 512
+# build-vmdisk-rootsize is the size of the disk-image used as root in a VM build
+# values in MB - e.g. 4096
+#build-vmdisk-rootsize = 4096
+# build-vmdisk-swapsize is the size of the disk-image used as swap in a VM build
+# values in MB - e.g. 1024
+#build-vmdisk-swapsize = 1024
+# Numeric uid:gid to assign to the "abuild" user in the build-root
+# or "caller" to use the current users uid:gid
+# This is convenient when sharing the buildroot with ordinary userids
+# on the host.
+# This should not be 0
+# build-uid =
+# extra packages to install when building packages locally (osc build)
+# this corresponds to osc build's -x option and can be overridden with that
+# -x '' can also be given on the command line to override this setting, or
+# you can have an empty setting here.
+#extra-pkgs = vim gdb strace
+# build platform is used if the platform argument is omitted to osc build
+#build_repository = openSUSE_Factory
+# default project for getpac or bco
+#getpac_default_project = openSUSE:Factory
+# alternate filesystem layout: have multiple subdirs, where colons were.
+#checkout_no_colon = 0
+# local files to ignore with status, addremove, ....
+#exclude_glob = .osc CVS .svn .* _linkerror *~ #*# *.orig *.bak *.changes.*
+# keep passwords in plaintext. If you see this comment, your osc
+# already uses the encrypted password, and only keeps them in plain text
+# for backwards compatibility. Default will change to 0 in future releases.
+# You can remove the plaintext password without harm, if you do not need
+# backwards compatibility.
+#plaintext_passwd = 1
+# limit the age of requests shown with 'osc req list'.
+# this is a default only, can be overridden by 'osc req list -D NNN'
+# Use 0 for unlimted.
+#request_list_days = 0
+# show info useful for debugging
+#debug = 1
+# show HTTP traffic useful for debugging
+#http_debug = 1
+# Skip signature verification of packages used for build.
+#no_verify = 1
+# jump into the debugger in case of errors
+#post_mortem = 1
+# print call traces in case of errors
+#traceback = 1
+# use KDE/Gnome/MacOS/Windows keyring for credentials if available
+#use_keyring = 1
+# check for unversioned/removed files before commit
+#check_filelist = 1
+# check for pending requests after executing an action (e.g. checkout, update, commit)
+#check_for_request_on_action = 0
+# what to do with the source package if the submitrequest has been accepted. If
+# nothing is specified the API default is used
+#submitrequest_on_accept_action = cleanup|update|noupdate
+#review requests interactively (default: off)
+#request_show_review = 1
+# Directory with executables to validate sources, esp before committing
+#source_validator_directory = /usr/lib/osc/source_validators
+
+[http://localhost]
+user=Admin
+pass=opensuse
+# set aliases for this apiurl
+# aliases = foo, bar
+# 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
+#http_headers = Host: foofoobar,
+# User: mumblegack
+# Force using of keyring for this API
+#keyring = 1
--- /dev/null
+[general]
+# URL to access API server, e.g. https://api.opensuse.org
+# you also need a section [https://api.opensuse.org] with the credentials
+apiurl = http://localhost
+# Downloaded packages are cached here. Must be writable by you.
+#packagecachedir = /var/tmp/osbuild-packagecache
+# Wrapper to call build as root (sudo, su -, ...)
+#su-wrapper = su -c
+# rootdir to setup the chroot environment
+# can contain %(repo)s, %(arch)s, %(project)s and %(package)s for replacement, e.g.
+# /srv/oscbuild/%(repo)s-%(arch)s or
+# /srv/oscbuild/%(repo)s-%(arch)s-%(project)s-%(package)s
+#build-root = /var/tmp/build-root
+# compile with N jobs (default: "getconf _NPROCESSORS_ONLN")
+#build-jobs = N
+# build-type to use - values can be (depending on the capabilities of the 'build' script)
+# empty - chroot build
+# kvm - kvm VM build (needs build-device, build-swap, build-memory)
+# xen - xen VM build (needs build-device, build-swap, build-memory)
+# experimental:
+# qemu - qemu VM build
+# lxc - lxc build
+#build-type =
+# build-device is the disk-image file to use as root for VM builds
+# e.g. /var/tmp/FILE.root
+#build-device = /var/tmp/FILE.root
+# build-swap is the disk-image to use as swap for VM builds
+# e.g. /var/tmp/FILE.swap
+#build-swap = /var/tmp/FILE.swap
+# build-memory is the amount of memory used in the VM
+# value in MB - e.g. 512
+#build-memory = 512
+# build-vmdisk-rootsize is the size of the disk-image used as root in a VM build
+# values in MB - e.g. 4096
+#build-vmdisk-rootsize = 4096
+# build-vmdisk-swapsize is the size of the disk-image used as swap in a VM build
+# values in MB - e.g. 1024
+#build-vmdisk-swapsize = 1024
+# Numeric uid:gid to assign to the "abuild" user in the build-root
+# or "caller" to use the current users uid:gid
+# This is convenient when sharing the buildroot with ordinary userids
+# on the host.
+# This should not be 0
+# build-uid =
+# extra packages to install when building packages locally (osc build)
+# this corresponds to osc build's -x option and can be overridden with that
+# -x '' can also be given on the command line to override this setting, or
+# you can have an empty setting here.
+#extra-pkgs = vim gdb strace
+# build platform is used if the platform argument is omitted to osc build
+#build_repository = openSUSE_Factory
+# default project for getpac or bco
+#getpac_default_project = openSUSE:Factory
+# alternate filesystem layout: have multiple subdirs, where colons were.
+#checkout_no_colon = 0
+# local files to ignore with status, addremove, ....
+#exclude_glob = .osc CVS .svn .* _linkerror *~ #*# *.orig *.bak *.changes.*
+# keep passwords in plaintext. If you see this comment, your osc
+# already uses the encrypted password, and only keeps them in plain text
+# for backwards compatibility. Default will change to 0 in future releases.
+# You can remove the plaintext password without harm, if you do not need
+# backwards compatibility.
+#plaintext_passwd = 1
+# limit the age of requests shown with 'osc req list'.
+# this is a default only, can be overridden by 'osc req list -D NNN'
+# Use 0 for unlimted.
+#request_list_days = 0
+# show info useful for debugging
+#debug = 1
+# show HTTP traffic useful for debugging
+#http_debug = 1
+# Skip signature verification of packages used for build.
+#no_verify = 1
+# jump into the debugger in case of errors
+#post_mortem = 1
+# print call traces in case of errors
+#traceback = 1
+# use KDE/Gnome/MacOS/Windows keyring for credentials if available
+#use_keyring = 1
+# check for unversioned/removed files before commit
+#check_filelist = 1
+# check for pending requests after executing an action (e.g. checkout, update, commit)
+#check_for_request_on_action = 0
+# what to do with the source package if the submitrequest has been accepted. If
+# nothing is specified the API default is used
+#submitrequest_on_accept_action = cleanup|update|noupdate
+#review requests interactively (default: off)
+#request_show_review = 1
+# Directory with executables to validate sources, esp before committing
+#source_validator_directory = /usr/lib/osc/source_validators
+
+[http://localhost]
+user=Admin
+pass=opensuse
+# set aliases for this apiurl
+# aliases = foo, bar
+# 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
+#http_headers = Host: foofoobar,
+# User: mumblegack
+# Force using of keyring for this API
+#keyring = 1
--- /dev/null
+../osc
\ No newline at end of file
--- /dev/null
+Index: common-two
+===================================================================
+--- common-two 2013-01-18 19:18:38.225983117 +0000
++++ common-two 2013-01-18 19:19:27.882082325 +0000
+@@ -1,4 +1,5 @@
+ line one
+ line two
+ line three
++an extra line
+ last line
--- /dev/null
+http://localhost
--- /dev/null
+<project name="home:user:branches:some:project">
+ <package name="common-one" state=" " />
+ <package name="common-two" state=" " />
+</project>
\ No newline at end of file
--- /dev/null
+home:user:branches:some:project
--- /dev/null
+line one
+line two
+line three
+an extra line
+last line
\ No newline at end of file
--- /dev/null
+<directory count='4'>
+ <entry name="common-one"/>
+ <entry name="common-two"/>
+ <entry name="common-three"/>
+ <entry name="only-in-new"/>
+</directory>
--- /dev/null
+line one
+line two
+line three
+an extra line
+last line
\ No newline at end of file
--- /dev/null
+<directory count='4'>
+ <entry name="common-one"/>
+ <entry name="common-two"/>
+ <entry name="common-three"/>
+ <entry name="only-in-new"/>
+</directory>
--- /dev/null
+<collection matches="0">
+</collection>
--- /dev/null
+line one
+line two
+line three
+last line
\ No newline at end of file
--- /dev/null
+<directory count='4'>
+ <entry name="common-one"/>
+ <entry name="common-two"/>
+ <entry name="common-three"/>
+ <entry name="only-in-old"/>
+</directory>
--- /dev/null
+[general]
+# URL to access API server, e.g. https://api.opensuse.org
+# you also need a section [https://api.opensuse.org] with the credentials
+apiurl = http://localhost
+# Downloaded packages are cached here. Must be writable by you.
+#packagecachedir = /var/tmp/osbuild-packagecache
+# Wrapper to call build as root (sudo, su -, ...)
+#su-wrapper = su -c
+# rootdir to setup the chroot environment
+# can contain %(repo)s, %(arch)s, %(project)s and %(package)s for replacement, e.g.
+# /srv/oscbuild/%(repo)s-%(arch)s or
+# /srv/oscbuild/%(repo)s-%(arch)s-%(project)s-%(package)s
+#build-root = /var/tmp/build-root
+# compile with N jobs (default: "getconf _NPROCESSORS_ONLN")
+#build-jobs = N
+# build-type to use - values can be (depending on the capabilities of the 'build' script)
+# empty - chroot build
+# kvm - kvm VM build (needs build-device, build-swap, build-memory)
+# xen - xen VM build (needs build-device, build-swap, build-memory)
+# experimental:
+# qemu - qemu VM build
+# lxc - lxc build
+#build-type =
+# build-device is the disk-image file to use as root for VM builds
+# e.g. /var/tmp/FILE.root
+#build-device = /var/tmp/FILE.root
+# build-swap is the disk-image to use as swap for VM builds
+# e.g. /var/tmp/FILE.swap
+#build-swap = /var/tmp/FILE.swap
+# build-memory is the amount of memory used in the VM
+# value in MB - e.g. 512
+#build-memory = 512
+# build-vmdisk-rootsize is the size of the disk-image used as root in a VM build
+# values in MB - e.g. 4096
+#build-vmdisk-rootsize = 4096
+# build-vmdisk-swapsize is the size of the disk-image used as swap in a VM build
+# values in MB - e.g. 1024
+#build-vmdisk-swapsize = 1024
+# Numeric uid:gid to assign to the "abuild" user in the build-root
+# or "caller" to use the current users uid:gid
+# This is convenient when sharing the buildroot with ordinary userids
+# on the host.
+# This should not be 0
+# build-uid =
+# extra packages to install when building packages locally (osc build)
+# this corresponds to osc build's -x option and can be overridden with that
+# -x '' can also be given on the command line to override this setting, or
+# you can have an empty setting here.
+#extra-pkgs = vim gdb strace
+# build platform is used if the platform argument is omitted to osc build
+#build_repository = openSUSE_Factory
+# default project for getpac or bco
+#getpac_default_project = openSUSE:Factory
+# alternate filesystem layout: have multiple subdirs, where colons were.
+#checkout_no_colon = 0
+# local files to ignore with status, addremove, ....
+#exclude_glob = .osc CVS .svn .* _linkerror *~ #*# *.orig *.bak *.changes.*
+# keep passwords in plaintext. If you see this comment, your osc
+# already uses the encrypted password, and only keeps them in plain text
+# for backwards compatibility. Default will change to 0 in future releases.
+# You can remove the plaintext password without harm, if you do not need
+# backwards compatibility.
+#plaintext_passwd = 1
+# limit the age of requests shown with 'osc req list'.
+# this is a default only, can be overridden by 'osc req list -D NNN'
+# Use 0 for unlimted.
+#request_list_days = 0
+# show info useful for debugging
+#debug = 1
+# show HTTP traffic useful for debugging
+#http_debug = 1
+# Skip signature verification of packages used for build.
+#no_verify = 1
+# jump into the debugger in case of errors
+#post_mortem = 1
+# print call traces in case of errors
+#traceback = 1
+# use KDE/Gnome/MacOS/Windows keyring for credentials if available
+#use_keyring = 1
+# check for unversioned/removed files before commit
+#check_filelist = 1
+# check for pending requests after executing an action (e.g. checkout, update, commit)
+#check_for_request_on_action = 0
+# what to do with the source package if the submitrequest has been accepted. If
+# nothing is specified the API default is used
+#submitrequest_on_accept_action = cleanup|update|noupdate
+#review requests interactively (default: off)
+#request_show_review = 1
+# Directory with executables to validate sources, esp before committing
+#source_validator_directory = /usr/lib/osc/source_validators
+
+[http://localhost]
+user=Admin
+pass=opensuse
+# set aliases for this apiurl
+# aliases = foo, bar
+# 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
+#http_headers = Host: foofoobar,
+# User: mumblegack
+# Force using of keyring for this API
+#keyring = 1
--- /dev/null
+http://localhost
--- /dev/null
+<project name="home:user:branches:some:project">
+ <package name="common-one" state=" " />
+ <package name="common-two" state=" " />
+</project>
\ No newline at end of file
--- /dev/null
+home:user:branches:some:project
--- /dev/null
+http://localhost
--- /dev/null
+<directory name="common-one" rev="f53d033d63c3d6e9a8e4493225976122" srcmd5="f53d033d63c3d6e9a8e4493225976122">
+ <linkinfo baserev="896e6d6d675d03b6934946d03a976450" lsrcmd5="0cf460222270b58e2a9a3d695b1d945d" package="common-one" project="some:project" srcmd5="8c7ed3cf5ec0b4aa20ef159fd8c51b76" />
+ <entry md5="1a4c23ccf2eb12403acbfa3258233a9d" mtime="1352816081" name="common-one.spec" size="3457" />
+</directory>
--- /dev/null
+<package name="common-one" project="home:user:branches:some:project">
+ <title>blah</title>
+ <description>foo</description>
+ <debuginfo>
+ <enable repository="openSUSE_12.2"/>
+ <enable repository="openSUSE_Factory"/>
+ <enable repository="SLE_11_SP2"/>
+ </debuginfo>
+</package>
+
--- /dev/null
+common-one
\ No newline at end of file
--- /dev/null
+home:user:branches:some:project
--- /dev/null
+contents are irrelevant
--- /dev/null
+contents are irrelevant
--- /dev/null
+http://localhost
--- /dev/null
+<directory name="common-two" rev="f53d033d63c3d6e9a8e4493225976122" srcmd5="f53d033d63c3d6e9a8e4493225976122">
+ <linkinfo baserev="896e6d6d675d03b6934946d03a976450" lsrcmd5="0cf460222270b58e2a9a3d695b1d945d" package="common-two" project="some:project" srcmd5="8c7ed3cf5ec0b4aa20ef159fd8c51b76" />
+ <entry md5="1a4c23ccf2eb12403acbfa3258233a9d" mtime="1352816081" name="common-two.spec" size="3457" />
+</directory>
--- /dev/null
+<package name="common-two" project="home:user:branches:some:project">
+ <title>blah</title>
+ <description>foo</description>
+ <debuginfo>
+ <enable repository="openSUSE_12.2"/>
+ <enable repository="openSUSE_Factory"/>
+ <enable repository="SLE_11_SP2"/>
+ </debuginfo>
+</package>
+
--- /dev/null
+common-two
\ No newline at end of file
--- /dev/null
+home:user:branches:some:project
--- /dev/null
+contents are irrelevant
--- /dev/null
+contents are irrelevant
--- /dev/null
+<collection matches="1">
+ <request id="148023">
+ <action type="submit">
+ <source project="home:user:branches:some:project" package="common-two" rev="7"/>
+ <target project="some:project" package="common-two"/>
+ <options>
+ <sourceupdate>update</sourceupdate>
+ </options>
+ </action>
+ <state name="new" who="user" when="2013-01-11T11:04:14">
+ <comment/>
+ </state>
+ <description>- Fix it to work
+- Improve support for something</description>
+ </request>
+</collection>
--- /dev/null
+http://localhost
--- /dev/null
+<project name="some:project">
+ <package name="common-one" state=" " />
+ <package name="common-two" state=" " />
+</project>
\ No newline at end of file
--- /dev/null
+some:project
--- /dev/null
+line one
+line two
+line three
+an extra line
+last line
\ No newline at end of file
--- /dev/null
+<directory count='4'>
+ <entry name="common-one"/>
+ <entry name="common-two"/>
+ <entry name="common-three"/>
+ <entry name="only-in-new"/>
+</directory>
--- /dev/null
+[general]
+# URL to access API server, e.g. https://api.opensuse.org
+# you also need a section [https://api.opensuse.org] with the credentials
+apiurl = http://localhost
+# Downloaded packages are cached here. Must be writable by you.
+#packagecachedir = /var/tmp/osbuild-packagecache
+# Wrapper to call build as root (sudo, su -, ...)
+#su-wrapper = su -c
+# rootdir to setup the chroot environment
+# can contain %(repo)s, %(arch)s, %(project)s and %(package)s for replacement, e.g.
+# /srv/oscbuild/%(repo)s-%(arch)s or
+# /srv/oscbuild/%(repo)s-%(arch)s-%(project)s-%(package)s
+#build-root = /var/tmp/build-root
+# compile with N jobs (default: "getconf _NPROCESSORS_ONLN")
+#build-jobs = N
+# build-type to use - values can be (depending on the capabilities of the 'build' script)
+# empty - chroot build
+# kvm - kvm VM build (needs build-device, build-swap, build-memory)
+# xen - xen VM build (needs build-device, build-swap, build-memory)
+# experimental:
+# qemu - qemu VM build
+# lxc - lxc build
+#build-type =
+# build-device is the disk-image file to use as root for VM builds
+# e.g. /var/tmp/FILE.root
+#build-device = /var/tmp/FILE.root
+# build-swap is the disk-image to use as swap for VM builds
+# e.g. /var/tmp/FILE.swap
+#build-swap = /var/tmp/FILE.swap
+# build-memory is the amount of memory used in the VM
+# value in MB - e.g. 512
+#build-memory = 512
+# build-vmdisk-rootsize is the size of the disk-image used as root in a VM build
+# values in MB - e.g. 4096
+#build-vmdisk-rootsize = 4096
+# build-vmdisk-swapsize is the size of the disk-image used as swap in a VM build
+# values in MB - e.g. 1024
+#build-vmdisk-swapsize = 1024
+# Numeric uid:gid to assign to the "abuild" user in the build-root
+# or "caller" to use the current users uid:gid
+# This is convenient when sharing the buildroot with ordinary userids
+# on the host.
+# This should not be 0
+# build-uid =
+# extra packages to install when building packages locally (osc build)
+# this corresponds to osc build's -x option and can be overridden with that
+# -x '' can also be given on the command line to override this setting, or
+# you can have an empty setting here.
+#extra-pkgs = vim gdb strace
+# build platform is used if the platform argument is omitted to osc build
+#build_repository = openSUSE_Factory
+# default project for getpac or bco
+#getpac_default_project = openSUSE:Factory
+# alternate filesystem layout: have multiple subdirs, where colons were.
+#checkout_no_colon = 0
+# local files to ignore with status, addremove, ....
+#exclude_glob = .osc CVS .svn .* _linkerror *~ #*# *.orig *.bak *.changes.*
+# keep passwords in plaintext. If you see this comment, your osc
+# already uses the encrypted password, and only keeps them in plain text
+# for backwards compatibility. Default will change to 0 in future releases.
+# You can remove the plaintext password without harm, if you do not need
+# backwards compatibility.
+#plaintext_passwd = 1
+# limit the age of requests shown with 'osc req list'.
+# this is a default only, can be overridden by 'osc req list -D NNN'
+# Use 0 for unlimted.
+#request_list_days = 0
+# show info useful for debugging
+#debug = 1
+# show HTTP traffic useful for debugging
+#http_debug = 1
+# Skip signature verification of packages used for build.
+#no_verify = 1
+# jump into the debugger in case of errors
+#post_mortem = 1
+# print call traces in case of errors
+#traceback = 1
+# use KDE/Gnome/MacOS/Windows keyring for credentials if available
+#use_keyring = 1
+# check for unversioned/removed files before commit
+#check_filelist = 1
+# check for pending requests after executing an action (e.g. checkout, update, commit)
+#check_for_request_on_action = 0
+# what to do with the source package if the submitrequest has been accepted. If
+# nothing is specified the API default is used
+#submitrequest_on_accept_action = cleanup|update|noupdate
+#review requests interactively (default: off)
+#request_show_review = 1
+# Directory with executables to validate sources, esp before committing
+#source_validator_directory = /usr/lib/osc/source_validators
+
+[http://localhost]
+user=Admin
+pass=opensuse
+# set aliases for this apiurl
+# aliases = foo, bar
+# 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
+#http_headers = Host: foofoobar,
+# User: mumblegack
+# Force using of keyring for this API
+#keyring = 1
--- /dev/null
+http://localhost
--- /dev/null
+<project name="osctest">
+ <package name="conflict" state=" " />
+ <package name="simple" state=" " />
+ <package name="added" state="A" />
+ <package name="deleted" state="D" />
+ <package name="missing" state="!" />
+ <package name="added_deleted" state="A" />
+ <package name="deleted_deleted" state="D" />
+</project>
--- /dev/null
+http://localhost
--- /dev/null
+<directory />
--- /dev/null
+http://localhost
--- /dev/null
+<directory name="conflict" rev="1" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="1">
+ <entry md5="2abd19de6a38ff2890af64f453df96b1" mtime="1282047303" name="conflict" size="22" />
+ <entry md5="d8e8fca2dc0f896fd7cb4cb0031ba249" mtime="1283505591" name="test" size="5" />
+</directory>
--- /dev/null
+osctest
\ No newline at end of file
--- /dev/null
+This file did change.
--- /dev/null
+Inconflict
--- /dev/null
+http://localhost
--- /dev/null
+<directory name="conflict" rev="1" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="1">
+ <entry md5="2abd19de6a38ff2890af64f453df96b1" mtime="1282047303" name="modified" size="22" />
+ <entry md5="d8e8fca2dc0f896fd7cb4cb0031ba249" mtime="1283505591" name="test" size="5" />
+</directory>
--- /dev/null
+osctest
\ No newline at end of file
--- /dev/null
+modified
+test
--- /dev/null
+This file did change.
--- /dev/null
+http://localhost
--- /dev/null
+<directory name="conflict" rev="1" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="1">
+ <entry md5="2abd19de6a38ff2890af64f453df96b1" mtime="1282047303" name="modified" size="22" />
+ <entry md5="d8e8fca2dc0f896fd7cb4cb0031ba249" mtime="1283505591" name="test" size="5" />
+</directory>
--- /dev/null
+osctest
\ No newline at end of file
--- /dev/null
+This file did change.
--- /dev/null
+http://localhost
--- /dev/null
+<directory name="simple" rev="1" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="1">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="676513fde5797c3785164942c97dfec1" mtime="1283506309" name="missing" size="8" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+ <entry md5="d8e8fca2dc0f896fd7cb4cb0031ba249" mtime="1283505591" name="test" size="5" />
+ <entry md5="ffffffffffffffffffffffffffffffff" mtime="1111111111" name="skipped" size="100" skipped="true" />
+</directory>
--- /dev/null
+osctest
\ No newline at end of file
--- /dev/null
+add
+missing
+missing_added
--- /dev/null
+This is a simple test.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change.
--- /dev/null
+added file
--- /dev/null
+This file did change.
--- /dev/null
+[general]
+# URL to access API server, e.g. https://api.opensuse.org
+# you also need a section [https://api.opensuse.org] with the credentials
+apiurl = http://localhost
+# Downloaded packages are cached here. Must be writable by you.
+#packagecachedir = /var/tmp/osbuild-packagecache
+# Wrapper to call build as root (sudo, su -, ...)
+#su-wrapper = su -c
+# rootdir to setup the chroot environment
+# can contain %(repo)s, %(arch)s, %(project)s and %(package)s for replacement, e.g.
+# /srv/oscbuild/%(repo)s-%(arch)s or
+# /srv/oscbuild/%(repo)s-%(arch)s-%(project)s-%(package)s
+#build-root = /var/tmp/build-root
+# compile with N jobs (default: "getconf _NPROCESSORS_ONLN")
+#build-jobs = N
+# build-type to use - values can be (depending on the capabilities of the 'build' script)
+# empty - chroot build
+# kvm - kvm VM build (needs build-device, build-swap, build-memory)
+# xen - xen VM build (needs build-device, build-swap, build-memory)
+# experimental:
+# qemu - qemu VM build
+# lxc - lxc build
+#build-type =
+# build-device is the disk-image file to use as root for VM builds
+# e.g. /var/tmp/FILE.root
+#build-device = /var/tmp/FILE.root
+# build-swap is the disk-image to use as swap for VM builds
+# e.g. /var/tmp/FILE.swap
+#build-swap = /var/tmp/FILE.swap
+# build-memory is the amount of memory used in the VM
+# value in MB - e.g. 512
+#build-memory = 512
+# build-vmdisk-rootsize is the size of the disk-image used as root in a VM build
+# values in MB - e.g. 4096
+#build-vmdisk-rootsize = 4096
+# build-vmdisk-swapsize is the size of the disk-image used as swap in a VM build
+# values in MB - e.g. 1024
+#build-vmdisk-swapsize = 1024
+# Numeric uid:gid to assign to the "abuild" user in the build-root
+# or "caller" to use the current users uid:gid
+# This is convenient when sharing the buildroot with ordinary userids
+# on the host.
+# This should not be 0
+# build-uid =
+# extra packages to install when building packages locally (osc build)
+# this corresponds to osc build's -x option and can be overridden with that
+# -x '' can also be given on the command line to override this setting, or
+# you can have an empty setting here.
+#extra-pkgs = vim gdb strace
+# build platform is used if the platform argument is omitted to osc build
+#build_repository = openSUSE_Factory
+# default project for getpac or bco
+#getpac_default_project = openSUSE:Factory
+# alternate filesystem layout: have multiple subdirs, where colons were.
+#checkout_no_colon = 0
+# local files to ignore with status, addremove, ....
+#exclude_glob = .osc CVS .svn .* _linkerror *~ #*# *.orig *.bak *.changes.*
+# keep passwords in plaintext. If you see this comment, your osc
+# already uses the encrypted password, and only keeps them in plain text
+# for backwards compatibility. Default will change to 0 in future releases.
+# You can remove the plaintext password without harm, if you do not need
+# backwards compatibility.
+#plaintext_passwd = 1
+# limit the age of requests shown with 'osc req list'.
+# this is a default only, can be overridden by 'osc req list -D NNN'
+# Use 0 for unlimted.
+#request_list_days = 0
+# show info useful for debugging
+#debug = 1
+# show HTTP traffic useful for debugging
+#http_debug = 1
+# Skip signature verification of packages used for build.
+#no_verify = 1
+# jump into the debugger in case of errors
+#post_mortem = 1
+# print call traces in case of errors
+#traceback = 1
+# use KDE/Gnome/MacOS/Windows keyring for credentials if available
+#use_keyring = 1
+# check for unversioned/removed files before commit
+#check_filelist = 1
+# check for pending requests after executing an action (e.g. checkout, update, commit)
+#check_for_request_on_action = 0
+# what to do with the source package if the submitrequest has been accepted. If
+# nothing is specified the API default is used
+#submitrequest_on_accept_action = cleanup|update|noupdate
+#review requests interactively (default: off)
+#request_show_review = 1
+# Directory with executables to validate sources, esp before committing
+#source_validator_directory = /usr/lib/osc/source_validators
+
+[http://localhost]
+user=Admin
+pass=opensuse
+# set aliases for this apiurl
+# aliases = foo, bar
+# 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
+#http_headers = Host: foofoobar,
+# User: mumblegack
+# Force using of keyring for this API
+#keyring = 1
--- /dev/null
+http://localhost
--- /dev/null
+<project name="osctest" />
--- /dev/null
+<project name="osctest" />
--- /dev/null
+http://localhost
--- /dev/null
+<directory name="buildfiles" rev="1" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="1">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+</directory>
--- /dev/null
+buildfiles
--- /dev/null
+osctest
\ No newline at end of file
--- /dev/null
+This is a simple test.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change but
+is modified.
--- /dev/null
+urlwithoutprotocolandtld
--- /dev/null
+<directory name="invalid_apiurl" rev="1" vrev="1" srcmd5="2738234914de5cc154b1494b1e98d940" />
--- /dev/null
+<package project="remote" name="foo">
+ <title>Title of New Package</title>
+ <description>
+LONG DESCRIPTION
+GOES
+HERE
+ </description>
+ <person userid="Admin" role="maintainer"/>
+ <person userid="Admin" role="bugowner"/>
+ <url>PUT_UPSTREAM_URL_HERE</url>
+</package>
--- /dev/null
+invalid_apiurl
--- /dev/null
+http://localhost
--- /dev/null
+<directory name="multiple" rev="1" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="1">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+</directory>
--- /dev/null
+osctest
\ No newline at end of file
--- /dev/null
+foo
+nofilesentry
--- /dev/null
+This is a simple test.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change but
+is modified.
--- /dev/null
+<directory name="noapiurl" rev="1" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="1">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+</directory>
--- /dev/null
+osctest
\ No newline at end of file
--- /dev/null
+This is a simple test.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change but
+is modified.
--- /dev/null
+http://localhost
--- /dev/null
+<directory name="simple" rev="1" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="1">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+</directory>
\ No newline at end of file
--- /dev/null
+simple
\ No newline at end of file
--- /dev/null
+osctest
\ No newline at end of file
--- /dev/null
+This is a simple test.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change but
+is modified.
--- /dev/null
+http://localhost
--- /dev/null
+<directory name="simple" rev="1" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="1">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+</directory>
\ No newline at end of file
--- /dev/null
+osctest
\ No newline at end of file
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change but
+is modified.
--- /dev/null
+http://localhost
--- /dev/null
+<directory name="simple" rev="1" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="1">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+</directory>
\ No newline at end of file
--- /dev/null
+osctest
\ No newline at end of file
--- /dev/null
+This is a simple test.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change but
+is modified.
--- /dev/null
+http://localhost
--- /dev/null
+<directory name="simple3" rev="1" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="1">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+</directory>
--- /dev/null
+osctest
\ No newline at end of file
--- /dev/null
+This is a simple test.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change but
+is modified.
--- /dev/null
+http://localhost
--- /dev/null
+<directory name="working_nonempty" rev="1" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="1">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+</directory>
--- /dev/null
+working_nonempty
--- /dev/null
+osctest
\ No newline at end of file
--- /dev/null
+foo
+remove
--- /dev/null
+This is a simple test.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change but
+is modified.
--- /dev/null
+http://localhost
--- /dev/null
+<directory name="working_nonempty" rev="1" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="1">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+</directory>
--- /dev/null
+working_nonempty
--- /dev/null
+osctest
\ No newline at end of file
--- /dev/null
+This is a simple test.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change but
+is modified.
--- /dev/null
+http://localhost
--- /dev/null
+<directory name="simple6" rev="1" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="1">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+</directory>
--- /dev/null
+osctest
\ No newline at end of file
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change but
+is modified.
--- /dev/null
+http://localhost
--- /dev/null
+<directory name="simple7" rev="1" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="1">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+ <entry md5="ffffffffffffffffffffffffffffffff" mtime="1111111111" name="skipped" size="42" skipped="true" />
+</directory>
--- /dev/null
+osctest
\ No newline at end of file
--- /dev/null
+This is a simple test.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change but
+is modified.
--- /dev/null
+http://localhost
--- /dev/null
+<directory name="simple8" rev="1" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="1">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+ <entry md5="ffffffffffffffffffffffffffffffff" mtime="1111111111" name="skipped" size="42" skipped="true" />
+</directory>
--- /dev/null
+osctest
\ No newline at end of file
--- /dev/null
+This is a simple test.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change but
+is modified.
--- /dev/null
+http://localhost
--- /dev/null
+<directory />
--- /dev/null
+working_empty
--- /dev/null
+http://localhost
--- /dev/null
+<directory name="working_nonempty" rev="1" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="1">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+</directory>
--- /dev/null
+working_nonempty
--- /dev/null
+osctest
\ No newline at end of file
--- /dev/null
+This is a simple test.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change but
+is modified.
--- /dev/null
+noschemeandnotld
--- /dev/null
+<project name="prj_noapiurl" />
--- /dev/null
+prj_invalidapiurl
--- /dev/null
+<project name="prj_noapiurl" />
--- /dev/null
+prj_noapiurl
--- /dev/null
+[general]
+# URL to access API server, e.g. https://api.opensuse.org
+# you also need a section [https://api.opensuse.org] with the credentials
+apiurl = http://localhost
+# Downloaded packages are cached here. Must be writable by you.
+#packagecachedir = /var/tmp/osbuild-packagecache
+# Wrapper to call build as root (sudo, su -, ...)
+#su-wrapper = su -c
+# rootdir to setup the chroot environment
+# can contain %(repo)s, %(arch)s, %(project)s and %(package)s for replacement, e.g.
+# /srv/oscbuild/%(repo)s-%(arch)s or
+# /srv/oscbuild/%(repo)s-%(arch)s-%(project)s-%(package)s
+#build-root = /var/tmp/build-root
+# compile with N jobs (default: "getconf _NPROCESSORS_ONLN")
+#build-jobs = N
+# build-type to use - values can be (depending on the capabilities of the 'build' script)
+# empty - chroot build
+# kvm - kvm VM build (needs build-device, build-swap, build-memory)
+# xen - xen VM build (needs build-device, build-swap, build-memory)
+# experimental:
+# qemu - qemu VM build
+# lxc - lxc build
+#build-type =
+# build-device is the disk-image file to use as root for VM builds
+# e.g. /var/tmp/FILE.root
+#build-device = /var/tmp/FILE.root
+# build-swap is the disk-image to use as swap for VM builds
+# e.g. /var/tmp/FILE.swap
+#build-swap = /var/tmp/FILE.swap
+# build-memory is the amount of memory used in the VM
+# value in MB - e.g. 512
+#build-memory = 512
+# build-vmdisk-rootsize is the size of the disk-image used as root in a VM build
+# values in MB - e.g. 4096
+#build-vmdisk-rootsize = 4096
+# build-vmdisk-swapsize is the size of the disk-image used as swap in a VM build
+# values in MB - e.g. 1024
+#build-vmdisk-swapsize = 1024
+# Numeric uid:gid to assign to the "abuild" user in the build-root
+# or "caller" to use the current users uid:gid
+# This is convenient when sharing the buildroot with ordinary userids
+# on the host.
+# This should not be 0
+# build-uid =
+# extra packages to install when building packages locally (osc build)
+# this corresponds to osc build's -x option and can be overridden with that
+# -x '' can also be given on the command line to override this setting, or
+# you can have an empty setting here.
+#extra-pkgs = vim gdb strace
+# build platform is used if the platform argument is omitted to osc build
+#build_repository = openSUSE_Factory
+# default project for getpac or bco
+#getpac_default_project = openSUSE:Factory
+# alternate filesystem layout: have multiple subdirs, where colons were.
+#checkout_no_colon = 0
+# local files to ignore with status, addremove, ....
+#exclude_glob = .osc CVS .svn .* _linkerror *~ #*# *.orig *.bak *.changes.*
+# keep passwords in plaintext. If you see this comment, your osc
+# already uses the encrypted password, and only keeps them in plain text
+# for backwards compatibility. Default will change to 0 in future releases.
+# You can remove the plaintext password without harm, if you do not need
+# backwards compatibility.
+#plaintext_passwd = 1
+# limit the age of requests shown with 'osc req list'.
+# this is a default only, can be overridden by 'osc req list -D NNN'
+# Use 0 for unlimted.
+#request_list_days = 0
+# show info useful for debugging
+#debug = 1
+# show HTTP traffic useful for debugging
+#http_debug = 1
+# Skip signature verification of packages used for build.
+#no_verify = 1
+# jump into the debugger in case of errors
+#post_mortem = 1
+# print call traces in case of errors
+#traceback = 1
+# use KDE/Gnome/MacOS/Windows keyring for credentials if available
+#use_keyring = 1
+# check for unversioned/removed files before commit
+#check_filelist = 1
+# check for pending requests after executing an action (e.g. checkout, update, commit)
+#check_for_request_on_action = 0
+# what to do with the source package if the submitrequest has been accepted. If
+# nothing is specified the API default is used
+#submitrequest_on_accept_action = cleanup|update|noupdate
+#review requests interactively (default: off)
+#request_show_review = 1
+# Directory with executables to validate sources, esp before committing
+#source_validator_directory = /usr/lib/osc/source_validators
+
+[http://localhost]
+user=Admin
+pass=opensuse
+# set aliases for this apiurl
+# aliases = foo, bar
+# 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
+#http_headers = Host: foofoobar,
+# User: mumblegack
+# Force using of keyring for this API
+#keyring = 1
--- /dev/null
+<request id="42">
+ <action type="submit">
+ <source package="bar" project="foo" rev="1" />
+ <target package="bar" project="foobar" />
+ </action>
+ <action type="delete">
+ <target project="deleteme" />
+ </action>
+ <state name="accepted" when="2010-12-27T01:36:29" who="user1" />
+ <history when="2010-12-13T13:02:03" who="creator">
+ <description>Create Request</description>
+ <comment>foobar</comment>
+ </history>
+ <title>title of the request</title>
+ <description>this is a
+very long
+description</description>
+</request>
--- /dev/null
+<request id="123">
+ <action type="submit">
+ <source package="abc" project="xyz" />
+ <options>
+ <sourceupdate>cleanup</sourceupdate>
+ <updatelink>1</updatelink>
+ </options>
+ </action>
+ <action type="add_role">
+ <target project="home:foo" />
+ <person name="bar" role="maintainer" />
+ <group name="groupxyz" role="reader" />
+ </action>
+ <state name="review" when="2010-12-27T01:36:29" who="abc" />
+ <review by_group="group1" state="new" when="2010-12-28T00:11:22" who="abc">
+ <comment>review start</comment>
+ </review>
+ <history when="2010-12-11T00:00:00" who="creator">
+ <description>Created request</description>
+ </history>
+</request>
--- /dev/null
+<request id="62">
+ <action type="set_bugowner">
+ <target project="foo" />
+ <person name="buguser" />
+ </action>
+ <action type="add_role">
+ <target project="foobar" />
+ <person name="xyz" role="maintainer" />
+ <group name="group1" role="reader" />
+ </action>
+ <action type="add_role">
+ <target project="foo" package="bar" />
+ <person name="abc" role="reviewer" />
+ </action>
+ <action type="change_devel">
+ <source project="devprj" package="devpkg" />
+ <target project="foo" package="bar" />
+ </action>
+ <action type="submit">
+ <source project="srcprj" package="srcpackage" />
+ <target project="tgtprj" package="tgtpackage" />
+ </action>
+ <action type="submit">
+ <source project="foo" package="bar" />
+ <target project="baz" />
+ </action>
+ <action type="delete">
+ <target project="deleteme" />
+ </action>
+ <action type="delete">
+ <target project="foo" package="bar" />
+ </action>
+ <state name="new" when="2010-12-29T14:57:25" who="Admin">
+ <comment></comment>
+ </state>
+</request>
--- /dev/null
+<request id="21">
+ <action type="set_bugowner">
+ <target project="foo" />
+ <person name="buguser" />
+ </action>
+ <state name="accepted" when="2010-12-29T16:37:45" who="foobar" />
+ <history when="2010-12-28T16:37:45" who="user" >
+ <description>Created Request</description>
+ </history>
+ <history when="2010-12-28T18:37:45" who="foobar" >
+ <description>Review Approved</description>
+ </history>
+ <description>This is
+a simple request with a lot of ... ... text and other stuff. This request also contains a
+description. This is useful to
+describe the request. blabla
+blabla</description>
+</request>
--- /dev/null
+<request id="123">
+ <action type="submit">
+ <source package="abc" project="xyz" />
+ <target project="foo" />
+ <options>
+ <sourceupdate>cleanup</sourceupdate>
+ <updatelink>1</updatelink>
+ </options>
+ </action>
+ <action type="add_role">
+ <target project="home:foo" />
+ <person name="bar" role="maintainer" />
+ <group name="groupxyz" role="reader" />
+ </action>
+ <state name="review" when="2010-12-27T01:36:29" who="abc">
+ <comment>currently in review</comment>
+ </state>
+ <review by_group="group1" state="new" when="2010-12-28T00:11:22" who="abc">
+ <comment>review start</comment>
+ </review>
+ <review by_group="group1" state="accepted" when="2010-12-29T00:11:22" who="abc">
+ <comment>accepted</comment>
+ </review>
+ <history name="new" when="2010-12-11T00:00:00" who="creator" />
+ <history name="revoked" when="2010-12-12T00:00:00" who="creator" />
+ <description>just a samll description
+in order to describe this
+request - blablabla
+test.</description>
+</request>
--- /dev/null
+[general]
+# URL to access API server, e.g. https://api.opensuse.org
+# you also need a section [https://api.opensuse.org] with the credentials
+apiurl = http://localhost
+# Downloaded packages are cached here. Must be writable by you.
+#packagecachedir = /var/tmp/osbuild-packagecache
+# Wrapper to call build as root (sudo, su -, ...)
+#su-wrapper = su -c
+# rootdir to setup the chroot environment
+# can contain %(repo)s, %(arch)s, %(project)s and %(package)s for replacement, e.g.
+# /srv/oscbuild/%(repo)s-%(arch)s or
+# /srv/oscbuild/%(repo)s-%(arch)s-%(project)s-%(package)s
+#build-root = /var/tmp/build-root
+# compile with N jobs (default: "getconf _NPROCESSORS_ONLN")
+#build-jobs = N
+# build-type to use - values can be (depending on the capabilities of the 'build' script)
+# empty - chroot build
+# kvm - kvm VM build (needs build-device, build-swap, build-memory)
+# xen - xen VM build (needs build-device, build-swap, build-memory)
+# experimental:
+# qemu - qemu VM build
+# lxc - lxc build
+#build-type =
+# build-device is the disk-image file to use as root for VM builds
+# e.g. /var/tmp/FILE.root
+#build-device = /var/tmp/FILE.root
+# build-swap is the disk-image to use as swap for VM builds
+# e.g. /var/tmp/FILE.swap
+#build-swap = /var/tmp/FILE.swap
+# build-memory is the amount of memory used in the VM
+# value in MB - e.g. 512
+#build-memory = 512
+# build-vmdisk-rootsize is the size of the disk-image used as root in a VM build
+# values in MB - e.g. 4096
+#build-vmdisk-rootsize = 4096
+# build-vmdisk-swapsize is the size of the disk-image used as swap in a VM build
+# values in MB - e.g. 1024
+#build-vmdisk-swapsize = 1024
+# Numeric uid:gid to assign to the "abuild" user in the build-root
+# or "caller" to use the current users uid:gid
+# This is convenient when sharing the buildroot with ordinary userids
+# on the host.
+# This should not be 0
+# build-uid =
+# extra packages to install when building packages locally (osc build)
+# this corresponds to osc build's -x option and can be overridden with that
+# -x '' can also be given on the command line to override this setting, or
+# you can have an empty setting here.
+#extra-pkgs = vim gdb strace
+# build platform is used if the platform argument is omitted to osc build
+#build_repository = openSUSE_Factory
+# default project for getpac or bco
+#getpac_default_project = openSUSE:Factory
+# alternate filesystem layout: have multiple subdirs, where colons were.
+#checkout_no_colon = 0
+# local files to ignore with status, addremove, ....
+#exclude_glob = .osc CVS .svn .* _linkerror *~ #*# *.orig *.bak *.changes.*
+# keep passwords in plaintext. If you see this comment, your osc
+# already uses the encrypted password, and only keeps them in plain text
+# for backwards compatibility. Default will change to 0 in future releases.
+# You can remove the plaintext password without harm, if you do not need
+# backwards compatibility.
+#plaintext_passwd = 1
+# limit the age of requests shown with 'osc req list'.
+# this is a default only, can be overridden by 'osc req list -D NNN'
+# Use 0 for unlimted.
+#request_list_days = 0
+# show info useful for debugging
+#debug = 1
+# show HTTP traffic useful for debugging
+#http_debug = 1
+# Skip signature verification of packages used for build.
+#no_verify = 1
+# jump into the debugger in case of errors
+#post_mortem = 1
+# print call traces in case of errors
+#traceback = 1
+# use KDE/Gnome/MacOS/Windows keyring for credentials if available
+#use_keyring = 1
+# check for unversioned/removed files before commit
+#check_filelist = 1
+# check for pending requests after executing an action (e.g. checkout, update, commit)
+#check_for_request_on_action = 0
+# what to do with the source package if the submitrequest has been accepted. If
+# nothing is specified the API default is used
+#submitrequest_on_accept_action = cleanup|update|noupdate
+#review requests interactively (default: off)
+#request_show_review = 1
+# Directory with executables to validate sources, esp before committing
+#source_validator_directory = /usr/lib/osc/source_validators
+
+[http://localhost]
+user=Admin
+pass=opensuse
+# set aliases for this apiurl
+# aliases = foo, bar
+# 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
+#http_headers = Host: foofoobar,
+# User: mumblegack
+# Force using of keyring for this API
+#keyring = 1
--- /dev/null
+http://localhost
--- /dev/null
+<project name="osctest" />
--- /dev/null
+http://localhost
--- /dev/null
+<directory name="conflict" rev="2" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="2">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+ <entry md5="eb9c2bf0eb63f3a7bc0ea37ef18aeba5" mtime="1282730880" name="somefile" size="13" />
+ <entry md5="81be947db54c2e225dc8eacce64d8a4a" mtime="1282731457" name="replaced" size="17" />
+ <entry md5="676513fde5797c3785164942c97dfec1" mtime="1282731738" name="missing" size="8" />
+ <entry md5="ffffffffffffffffffffffffffffffff" mtime="1111111111" name="deleted" size="9" />
+ <entry md5="ffffffffffffffffffffffffffffffff" mtime="1111111111" name="skipped" size="12" skipped="true" />
+</directory>
--- /dev/null
+simple
\ No newline at end of file
--- /dev/null
+osctest
\ No newline at end of file
--- /dev/null
+toadd1
+replaced
+addedmissing
--- /dev/null
+somefile
+deleted
--- /dev/null
+This is a simple test.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change.
--- /dev/null
+yet another file
--- /dev/null
+some content
--- /dev/null
+<<<<<<< foo.mine
+This is no test.
+=======
+This is a simple test.
+>>>>>>> foo.r2
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change but
+is modified.
--- /dev/null
+foo replaced
--- /dev/null
+<directory name="srcpkg" rev="eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" srcmd5="eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" vrev="1">
+ <linkinfo project="srcsrcprj" package="srcsrcpkg" srcmd5="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" baserev="bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" xsrcmd5="eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" lsrcmd5="cccccccccccccccccccccccccccccccc" />
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="_link" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+</directory>
--- /dev/null
+<link package="srcpkg" project="srcprj" rev="7" />
--- /dev/null
+<link package="srcpkg" project="srcprj" rev="eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" vrev="1" />
--- /dev/null
+<link package="srcpkg" />
--- /dev/null
+[general]
+# URL to access API server, e.g. https://api.opensuse.org
+# you also need a section [https://api.opensuse.org] with the credentials
+apiurl = http://localhost
+# Downloaded packages are cached here. Must be writable by you.
+#packagecachedir = /var/tmp/osbuild-packagecache
+# Wrapper to call build as root (sudo, su -, ...)
+#su-wrapper = su -c
+# rootdir to setup the chroot environment
+# can contain %(repo)s, %(arch)s, %(project)s and %(package)s for replacement, e.g.
+# /srv/oscbuild/%(repo)s-%(arch)s or
+# /srv/oscbuild/%(repo)s-%(arch)s-%(project)s-%(package)s
+#build-root = /var/tmp/build-root
+# compile with N jobs (default: "getconf _NPROCESSORS_ONLN")
+#build-jobs = N
+# build-type to use - values can be (depending on the capabilities of the 'build' script)
+# empty - chroot build
+# kvm - kvm VM build (needs build-device, build-swap, build-memory)
+# xen - xen VM build (needs build-device, build-swap, build-memory)
+# experimental:
+# qemu - qemu VM build
+# lxc - lxc build
+#build-type =
+# build-device is the disk-image file to use as root for VM builds
+# e.g. /var/tmp/FILE.root
+#build-device = /var/tmp/FILE.root
+# build-swap is the disk-image to use as swap for VM builds
+# e.g. /var/tmp/FILE.swap
+#build-swap = /var/tmp/FILE.swap
+# build-memory is the amount of memory used in the VM
+# value in MB - e.g. 512
+#build-memory = 512
+# build-vmdisk-rootsize is the size of the disk-image used as root in a VM build
+# values in MB - e.g. 4096
+#build-vmdisk-rootsize = 4096
+# build-vmdisk-swapsize is the size of the disk-image used as swap in a VM build
+# values in MB - e.g. 1024
+#build-vmdisk-swapsize = 1024
+# Numeric uid:gid to assign to the "abuild" user in the build-root
+# or "caller" to use the current users uid:gid
+# This is convenient when sharing the buildroot with ordinary userids
+# on the host.
+# This should not be 0
+# build-uid =
+# extra packages to install when building packages locally (osc build)
+# this corresponds to osc build's -x option and can be overridden with that
+# -x '' can also be given on the command line to override this setting, or
+# you can have an empty setting here.
+#extra-pkgs = vim gdb strace
+# build platform is used if the platform argument is omitted to osc build
+#build_repository = openSUSE_Factory
+# default project for getpac or bco
+#getpac_default_project = openSUSE:Factory
+# alternate filesystem layout: have multiple subdirs, where colons were.
+#checkout_no_colon = 0
+# local files to ignore with status, addremove, ....
+#exclude_glob = .osc CVS .svn .* _linkerror *~ #*# *.orig *.bak *.changes.*
+# keep passwords in plaintext. If you see this comment, your osc
+# already uses the encrypted password, and only keeps them in plain text
+# for backwards compatibility. Default will change to 0 in future releases.
+# You can remove the plaintext password without harm, if you do not need
+# backwards compatibility.
+#plaintext_passwd = 1
+# limit the age of requests shown with 'osc req list'.
+# this is a default only, can be overridden by 'osc req list -D NNN'
+# Use 0 for unlimted.
+#request_list_days = 0
+# show info useful for debugging
+#debug = 1
+# show HTTP traffic useful for debugging
+#http_debug = 1
+# Skip signature verification of packages used for build.
+#no_verify = 1
+# jump into the debugger in case of errors
+#post_mortem = 1
+# print call traces in case of errors
+#traceback = 1
+# use KDE/Gnome/MacOS/Windows keyring for credentials if available
+#use_keyring = 1
+# check for unversioned/removed files before commit
+#check_filelist = 1
+# check for pending requests after executing an action (e.g. checkout, update, commit)
+#check_for_request_on_action = 0
+# what to do with the source package if the submitrequest has been accepted. If
+# nothing is specified the API default is used
+#submitrequest_on_accept_action = cleanup|update|noupdate
+#review requests interactively (default: off)
+#request_show_review = 1
+# Directory with executables to validate sources, esp before committing
+#source_validator_directory = /usr/lib/osc/source_validators
+
+[http://localhost]
+user=Admin
+pass=opensuse
+# set aliases for this apiurl
+# aliases = foo, bar
+# 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
+#http_headers = Host: foofoobar,
+# User: mumblegack
+# Force using of keyring for this API
+#keyring = 1
--- /dev/null
+<link package="srcpkg" project="srcprj" rev="42" />
--- /dev/null
+<directory name="srcpkg" rev="42" srcmd5="ffffffffffffffffffffffffffffffff" vrev="1">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+</directory>
--- /dev/null
+<link package="srcpkg" project="srcprj" />
--- /dev/null
+import os.path
+import sys
+import unittest
+
+try:
+ import xmlrunner # JUnit like XML reporting
+ have_xmlrunner = True
+except ImportError:
+ have_xmlrunner = False
+
+import test_update
+import test_addfiles
+import test_deletefiles
+import test_revertfiles
+import test_difffiles
+import test_init_package
+import test_init_project
+import test_commit
+import test_repairwc
+import test_package_status
+import test_project_status
+import test_request
+import test_setlinkrev
+import test_prdiff
+import test_conf
+
+suite = unittest.TestSuite()
+suite.addTests(test_addfiles.suite())
+suite.addTests(test_deletefiles.suite())
+suite.addTests(test_revertfiles.suite())
+suite.addTests(test_update.suite())
+suite.addTests(test_difffiles.suite())
+suite.addTests(test_init_package.suite())
+suite.addTests(test_init_project.suite())
+suite.addTests(test_commit.suite())
+suite.addTests(test_repairwc.suite())
+suite.addTests(test_package_status.suite())
+suite.addTests(test_project_status.suite())
+suite.addTests(test_request.suite())
+suite.addTests(test_setlinkrev.suite())
+suite.addTests(test_prdiff.suite())
+suite.addTests(test_conf.suite())
+
+if have_xmlrunner:
+ result = xmlrunner.XMLTestRunner(output=os.path.join(os.getcwd(), 'junit-xml-results')).run(suite)
+else:
+ result = unittest.TextTestRunner(verbosity=1).run(suite)
+sys.exit(not result.wasSuccessful())
--- /dev/null
+import osc.core
+import osc.oscerr
+import os
+import sys
+from common import OscTestCase
+
+FIXTURES_DIR = os.path.join(os.getcwd(), 'tests/addfile_fixtures')
+
+def suite():
+ import unittest
+ return unittest.makeSuite(TestAddFiles)
+
+class TestAddFiles(OscTestCase):
+ def _get_fixtures_dir(self):
+ return FIXTURES_DIR
+
+ def testSimpleAdd(self):
+ """add one file ('toadd1') to the wc"""
+ self._change_to_pkg('simple')
+ p = osc.core.Package('.')
+ p.addfile('toadd1')
+ exp = 'A toadd1\n'
+ self.assertEqual(sys.stdout.getvalue(), exp)
+ self.assertFalse(os.path.exists(os.path.join('.osc', 'toadd1')))
+ self._check_status(p, 'toadd1', 'A')
+ self._check_addlist('toadd1\n')
+
+ def testSimpleMultipleAdd(self):
+ """add multiple files ('toadd1', 'toadd2') to the wc"""
+ self._change_to_pkg('simple')
+ p = osc.core.Package('.')
+ p.addfile('toadd1')
+ p.addfile('toadd2')
+ exp = 'A toadd1\nA toadd2\n'
+ self.assertEqual(sys.stdout.getvalue(), exp)
+ self.assertFalse(os.path.exists(os.path.join('.osc', 'toadd1')))
+ self.assertFalse(os.path.exists(os.path.join('.osc', 'toadd2')))
+ self._check_status(p, 'toadd1', 'A')
+ self._check_status(p, 'toadd2', 'A')
+ self._check_addlist('toadd1\ntoadd2\n')
+
+ def testAddVersionedFile(self):
+ """add a versioned file"""
+ self._change_to_pkg('simple')
+ p = osc.core.Package('.')
+ self.assertRaises(osc.oscerr.PackageFileConflict, p.addfile, 'merge')
+ self.assertFalse(os.path.exists(os.path.join('.osc', '_to_be_added')))
+ self._check_status(p, 'merge', ' ')
+
+ def testAddUnversionedFileTwice(self):
+ """add the same file twice"""
+ self._change_to_pkg('simple')
+ p = osc.core.Package('.')
+ p.addfile('toadd1')
+ self.assertRaises(osc.oscerr.PackageFileConflict, p.addfile, 'toadd1')
+ exp = 'A toadd1\n'
+ self.assertEqual(sys.stdout.getvalue(), exp)
+ self.assertFalse(os.path.exists(os.path.join('.osc', 'toadd1')))
+ self._check_status(p, 'toadd1', 'A')
+ self._check_addlist('toadd1\n')
+
+ def testReplace(self):
+ """replace a deleted file ('foo')"""
+ self._change_to_pkg('simple')
+ p = osc.core.Package('.')
+ open('foo', 'w').write('replaced file\n')
+ p.addfile('foo')
+ exp = 'A foo\n'
+ self.assertEqual(sys.stdout.getvalue(), exp)
+ self.assertTrue(os.path.exists(os.path.join('.osc', 'foo')))
+ self.assertNotEqual(open(os.path.join('.osc', 'foo'), 'r').read(), 'replaced file\n')
+ self.assertFalse(os.path.exists(os.path.join('.osc', '_to_be_deleted')))
+ self._check_status(p, 'foo', 'R')
+ self._check_addlist('foo\n')
+
+ def testAddNonExistentFile(self):
+ """add a non existent file"""
+ self._change_to_pkg('simple')
+ p = osc.core.Package('.')
+ self.assertRaises(osc.oscerr.OscIOError, p.addfile, 'doesnotexist')
+ self.assertFalse(os.path.exists(os.path.join('.osc', '_to_be_added')))
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main()
--- /dev/null
+import osc.core
+import osc.oscerr
+import os
+import sys
+import urllib2
+from common import GET, PUT, POST, DELETE, OscTestCase
+from xml.etree import cElementTree as ET
+FIXTURES_DIR = os.path.join(os.getcwd(), 'tests/commit_fixtures')
+
+def suite():
+ import unittest
+ return unittest.makeSuite(TestCommit)
+
+rev_dummy = '<revision rev="repository">\n <srcmd5>empty</srcmd5>\n</revision>'
+
+class TestCommit(OscTestCase):
+ def _get_fixtures_dir(self):
+ return FIXTURES_DIR
+
+ @GET('http://localhost/source/osctest/simple?rev=latest', file='testSimple_filesremote')
+ @POST('http://localhost/source/osctest/simple?cmd=getprojectservices',
+ exp='', text='<services />')
+ @POST('http://localhost/source/osctest/simple?comment=&cmd=commitfilelist&user=Admin',
+ file='testSimple_missingfilelist', expfile='testSimple_lfilelist')
+ @PUT('http://localhost/source/osctest/simple/nochange?rev=repository',
+ exp='This file didn\'t change but\nis modified.\n', text=rev_dummy)
+ @POST('http://localhost/source/osctest/simple?comment=&cmd=commitfilelist&user=Admin',
+ file='testSimple_cfilesremote', expfile='testSimple_lfilelist')
+ def test_simple(self):
+ """a simple commit (only one modified file)"""
+ self._change_to_pkg('simple')
+ p = osc.core.Package('.')
+ p.commit()
+ exp = 'Sending nochange\nTransmitting file data .\nCommitted revision 2.\n'
+ self.assertEqual(sys.stdout.getvalue(), exp)
+ self._check_digests('testSimple_cfilesremote')
+ self.assertTrue(os.path.exists('nochange'))
+ self.assertEqual(open('nochange', 'r').read(), open(os.path.join('.osc', 'nochange'), 'r').read())
+ self._check_status(p, 'nochange', ' ')
+ self._check_status(p, 'foo', ' ')
+ self._check_status(p, 'merge', ' ')
+
+ @GET('http://localhost/source/osctest/add?rev=latest', file='testAddfile_filesremote')
+ @POST('http://localhost/source/osctest/add?cmd=getprojectservices',
+ exp='', text='<services />')
+ @POST('http://localhost/source/osctest/add?comment=&cmd=commitfilelist&user=Admin',
+ file='testAddfile_missingfilelist', expfile='testAddfile_lfilelist')
+ @PUT('http://localhost/source/osctest/add/add?rev=repository',
+ exp='added file\n', text=rev_dummy)
+ @POST('http://localhost/source/osctest/add?comment=&cmd=commitfilelist&user=Admin',
+ file='testAddfile_cfilesremote', expfile='testAddfile_lfilelist')
+ def test_addfile(self):
+ """commit a new file"""
+ self._change_to_pkg('add')
+ p = osc.core.Package('.')
+ p.commit()
+ exp = 'Sending add\nTransmitting file data .\nCommitted revision 2.\n'
+ self.assertEqual(sys.stdout.getvalue(), exp)
+ self._check_digests('testAddfile_cfilesremote')
+ self.assertTrue(os.path.exists('add'))
+ self.assertEqual(open('add', 'r').read(), open(os.path.join('.osc', 'add'), 'r').read())
+ self.assertFalse(os.path.exists(os.path.join('.osc', '_to_be_added')))
+ self._check_status(p, 'add', ' ')
+ self._check_status(p, 'foo', ' ')
+ self._check_status(p, 'merge', ' ')
+ self._check_status(p, 'nochange', ' ')
+
+ @GET('http://localhost/source/osctest/delete?rev=latest', file='testDeletefile_filesremote')
+ @POST('http://localhost/source/osctest/delete?cmd=getprojectservices',
+ exp='', text='<services />')
+ @POST('http://localhost/source/osctest/delete?comment=&cmd=commitfilelist&user=Admin',
+ file='testDeletefile_cfilesremote', expfile='testDeletefile_lfilelist')
+ def test_deletefile(self):
+ """delete a file"""
+ self._change_to_pkg('delete')
+ p = osc.core.Package('.')
+ p.commit()
+ exp = 'Deleting nochange\nTransmitting file data \nCommitted revision 2.\n'
+ self.assertEqual(sys.stdout.getvalue(), exp)
+ self._check_digests('testDeletefile_cfilesremote')
+ self.assertFalse(os.path.exists('nochange'))
+ self.assertFalse(os.path.exists(os.path.join('.osc', 'nochange')))
+ self.assertFalse(os.path.exists(os.path.join('.osc', '_to_be_deleted')))
+ self._check_status(p, 'foo', ' ')
+ self._check_status(p, 'merge', ' ')
+
+ @GET('http://localhost/source/osctest/conflict?rev=latest', file='testConflictfile_filesremote')
+ @POST('http://localhost/source/osctest/conflict?cmd=getprojectservices',
+ exp='', text='<services />')
+ def test_conflictfile(self):
+ """package has a file which is in conflict state"""
+ self._change_to_pkg('conflict')
+ ret = osc.core.Package('.').commit()
+ self.assertTrue(ret == 1)
+ exp = 'Please resolve all conflicts before committing using "osc resolved FILE"!\n'
+ self.assertEqual(sys.stdout.getvalue(), exp)
+ self._check_digests('testConflictfile_filesremote')
+ self._check_conflictlist('merge\n')
+
+ @GET('http://localhost/source/osctest/nochanges?rev=latest', file='testNoChanges_filesremote')
+ @POST('http://localhost/source/osctest/nochanges?cmd=getprojectservices',
+ exp='', text='<services />')
+ def test_nochanges(self):
+ """package has no changes (which can be committed)"""
+ self._change_to_pkg('nochanges')
+ p = osc.core.Package('.')
+ ret = p.commit()
+ self.assertTrue(ret == 1)
+ exp = 'nothing to do for package nochanges\n'
+ self.assertEqual(sys.stdout.getvalue(), exp)
+ self._check_status(p, 'foo', 'S')
+ self._check_status(p, 'merge', '!')
+ self._check_status(p, 'nochange', ' ')
+
+ @GET('http://localhost/source/osctest/multiple?rev=latest', file='testMultiple_filesremote')
+ @POST('http://localhost/source/osctest/multiple?cmd=getprojectservices',
+ exp='', text='<services />')
+ @POST('http://localhost/source/osctest/multiple?comment=&cmd=commitfilelist&user=Admin',
+ file='testMultiple_missingfilelist', expfile='testMultiple_lfilelist')
+ @PUT('http://localhost/source/osctest/multiple/nochange?rev=repository', exp='This file did change.\n', text=rev_dummy)
+ @PUT('http://localhost/source/osctest/multiple/add?rev=repository', exp='added file\n', text=rev_dummy)
+ @PUT('http://localhost/source/osctest/multiple/add2?rev=repository', exp='add2\n', text=rev_dummy)
+ @POST('http://localhost/source/osctest/multiple?comment=&cmd=commitfilelist&user=Admin',
+ file='testMultiple_cfilesremote', expfile='testMultiple_lfilelist')
+ def test_multiple(self):
+ """a simple commit (only one modified file)"""
+ self._change_to_pkg('multiple')
+ p = osc.core.Package('.')
+ p.commit()
+ exp = 'Deleting foo\nDeleting merge\nSending nochange\n' \
+ 'Sending add\nSending add2\nTransmitting file data ...\nCommitted revision 2.\n'
+ self.assertEqual(sys.stdout.getvalue(), exp)
+ self._check_digests('testMultiple_cfilesremote')
+ self.assertFalse(os.path.exists(os.path.join('.osc', '_to_be_added')))
+ self.assertFalse(os.path.exists(os.path.join('.osc', '_to_be_deleted')))
+ self.assertFalse(os.path.exists(os.path.join('.osc', 'foo')))
+ self.assertFalse(os.path.exists(os.path.join('.osc', 'merge')))
+ self.assertRaises(osc.oscerr.OscIOError, p.status, 'foo')
+ self.assertRaises(osc.oscerr.OscIOError, p.status, 'merge')
+ self._check_status(p, 'add', ' ')
+ self._check_status(p, 'add2', ' ')
+ self._check_status(p, 'nochange', ' ')
+
+ @GET('http://localhost/source/osctest/multiple?rev=latest', file='testPartial_filesremote')
+ @POST('http://localhost/source/osctest/multiple?cmd=getprojectservices',
+ exp='', text='<services />')
+ @POST('http://localhost/source/osctest/multiple?comment=&cmd=commitfilelist&user=Admin',
+ file='testPartial_missingfilelist', expfile='testPartial_lfilelist')
+ @PUT('http://localhost/source/osctest/multiple/add?rev=repository', exp='added file\n', text=rev_dummy)
+ @PUT('http://localhost/source/osctest/multiple/nochange?rev=repository', exp='This file did change.\n', text=rev_dummy)
+ @POST('http://localhost/source/osctest/multiple?comment=&cmd=commitfilelist&user=Admin',
+ file='testPartial_cfilesremote', expfile='testPartial_lfilelist')
+ def test_partial(self):
+ """commit only some files"""
+ self._change_to_pkg('multiple')
+ p = osc.core.Package('.')
+ p.todo = ['foo', 'add', 'nochange']
+ p.commit()
+ exp = 'Deleting foo\nSending nochange\n' \
+ 'Sending add\nTransmitting file data ..\nCommitted revision 2.\n'
+ self.assertEqual(sys.stdout.getvalue(), exp)
+ self._check_digests('testPartial_cfilesremote')
+ self._check_addlist('add2\n')
+ self._check_deletelist('merge\n')
+ self._check_status(p, 'add2', 'A')
+ self._check_status(p, 'merge', 'D')
+ self._check_status(p, 'add', ' ')
+ self._check_status(p, 'nochange', ' ')
+ self.assertRaises(osc.oscerr.OscIOError, p.status, 'foo')
+
+ @GET('http://localhost/source/osctest/simple?rev=latest', file='testSimple_filesremote')
+ @POST('http://localhost/source/osctest/simple?cmd=getprojectservices',
+ exp='', text='<services />')
+ @POST('http://localhost/source/osctest/simple?comment=&cmd=commitfilelist&user=Admin',
+ file='testSimple_missingfilelist', expfile='testSimple_lfilelist')
+ @PUT('http://localhost/source/osctest/simple/nochange?rev=repository', exp='This file didn\'t change but\nis modified.\n',
+ exception=IOError('test exception'), text=rev_dummy)
+ def test_interrupt(self):
+ """interrupt a commit"""
+ self._change_to_pkg('simple')
+ p = osc.core.Package('.')
+ self.assertRaises(IOError, p.commit)
+ exp = 'Sending nochange\nTransmitting file data .'
+ self.assertTrue(sys.stdout.getvalue(), exp)
+ self._check_digests('testSimple_filesremote')
+ self.assertTrue(os.path.exists('nochange'))
+ self._check_status(p, 'nochange', 'M')
+
+ @GET('http://localhost/source/osctest/allstates?rev=latest', file='testPartial_filesremote')
+ @POST('http://localhost/source/osctest/allstates?cmd=getprojectservices',
+ exp='', text='<services />')
+ @POST('http://localhost/source/osctest/allstates?comment=&cmd=commitfilelist&user=Admin',
+ file='testAllStates_missingfilelist', expfile='testAllStates_lfilelist')
+ @PUT('http://localhost/source/osctest/allstates/add?rev=repository', exp='added file\n', text=rev_dummy)
+ @PUT('http://localhost/source/osctest/allstates/missing?rev=repository', exp='replaced\n', text=rev_dummy)
+ @PUT('http://localhost/source/osctest/allstates/nochange?rev=repository', exp='This file did change.\n', text=rev_dummy)
+ @POST('http://localhost/source/osctest/allstates?comment=&cmd=commitfilelist&user=Admin',
+ file='testAllStates_cfilesremote', expfile='testAllStates_lfilelist')
+ def test_allstates(self):
+ """commit all files (all states are available except 'C')"""
+ self._change_to_pkg('allstates')
+ p = osc.core.Package('.')
+ p.commit()
+ exp = 'Deleting foo\nSending missing\nSending nochange\n' \
+ 'Sending add\nTransmitting file data ...\nCommitted revision 2.\n'
+ self.assertEqual(sys.stdout.getvalue(), exp)
+ self._check_digests('testAllStates_expfiles', 'skipped')
+ self.assertFalse(os.path.exists(os.path.join('.osc', '_to_be_added')))
+ self.assertFalse(os.path.exists(os.path.join('.osc', '_to_be_deleted')))
+ self.assertFalse(os.path.exists('foo'))
+ self.assertFalse(os.path.exists(os.path.join('.osc', 'foo')))
+ self._check_status(p, 'add', ' ')
+ self._check_status(p, 'nochange', ' ')
+ self._check_status(p, 'merge', '!')
+ self._check_status(p, 'missing', ' ')
+ self._check_status(p, 'skipped', 'S')
+ self._check_status(p, 'test', ' ')
+
+ @GET('http://localhost/source/osctest/add?rev=latest', file='testAddfile_filesremote')
+ @POST('http://localhost/source/osctest/add?cmd=getprojectservices',
+ exp='', text='<services />')
+ @POST('http://localhost/source/osctest/add?comment=&cmd=commitfilelist&user=Admin',
+ file='testAddfile_cfilesremote', expfile='testAddfile_lfilelist')
+ def test_remoteexists(self):
+ """file 'add' should be committed but already exists on the server"""
+ self._change_to_pkg('add')
+ p = osc.core.Package('.')
+ p.commit()
+ exp = 'Sending add\nTransmitting file data \nCommitted revision 2.\n'
+ self.assertEqual(sys.stdout.getvalue(), exp)
+ self._check_digests('testAddfile_cfilesremote')
+ self.assertTrue(os.path.exists('add'))
+ self.assertEqual(open('add', 'r').read(), open(os.path.join('.osc', 'add'), 'r').read())
+ self.assertFalse(os.path.exists(os.path.join('.osc', '_to_be_added')))
+ self._check_status(p, 'add', ' ')
+ self._check_status(p, 'foo', ' ')
+ self._check_status(p, 'merge', ' ')
+ self._check_status(p, 'nochange', ' ')
+
+ @GET('http://localhost/source/osctest/branch?rev=latest', file='testExpand_filesremote')
+ @POST('http://localhost/source/osctest/branch?cmd=getprojectservices',
+ exp='', text='<services />')
+ @POST('http://localhost/source/osctest/branch?comment=&cmd=commitfilelist&user=Admin&keeplink=1',
+ file='testExpand_missingfilelist', expfile='testExpand_lfilelist')
+ @PUT('http://localhost/source/osctest/branch/simple?rev=repository', exp='simple modified file.\n', text=rev_dummy)
+ @POST('http://localhost/source/osctest/branch?comment=&cmd=commitfilelist&user=Admin&keeplink=1',
+ file='testExpand_cfilesremote', expfile='testExpand_lfilelist')
+ @GET('http://localhost/source/osctest/branch?rev=87ea02aede261b0267aabaa97c756e7a', file='testExpand_expandedfilesremote')
+ def test_expand(self):
+ """commit an expanded package"""
+ self._change_to_pkg('branch')
+ p = osc.core.Package('.')
+ p.commit()
+ exp = 'Sending simple\nTransmitting file data .\nCommitted revision 7.\n'
+ self.assertEqual(sys.stdout.getvalue(), exp)
+ self._check_digests('testExpand_expandedfilesremote')
+ self._check_status(p, 'simple', ' ')
+
+ @GET('http://localhost/source/osctest/added_missing?rev=latest', file='testAddedMissing_filesremote')
+ @POST('http://localhost/source/osctest/added_missing?cmd=getprojectservices',
+ exp='', text='<services />')
+ def test_added_missing(self):
+ """commit an added file which is missing"""
+ self._change_to_pkg('added_missing')
+ p = osc.core.Package('.')
+ ret = p.commit()
+ self.assertTrue(ret == 1)
+ exp = 'file \'add\' is marked as \'A\' but does not exist\n'
+ self.assertEqual(sys.stdout.getvalue(), exp)
+ self._check_status(p, 'add', '!')
+
+ @GET('http://localhost/source/osctest/added_missing?rev=latest', file='testAddedMissing_filesremote')
+ @POST('http://localhost/source/osctest/added_missing?cmd=getprojectservices',
+ exp='', text='<services />')
+ @POST('http://localhost/source/osctest/added_missing?comment=&cmd=commitfilelist&user=Admin',
+ file='testAddedMissing_missingfilelist', expfile='testAddedMissing_lfilelist')
+ @PUT('http://localhost/source/osctest/added_missing/bar?rev=repository', exp='foobar\n', text=rev_dummy)
+ @POST('http://localhost/source/osctest/added_missing?comment=&cmd=commitfilelist&user=Admin',
+ file='testAddedMissing_cfilesremote', expfile='testAddedMissing_lfilelist')
+ def test_added_missing2(self):
+ """commit an added file, another added file missing (but it's not part of the commit)"""
+ self._change_to_pkg('added_missing')
+ p = osc.core.Package('.')
+ p.todo = ['bar']
+ p.commit()
+ exp = 'Sending bar\nTransmitting file data .\nCommitted revision 2.\n'
+ self.assertEqual(sys.stdout.getvalue(), exp)
+ self._check_status(p, 'add', '!')
+ self._check_status(p, 'bar', ' ')
+
+ @GET('http://localhost/source/osctest/simple?rev=latest', file='testSimple_filesremote')
+ @POST('http://localhost/source/osctest/simple?cmd=getprojectservices',
+ exp='', text='<services />')
+ @POST('http://localhost/source/osctest/simple?comment=&cmd=commitfilelist&user=Admin',
+ file='testSimple_missingfilelist', expfile='testSimple_lfilelist')
+ @PUT('http://localhost/source/osctest/simple/nochange?rev=repository',
+ exp='This file didn\'t change but\nis modified.\n', text=rev_dummy)
+ @POST('http://localhost/source/osctest/simple?comment=&cmd=commitfilelist&user=Admin',
+ expfile='testSimple_lfilelist', text='an error occured', code=500)
+ def test_commitfilelist_error(self):
+ """commit modified file but when committing the filelist the server returns status 500 (see ticket #65)"""
+ self._change_to_pkg('simple')
+ p = osc.core.Package('.')
+ self._check_status(p, 'nochange', 'M')
+ self.assertRaises(urllib2.HTTPError, p.commit)
+ exp = 'Sending nochange\nTransmitting file data .'
+ self.assertEqual(sys.stdout.getvalue(), exp)
+ self._check_status(p, 'nochange', 'M')
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main()
--- /dev/null
+from osc.conf import passx_encode, passx_decode
+from common import OscTestCase
+
+import os
+
+FIXTURES_DIR = os.path.join(os.getcwd(), 'tests/conf_fixtures')
+
+def suite():
+ import unittest
+ return unittest.makeSuite(TestConf)
+
+class TestConf(OscTestCase):
+ def _get_fixtures_dir(self):
+ return FIXTURES_DIR
+
+ def setUp(self):
+ return super(TestConf, self).setUp(copytree=False)
+
+ def testPassxEncodeDecode(self):
+
+ passwd = "J0e'sPassword!@#"
+ passx = passx_encode(passwd)
+ #base64.b64encode(passwd.encode('bz2'))
+ passx27 = "QlpoOTFBWSZTWaDg4dQAAAKfgCiAQABAEEAAJgCYgCAAMQAACEyYmTyei67AsYSDSaLuSKcKEhQcHDqA"
+
+ self.assertEqual(passwd, passx_decode(passx))
+ self.assertEqual(passwd, passx_decode(passx27))
+ self.assertEqual(passx, passx27)
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main()
--- /dev/null
+import osc.core
+import osc.oscerr
+import os
+from common import OscTestCase
+
+FIXTURES_DIR = os.path.join(os.getcwd(), 'tests/deletefile_fixtures')
+
+def suite():
+ import unittest
+ return unittest.makeSuite(TestDeleteFiles)
+
+class TestDeleteFiles(OscTestCase):
+ def _get_fixtures_dir(self):
+ return FIXTURES_DIR
+
+ def testSimpleRemove(self):
+ """delete a file ('foo') from the wc"""
+ self._change_to_pkg('simple')
+ p = osc.core.Package('.')
+ ret = p.delete_file('foo')
+ self.__check_ret(ret, True, ' ')
+ self.assertFalse(os.path.exists('foo'))
+ self.assertTrue(os.path.exists(os.path.join('.osc', 'foo')))
+ self._check_deletelist('foo\n')
+ self._check_status(p, 'foo', 'D')
+
+ def testDeleteModified(self):
+ """delete modified file ('nochange') from the wc (without force)"""
+ self._change_to_pkg('simple')
+ p = osc.core.Package('.')
+ ret = p.delete_file('nochange')
+ self.__check_ret(ret, False, 'M')
+ self.assertTrue(os.path.exists('nochange'))
+ self.assertTrue(os.path.exists(os.path.join('.osc', 'nochange')))
+ self.assertFalse(os.path.exists(os.path.join('.osc', '_to_be_deleted')))
+ self._check_status(p, 'nochange', 'M')
+
+ def testDeleteUnversioned(self):
+ """delete an unversioned file ('toadd2') from the wc"""
+ self._change_to_pkg('simple')
+ p = osc.core.Package('.')
+ ret = p.delete_file('toadd2')
+ self.__check_ret(ret, False, '?')
+ self.assertTrue(os.path.exists('toadd2'))
+ self.assertFalse(os.path.exists(os.path.join('.osc', '_to_be_deleted')))
+ self._check_status(p, 'toadd2', '?')
+
+ def testDeleteAdded(self):
+ """delete an added file ('toadd1') from the wc (without force)"""
+ self._change_to_pkg('simple')
+ p = osc.core.Package('.')
+ ret = p.delete_file('toadd1')
+ self.__check_ret(ret, False, 'A')
+ self.assertTrue(os.path.exists('toadd1'))
+ self.assertFalse(os.path.exists(os.path.join('.osc', '_to_be_deleted')))
+ self._check_status(p, 'toadd1', 'A')
+
+ def testDeleteReplaced(self):
+ """delete an added file ('merge') from the wc (without force)"""
+ self._change_to_pkg('replace')
+ p = osc.core.Package('.')
+ ret = p.delete_file('merge')
+ self.__check_ret(ret, False, 'R')
+ self.assertTrue(os.path.exists('merge'))
+ self.assertFalse(os.path.exists(os.path.join('.osc', '_to_be_deleted')))
+ self._check_addlist('toadd1\nmerge\n')
+ self._check_status(p, 'merge', 'R')
+
+ def testDeleteConflict(self):
+ """delete a file ('foo', state='C') from the wc (without force)"""
+ self._change_to_pkg('conflict')
+ p = osc.core.Package('.')
+ ret = p.delete_file('foo')
+ self.__check_ret(ret, False, 'C')
+ self.assertTrue(os.path.exists('foo'))
+ self.assertTrue(os.path.exists(os.path.join('.osc', 'foo')))
+ self.assertFalse(os.path.exists(os.path.join('.osc', '_to_be_deleted')))
+ self._check_conflictlist('foo\n')
+ self._check_status(p, 'foo', 'C')
+
+ def testDeleteModifiedForce(self):
+ """force deletion modified file ('nochange') from wc"""
+ self._change_to_pkg('simple')
+ p = osc.core.Package('.')
+ ret = p.delete_file('nochange', force=True)
+ self.__check_ret(ret, True, 'M')
+ self.assertFalse(os.path.exists('nochange'))
+ self.assertTrue(os.path.exists(os.path.join('.osc', 'nochange')))
+ self._check_deletelist('nochange\n')
+ self._check_status(p, 'nochange', 'D')
+
+ def testDeleteUnversionedForce(self):
+ """delete an unversioned file ('toadd2') from the wc (with force)"""
+ self._change_to_pkg('simple')
+ p = osc.core.Package('.')
+ ret = p.delete_file('toadd2', force=True)
+ self.__check_ret(ret, True, '?')
+ self.assertFalse(os.path.exists('toadd2'))
+ self.assertFalse(os.path.exists(os.path.join('.osc', '_to_be_deleted')))
+ self.assertRaises(osc.oscerr.OscIOError, p.status, 'toadd2')
+
+ def testDeleteAddedForce(self):
+ """delete an added file ('toadd1') from the wc (with force)"""
+ self._change_to_pkg('simple')
+ p = osc.core.Package('.')
+ ret = p.delete_file('toadd1', force=True)
+ self.__check_ret(ret, True, 'A')
+ self.assertFalse(os.path.exists('toadd1'))
+ self.assertFalse(os.path.exists(os.path.join('.osc', '_to_be_deleted')))
+ self.assertFalse(os.path.exists(os.path.join('.osc', '_to_be_added')))
+ self.assertRaises(osc.oscerr.OscIOError, p.status, 'toadd1')
+
+ def testDeleteReplacedForce(self):
+ """delete an added file ('merge') from the wc (with force)"""
+ self._change_to_pkg('replace')
+ p = osc.core.Package('.')
+ ret = p.delete_file('merge', force=True)
+ self.__check_ret(ret, True, 'R')
+ self.assertFalse(os.path.exists('merge'))
+ self.assertTrue(os.path.exists(os.path.join('.osc', 'merge')))
+ self._check_deletelist('merge\n')
+ self._check_addlist('toadd1\n')
+ self._check_status(p, 'merge', 'D')
+
+ def testDeleteConflictForce(self):
+ """delete a file ('foo', state='C') from the wc (with force)"""
+ self._change_to_pkg('conflict')
+ p = osc.core.Package('.')
+ ret = p.delete_file('foo', force=True)
+ self.__check_ret(ret, True, 'C')
+ self.assertFalse(os.path.exists('foo'))
+ self.assertTrue(os.path.exists('foo.r2'))
+ self.assertTrue(os.path.exists('foo.mine'))
+ self.assertTrue(os.path.exists(os.path.join('.osc', 'foo')))
+ self._check_deletelist('foo\n')
+ self.assertFalse(os.path.exists(os.path.join('.osc', '_in_conflict')))
+ self._check_status(p, 'foo', 'D')
+
+ def testDeleteMultiple(self):
+ """delete mutliple files from the wc"""
+ self._change_to_pkg('simple')
+ p = osc.core.Package('.')
+ ret = p.delete_file('foo')
+ self.__check_ret(ret, True, ' ')
+ ret = p.delete_file('merge')
+ self.__check_ret(ret, True, ' ')
+ self.assertFalse(os.path.exists('foo'))
+ self.assertFalse(os.path.exists('merge'))
+ self.assertTrue(os.path.exists(os.path.join('.osc', 'foo')))
+ self.assertTrue(os.path.exists(os.path.join('.osc', 'merge')))
+ self._check_deletelist('foo\nmerge\n')
+
+ def testDeleteAlreadyDeleted(self):
+ """delete already deleted file from the wc"""
+ self._change_to_pkg('already_deleted')
+ p = osc.core.Package('.')
+ ret = p.delete_file('foo')
+ self.__check_ret(ret, True, 'D')
+ self.assertFalse(os.path.exists('foo'))
+ self.assertTrue(os.path.exists(os.path.join('.osc', 'foo')))
+ self._check_deletelist('foo\n')
+ self._check_status(p, 'foo', 'D')
+
+ def testDeleteAddedMissing(self):
+ """
+ delete a file which was added to the wc and is removed again
+ (via a non osc command). It's current state is '!'
+ """
+ self._change_to_pkg('delete')
+ p = osc.core.Package('.')
+ ret = p.delete_file('toadd1')
+ self.__check_ret(ret, True, '!')
+ self.assertFalse(os.path.exists('toadd1'))
+ self.assertFalse(os.path.exists(os.path.join('.osc', 'toadd1')))
+ self._check_deletelist('foo\n')
+ self.assertFalse(os.path.exists(os.path.join('.osc', '_to_be_added')))
+
+ def testDeleteSkippedLocalNotExistent(self):
+ """
+ delete a skipped file: no local file with that name exists
+ """
+ self._change_to_pkg('simple')
+ p = osc.core.Package('.')
+ ret = p.delete_file('skipped')
+ self.__check_ret(ret, False, 'S')
+ self.assertFalse(os.path.exists(os.path.join('.osc', '_to_be_deleted')))
+
+ def testDeleteSkippedLocalExistent(self):
+ """
+ delete a skipped file: a local file with that name exists and will be deleted
+ (for instance _service:* files have status 'S' but a local files might exist)
+ """
+ self._change_to_pkg('simple')
+ p = osc.core.Package('.')
+ ret = p.delete_file('skipped_exists')
+ self.__check_ret(ret, True, 'S')
+ self.assertFalse(os.path.exists('skipped_exists'))
+ self.assertFalse(os.path.exists(os.path.join('.osc', '_to_be_deleted')))
+
+ def __check_ret(self, ret, exp1, exp2):
+ self.assertTrue(len(ret) == 2)
+ self.assertTrue(ret[0] == exp1)
+ self.assertTrue(ret[1] == exp2)
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main()
--- /dev/null
+import osc.core
+import osc.oscerr
+import os
+import re
+from common import GET, OscTestCase
+
+FIXTURES_DIR = os.path.join(os.getcwd(), 'tests/difffile_fixtures')
+
+def suite():
+ import unittest
+ return unittest.makeSuite(TestDiffFiles)
+
+class TestDiffFiles(OscTestCase):
+ diff_hdr = 'Index: %s\n==================================================================='
+ def _get_fixtures_dir(self):
+ return FIXTURES_DIR
+
+ def testDiffUnmodified(self):
+ """diff an unmodified file"""
+ self._change_to_pkg('simple')
+ p = osc.core.Package('.')
+ p.todo = ['merge']
+ self.__check_diff(p, '', None)
+
+ def testDiffAdded(self):
+ """diff an added file"""
+ self._change_to_pkg('simple')
+ p = osc.core.Package('.')
+ p.todo = ['toadd1']
+ exp = """%s
+--- toadd1\t(revision 0)
++++ toadd1\t(revision 0)
+@@ -0,0 +1,1 @@
++toadd1
+""" % (TestDiffFiles.diff_hdr % 'toadd1')
+ self.__check_diff(p, exp, None)
+
+ def testDiffRemoved(self):
+ """diff a removed file"""
+ self._change_to_pkg('simple')
+ p = osc.core.Package('.')
+ p.todo = ['somefile']
+ exp = """%s
+--- somefile\t(revision 2)
++++ somefile\t(working copy)
+@@ -1,1 +0,0 @@
+-some content
+""" % (TestDiffFiles.diff_hdr % 'somefile')
+ self.__check_diff(p, exp, None)
+
+ def testDiffMissing(self):
+ """diff a missing file (missing files are ignored)"""
+ self._change_to_pkg('simple')
+ p = osc.core.Package('.')
+ p.todo = ['missing']
+ self.__check_diff(p, '', None)
+
+ def testDiffReplaced(self):
+ """diff a replaced file"""
+ self._change_to_pkg('simple')
+ p = osc.core.Package('.')
+ p.todo = ['replaced']
+ exp = """%s
+--- replaced\t(revision 2)
++++ replaced\t(working copy)
+@@ -1,1 +1,1 @@
+-yet another file
++foo replaced
+""" % (TestDiffFiles.diff_hdr % 'replaced')
+ self.__check_diff(p, exp, None)
+
+ def testDiffSkipped(self):
+ """diff a skipped file (skipped files are ignored)"""
+ self._change_to_pkg('simple')
+ p = osc.core.Package('.')
+ p.todo = ['skipped']
+ self.__check_diff(p, '', None)
+
+ def testDiffConflict(self):
+ """diff a file which is in the conflict state"""
+ self._change_to_pkg('simple')
+ p = osc.core.Package('.')
+ p.todo = ['foo']
+ exp = """%s
+--- foo\t(revision 2)
++++ foo\t(working copy)
+@@ -1,1 +1,5 @@
++<<<<<<< foo.mine
++This is no test.
++=======
+ This is a simple test.
++>>>>>>> foo.r2
+""" % (TestDiffFiles.diff_hdr % 'foo')
+ self.__check_diff(p, exp, None)
+
+ def testDiffModified(self):
+ """diff a modified file"""
+ self._change_to_pkg('simple')
+ p = osc.core.Package('.')
+ p.todo = ['nochange']
+ exp = """%s
+--- nochange\t(revision 2)
++++ nochange\t(working copy)
+@@ -1,1 +1,2 @@
+-This file didn't change.
++This file didn't change but
++is modified.
+""" % (TestDiffFiles.diff_hdr % 'nochange')
+ self.__check_diff(p, exp, None)
+
+ def testDiffUnversioned(self):
+ """diff an unversioned file"""
+ self._change_to_pkg('simple')
+ p = osc.core.Package('.')
+ p.todo = ['toadd2']
+ self.assertRaises(osc.oscerr.OscIOError, self.__check_diff, p, '', None)
+
+ def testDiffAddedMissing(self):
+ """diff a file which has satus 'A' but the local file does not exist"""
+ self._change_to_pkg('simple')
+ p = osc.core.Package('.')
+ p.todo = ['addedmissing']
+ self.assertRaises(osc.oscerr.OscIOError, self.__check_diff, p, '', None)
+
+ def testDiffMultipleFiles(self):
+ """diff multiple files"""
+ self._change_to_pkg('simple')
+ p = osc.core.Package('.')
+ p.todo = ['nochange', 'somefile']
+ exp = """%s
+--- nochange\t(revision 2)
++++ nochange\t(working copy)
+@@ -1,1 +1,2 @@
+-This file didn't change.
++This file didn't change but
++is modified.
+%s
+--- somefile\t(revision 2)
++++ somefile\t(working copy)
+@@ -1,1 +0,0 @@
+-some content
+""" % (TestDiffFiles.diff_hdr % 'nochange', TestDiffFiles.diff_hdr % 'somefile')
+ self.__check_diff(p, exp, None)
+
+ def testDiffReplacedEmptyTodo(self):
+ """diff a complete package"""
+ self._change_to_pkg('replaced')
+ p = osc.core.Package('.')
+ exp = """%s
+--- replaced\t(revision 2)
++++ replaced\t(working copy)
+@@ -1,1 +1,1 @@
+-yet another file
++foo replaced
+""" % (TestDiffFiles.diff_hdr % 'replaced')
+ self.__check_diff(p, exp, None)
+
+ def testDiffBinaryAdded(self):
+ """diff an added binary file"""
+ self._change_to_pkg('binary')
+ p = osc.core.Package('.')
+ p.todo = ['binary_added']
+ exp = """%s
+Binary file 'binary_added' added.
+""" % (TestDiffFiles.diff_hdr % 'binary_added')
+ self.__check_diff(p, exp, None)
+
+ def testDiffBinaryDeleted(self):
+ """diff a deleted binary file"""
+ self._change_to_pkg('binary')
+ p = osc.core.Package('.')
+ p.todo = ['binary_deleted']
+ exp = """%s
+Binary file 'binary_deleted' deleted.
+""" % (TestDiffFiles.diff_hdr % 'binary_deleted')
+ self.__check_diff(p, exp, None)
+
+ def testDiffBinaryModified(self):
+ """diff a modified binary file"""
+ self._change_to_pkg('binary')
+ p = osc.core.Package('.')
+ p.todo = ['binary']
+ exp = """%s
+Binary file 'binary' has changed.
+""" % (TestDiffFiles.diff_hdr % 'binary')
+ self.__check_diff(p, exp, None)
+
+ # diff with revision
+ @GET('http://localhost/source/osctest/remote_simple_noadd?rev=3', file='testDiffRemoteNoChange_files')
+ def testDiffRemoteNoChange(self):
+ """diff against remote revision where no file changed"""
+ self._change_to_pkg('remote_simple_noadd')
+ p = osc.core.Package('.')
+ self.__check_diff(p, '', 3)
+
+ @GET('http://localhost/source/osctest/remote_simple?rev=3', file='testDiffRemoteModified_files')
+ @GET('http://localhost/source/osctest/remote_simple/merge?rev=3', file='testDiffRemoteModified_merge')
+ def testDiffRemoteModified(self):
+ """diff against a remote revision with one modified file"""
+ self._change_to_pkg('remote_simple')
+ p = osc.core.Package('.')
+ exp = """%s
+--- merge\t(revision 3)
++++ merge\t(working copy)
+@@ -1,3 +1,4 @@
+ Is it
+ possible to
+ merge this file?
++I hope so...
+%s
+--- toadd1\t(revision 0)
++++ toadd1\t(revision 0)
+@@ -0,0 +1,1 @@
++toadd1
+""" % (TestDiffFiles.diff_hdr % 'merge', TestDiffFiles.diff_hdr % 'toadd1')
+ self.__check_diff(p, exp, 3)
+
+ @GET('http://localhost/source/osctest/remote_simple?rev=3', file='testDiffRemoteDeletedLocalAdded_files')
+ def testDiffRemoteNotExistingLocalAdded(self):
+ """
+ a file which doesn't exist in a remote revision and
+ has status A in the wc
+ """
+ self._change_to_pkg('remote_simple')
+ p = osc.core.Package('.')
+ exp = """%s
+--- toadd1\t(revision 0)
++++ toadd1\t(revision 0)
+@@ -0,0 +1,1 @@
++toadd1
+""" % (TestDiffFiles.diff_hdr % 'toadd1')
+ self.__check_diff(p, exp, 3)
+
+ @GET('http://localhost/source/osctest/remote_simple_noadd?rev=3', file='testDiffRemoteExistingLocalNotExisting_files')
+ @GET('http://localhost/source/osctest/remote_simple_noadd/foobar?rev=3', file='testDiffRemoteExistingLocalNotExisting_foobar')
+ @GET('http://localhost/source/osctest/remote_simple_noadd/binary?rev=3', file='testDiffRemoteExistingLocalNotExisting_binary')
+ def testDiffRemoteExistingLocalNotExisting(self):
+ """
+ a file doesn't exist in the local wc but exists
+ in the remote revision
+ """
+ self._change_to_pkg('remote_simple_noadd')
+ p = osc.core.Package('.')
+ exp = """%s
+--- foobar\t(revision 3)
++++ foobar\t(working copy)
+@@ -1,2 +0,0 @@
+-foobar
+-barfoo
+%s
+Binary file 'binary' deleted.
+""" % (TestDiffFiles.diff_hdr % 'foobar', TestDiffFiles.diff_hdr % 'binary')
+ self.__check_diff(p, exp, 3)
+
+ @GET('http://localhost/source/osctest/remote_localmodified?rev=3', file='testDiffRemoteUnchangedLocalModified_files')
+ @GET('http://localhost/source/osctest/remote_localmodified/nochange?rev=3', file='testDiffRemoteUnchangedLocalModified_nochange')
+ @GET('http://localhost/source/osctest/remote_localmodified/binary?rev=3', file='testDiffRemoteUnchangedLocalModified_binary')
+ def testDiffRemoteUnchangedLocalModified(self):
+ """remote revision didn't change, local file is modified"""
+ self._change_to_pkg('remote_localmodified')
+ p = osc.core.Package('.')
+ exp = """%s
+--- nochange\t(revision 3)
++++ nochange\t(working copy)
+@@ -1,1 +1,2 @@
+ This file didn't change.
++oh it does
+%s
+Binary file 'binary' has changed.
+""" % (TestDiffFiles.diff_hdr % 'nochange', TestDiffFiles.diff_hdr % 'binary')
+ self.__check_diff(p, exp, 3)
+
+ @GET('http://localhost/source/osctest/remote_simple_noadd?rev=3', file='testDiffRemoteMissingLocalExisting_files')
+ def testDiffRemoteMissingLocalExisting(self):
+ """
+ remote revision misses a file which exists in the local wc (state ' ')"""
+ self._change_to_pkg('remote_simple_noadd')
+ p = osc.core.Package('.')
+ exp = """%s
+--- foo\t(revision 0)
++++ foo\t(working copy)
+@@ -0,0 +1,1 @@
++This is a simple test.
+""" % (TestDiffFiles.diff_hdr % 'foo')
+ self.__check_diff(p, exp, 3)
+
+ @GET('http://localhost/source/osctest/remote_localdelete?rev=3', file='testDiffRemoteMissingLocalDeleted_files')
+ def testDiffRemoteMissingLocalDeleted(self):
+ """
+ remote revision misses a file which is marked for
+ deletion in the local wc
+ """
+ # empty diff is expected (svn does the same)
+ self._change_to_pkg('remote_localdelete')
+ p = osc.core.Package('.')
+ self.__check_diff(p, '', 3)
+
+ def __check_diff(self, p, exp, revision=None):
+ got = ''
+ for i in p.get_diff(revision):
+ got += ''.join(i)
+
+ # When a hunk header refers to a single line in the "from"
+ # file and/or the "to" file, e.g.
+ #
+ # @@ -37,37 +41,43 @@
+ # @@ -37,39 +41,41 @@
+ # @@ -37,37 +41,41 @@
+ #
+ # some systems will avoid repeating the line number:
+ #
+ # @@ -37 +41,43 @@
+ # @@ -37,39 +41 @@
+ # @@ -37 +41 @@
+ #
+ # so we need to canonise the output to avoid false negative
+ # test failures.
+
+ # TODO: Package.get_diff should return a consistent format
+ # (regardless of the used python version)
+ def __canonise_diff(diff):
+ # we cannot use re.M because python 2.6's re.sub does
+ # not support a flags argument
+ diff = [re.sub('^@@ -(\d+) ', '@@ -\\1,\\1 ', line)
+ for line in diff.split('\n')]
+ diff = [re.sub('^(@@ -\d+,\d+) \+(\d+) ', '\\1 +\\2,\\2 ', line)
+ for line in diff]
+ return '\n'.join(diff)
+
+ got = __canonise_diff(got)
+ exp = __canonise_diff(exp)
+ self.assertEqualMultiline(got, exp)
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main()
--- /dev/null
+import osc.core
+import osc.oscerr
+import os
+from common import OscTestCase
+FIXTURES_DIR = os.path.join(os.getcwd(), 'tests/init_package_fixtures')
+
+def suite():
+ import unittest
+ return unittest.makeSuite(TestInitPackage)
+
+class TestInitPackage(OscTestCase):
+ def _get_fixtures_dir(self):
+ # workaround for git because it doesn't allow empty dirs
+ if not os.path.exists(os.path.join(FIXTURES_DIR, 'osctest')):
+ os.mkdir(os.path.join(FIXTURES_DIR, 'osctest'))
+ return FIXTURES_DIR
+
+ def tearDown(self):
+ if os.path.exists(os.path.join(FIXTURES_DIR, 'osctest')):
+ os.rmdir(os.path.join(FIXTURES_DIR, 'osctest'))
+ OscTestCase.tearDown(self)
+
+ def test_simple(self):
+ """initialize a package dir"""
+ pac_dir = os.path.join(self.tmpdir, 'testpkg')
+ osc.core.Package.init_package('http://localhost', 'osctest', 'testpkg', pac_dir)
+ storedir = os.path.join(pac_dir, osc.core.store)
+ self.assertFalse(os.path.exists(os.path.join(storedir, '_meta_mode')))
+ self.assertFalse(os.path.exists(os.path.join(storedir, '_size_limit')))
+ self._check_list(os.path.join(storedir, '_project'), 'osctest\n')
+ self._check_list(os.path.join(storedir, '_package'), 'testpkg\n')
+ self._check_list(os.path.join(storedir, '_files'), '<directory />\n')
+ self._check_list(os.path.join(storedir, '_apiurl'), 'http://localhost\n')
+
+ def test_size_limit(self):
+ """initialize a package dir with size_limit parameter"""
+ pac_dir = os.path.join(self.tmpdir, 'testpkg')
+ osc.core.Package.init_package('http://localhost', 'osctest', 'testpkg', pac_dir, size_limit=42)
+ storedir = os.path.join(pac_dir, osc.core.store)
+ self.assertFalse(os.path.exists(os.path.join(storedir, '_meta_mode')))
+ self._check_list(os.path.join(storedir, '_size_limit'), '42\n')
+ self._check_list(os.path.join(storedir, '_project'), 'osctest\n')
+ self._check_list(os.path.join(storedir, '_package'), 'testpkg\n')
+ self._check_list(os.path.join(storedir, '_files'), '<directory />\n')
+ self._check_list(os.path.join(storedir, '_apiurl'), 'http://localhost\n')
+
+ def test_meta_mode(self):
+ """initialize a package dir with meta paramter"""
+ pac_dir = os.path.join(self.tmpdir, 'testpkg')
+ osc.core.Package.init_package('http://localhost', 'osctest', 'testpkg', pac_dir, meta=True)
+ storedir = os.path.join(pac_dir, osc.core.store)
+ self.assertFalse(os.path.exists(os.path.join(storedir, '_size_limit')))
+ self._check_list(os.path.join(storedir, '_meta_mode'), '')
+ self._check_list(os.path.join(storedir, '_project'), 'osctest\n')
+ self._check_list(os.path.join(storedir, '_package'), 'testpkg\n')
+ self._check_list(os.path.join(storedir, '_files'), '<directory />\n')
+ self._check_list(os.path.join(storedir, '_apiurl'), 'http://localhost\n')
+
+ def test_dirExists(self):
+ """initialize a package dir (dir already exists)"""
+ pac_dir = os.path.join(self.tmpdir, 'testpkg')
+ os.mkdir(pac_dir)
+ osc.core.Package.init_package('http://localhost', 'osctest', 'testpkg', pac_dir)
+ storedir = os.path.join(pac_dir, osc.core.store)
+ self.assertFalse(os.path.exists(os.path.join(storedir, '_meta_mode')))
+ self.assertFalse(os.path.exists(os.path.join(storedir, '_size_limit')))
+ self._check_list(os.path.join(storedir, '_project'), 'osctest\n')
+ self._check_list(os.path.join(storedir, '_package'), 'testpkg\n')
+ self._check_list(os.path.join(storedir, '_files'), '<directory />\n')
+ self._check_list(os.path.join(storedir, '_apiurl'), 'http://localhost\n')
+
+ def test_storedirExists(self):
+ """initialize a package dir (dir+storedir already exists)"""
+ pac_dir = os.path.join(self.tmpdir, 'testpkg')
+ os.mkdir(pac_dir)
+ os.mkdir(os.path.join(pac_dir, osc.core.store))
+ self.assertRaises(osc.oscerr.OscIOError, osc.core.Package.init_package, 'http://localhost', 'osctest', 'testpkg', pac_dir)
+
+ def test_dirIsFile(self):
+ """initialize a package dir (dir is a file)"""
+ pac_dir = os.path.join(self.tmpdir, 'testpkg')
+ os.mkdir(pac_dir)
+ open(os.path.join(pac_dir, osc.core.store), 'w').write('foo\n')
+ self.assertRaises(osc.oscerr.OscIOError, osc.core.Package.init_package, 'http://localhost', 'osctest', 'testpkg', pac_dir)
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main()
--- /dev/null
+import osc.core
+import osc.oscerr
+import os
+from common import GET, OscTestCase
+FIXTURES_DIR = os.path.join(os.getcwd(), 'tests/init_project_fixtures')
+
+def suite():
+ import unittest
+ return unittest.makeSuite(TestInitProject)
+
+class TestInitProject(OscTestCase):
+ def _get_fixtures_dir(self):
+ # workaround for git because it doesn't allow empty dirs
+ if not os.path.exists(os.path.join(FIXTURES_DIR, 'osctest')):
+ os.mkdir(os.path.join(FIXTURES_DIR, 'osctest'))
+ return FIXTURES_DIR
+
+ def tearDown(self):
+ if os.path.exists(os.path.join(FIXTURES_DIR, 'osctest')):
+ os.rmdir(os.path.join(FIXTURES_DIR, 'osctest'))
+ OscTestCase.tearDown(self)
+
+ def test_simple(self):
+ """initialize a project dir"""
+ prj_dir = os.path.join(self.tmpdir, 'testprj')
+ prj = osc.core.Project.init_project('http://localhost', prj_dir, 'testprj', getPackageList=False)
+ self.assertTrue(isinstance(prj, osc.core.Project))
+ storedir = os.path.join(prj_dir, osc.core.store)
+ self._check_list(os.path.join(storedir, '_project'), 'testprj\n')
+ self._check_list(os.path.join(storedir, '_apiurl'), 'http://localhost\n')
+ self._check_list(os.path.join(storedir, '_packages'), '<project name="testprj" />')
+
+ def test_dirExists(self):
+ """initialize a project dir but the dir already exists"""
+ prj_dir = os.path.join(self.tmpdir, 'testprj')
+ os.mkdir(prj_dir)
+ prj = osc.core.Project.init_project('http://localhost', prj_dir, 'testprj', getPackageList=False)
+ self.assertTrue(isinstance(prj, osc.core.Project))
+ storedir = os.path.join(prj_dir, osc.core.store)
+ self._check_list(os.path.join(storedir, '_project'), 'testprj\n')
+ self._check_list(os.path.join(storedir, '_apiurl'), 'http://localhost\n')
+ self._check_list(os.path.join(storedir, '_packages'), '<project name="testprj" />')
+
+ def test_storedirExists(self):
+ """initialize a project dir but the storedir already exists"""
+ prj_dir = os.path.join(self.tmpdir, 'testprj')
+ os.mkdir(prj_dir)
+ os.mkdir(os.path.join(prj_dir, osc.core.store))
+ self.assertRaises(osc.oscerr.OscIOError, osc.core.Project.init_project, 'http://localhost', prj_dir, 'testprj')
+
+ @GET('http://localhost/source/testprj', text='<directory count="0" />')
+ def test_no_package_tracking(self):
+ """initialize a project dir but disable package tracking; enable getPackageList=True;
+ disable wc_check (because we didn't disable the package tracking before the Project class
+ was imported therefore REQ_STOREFILES contains '_packages')
+ """
+ import osc.conf
+ # disable package tracking
+ osc.conf.config['do_package_tracking'] = False
+ prj_dir = os.path.join(self.tmpdir, 'testprj')
+ os.mkdir(prj_dir)
+ prj = osc.core.Project.init_project('http://localhost', prj_dir, 'testprj', False, wc_check=False)
+ self.assertTrue(isinstance(prj, osc.core.Project))
+ storedir = os.path.join(prj_dir, osc.core.store)
+ self._check_list(os.path.join(storedir, '_project'), 'testprj\n')
+ self._check_list(os.path.join(storedir, '_apiurl'), 'http://localhost\n')
+ self.assertFalse(os.path.exists(os.path.join(storedir, '_packages')))
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main()
--- /dev/null
+import osc.core
+import osc.oscerr
+import os
+from common import OscTestCase
+
+FIXTURES_DIR = os.path.join(os.getcwd(), 'tests/project_package_status_fixtures')
+
+def suite():
+ import unittest
+ return unittest.makeSuite(TestPackageStatus)
+
+class TestPackageStatus(OscTestCase):
+ def _get_fixtures_dir(self):
+ return FIXTURES_DIR
+
+ def test_allfiles(self):
+ """get the status of all files in the wc"""
+ self._change_to_pkg('simple')
+ p = osc.core.Package('.')
+ exp_st = [('A', 'add'), ('?', 'exists'), ('D', 'foo'), ('!', 'merge'), ('R', 'missing'),
+ ('!', 'missing_added'), ('M', 'nochange'), ('S', 'skipped'), (' ', 'test')]
+ st = p.get_status()
+ self.assertEqual(exp_st, st)
+
+ def test_todo(self):
+ """
+ get the status of some files in the wc.
+ """
+ self._change_to_pkg('simple')
+ p = osc.core.Package('.')
+ p.todo = ['test', 'missing_added', 'foo']
+ exp_st = [('D', 'foo'), ('!', 'missing_added')]
+ st = p.get_status(False, ' ')
+ self.assertEqual(exp_st, st)
+
+ def test_todo_noexcl(self):
+ """ get the status of some files in the wc. """
+ self._change_to_pkg('simple')
+ p = osc.core.Package('.')
+ p.todo = ['test', 'missing_added', 'foo']
+ exp_st = [('D', 'foo'), ('!', 'missing_added'), (' ', 'test')]
+ st = p.get_status()
+ self.assertEqual(exp_st, st)
+
+ def test_exclude_state(self):
+ """get the status of all files in the wc but exclude some states"""
+ self._change_to_pkg('simple')
+ p = osc.core.Package('.')
+ exp_st = [('A', 'add'), ('?', 'exists'), ('D', 'foo')]
+ st = p.get_status(False, '!', 'S', ' ', 'M', 'R')
+ self.assertEqual(exp_st, st)
+
+ def test_nonexistent(self):
+ """get the status of a non existent file"""
+ self._change_to_pkg('simple')
+ p = osc.core.Package('.')
+ p.todo = ['doesnotexist']
+ self.assertRaises(osc.oscerr.OscIOError, p.get_status)
+
+ def test_conflict(self):
+ """get status of the wc (one file in conflict state)"""
+ self._change_to_pkg('conflict')
+ p = osc.core.Package('.')
+ exp_st = [('C', 'conflict'), ('?', 'exists'), (' ', 'test')]
+ st = p.get_status()
+ self.assertEqual(exp_st, st)
+
+ def test_excluded(self):
+ """get status of the wc (ignore excluded files); package has state ' '"""
+ self._change_to_pkg('excluded')
+ p = osc.core.Package('.')
+ exp_st = [('?', 'exists'), ('M', 'modified')]
+ st = p.get_status(False, ' ')
+ self.assertEqual(exp_st, st)
+
+ def test_noexcluded(self):
+ """get status of the wc (include excluded files)"""
+ self._change_to_pkg('excluded')
+ p = osc.core.Package('.')
+ exp_st = [('?', '_linkerror'), ('?', 'exists'), ('?', 'foo.orig'), ('M', 'modified'), (' ', 'test')]
+ st = p.get_status(True)
+ self.assertEqual(exp_st, st)
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main()
--- /dev/null
+import osc.commandline
+import osc.core
+import osc.oscerr
+import os
+import re
+import sys
+from common import GET, POST, OscTestCase, addExpectedRequest, EXPECTED_REQUESTS
+
+
+FIXTURES_DIR = os.path.join(os.getcwd(), 'tests/prdiff_fixtures')
+API_URL = 'http://localhost/'
+UPSTREAM = 'some:project'
+BRANCH = 'home:user:branches:' + UPSTREAM
+
+def rdiff_url(pkg, oldprj, newprj):
+ return API_URL + 'source/%s/%s?unified=1&opackage=%s&oproject=%s&cmd=diff&expand=1&tarlimit=0&filelimit=0' % \
+ (newprj, pkg, pkg, oldprj.replace(':', '%3A'))
+
+def request_url(prj):
+ return API_URL + 'search/request?match=%%28state%%2F%%40name%%3D%%27new%%27+or+state%%2F%%40name%%3D%%27review%%27%%29+and+%%28action%%2Ftarget%%2F%%40project%%3D%%27%s%%27+or+submit%%2Ftarget%%2F%%40project%%3D%%27%s%%27+or+action%%2Fsource%%2F%%40project%%3D%%27%s%%27+or+submit%%2Fsource%%2F%%40project%%3D%%27%s%%27%%29' % \
+ tuple([prj.replace(':', '%3A')] * 4)
+
+def GET_PROJECT_PACKAGES(*projects):
+ def decorator(test_method):
+ def wrapped_test_method(*args):
+ for project in projects:
+ addExpectedRequest('GET', API_URL + 'source/' + project,
+ file='%s/directory' % project)
+ test_method(*args)
+ # "rename" method otherwise we cannot specify a TestCaseClass.testName
+ # cmdline arg when using unittest.main()
+ wrapped_test_method.__name__ = test_method.__name__
+ return wrapped_test_method
+ return decorator
+
+def POST_RDIFF(oldprj, newprj):
+ def decorator(test_method):
+ def wrapped_test_method(*args):
+ addExpectedRequest('POST', rdiff_url('common-one', oldprj, newprj), exp='', text='')
+ addExpectedRequest('POST', rdiff_url('common-two', oldprj, newprj), exp='', file='common-two-diff')
+ addExpectedRequest('POST', rdiff_url('common-three', oldprj, newprj), exp='', text='')
+ test_method(*args)
+ # "rename" method otherwise we cannot specify a TestCaseClass.testName
+ # cmdline arg when using unittest.main()
+ wrapped_test_method.__name__ = test_method.__name__
+ return wrapped_test_method
+ return decorator
+
+def suite():
+ import unittest
+ return unittest.makeSuite(TestProjectDiff)
+
+class TestProjectDiff(OscTestCase):
+ diff_hdr = 'Index: %s\n==================================================================='
+ def _get_fixtures_dir(self):
+ return FIXTURES_DIR
+
+ def _change_to_tmpdir(self, *args):
+ os.chdir(os.path.join(self.tmpdir, *args))
+
+ def _run_prdiff(self, *args):
+ """Runs osc prdiff, returning captured STDOUT as a string."""
+ cli = osc.commandline.Osc()
+ argv = ['osc', '--no-keyring', '--no-gnome-keyring', 'prdiff']
+ argv.extend(args)
+ cli.main(argv=argv)
+ return sys.stdout.getvalue()
+
+
+ def testPrdiffTooManyArgs(self):
+ def runner():
+ self._run_prdiff('one', 'two', 'superfluous-arg')
+ self.assertRaises(osc.oscerr.WrongArgs, runner)
+
+
+ @GET_PROJECT_PACKAGES(UPSTREAM, BRANCH)
+ @POST_RDIFF(UPSTREAM, BRANCH)
+ @POST(rdiff_url('only-in-new', UPSTREAM, BRANCH), exp='', text='')
+ def testPrdiffZeroArgs(self):
+ exp = """identical: common-one
+differs: common-two
+identical: common-three
+identical: only-in-new
+"""
+ def runner():
+ self._run_prdiff()
+
+ os.chdir('/tmp')
+ self.assertRaises(osc.oscerr.WrongArgs, runner)
+
+ self._change_to_tmpdir(FIXTURES_DIR, UPSTREAM)
+ self.assertRaises(osc.oscerr.WrongArgs, runner)
+
+ self._change_to_tmpdir(FIXTURES_DIR, BRANCH)
+ out = self._run_prdiff()
+ self.assertEqualMultiline(out, exp)
+
+
+ @GET_PROJECT_PACKAGES(UPSTREAM, BRANCH)
+ @POST_RDIFF(UPSTREAM, BRANCH)
+ @POST(rdiff_url('only-in-new', UPSTREAM, BRANCH), exp='', text='')
+ def testPrdiffOneArg(self):
+ self._change_to_tmpdir()
+ exp = """identical: common-one
+differs: common-two
+identical: common-three
+identical: only-in-new
+"""
+ out = self._run_prdiff('home:user:branches:some:project')
+ self.assertEqualMultiline(out, exp)
+
+
+ @GET_PROJECT_PACKAGES('old:prj', 'new:prj')
+ @POST_RDIFF('old:prj', 'new:prj')
+ def testPrdiffTwoArgs(self):
+ self._change_to_tmpdir()
+ exp = """identical: common-one
+differs: common-two
+identical: common-three
+"""
+ out = self._run_prdiff('old:prj', 'new:prj')
+ self.assertEqualMultiline(out, exp)
+
+
+ @GET_PROJECT_PACKAGES('old:prj', 'new:prj')
+ @POST_RDIFF('old:prj', 'new:prj')
+ def testPrdiffOldOnly(self):
+ self._change_to_tmpdir()
+ exp = """identical: common-one
+differs: common-two
+identical: common-three
+old only: only-in-old
+"""
+ out = self._run_prdiff('--show-not-in-new', 'old:prj', 'new:prj')
+ self.assertEqualMultiline(out, exp)
+
+
+ @GET_PROJECT_PACKAGES('old:prj', 'new:prj')
+ @POST_RDIFF('old:prj', 'new:prj')
+ def testPrdiffNewOnly(self):
+ self._change_to_tmpdir()
+ exp = """identical: common-one
+differs: common-two
+identical: common-three
+new only: only-in-new
+"""
+ out = self._run_prdiff('--show-not-in-old', 'old:prj', 'new:prj')
+ self.assertEqualMultiline(out, exp)
+
+
+ @GET_PROJECT_PACKAGES('old:prj', 'new:prj')
+ @POST_RDIFF('old:prj', 'new:prj')
+ def testPrdiffDiffstat(self):
+ self._change_to_tmpdir()
+ exp = """identical: common-one
+differs: common-two
+
+ common-two | 1 +
+ 1 file changed, 1 insertion(+)
+
+identical: common-three
+"""
+ out = self._run_prdiff('--diffstat', 'old:prj', 'new:prj')
+ self.assertEqualMultiline(out, exp)
+
+
+ @GET_PROJECT_PACKAGES('old:prj', 'new:prj')
+ @POST_RDIFF('old:prj', 'new:prj')
+ def testPrdiffUnified(self):
+ self._change_to_tmpdir()
+ exp = """identical: common-one
+differs: common-two
+
+Index: common-two
+===================================================================
+--- common-two\t2013-01-18 19:18:38.225983117 +0000
++++ common-two\t2013-01-18 19:19:27.882082325 +0000
+@@ -1,4 +1,5 @@
+ line one
+ line two
+ line three
++an extra line
+ last line
+
+identical: common-three
+"""
+ out = self._run_prdiff('--unified', 'old:prj', 'new:prj')
+ self.assertEqualMultiline(out, exp)
+
+
+ @GET_PROJECT_PACKAGES('old:prj', 'new:prj')
+ @POST(rdiff_url('common-two', 'old:prj', 'new:prj'), exp='', file='common-two-diff')
+ @POST(rdiff_url('common-three', 'old:prj', 'new:prj'), exp='', text='')
+ def testPrdiffInclude(self):
+ self._change_to_tmpdir()
+ exp = """differs: common-two
+identical: common-three
+"""
+ out = self._run_prdiff('--include', 'common-t',
+ 'old:prj', 'new:prj')
+ self.assertEqualMultiline(out, exp)
+
+
+ @GET_PROJECT_PACKAGES('old:prj', 'new:prj')
+ @POST(rdiff_url('common-two', 'old:prj', 'new:prj'), exp='', file='common-two-diff')
+ @POST(rdiff_url('common-three', 'old:prj', 'new:prj'), exp='', text='')
+ def testPrdiffExclude(self):
+ self._change_to_tmpdir()
+ exp = """differs: common-two
+identical: common-three
+"""
+ out = self._run_prdiff('--exclude', 'one', 'old:prj', 'new:prj')
+ self.assertEqualMultiline(out, exp)
+
+
+ @GET_PROJECT_PACKAGES('old:prj', 'new:prj')
+ @POST(rdiff_url('common-two', 'old:prj', 'new:prj'), exp='', file='common-two-diff')
+ def testPrdiffIncludeExclude(self):
+ self._change_to_tmpdir()
+ exp = """differs: common-two
+"""
+ out = self._run_prdiff('--include', 'common-t',
+ '--exclude', 'three',
+ 'old:prj', 'new:prj')
+ self.assertEqualMultiline(out, exp)
+
+
+ @GET_PROJECT_PACKAGES(UPSTREAM, BRANCH)
+ @GET(request_url(UPSTREAM), exp='', file='request')
+ @POST(rdiff_url('common-one', UPSTREAM, BRANCH), exp='', text='')
+ @POST(rdiff_url('common-two', UPSTREAM, BRANCH), exp='', file='common-two-diff')
+ @POST(rdiff_url('common-three', UPSTREAM, BRANCH), exp='', file='common-two-diff')
+ @POST(rdiff_url('only-in-new', UPSTREAM, BRANCH), exp='', text='')
+ def testPrdiffRequestsMatching(self):
+ self._change_to_tmpdir()
+ exp = """identical: common-one
+differs: common-two
+
+148023 State:new By:user When:2013-01-11T11:04:14
+ submit: home:user:branches:some:project/common-two@7 -> some:project
+ Descr: - Fix it to work - Improve support for something
+
+differs: common-three
+identical: only-in-new
+"""
+ out = self._run_prdiff('--requests', UPSTREAM, BRANCH)
+ self.assertEqualMultiline(out, exp)
+
+
+ # Reverse the direction of the diff.
+ @GET_PROJECT_PACKAGES(BRANCH, UPSTREAM)
+ @GET(request_url(BRANCH), exp='', file='no-requests')
+ @POST(rdiff_url('common-one', BRANCH, UPSTREAM), exp='', text='')
+ @POST(rdiff_url('common-two', BRANCH, UPSTREAM), exp='', file='common-two-diff')
+ @POST(rdiff_url('common-three', BRANCH, UPSTREAM), exp='', file='common-two-diff')
+ @POST(rdiff_url('only-in-new', BRANCH, UPSTREAM), exp='', text='')
+ def testPrdiffRequestsSwitched(self):
+ self._change_to_tmpdir()
+ exp = """identical: common-one
+differs: common-two
+differs: common-three
+identical: only-in-new
+"""
+ out = self._run_prdiff('--requests', BRANCH, UPSTREAM)
+ self.assertEqualMultiline(out, exp)
+
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main()
--- /dev/null
+import osc.core
+import osc.oscerr
+import os
+from common import OscTestCase
+
+FIXTURES_DIR = os.path.join(os.getcwd(), 'tests/project_package_status_fixtures')
+
+def suite():
+ import unittest
+ return unittest.makeSuite(TestProjectStatus)
+
+class TestProjectStatus(OscTestCase):
+ def _get_fixtures_dir(self):
+ return FIXTURES_DIR
+
+ def test_simple(self):
+ """get the status of a package with state ' '"""
+ self._change_to_pkg('.')
+ prj = osc.core.Project('.', getPackageList=False)
+ exp_st = ' '
+ st = prj.status('simple')
+ self.assertEqual(exp_st, st)
+
+ def test_added(self):
+ """get the status of an added package"""
+ self._change_to_pkg('.')
+ prj = osc.core.Project('.', getPackageList=False)
+ exp_st = 'A'
+ st = prj.status('added')
+ self.assertEqual(exp_st, st)
+
+ def test_deleted(self):
+ """get the status of a deleted package"""
+ self._change_to_pkg('.')
+ prj = osc.core.Project('.', getPackageList=False)
+ exp_st = 'D'
+ st = prj.status('deleted')
+ self.assertEqual(exp_st, st)
+
+ def test_added_deleted(self):
+ """
+ get the status of a package which was added and deleted
+ afterwards (with a non osc command)
+ """
+ self._change_to_pkg('.')
+ prj = osc.core.Project('.', getPackageList=False)
+ exp_st = '!'
+ st = prj.status('added_deleted')
+ self.assertEqual(exp_st, st)
+
+ def test_missing(self):
+ """
+ get the status of a package with state " "
+ which was removed by a non osc command
+ """
+ self._change_to_pkg('.')
+ prj = osc.core.Project('.', getPackageList=False)
+ exp_st = '!'
+ st = prj.status('missing')
+ self.assertEqual(exp_st, st)
+
+ def test_deleted_deleted(self):
+ """
+ get the status of a package which was deleted (with an
+ osc command) and afterwards the package directory was
+ deleted with a non osc command
+ """
+ self._change_to_pkg('.')
+ prj = osc.core.Project('.', getPackageList=False)
+ exp_st = 'D'
+ st = prj.status('deleted_deleted')
+ self.assertEqual(exp_st, st)
+
+ def test_unversioned_exists(self):
+ """get the status of an unversioned package"""
+ self._change_to_pkg('.')
+ prj = osc.core.Project('.', getPackageList=False)
+ exp_st = '?'
+ st = prj.status('excluded')
+ self.assertEqual(exp_st, st)
+
+ def test_unversioned_nonexistent(self):
+ """get the status of an unversioned, nonexistent package"""
+ self._change_to_pkg('.')
+ prj = osc.core.Project('.', getPackageList=False)
+ self.assertRaises(osc.oscerr.OscIOError, prj.status, 'doesnotexist')
+
+ def test_get_status(self):
+ """get the status of the complete project"""
+ self._change_to_pkg('.')
+ prj = osc.core.Project('.', getPackageList=False)
+ exp_st = [(' ', 'conflict'), (' ', 'simple'), ('A', 'added'), ('D', 'deleted'),
+ ('!', 'missing'), ('!', 'added_deleted'), ('D', 'deleted_deleted'), ('?', 'excluded')]
+ st = prj.get_status()
+ self.assertEqual(exp_st, st)
+
+ def test_get_status_excl(self):
+ """get the status of the complete project (exclude some states)"""
+ self._change_to_pkg('.')
+ prj = osc.core.Project('.', getPackageList=False)
+ exp_st = [('A', 'added'), ('!', 'missing'), ('!', 'added_deleted')]
+ st = prj.get_status('D', ' ', '?')
+ self.assertEqual(exp_st, st)
+
+ def test_get_pacobj_simple(self):
+ """package exists"""
+ self._change_to_pkg('.')
+ prj = osc.core.Project('.', getPackageList=False)
+ p = prj.get_pacobj('simple')
+ self.assertTrue(isinstance(p, osc.core.Package))
+ self.assertEqual(p.name, 'simple')
+
+ def test_get_pacobj_added(self):
+ """package has state 'A', also test pac_kwargs"""
+ self._change_to_pkg('.')
+ prj = osc.core.Project('.', getPackageList=False)
+ p = prj.get_pacobj('added', progress_obj={})
+ self.assertTrue(isinstance(p, osc.core.Package))
+ self.assertEqual(p.name, 'added')
+ self.assertEqual(p.progress_obj, {})
+
+ def test_get_pacobj_deleted(self):
+ """package has state 'D' and exists, also test pac_args"""
+ self._change_to_pkg('.')
+ prj = osc.core.Project('.', getPackageList=False)
+ p = prj.get_pacobj('deleted', {})
+ self.assertTrue(isinstance(p, osc.core.Package))
+ self.assertEqual(p.name, 'deleted')
+ self.assertEqual(p.progress_obj, {})
+
+ def test_get_pacobj_missing(self):
+ """package is missing"""
+ self._change_to_pkg('.')
+ prj = osc.core.Project('.', getPackageList=False)
+ p = prj.get_pacobj('missing')
+ self.assertTrue(isinstance(p, type(None)))
+
+ def test_get_pacobj_deleted_deleted(self):
+ """package has state 'D' and does not exist"""
+ self._change_to_pkg('.')
+ prj = osc.core.Project('.', getPackageList=False)
+ p = prj.get_pacobj('deleted_deleted')
+ self.assertTrue(isinstance(p, type(None)))
+
+ def test_get_pacobj_unversioned(self):
+ """package/dir has state '?'"""
+ self._change_to_pkg('.')
+ prj = osc.core.Project('.', getPackageList=False)
+ p = prj.get_pacobj('excluded')
+ self.assertTrue(isinstance(p, type(None)))
+
+ def test_get_pacobj_nonexistent(self):
+ """package/dir does not exist"""
+ self._change_to_pkg('.')
+ prj = osc.core.Project('.', getPackageList=False)
+ p = prj.get_pacobj('doesnotexist')
+ self.assertTrue(isinstance(p, type(None)))
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main()
--- /dev/null
+import osc.core
+import osc.oscerr
+import os
+import sys
+from common import GET, PUT, POST, DELETE, OscTestCase
+from xml.etree import cElementTree as ET
+FIXTURES_DIR = os.path.join(os.getcwd(), 'tests/repairwc_fixtures')
+
+def suite():
+ import unittest
+ return unittest.makeSuite(TestRepairWC)
+
+class TestRepairWC(OscTestCase):
+ def _get_fixtures_dir(self):
+ return FIXTURES_DIR
+
+ def __assertNotRaises(self, exception, meth, *args, **kwargs):
+ try:
+ meth(*args, **kwargs)
+ except exception:
+ self.fail('%s raised' % exception.__name__)
+
+ def test_working_empty(self):
+ """consistent, empty working copy"""
+ self._change_to_pkg('working_empty')
+ self.__assertNotRaises(osc.oscerr.WorkingCopyInconsistent, osc.core.Package, '.')
+
+ def test_working_nonempty(self):
+ """
+ consistent, non-empty working copy. One file is in conflict,
+ one file is marked for deletion and one file has state 'A'
+ """
+ self._change_to_pkg('working_nonempty')
+ self.__assertNotRaises(osc.oscerr.WorkingCopyInconsistent, osc.core.Package, '.')
+
+ def test_buildfiles(self):
+ """
+ wc has a _buildconfig_prj_arch and a _buildinfo_prj_arch.xml in the storedir
+ """
+ self._change_to_pkg('buildfiles')
+ self.__assertNotRaises(osc.oscerr.WorkingCopyInconsistent, osc.core.Package, '.')
+
+ @GET('http://localhost/source/osctest/simple1/foo?rev=1', text='This is a simple test.\n')
+ def test_simple1(self):
+ """a file is marked for deletion but storefile doesn't exist"""
+ self._change_to_pkg('simple1')
+ self.assertRaises(osc.oscerr.WorkingCopyInconsistent, osc.core.Package, '.')
+ p = osc.core.Package('.', wc_check=False)
+ p.wc_repair()
+ self.assertTrue(os.path.exists(os.path.join('.osc', 'foo')))
+ self._check_deletelist('foo\n')
+ self._check_status(p, 'foo', 'D')
+ self._check_status(p, 'nochange', 'M')
+ self._check_status(p, 'merge', ' ')
+ self._check_status(p, 'toadd1', '?')
+ # additional cleanup check
+ self.__assertNotRaises(osc.oscerr.WorkingCopyInconsistent, osc.core.Package, '.')
+
+ def test_simple2(self):
+ """a file "somefile" exists in the storedir which isn't tracked"""
+ self._change_to_pkg('simple2')
+ self.assertRaises(osc.oscerr.WorkingCopyInconsistent, osc.core.Package, '.')
+ p = osc.core.Package('.', wc_check=False)
+ p.wc_repair()
+ self.assertFalse(os.path.exists(os.path.join('.osc', 'somefile')))
+ self._check_deletelist('foo\n')
+ self._check_status(p, 'foo', 'D')
+ self._check_status(p, 'nochange', 'M')
+ self._check_status(p, 'merge', ' ')
+ self._check_status(p, 'toadd1', '?')
+ # additional cleanup check
+ self.__assertNotRaises(osc.oscerr.WorkingCopyInconsistent, osc.core.Package, '.')
+
+ def test_simple3(self):
+ """toadd1 has state 'A' and a file .osc/toadd1 exists"""
+ self._change_to_pkg('simple3')
+ self.assertRaises(osc.oscerr.WorkingCopyInconsistent, osc.core.Package, '.')
+ p = osc.core.Package('.', wc_check=False)
+ p.wc_repair()
+ self.assertFalse(os.path.exists(os.path.join('.osc', 'toadd1')))
+ self._check_deletelist('foo\n')
+ self._check_status(p, 'foo', 'D')
+ self._check_status(p, 'nochange', 'M')
+ self._check_status(p, 'merge', ' ')
+ self._check_addlist('toadd1\n')
+ self._check_status(p, 'toadd1', 'A')
+ # additional cleanup check
+ self.__assertNotRaises(osc.oscerr.WorkingCopyInconsistent, osc.core.Package, '.')
+
+ def test_simple4(self):
+ """a file is listed in _to_be_deleted but isn't present in _files"""
+ self._change_to_pkg('simple4')
+ self.assertRaises(osc.oscerr.WorkingCopyInconsistent, osc.core.Package, '.')
+ p = osc.core.Package('.', wc_check=False)
+ p.wc_repair()
+ self._check_deletelist('foo\n')
+ self._check_status(p, 'foo', 'D')
+ self._check_status(p, 'nochange', 'M')
+ self._check_status(p, 'merge', ' ')
+ self._check_status(p, 'toadd1', '?')
+ # additional cleanup check
+ self.__assertNotRaises(osc.oscerr.WorkingCopyInconsistent, osc.core.Package, '.')
+
+ def test_simple5(self):
+ """a file is listed in _in_conflict but isn't present in _files"""
+ self._change_to_pkg('simple5')
+ self.assertRaises(osc.oscerr.WorkingCopyInconsistent, osc.core.Package, '.')
+ p = osc.core.Package('.', wc_check=False)
+ p.wc_repair()
+ self.assertFalse(os.path.exists(os.path.join('.osc', '_in_conflict')))
+ self._check_deletelist('foo\n')
+ self._check_status(p, 'foo', 'D')
+ self._check_status(p, 'nochange', 'M')
+ self._check_status(p, 'merge', ' ')
+ self._check_status(p, 'toadd1', '?')
+ # additional cleanup check
+ self.__assertNotRaises(osc.oscerr.WorkingCopyInconsistent, osc.core.Package, '.')
+
+ @GET('http://localhost/source/osctest/simple6/foo?rev=1', text='This is a simple test.\n')
+ def test_simple6(self):
+ """
+ a file is listed in _to_be_deleted and is present
+ in _files but the storefile is missing
+ """
+ self._change_to_pkg('simple6')
+ self.assertRaises(osc.oscerr.WorkingCopyInconsistent, osc.core.Package, '.')
+ p = osc.core.Package('.', wc_check=False)
+ p.wc_repair()
+ self.assertTrue(os.path.exists(os.path.join('.osc', 'foo')))
+ self._check_deletelist('foo\n')
+ self._check_status(p, 'foo', 'D')
+ self._check_status(p, 'nochange', 'M')
+ self._check_status(p, 'merge', ' ')
+ self._check_status(p, 'toadd1', '?')
+ # additional cleanup check
+ self.__assertNotRaises(osc.oscerr.WorkingCopyInconsistent, osc.core.Package, '.')
+
+ def test_simple7(self):
+ """files marked as skipped don't exist in the storedir"""
+ self._change_to_pkg('simple7')
+ self.__assertNotRaises(osc.oscerr.WorkingCopyInconsistent, osc.core.Package, '.')
+
+ def test_simple8(self):
+ """
+ a file is marked as skipped but the skipped file exists in the storedir
+ """
+ self._change_to_pkg('simple8')
+ self.assertRaises(osc.oscerr.WorkingCopyInconsistent, osc.core.Package, '.')
+ p = osc.core.Package('.', wc_check=False)
+ p.wc_repair()
+ self.assertFalse(os.path.exists(os.path.join('.osc', 'skipped')))
+ self._check_deletelist('foo\n')
+ self._check_status(p, 'foo', 'D')
+ self._check_status(p, 'nochange', 'M')
+ self._check_status(p, 'merge', ' ')
+ self._check_status(p, 'toadd1', '?')
+ self._check_status(p, 'skipped', 'S')
+ # additional cleanup check
+ self.__assertNotRaises(osc.oscerr.WorkingCopyInconsistent, osc.core.Package, '.')
+
+ @GET('http://localhost/source/osctest/multiple/merge?rev=1', text='Is it\npossible to\nmerge this file?I hope so...\n')
+ @GET('http://localhost/source/osctest/multiple/nochange?rev=1', text='This file didn\'t change.\n')
+ def test_multiple(self):
+ """
+ a storefile is missing, a file is listed in _to_be_deleted
+ but is not present in _files, a file is listed in _in_conflict
+ but the storefile is missing and a file exists in the storedir
+ but is not present in _files
+ """
+ self._change_to_pkg('multiple')
+ self.assertRaises(osc.oscerr.WorkingCopyInconsistent, osc.core.Package, '.')
+ p = osc.core.Package('.', wc_check=False)
+ p.wc_repair()
+ self.assertTrue(os.path.exists(os.path.join('.osc', 'foo')))
+ self.assertFalse(os.path.exists(os.path.join('.osc', 'unknown_file')))
+ self._check_deletelist('foo\n')
+ self._check_status(p, 'foo', 'D')
+ self._check_status(p, 'nochange', 'C')
+ self._check_status(p, 'merge', ' ')
+ self._check_status(p, 'foobar', 'A')
+ self._check_status(p, 'toadd1', '?')
+ # additional cleanup check
+ self.__assertNotRaises(osc.oscerr.WorkingCopyInconsistent, osc.core.Package, '.')
+
+ def test_noapiurl(self):
+ """the package wc has no _apiurl file"""
+ self._change_to_pkg('noapiurl')
+ p = osc.core.Package('.', wc_check=False)
+ p.wc_repair('http://localhost')
+ self.assertTrue(os.path.exists(os.path.join('.osc', '_apiurl')))
+ self.assertEqual(open(os.path.join('.osc', '_apiurl')).read(), 'http://localhost\n')
+ self.assertEqual(p.apiurl, 'http://localhost')
+
+ def test_invalidapiurl(self):
+ """the package wc has an invalid apiurl file (invalid url format)"""
+ self._change_to_pkg('invalid_apiurl')
+ p = osc.core.Package('.', wc_check=False)
+ p.wc_repair('http://localhost')
+ self.assertTrue(os.path.exists(os.path.join('.osc', '_apiurl')))
+ self.assertEqual(open(os.path.join('.osc', '_apiurl')).read(), 'http://localhost\n')
+ self.assertEqual(p.apiurl, 'http://localhost')
+
+ def test_invalidapiurl_param(self):
+ """pass an invalid apiurl to wc_repair"""
+ try:
+ from urllib.error import URLError
+ except ImportError:
+ from urllib2 import URLError
+ self._change_to_pkg('invalid_apiurl')
+ p = osc.core.Package('.', wc_check=False)
+ self.assertRaises(URLError, p.wc_repair, 'http:/localhost')
+ self.assertRaises(URLError, p.wc_repair, 'invalid')
+
+ def test_noapiurlNotExistingApiurl(self):
+ """the package wc has no _apiurl file and no apiurl is passed to repairwc"""
+ self._change_to_pkg('noapiurl')
+ self.assertRaises(osc.oscerr.WorkingCopyInconsistent, osc.core.Package, '.')
+ p = osc.core.Package('.', wc_check=False)
+ self.assertRaises(osc.oscerr.WorkingCopyInconsistent, p.wc_repair)
+ self.assertFalse(os.path.exists(os.path.join('.osc', '_apiurl')))
+
+ def test_project_noapiurl(self):
+ """the project wc has no _apiurl file"""
+ import shutil
+ prj_dir = os.path.join(self.tmpdir, 'prj_noapiurl')
+ shutil.copytree(os.path.join(self._get_fixtures_dir(), 'prj_noapiurl'), prj_dir)
+ storedir = os.path.join(prj_dir, osc.core.store)
+ self.assertRaises(osc.oscerr.WorkingCopyInconsistent, osc.core.Project, prj_dir, getPackageList=False)
+ prj = osc.core.Project(prj_dir, wc_check=False, getPackageList=False)
+ prj.wc_repair('http://localhost')
+ self.assertTrue(os.path.exists(os.path.join(storedir, '_apiurl')))
+ self.assertTrue(os.path.exists(os.path.join(storedir, '_apiurl')))
+ self.assertEqual(open(os.path.join(storedir, '_apiurl'), 'r').read(), 'http://localhost\n')
+
+ def test_project_invalidapiurl(self):
+ """the project wc has an invalid _apiurl file (invalid url format)"""
+ import shutil
+ prj_dir = os.path.join(self.tmpdir, 'prj_invalidapiurl')
+ shutil.copytree(os.path.join(self._get_fixtures_dir(), 'prj_invalidapiurl'), prj_dir)
+ storedir = os.path.join(prj_dir, osc.core.store)
+ self.assertRaises(osc.oscerr.WorkingCopyInconsistent, osc.core.Project, prj_dir, getPackageList=False)
+ prj = osc.core.Project(prj_dir, wc_check=False, getPackageList=False)
+ prj.wc_repair('http://localhost')
+ self.assertTrue(os.path.exists(os.path.join(storedir, '_apiurl')))
+ self.assertTrue(os.path.exists(os.path.join(storedir, '_apiurl')))
+ self.assertEqual(open(os.path.join(storedir, '_apiurl'), 'r').read(), 'http://localhost\n')
+
+ def test_project_invalidapiurl_param(self):
+ """pass an invalid apiurl to wc_repair"""
+ import shutil
+ try:
+ from urllib.error import URLError
+ except ImportError:
+ from urllib2 import URLError
+ prj_dir = os.path.join(self.tmpdir, 'prj_invalidapiurl')
+ shutil.copytree(os.path.join(self._get_fixtures_dir(), 'prj_invalidapiurl'), prj_dir)
+ storedir = os.path.join(prj_dir, osc.core.store)
+ self.assertRaises(osc.oscerr.WorkingCopyInconsistent, osc.core.Project, prj_dir, getPackageList=False)
+ prj = osc.core.Project(prj_dir, wc_check=False, getPackageList=False)
+ self.assertRaises(URLError, prj.wc_repair, 'http:/localhost')
+ self.assertRaises(URLError, prj.wc_repair, 'invalid')
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main()
--- /dev/null
+import osc.core
+import osc.oscerr
+import os
+from common import OscTestCase
+
+FIXTURES_DIR = os.path.join(os.getcwd(), 'tests/request_fixtures')
+
+def suite():
+ import unittest
+ return unittest.makeSuite(TestRequest)
+
+class TestRequest(OscTestCase):
+ def _get_fixtures_dir(self):
+ return FIXTURES_DIR
+
+ def setUp(self):
+ OscTestCase.setUp(self, copytree=False)
+
+ def test_createsr(self):
+ """create a simple submitrequest"""
+ r = osc.core.Request()
+ r.add_action('submit', src_project='foo', src_package='bar', src_rev='42',
+ tgt_project='foobar', tgt_package='bar')
+ self.assertEqual(r.actions[0].type, 'submit')
+ self.assertEqual(r.actions[0].src_project, 'foo')
+ self.assertEqual(r.actions[0].src_package, 'bar')
+ self.assertEqual(r.actions[0].src_rev, '42')
+ self.assertEqual(r.actions[0].tgt_project, 'foobar')
+ self.assertEqual(r.actions[0].tgt_package, 'bar')
+ self.assertTrue(r.actions[0].opt_sourceupdate is None)
+ self.assertTrue(r.actions[0].opt_updatelink is None)
+ self.assertTrue(len(r.statehistory) == 0)
+ self.assertTrue(len(r.reviews) == 0)
+ self.assertRaises(AttributeError, getattr, r.actions[0], 'doesnotexist')
+ exp = """<request>
+ <action type="submit">
+ <source package="bar" project="foo" rev="42" />
+ <target package="bar" project="foobar" />
+ </action>
+</request>"""
+ self.assertEqual(exp, r.to_str())
+
+ def test_createsr_with_option(self):
+ """create a submitrequest with option"""
+ """create a simple submitrequest"""
+ r = osc.core.Request()
+ r.add_action('submit', src_project='foo', src_package='bar',
+ tgt_project='foobar', tgt_package='bar', opt_sourceupdate='cleanup', opt_updatelink='1')
+ self.assertEqual(r.actions[0].type, 'submit')
+ self.assertEqual(r.actions[0].src_project, 'foo')
+ self.assertEqual(r.actions[0].src_package, 'bar')
+ self.assertEqual(r.actions[0].tgt_project, 'foobar')
+ self.assertEqual(r.actions[0].tgt_package, 'bar')
+ self.assertEqual(r.actions[0].opt_sourceupdate, 'cleanup')
+ self.assertEqual(r.actions[0].opt_updatelink, '1')
+ self.assertTrue(r.actions[0].src_rev is None)
+ self.assertTrue(len(r.statehistory) == 0)
+ self.assertTrue(len(r.reviews) == 0)
+ self.assertRaises(AttributeError, getattr, r.actions[0], 'doesnotexist')
+ exp = """<request>
+ <action type="submit">
+ <source package="bar" project="foo" />
+ <target package="bar" project="foobar" />
+ <options>
+ <sourceupdate>cleanup</sourceupdate>
+ <updatelink>1</updatelink>
+ </options>
+ </action>
+</request>"""
+ self.assertEqual(exp, r.to_str())
+
+ def test_createsr_missing_tgt_package(self):
+ """create a submitrequest with missing target package"""
+ r = osc.core.Request()
+ r.add_action('submit', src_project='foo', src_package='bar',
+ tgt_project='foobar')
+ self.assertEqual(r.actions[0].type, 'submit')
+ self.assertEqual(r.actions[0].src_project, 'foo')
+ self.assertEqual(r.actions[0].src_package, 'bar')
+ self.assertEqual(r.actions[0].tgt_project, 'foobar')
+ self.assertTrue(len(r.statehistory) == 0)
+ self.assertTrue(len(r.reviews) == 0)
+ self.assertTrue(r.actions[0].tgt_package is None)
+ self.assertRaises(AttributeError, getattr, r.actions[0], 'doesnotexist')
+ exp = """<request>
+ <action type="submit">
+ <source package="bar" project="foo" />
+ <target project="foobar" />
+ </action>
+</request>"""
+ self.assertEqual(exp, r.to_str())
+
+ def test_createsr_invalid_argument(self):
+ """create a submitrequest with invalid action argument"""
+ r = osc.core.Request()
+ self.assertRaises(osc.oscerr.WrongArgs, r.add_action, 'submit', src_project='foo', src_invalid='bar')
+
+ def test_create_request_invalid_type(self):
+ """create a request with an invalid action type"""
+ r = osc.core.Request()
+ self.assertRaises(osc.oscerr.WrongArgs, r.add_action, 'invalid', foo='bar')
+
+ def test_create_add_role_person(self):
+ """create an add_role request (person element)"""
+ r = osc.core.Request()
+ r.add_action('add_role', tgt_project='foo', tgt_package='bar', person_name='user', person_role='reader')
+ self.assertEqual(r.actions[0].type, 'add_role')
+ self.assertEqual(r.actions[0].tgt_project, 'foo')
+ self.assertEqual(r.actions[0].tgt_package, 'bar')
+ self.assertEqual(r.actions[0].person_name, 'user')
+ self.assertEqual(r.actions[0].person_role, 'reader')
+ self.assertTrue(r.actions[0].group_name is None)
+ self.assertTrue(r.actions[0].group_role is None)
+ exp = """<request>
+ <action type="add_role">
+ <target package="bar" project="foo" />
+ <person name="user" role="reader" />
+ </action>
+</request>"""
+ self.assertEqual(exp, r.to_str())
+
+ def test_create_add_role_group(self):
+ """create an add_role request (group element)"""
+ r = osc.core.Request()
+ r.add_action('add_role', tgt_project='foo', tgt_package='bar', group_name='group', group_role='reviewer')
+ self.assertEqual(r.actions[0].type, 'add_role')
+ self.assertEqual(r.actions[0].tgt_project, 'foo')
+ self.assertEqual(r.actions[0].tgt_package, 'bar')
+ self.assertEqual(r.actions[0].group_name, 'group')
+ self.assertEqual(r.actions[0].group_role, 'reviewer')
+ self.assertTrue(r.actions[0].person_name is None)
+ self.assertTrue(r.actions[0].person_role is None)
+ self.assertTrue(len(r.statehistory) == 0)
+ self.assertTrue(len(r.reviews) == 0)
+ exp = """<request>
+ <action type="add_role">
+ <target package="bar" project="foo" />
+ <group name="group" role="reviewer" />
+ </action>
+</request>"""
+ self.assertEqual(exp, r.to_str())
+
+ def test_create_add_role_person_group(self):
+ """create an add_role request (person+group element)"""
+ r = osc.core.Request()
+ r.add_action('add_role', tgt_project='foo', tgt_package='bar', person_name='user', person_role='reader',
+ group_name='group', group_role='reviewer')
+ self.assertEqual(r.actions[0].type, 'add_role')
+ self.assertEqual(r.actions[0].tgt_project, 'foo')
+ self.assertEqual(r.actions[0].tgt_package, 'bar')
+ self.assertEqual(r.actions[0].person_name, 'user')
+ self.assertEqual(r.actions[0].person_role, 'reader')
+ self.assertEqual(r.actions[0].group_name, 'group')
+ self.assertEqual(r.actions[0].group_role, 'reviewer')
+ self.assertTrue(len(r.statehistory) == 0)
+ self.assertTrue(len(r.reviews) == 0)
+ exp = """<request>
+ <action type="add_role">
+ <target package="bar" project="foo" />
+ <person name="user" role="reader" />
+ <group name="group" role="reviewer" />
+ </action>
+</request>"""
+ self.assertEqual(exp, r.to_str())
+
+ def test_create_set_bugowner_project(self):
+ """create a set_bugowner request for a project"""
+ r = osc.core.Request()
+ r.add_action('set_bugowner', tgt_project='foobar', person_name='buguser')
+ self.assertEqual(r.actions[0].type, 'set_bugowner')
+ self.assertEqual(r.actions[0].tgt_project, 'foobar')
+ self.assertEqual(r.actions[0].person_name, 'buguser')
+ self.assertTrue(r.actions[0].tgt_package is None)
+ self.assertTrue(len(r.statehistory) == 0)
+ self.assertTrue(len(r.reviews) == 0)
+ exp = """<request>
+ <action type="set_bugowner">
+ <target project="foobar" />
+ <person name="buguser" />
+ </action>
+</request>"""
+ self.assertEqual(exp, r.to_str())
+
+ def test_create_set_bugowner_package(self):
+ """create a set_bugowner request for a package"""
+ r = osc.core.Request()
+ r.add_action('set_bugowner', tgt_project='foobar', tgt_package='baz', person_name='buguser')
+ self.assertEqual(r.actions[0].type, 'set_bugowner')
+ self.assertEqual(r.actions[0].tgt_project, 'foobar')
+ self.assertEqual(r.actions[0].tgt_package, 'baz')
+ self.assertEqual(r.actions[0].person_name, 'buguser')
+ self.assertTrue(len(r.statehistory) == 0)
+ self.assertTrue(len(r.reviews) == 0)
+ exp = """<request>
+ <action type="set_bugowner">
+ <target package="baz" project="foobar" />
+ <person name="buguser" />
+ </action>
+</request>"""
+ self.assertEqual(exp, r.to_str())
+
+ def test_create_delete_project(self):
+ """create a delete request for a project"""
+ r = osc.core.Request()
+ r.add_action('delete', tgt_project='foo')
+ self.assertEqual(r.actions[0].type, 'delete')
+ self.assertEqual(r.actions[0].tgt_project, 'foo')
+ self.assertTrue(r.actions[0].tgt_package is None)
+ self.assertTrue(len(r.statehistory) == 0)
+ self.assertTrue(len(r.reviews) == 0)
+ exp = """<request>
+ <action type="delete">
+ <target project="foo" />
+ </action>
+</request>"""
+ self.assertEqual(exp, r.to_str())
+
+ def test_create_delete_package(self):
+ """create a delete request for a package"""
+ r = osc.core.Request()
+ r.add_action('delete', tgt_project='foo', tgt_package='deleteme')
+ self.assertEqual(r.actions[0].type, 'delete')
+ self.assertEqual(r.actions[0].tgt_project, 'foo')
+ self.assertEqual(r.actions[0].tgt_package, 'deleteme')
+ self.assertTrue(len(r.statehistory) == 0)
+ self.assertTrue(len(r.reviews) == 0)
+ exp = """<request>
+ <action type="delete">
+ <target package="deleteme" project="foo" />
+ </action>
+</request>"""
+ self.assertEqual(exp, r.to_str())
+
+ def test_create_change_devel(self):
+ """create a change devel request"""
+ r = osc.core.Request()
+ r.add_action('change_devel', src_project='foo', src_package='bar', tgt_project='devprj', tgt_package='devpkg')
+ self.assertEqual(r.actions[0].type, 'change_devel')
+ self.assertEqual(r.actions[0].src_project, 'foo')
+ self.assertEqual(r.actions[0].src_package, 'bar')
+ self.assertEqual(r.actions[0].tgt_project, 'devprj')
+ self.assertEqual(r.actions[0].tgt_package, 'devpkg')
+ self.assertTrue(len(r.statehistory) == 0)
+ self.assertTrue(len(r.reviews) == 0)
+ exp = """<request>
+ <action type="change_devel">
+ <source package="bar" project="foo" />
+ <target package="devpkg" project="devprj" />
+ </action>
+</request>"""
+ self.assertEqual(exp, r.to_str())
+
+ def test_action_from_xml1(self):
+ """create action from xml"""
+ from xml.etree import cElementTree as ET
+ xml = """<action type="add_role">
+ <target package="bar" project="foo" />
+ <person name="user" role="reader" />
+ <group name="group" role="reviewer" />
+</action>"""
+ action = osc.core.Action.from_xml(ET.fromstring(xml))
+ self.assertEqual(action.type, 'add_role')
+ self.assertEqual(action.tgt_project, 'foo')
+ self.assertEqual(action.tgt_package, 'bar')
+ self.assertEqual(action.person_name, 'user')
+ self.assertEqual(action.person_role, 'reader')
+ self.assertEqual(action.group_name, 'group')
+ self.assertEqual(action.group_role, 'reviewer')
+ self.assertEqual(xml, action.to_str())
+
+ def test_action_from_xml2(self):
+ """create action from xml"""
+ from xml.etree import cElementTree as ET
+ xml = """<action type="submit">
+ <source package="bar" project="foo" />
+ <target package="bar" project="foobar" />
+ <options>
+ <sourceupdate>cleanup</sourceupdate>
+ <updatelink>1</updatelink>
+ </options>
+</action>"""
+ action = osc.core.Action.from_xml(ET.fromstring(xml))
+ self.assertEqual(action.type, 'submit')
+ self.assertEqual(action.src_project, 'foo')
+ self.assertEqual(action.src_package, 'bar')
+ self.assertEqual(action.tgt_project, 'foobar')
+ self.assertEqual(action.tgt_package, 'bar')
+ self.assertEqual(action.opt_sourceupdate, 'cleanup')
+ self.assertEqual(action.opt_updatelink, '1')
+ self.assertTrue(action.src_rev is None)
+ self.assertEqual(xml, action.to_str())
+
+ def test_action_from_xml3(self):
+ """create action from xml (with acceptinfo element)"""
+ from xml.etree import cElementTree as ET
+ xml = """<action type="submit">
+ <source package="bar" project="testprj" />
+ <target package="baz" project="foobar" />
+ <acceptinfo rev="5" srcmd5="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" xsrcmd5="ffffffffffffffffffffffffffffffff" />
+</action>"""
+ action = osc.core.Action.from_xml(ET.fromstring(xml))
+ self.assertEqual(action.type, 'submit')
+ self.assertEqual(action.src_project, 'testprj')
+ self.assertEqual(action.src_package, 'bar')
+ self.assertEqual(action.tgt_project, 'foobar')
+ self.assertEqual(action.tgt_package, 'baz')
+ self.assertTrue(action.opt_sourceupdate is None)
+ self.assertTrue(action.opt_updatelink is None)
+ self.assertTrue(action.src_rev is None)
+ self.assertEqual(action.acceptinfo_rev, '5')
+ self.assertEqual(action.acceptinfo_srcmd5, 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')
+ self.assertEqual(action.acceptinfo_xsrcmd5, 'ffffffffffffffffffffffffffffffff')
+ self.assertTrue(action.acceptinfo_osrcmd5 is None)
+ self.assertTrue(action.acceptinfo_oxsrcmd5 is None)
+ self.assertEqual(xml, action.to_str())
+
+ def test_action_from_xml_unknown_type(self):
+ """try to create action from xml with unknown type"""
+ from xml.etree import cElementTree as ET
+ xml = '<action type="foo"><source package="bar" project="foo" /></action>'
+ self.assertRaises(osc.oscerr.WrongArgs, osc.core.Action.from_xml, ET.fromstring(xml))
+
+ def test_read_request1(self):
+ """read in a request"""
+ from xml.etree import cElementTree as ET
+ xml = open(os.path.join(self._get_fixtures_dir(), 'test_read_request1.xml'), 'r').read().strip()
+ r = osc.core.Request()
+ r.read(ET.fromstring(xml))
+ self.assertEqual(r.reqid, '42')
+ self.assertEqual(r.actions[0].type, 'submit')
+ self.assertEqual(r.actions[0].src_project, 'foo')
+ self.assertEqual(r.actions[0].src_package, 'bar')
+ self.assertEqual(r.actions[0].src_rev, '1')
+ self.assertEqual(r.actions[0].tgt_project, 'foobar')
+ self.assertEqual(r.actions[0].tgt_package, 'bar')
+ self.assertTrue(r.actions[0].opt_sourceupdate is None)
+ self.assertTrue(r.actions[0].opt_updatelink is None)
+ self.assertEqual(r.actions[1].type, 'delete')
+ self.assertEqual(r.actions[1].tgt_project, 'deleteme')
+ self.assertTrue(r.actions[1].tgt_package is None)
+ self.assertEqual(r.state.name, 'accepted')
+ self.assertEqual(r.state.when, '2010-12-27T01:36:29')
+ self.assertEqual(r.state.who, 'user1')
+ self.assertEqual(r.state.comment, '')
+ self.assertEqual(r.statehistory[0].when, '2010-12-13T13:02:03')
+ self.assertEqual(r.statehistory[0].who, 'creator')
+ self.assertEqual(r.statehistory[0].comment, 'foobar')
+ self.assertEqual(r.title, 'title of the request')
+ self.assertEqual(r.description, 'this is a\nvery long\ndescription')
+ self.assertTrue(len(r.statehistory) == 1)
+ self.assertTrue(len(r.reviews) == 0)
+ self.assertEqual(xml, r.to_str())
+
+ def test_read_request2(self):
+ """read in a request (with reviews)"""
+ from xml.etree import cElementTree as ET
+ xml = open(os.path.join(self._get_fixtures_dir(), 'test_read_request2.xml'), 'r').read().strip()
+ r = osc.core.Request()
+ r.read(ET.fromstring(xml))
+ self.assertEqual(r.reqid, '123')
+ self.assertEqual(r.actions[0].type, 'submit')
+ self.assertEqual(r.actions[0].src_project, 'xyz')
+ self.assertEqual(r.actions[0].src_package, 'abc')
+ self.assertTrue(r.actions[0].src_rev is None)
+ self.assertEqual(r.actions[0].opt_sourceupdate, 'cleanup')
+ self.assertEqual(r.actions[0].opt_updatelink, '1')
+ self.assertEqual(r.actions[1].type, 'add_role')
+ self.assertEqual(r.actions[1].tgt_project, 'home:foo')
+ self.assertEqual(r.actions[1].person_name, 'bar')
+ self.assertEqual(r.actions[1].person_role, 'maintainer')
+ self.assertEqual(r.actions[1].group_name, 'groupxyz')
+ self.assertEqual(r.actions[1].group_role, 'reader')
+ self.assertTrue(r.actions[1].tgt_package is None)
+ self.assertEqual(r.state.name, 'review')
+ self.assertEqual(r.state.when, '2010-12-27T01:36:29')
+ self.assertEqual(r.state.who, 'abc')
+ self.assertEqual(r.state.comment, '')
+ self.assertEqual(r.reviews[0].state, 'new')
+ self.assertEqual(r.reviews[0].by_group, 'group1')
+ self.assertEqual(r.reviews[0].when, '2010-12-28T00:11:22')
+ self.assertEqual(r.reviews[0].who, 'abc')
+ self.assertEqual(r.reviews[0].comment, 'review start')
+ self.assertTrue(r.reviews[0].by_user is None)
+ self.assertEqual(r.statehistory[0].when, '2010-12-11T00:00:00')
+ self.assertEqual(r.statehistory[0].who, 'creator')
+ self.assertEqual(r.statehistory[0].comment, '')
+ self.assertEqual(r.get_creator(), 'creator')
+ self.assertTrue(len(r.statehistory) == 1)
+ self.assertTrue(len(r.reviews) == 1)
+ self.assertEqual(xml, r.to_str())
+
+ def test_read_request3(self):
+ """read in a request (with an "empty" comment+description)"""
+ from xml.etree import cElementTree as ET
+ xml = """<request id="2">
+ <action type="set_bugowner">
+ <target project="foo" />
+ <person name="buguser" />
+ </action>
+ <state name="new" when="2010-12-28T12:36:29" who="xyz">
+ <comment></comment>
+ </state>
+ <description></description>
+</request>"""
+ r = osc.core.Request()
+ r.read(ET.fromstring(xml))
+ self.assertEqual(r.reqid, '2')
+ self.assertEqual(r.actions[0].type, 'set_bugowner')
+ self.assertEqual(r.actions[0].tgt_project, 'foo')
+ self.assertEqual(r.actions[0].person_name, 'buguser')
+ self.assertEqual(r.state.name, 'new')
+ self.assertEqual(r.state.when, '2010-12-28T12:36:29')
+ self.assertEqual(r.state.who, 'xyz')
+ self.assertEqual(r.state.comment, '')
+ self.assertEqual(r.description, '')
+ self.assertTrue(len(r.statehistory) == 0)
+ self.assertTrue(len(r.reviews) == 0)
+ self.assertEqual(r.get_creator(), 'xyz')
+ exp = """<request id="2">
+ <action type="set_bugowner">
+ <target project="foo" />
+ <person name="buguser" />
+ </action>
+ <state name="new" when="2010-12-28T12:36:29" who="xyz" />
+</request>"""
+
+ self.assertEqual(exp, r.to_str())
+
+ def test_request_list_view1(self):
+ """test the list_view method"""
+ from xml.etree import cElementTree as ET
+ xml = open(os.path.join(self._get_fixtures_dir(), 'test_request_list_view1.xml'), 'r').read().strip()
+ exp = """\
+ 62 State:new By:Admin When:2010-12-29T14:57:25
+ set_bugowner: buguser foo
+ add_role: person: xyz as maintainer, group: group1 as reader foobar
+ add_role: person: abc as reviewer foo/bar
+ change_devel: foo/bar developed in devprj/devpkg
+ submit: srcprj/srcpackage -> tgtprj/tgtpackage
+ submit: foo/bar -> baz
+ delete: deleteme
+ delete: foo/bar\n"""
+ r = osc.core.Request()
+ r.read(ET.fromstring(xml))
+ self.assertEqual(exp, r.list_view())
+
+ def test_request_list_view2(self):
+ """test the list_view method (with history elements and description)"""
+ from xml.etree import cElementTree as ET
+ xml = open(os.path.join(self._get_fixtures_dir(), 'test_request_list_view2.xml'), 'r').read().strip()
+ r = osc.core.Request()
+ r.read(ET.fromstring(xml))
+ exp = """\
+ 21 State:accepted By:foobar When:2010-12-29T16:37:45
+ set_bugowner: buguser foo
+ From: Created Request: user -> Review Approved: foobar
+ Descr: This is a simple request with a lot of ... ... text and other
+ stuff. This request also contains a description. This is useful
+ to describe the request. blabla blabla\n"""
+ self.assertEqual(exp, r.list_view())
+
+ def test_request_str1(self):
+ from xml.etree import cElementTree as ET
+ """test the __str__ method"""
+ xml = open(os.path.join(self._get_fixtures_dir(), 'test_request_str1.xml'), 'r').read().strip()
+ r = osc.core.Request()
+ r = osc.core.Request()
+ r.read(ET.fromstring(xml))
+ self.assertEqual(r.get_creator(), 'creator')
+ exp = """\
+Request: #123
+
+ submit: xyz/abc(cleanup) -> foo ***update link***
+ add_role: person: bar as maintainer, group: groupxyz as reader home:foo
+
+
+Message:
+just a samll description
+in order to describe this
+request - blablabla
+test.
+
+State: review 2010-12-27T01:36:29 abc
+Comment: currently in review
+
+Review: accepted Group: group1 2010-12-29T00:11:22 abc accepted
+ new Group: group1 2010-12-28T00:11:22 abc review start
+
+History: 2010-12-12T00:00:00 creator revoked
+ 2010-12-11T00:00:00 creator new"""
+ self.assertEqual(exp, str(r))
+
+ def test_request_str2(self):
+ """test the __str__ method"""
+ from xml.etree import cElementTree as ET
+ xml = """\
+<request id="98765">
+ <action type="change_devel">
+ <source project="devprj" package="devpkg" />
+ <target project="foo" package="bar" />
+ </action>
+ <action type="delete">
+ <target project="deleteme" />
+ </action>
+ <state name="new" when="2010-12-29T00:11:22" who="creator" />
+</request>"""
+ r = osc.core.Request()
+ r.read(ET.fromstring(xml))
+ self.assertEqual(r.get_creator(), 'creator')
+ exp = """\
+Request: #98765
+
+ change_devel: foo/bar developed in devprj/devpkg
+ delete: deleteme
+
+
+Message:
+<no message>
+
+State: new 2010-12-29T00:11:22 creator
+Comment: <no comment>"""
+ self.assertEqual(exp, str(r))
+
+ def test_legacy_request(self):
+ """load old-style submitrequest"""
+ from xml.etree import cElementTree as ET
+ xml = """\
+<request id="1234" type="submit">
+ <submit>
+ <source package="baz" project="foobar" />
+ <target package="baz" project="foo" />
+ </submit>
+ <state name="new" when="2010-12-30T02:11:22" who="olduser" />
+</request>"""
+ r = osc.core.Request()
+ r.read(ET.fromstring(xml))
+ self.assertEqual(r.reqid, '1234')
+ self.assertEqual(r.actions[0].type, 'submit')
+ self.assertEqual(r.actions[0].src_project, 'foobar')
+ self.assertEqual(r.actions[0].src_package, 'baz')
+ self.assertEqual(r.actions[0].tgt_project, 'foo')
+ self.assertEqual(r.actions[0].tgt_package, 'baz')
+ self.assertTrue(r.actions[0].opt_sourceupdate is None)
+ self.assertTrue(r.actions[0].opt_updatelink is None)
+ self.assertEqual(r.state.name, 'new')
+ self.assertEqual(r.state.when, '2010-12-30T02:11:22')
+ self.assertEqual(r.state.who, 'olduser')
+ self.assertEqual(r.state.comment, '')
+ self.assertEqual(r.get_creator(), 'olduser')
+ exp = """\
+<request id="1234">
+ <action type="submit">
+ <source package="baz" project="foobar" />
+ <target package="baz" project="foo" />
+ </action>
+ <state name="new" when="2010-12-30T02:11:22" who="olduser" />
+</request>"""
+ self.assertEqual(exp, r.to_str())
+
+ def test_get_actions(self):
+ """test get_actions method"""
+ from xml.etree import cElementTree as ET
+ xml = open(os.path.join(self._get_fixtures_dir(), 'test_request_list_view1.xml'), 'r').read().strip()
+ r = osc.core.Request()
+ r.read(ET.fromstring(xml))
+ sr_actions = r.get_actions('submit')
+ self.assertTrue(len(sr_actions) == 2)
+ for i in sr_actions:
+ self.assertEqual(i.type, 'submit')
+ self.assertTrue(len(r.get_actions('submit', 'delete', 'change_devel')) == 5)
+ self.assertTrue(len(r.get_actions()) == 8)
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main()
--- /dev/null
+import osc.core
+import osc.oscerr
+import os
+from common import OscTestCase
+
+FIXTURES_DIR = os.path.join(os.getcwd(), 'tests/revertfile_fixtures')
+
+def suite():
+ import unittest
+ return unittest.makeSuite(TestRevertFiles)
+
+class TestRevertFiles(OscTestCase):
+ def _get_fixtures_dir(self):
+ return FIXTURES_DIR
+
+ def testRevertUnchanged(self):
+ """revert an unchanged file (state == ' ')"""
+ self._change_to_pkg('simple')
+ p = osc.core.Package('.')
+ self.assertRaises(osc.oscerr.OscIOError, p.revert, 'toadd2')
+ self._check_status(p, 'toadd2', '?')
+
+ def testRevertModified(self):
+ """revert a modified file"""
+ self._change_to_pkg('simple')
+ p = osc.core.Package('.')
+ p.revert('nochange')
+ self.__check_file('nochange')
+ self._check_status(p, 'nochange', ' ')
+
+ def testRevertAdded(self):
+ """revert an added file"""
+ self._change_to_pkg('simple')
+ p = osc.core.Package('.')
+ p.revert('toadd1')
+ self.assertTrue(os.path.exists('toadd1'))
+ self._check_addlist('replaced\naddedmissing\n')
+ self._check_status(p, 'toadd1', '?')
+
+ def testRevertDeleted(self):
+ """revert a deleted file"""
+ self._change_to_pkg('simple')
+ p = osc.core.Package('.')
+ p.revert('somefile')
+ self.__check_file('somefile')
+ self._check_deletelist('deleted\n')
+ self._check_status(p, 'somefile', ' ')
+
+ def testRevertMissing(self):
+ """revert a missing (state == '!') file"""
+ self._change_to_pkg('simple')
+ p = osc.core.Package('.')
+ p.revert('missing')
+ self.__check_file('missing')
+ self._check_status(p, 'missing', ' ')
+
+ def testRevertMissingAdded(self):
+ """revert a missing file which was added to the wc"""
+ self._change_to_pkg('simple')
+ p = osc.core.Package('.')
+ p.revert('addedmissing')
+ self._check_addlist('toadd1\nreplaced\n')
+ self.assertRaises(osc.oscerr.OscIOError, p.status, 'addedmissing')
+
+ def testRevertReplaced(self):
+ """revert a replaced (state == 'R') file"""
+ self._change_to_pkg('simple')
+ p = osc.core.Package('.')
+ p.revert('replaced')
+ self.__check_file('replaced')
+ self._check_addlist('toadd1\naddedmissing\n')
+ self._check_status(p, 'replaced', ' ')
+
+ def testRevertConflict(self):
+ """revert a file which is in the conflict state"""
+ self._change_to_pkg('simple')
+ p = osc.core.Package('.')
+ p.revert('foo')
+ self.__check_file('foo')
+ self.assertFalse(os.path.exists(os.path.join('.osc', '_in_conflict')))
+ self._check_status(p, 'foo', ' ')
+
+ def testRevertSkipped(self):
+ """revert a skipped file"""
+ self._change_to_pkg('simple')
+ p = osc.core.Package('.')
+ self.assertRaises(osc.oscerr.OscIOError, p.revert, 'skipped')
+
+ def __check_file(self, fname):
+ storefile = os.path.join('.osc', fname)
+ self.assertTrue(os.path.exists(fname))
+ self.assertTrue(os.path.exists(storefile))
+ self.assertEqual(open(fname, 'r').read(), open(storefile, 'r').read())
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main()
--- /dev/null
+import osc.core
+import osc.oscerr
+import os
+from common import GET, PUT, OscTestCase
+FIXTURES_DIR = os.path.join(os.getcwd(), 'tests/setlinkrev_fixtures')
+
+def suite():
+ import unittest
+ return unittest.makeSuite(TestSetLinkRev)
+
+class TestSetLinkRev(OscTestCase):
+ def setUp(self):
+ OscTestCase.setUp(self, copytree=False)
+
+ def _get_fixtures_dir(self):
+ return FIXTURES_DIR
+
+ @GET('http://localhost/source/osctest/simple/_link', file='simple_link')
+ @GET('http://localhost/source/srcprj/srcpkg?rev=latest', file='simple_filesremote')
+ @PUT('http://localhost/source/osctest/simple/_link',
+ exp='<link package="srcpkg" project="srcprj" rev="42" />', text='dummytext')
+ def test_simple1(self):
+ """a simple set_link_rev call without revision"""
+ osc.core.set_link_rev('http://localhost', 'osctest', 'simple')
+
+ @GET('http://localhost/source/osctest/simple/_link', file='simple_link')
+ @PUT('http://localhost/source/osctest/simple/_link',
+ exp='<link package="srcpkg" project="srcprj" rev="42" />', text='dummytext')
+ def test_simple2(self):
+ """a simple set_link_rev call with revision"""
+ osc.core.set_link_rev('http://localhost', 'osctest', 'simple', '42')
+
+ @GET('http://localhost/source/osctest/simple/_link', file='noproject_link')
+ @GET('http://localhost/source/osctest/srcpkg?rev=latest&expand=1', file='expandedsrc_filesremote')
+ @PUT('http://localhost/source/osctest/simple/_link',
+ exp='<link package="srcpkg" rev="eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" vrev="1" />', text='dummytext')
+ def test_expandedsrc(self):
+ """expand src package"""
+ osc.core.set_link_rev('http://localhost', 'osctest', 'simple', expand=True)
+
+ @GET('http://localhost/source/osctest/simple/_link', file='link_with_rev')
+ @GET('http://localhost/source/srcprj/srcpkg?rev=latest', file='simple_filesremote')
+ @PUT('http://localhost/source/osctest/simple/_link',
+ exp='<link package="srcpkg" project="srcprj" rev="42" />', text='dummytext')
+ def test_existingrev(self):
+ """link already has a rev attribute, update it to current version"""
+ # we could also avoid the superfluous PUT
+ osc.core.set_link_rev('http://localhost', 'osctest', 'simple')
+
+ @GET('http://localhost/source/osctest/simple/_link', file='link_with_rev')
+ @GET('http://localhost/source/srcprj/srcpkg?rev=latest&expand=1', file='expandedsrc_filesremote')
+ @PUT('http://localhost/source/osctest/simple/_link',
+ exp='<link package="srcpkg" project="srcprj" rev="eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" vrev="1" />',
+ text='dummytext')
+ def test_expandexistingrev(self):
+ """link already has a rev attribute, update it to current version"""
+ osc.core.set_link_rev('http://localhost', 'osctest', 'simple', expand=True)
+
+ @GET('http://localhost/source/osctest/simple/_link', file='simple_link')
+ @GET('http://localhost/source/srcprj/srcpkg?rev=latest&expand=1', text='conflict in file merge', code=400)
+ def test_linkerror(self):
+ """link is broken"""
+ try:
+ from urllib.error import HTTPError
+ except ImportError:
+ from urllib2 import HTTPError
+ # the backend returns status 400 if we try to expand a broken _link
+ self.assertRaises(HTTPError, osc.core.set_link_rev, 'http://localhost', 'osctest', 'simple', expand=True)
+
+ @GET('http://localhost/source/osctest/simple/_link', file='rev_link')
+ @PUT('http://localhost/source/osctest/simple/_link',
+ exp='<link package="srcpkg" project="srcprj" />', text='dummytext')
+ def test_deleterev(self):
+ """delete rev attribute from link xml"""
+ osc.core.set_link_rev('http://localhost', 'osctest', 'simple', revision=None)
+
+ @GET('http://localhost/source/osctest/simple/_link', file='md5_rev_link')
+ @PUT('http://localhost/source/osctest/simple/_link',
+ exp='<link package="srcpkg" project="srcprj" />', text='dummytext')
+ def test_deleterev(self):
+ """delete rev and vrev attribute from link xml"""
+ osc.core.set_link_rev('http://localhost', 'osctest', 'simple', revision=None)
+
+ @GET('http://localhost/source/osctest/simple/_link', file='simple_link')
+ @PUT('http://localhost/source/osctest/simple/_link',
+ exp='<link package="srcpkg" project="srcprj" />', text='dummytext')
+ def test_deleterevnonexistent(self):
+ """delete non existent rev attribute from link xml"""
+ osc.core.set_link_rev('http://localhost', 'osctest', 'simple', revision=None)
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main()
--- /dev/null
+import osc.core
+import osc.oscerr
+import os
+import sys
+from common import GET, OscTestCase
+FIXTURES_DIR = os.path.join(os.getcwd(), 'tests/update_fixtures')
+
+def suite():
+ import unittest
+ return unittest.makeSuite(TestUpdate)
+
+class TestUpdate(OscTestCase):
+ def _get_fixtures_dir(self):
+ return FIXTURES_DIR
+
+ @GET('http://localhost/source/osctest/simple?rev=latest', file='testUpdateNoChanges_files')
+ @GET('http://localhost/source/osctest/simple/_meta', file='meta.xml')
+ def testUpdateNoChanges(self):
+ """update without any changes (the wc is the most recent version)"""
+ self._change_to_pkg('simple')
+ osc.core.Package('.').update()
+ self.assertEqual(sys.stdout.getvalue(), 'At revision 1.\n')
+
+ @GET('http://localhost/source/osctest/simple?rev=2', file='testUpdateNewFile_files')
+ @GET('http://localhost/source/osctest/simple/upstream_added?rev=2', file='testUpdateNewFile_upstream_added')
+ @GET('http://localhost/source/osctest/simple/_meta', file='meta.xml')
+ def testUpdateNewFile(self):
+ """a new file was added to the remote package"""
+ self._change_to_pkg('simple')
+ osc.core.Package('.').update(rev=2)
+ exp = 'A upstream_added\nAt revision 2.\n'
+ self.assertEqual(sys.stdout.getvalue(), exp)
+ self._check_digests('testUpdateNewFile_files')
+
+ @GET('http://localhost/source/osctest/simple?rev=2', file='testUpdateNewFileLocalExists_files')
+ def testUpdateNewFileLocalExists(self):
+ """
+ a new file was added to the remote package but the same (unversioned)
+ file exists locally
+ """
+ self._change_to_pkg('simple')
+ self.assertRaises(osc.oscerr.PackageFileConflict, osc.core.Package('.').update, rev=2)
+
+ @GET('http://localhost/source/osctest/simple?rev=2', file='testUpdateDeletedFile_files')
+ @GET('http://localhost/source/osctest/simple/_meta', file='meta.xml')
+ def testUpdateDeletedFile(self):
+ """a file was deleted from the remote package"""
+ self._change_to_pkg('simple')
+ osc.core.Package('.').update(rev=2)
+ exp = 'D foo\nAt revision 2.\n'
+ self.assertEqual(sys.stdout.getvalue(), exp)
+ self._check_digests('testUpdateDeletedFile_files')
+ self.assertFalse(os.path.exists('foo'))
+ self.assertFalse(os.path.exists(os.path.join('.osc', 'foo')))
+
+ @GET('http://localhost/source/osctest/simple?rev=2', file='testUpdateUpstreamModifiedFile_files')
+ @GET('http://localhost/source/osctest/simple/foo?rev=2', file='testUpdateUpstreamModifiedFile_foo')
+ @GET('http://localhost/source/osctest/simple/_meta', file='meta.xml')
+ def testUpdateUpstreamModifiedFile(self):
+ """a file was modified in the remote package (local file isn't modified)"""
+
+ self._change_to_pkg('simple')
+ osc.core.Package('.').update(rev=2)
+ exp = 'U foo\nAt revision 2.\n'
+ self.assertEqual(sys.stdout.getvalue(), exp)
+ self._check_digests('testUpdateUpstreamModifiedFile_files')
+
+ @GET('http://localhost/source/osctest/conflict?rev=2', file='testUpdateConflict_files')
+ @GET('http://localhost/source/osctest/conflict/merge?rev=2', file='testUpdateConflict_merge')
+ @GET('http://localhost/source/osctest/conflict/_meta', file='meta.xml')
+ def testUpdateConflict(self):
+ """
+ a file was modified in the remote package (local file is also modified
+ and a merge isn't possible)
+ """
+ self._change_to_pkg('conflict')
+ osc.core.Package('.').update(rev=2)
+ exp = 'C merge\nAt revision 2.\n'
+ self._check_digests('testUpdateConflict_files')
+ self.assertEqual(sys.stdout.getvalue(), exp)
+ self._check_conflictlist('merge\n')
+
+ @GET('http://localhost/source/osctest/already_in_conflict?rev=2', file='testUpdateAlreadyInConflict_files')
+ @GET('http://localhost/source/osctest/already_in_conflict/merge?rev=2', file='testUpdateAlreadyInConflict_merge')
+ @GET('http://localhost/source/osctest/already_in_conflict/_meta', file='meta.xml')
+ def testUpdateAlreadyInConflict(self):
+ """
+ a file was modified in the remote package (the local file is already in conflict)
+ """
+ self._change_to_pkg('already_in_conflict')
+ osc.core.Package('.').update(rev=2)
+ exp = 'skipping \'merge\' (this is due to conflicts)\nAt revision 2.\n'
+ self.assertEqual(sys.stdout.getvalue(), exp)
+ self._check_conflictlist('merge\n')
+ self._check_digests('testUpdateAlreadyInConflict_files')
+
+ @GET('http://localhost/source/osctest/deleted?rev=2', file='testUpdateLocalDeletions_files')
+ @GET('http://localhost/source/osctest/deleted/foo?rev=2', file='testUpdateLocalDeletions_foo')
+ @GET('http://localhost/source/osctest/deleted/merge?rev=2', file='testUpdateLocalDeletions_merge')
+ @GET('http://localhost/source/osctest/deleted/_meta', file='meta.xml')
+ def testUpdateLocalDeletions(self):
+ """
+ the files 'foo' and 'merge' were modified in the remote package
+ and marked for deletion in the local wc. Additionally the file
+ 'merge' was modified in the wc before deletion so the local file
+ still exists (and a merge with the remote file is not possible)
+ """
+ self._change_to_pkg('deleted')
+ osc.core.Package('.').update(rev=2)
+ exp = 'U foo\nC merge\nAt revision 2.\n'
+ self.assertEqual(sys.stdout.getvalue(), exp)
+ self._check_deletelist('foo\n')
+ self._check_conflictlist('merge\n')
+ self.assertEqual(open('foo', 'r').read(), open(os.path.join('.osc', 'foo'), 'r').read())
+ self._check_digests('testUpdateLocalDeletions_files')
+
+ @GET('http://localhost/source/osctest/restore?rev=latest', file='testUpdateRestore_files')
+ @GET('http://localhost/source/osctest/restore/foo?rev=1', file='testUpdateRestore_foo')
+ @GET('http://localhost/source/osctest/restore/_meta', file='meta.xml')
+ def testUpdateRestore(self):
+ """local file 'foo' was deleted with a non osc command and will be restored"""
+ self._change_to_pkg('restore')
+ osc.core.Package('.').update()
+ exp = 'Restored \'foo\'\nAt revision 1.\n'
+ self.assertEqual(sys.stdout.getvalue(), exp)
+ self._check_digests('testUpdateRestore_files')
+
+ @GET('http://localhost/source/osctest/limitsize?rev=latest', file='testUpdateLimitSizeNoChange_filesremote')
+ @GET('http://localhost/source/osctest/limitsize/_meta', file='meta.xml')
+ def testUpdateLimitSizeNoChange(self):
+ """
+ a new file was added to the remote package but isn't checked out because
+ of the size constraint
+ """
+ self._change_to_pkg('limitsize')
+ osc.core.Package('.').update(size_limit=50)
+ exp = 'D bigfile\nAt revision 2.\n'
+ self.assertEqual(sys.stdout.getvalue(), exp)
+ self.assertFalse(os.path.exists(os.path.join('.osc', 'bigfile')))
+ self.assertFalse(os.path.exists('bigfile'))
+ self._check_digests('testUpdateLimitSizeNoChange_files', 'bigfile')
+
+ @GET('http://localhost/source/osctest/limitsize_local?rev=latest', file='testUpdateLocalLimitSizeNoChange_filesremote')
+ @GET('http://localhost/source/osctest/limitsize_local/_meta', file='meta.xml')
+ def testUpdateLocalLimitSizeNoChange(self):
+ """
+ a new file was added to the remote package but isn't checked out because
+ of the local size constraint
+ """
+ self._change_to_pkg('limitsize_local')
+ p = osc.core.Package('.')
+ p.update()
+ exp = 'D bigfile\nD merge\nAt revision 2.\n'
+ self.assertEqual(sys.stdout.getvalue(), exp)
+ self.assertFalse(os.path.exists(os.path.join('.osc', 'bigfile')))
+ self.assertFalse(os.path.exists(os.path.join('.osc', 'merge')))
+ self.assertFalse(os.path.exists('bigfile'))
+ self._check_digests('testUpdateLocalLimitSizeNoChange_files', 'bigfile', 'merge')
+ self._check_status(p, 'bigfile', 'S')
+ self._check_status(p, 'merge', 'S')
+
+ @GET('http://localhost/source/osctest/limitsize?rev=latest', file='testUpdateLimitSizeAddDelete_filesremote')
+ @GET('http://localhost/source/osctest/limitsize/exists?rev=2', file='testUpdateLimitSizeAddDelete_exists')
+ @GET('http://localhost/source/osctest/limitsize/_meta', file='meta.xml')
+ def testUpdateLimitSizeAddDelete(self):
+ """
+ a new file (exists) was added to the remote package with
+ size < size_limit and one file (nochange) was deleted from the
+ remote package (local file 'nochange' is modified). Additionally
+ files which didn't change are removed the local wc due to the
+ size constraint.
+ """
+ self._change_to_pkg('limitsize')
+ osc.core.Package('.').update(size_limit=10)
+ exp = 'A exists\nD bigfile\nD foo\nD merge\nD nochange\nAt revision 2.\n'
+ self.assertEqual(sys.stdout.getvalue(), exp)
+ self.assertFalse(os.path.exists(os.path.join('.osc', 'bigfile')))
+ self.assertFalse(os.path.exists('bigfile'))
+ self.assertFalse(os.path.exists(os.path.join('.osc', 'foo')))
+ self.assertFalse(os.path.exists('foo'))
+ self.assertFalse(os.path.exists(os.path.join('.osc', 'merge')))
+ self.assertFalse(os.path.exists('merge'))
+ # exists because local version is modified
+ self.assertTrue(os.path.exists('nochange'))
+
+ self._check_digests('testUpdateLimitSizeAddDelete_files', 'bigfile', 'foo', 'merge', 'nochange')
+
+ @GET('http://localhost/source/osctest/services?rev=latest', file='testUpdateServiceFilesAddDelete_filesremote')
+ @GET('http://localhost/source/osctest/services/bigfile?rev=2', file='testUpdateServiceFilesAddDelete_bigfile')
+ @GET('http://localhost/source/osctest/services/_service%3Abar?rev=2', file='testUpdateServiceFilesAddDelete__service:bar')
+ @GET('http://localhost/source/osctest/services/_service%3Afoo?rev=2', file='testUpdateServiceFilesAddDelete__service:foo')
+ @GET('http://localhost/source/osctest/services/_meta', file='meta.xml')
+ def testUpdateAddDeleteServiceFiles(self):
+ """update package with _service:* files"""
+ self._change_to_pkg('services')
+ osc.core.Package('.').update(service_files=True)
+ exp = 'A bigfile\nD _service:exists\nA _service:bar\nA _service:foo\nAt revision 2.\n'
+ self.assertEqual(sys.stdout.getvalue(), exp)
+ self.assertFalse(os.path.exists(os.path.join('.osc', '_service:bar')))
+ self.assertTrue(os.path.exists('_service:bar'))
+ self.assertEqual(open('_service:bar').read(), 'another service\n')
+ self.assertFalse(os.path.exists(os.path.join('.osc', '_service:foo')))
+ self.assertTrue(os.path.exists('_service:foo'))
+ self.assertEqual(open('_service:foo').read(), 'small\n')
+ self.assertTrue(os.path.exists('_service:exists'))
+ self._check_digests('testUpdateServiceFilesAddDelete_files', '_service:foo', '_service:bar')
+
+ @GET('http://localhost/source/osctest/services?rev=latest', file='testUpdateServiceFilesAddDelete_filesremote')
+ @GET('http://localhost/source/osctest/services/bigfile?rev=2', file='testUpdateServiceFilesAddDelete_bigfile')
+ @GET('http://localhost/source/osctest/services/_meta', file='meta.xml')
+ def testUpdateDisableAddDeleteServiceFiles(self):
+ """update package with _service:* files (with service_files=False)"""
+ self._change_to_pkg('services')
+ osc.core.Package('.').update()
+ exp = 'A bigfile\nD _service:exists\nAt revision 2.\n'
+ self.assertEqual(sys.stdout.getvalue(), exp)
+ self.assertFalse(os.path.exists(os.path.join('.osc', '_service:bar')))
+ self.assertFalse(os.path.exists('_service:bar'))
+ self.assertFalse(os.path.exists(os.path.join('.osc', '_service:foo')))
+ self.assertFalse(os.path.exists('_service:foo'))
+ self.assertTrue(os.path.exists('_service:exists'))
+ self._check_digests('testUpdateServiceFilesAddDelete_files', '_service:foo', '_service:bar')
+
+ @GET('http://localhost/source/osctest/metamode?meta=1&rev=latest', file='testUpdateMetaMode_filesremote')
+ @GET('http://localhost/source/osctest/metamode/_meta?rev=1', file='testUpdateMetaMode__meta')
+ def testUpdateMetaMode(self):
+ """update package with metamode enabled"""
+ self._change_to_pkg('metamode')
+ p = osc.core.Package('.')
+ p.update()
+ exp = 'A _meta\nD foo\nD merge\nD nochange\nAt revision 1.\n'
+ self.assertEqual(sys.stdout.getvalue(), exp)
+ self.assertFalse(os.path.exists('foo'))
+ self.assertFalse(os.path.exists('merge'))
+ self.assertFalse(os.path.exists('nochange'))
+ self._check_digests('testUpdateMetaMode_filesremote')
+ self._check_status(p, '_meta', ' ')
+
+ @GET('http://localhost/source/osctest/new?rev=latest', file='testUpdateNew_filesremote')
+ @GET('http://localhost/source/osctest/new/_meta', file='meta.xml')
+ def testUpdateNew(self):
+ """update a new (empty) package. The package has no revision."""
+ self._change_to_pkg('new')
+ p = osc.core.Package('.')
+ p.update()
+ exp = 'At revision None.\n'
+ self.assertEqual(sys.stdout.getvalue(), exp)
+ self._check_digests('testUpdateNew_filesremote')
+
+ # tests to recover from an aborted/broken update
+
+ @GET('http://localhost/source/osctest/simple/foo?rev=2', file='testUpdateResume_foo')
+ @GET('http://localhost/source/osctest/simple/merge?rev=2', file='testUpdateResume_merge')
+ @GET('http://localhost/source/osctest/simple/_meta', file='meta.xml')
+ @GET('http://localhost/source/osctest/simple?rev=2', file='testUpdateResume_files')
+ @GET('http://localhost/source/osctest/simple/_meta', file='meta.xml')
+ def testUpdateResume(self):
+ """resume an aborted update"""
+ self._change_to_pkg('resume')
+ osc.core.Package('.').update(rev=2)
+ exp = 'resuming broken update...\nU foo\nU merge\nAt revision 2.\nAt revision 2.\n'
+ self.assertEqual(sys.stdout.getvalue(), exp)
+ self.assertFalse(os.path.exists(os.path.join('.osc', '_in_update')))
+ self._check_digests('testUpdateResume_files')
+
+ @GET('http://localhost/source/osctest/simple/foo?rev=1', file='testUpdateResumeDeletedFile_foo')
+ @GET('http://localhost/source/osctest/simple/merge?rev=1', file='testUpdateResumeDeletedFile_merge')
+ @GET('http://localhost/source/osctest/simple/_meta', file='meta.xml')
+ @GET('http://localhost/source/osctest/simple?rev=1', file='testUpdateResumeDeletedFile_files')
+ @GET('http://localhost/source/osctest/simple/_meta', file='meta.xml')
+ def testUpdateResumeDeletedFile(self):
+ """
+ resume an aborted update (the file 'added' was already deleted in the first update
+ run). It's marked as deleted again (this is due to an expected issue with the update
+ code)
+ """
+ self._change_to_pkg('resume_deleted')
+ osc.core.Package('.').update(rev=1)
+ exp = 'resuming broken update...\nD added\nU foo\nU merge\nAt revision 1.\nAt revision 1.\n'
+ self.assertEqual(sys.stdout.getvalue(), exp)
+ self.assertFalse(os.path.exists(os.path.join('.osc', '_in_update')))
+ self.assertFalse(os.path.exists('added'))
+ self.assertFalse(os.path.exists(os.path.join('.osc', 'added')))
+ self._check_digests('testUpdateResumeDeletedFile_files')
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main()
--- /dev/null
+<package project="osctest" name="simple">
+ <title/>
+ <description>
+
+ </description>
+ <person userid="Admin" role="maintainer"/>
+ <person userid="Admin" role="bugowner"/>
+</package>
\ No newline at end of file
--- /dev/null
+[general]
+# URL to access API server, e.g. https://api.opensuse.org
+# you also need a section [https://api.opensuse.org] with the credentials
+apiurl = http://localhost
+# Downloaded packages are cached here. Must be writable by you.
+#packagecachedir = /var/tmp/osbuild-packagecache
+# Wrapper to call build as root (sudo, su -, ...)
+#su-wrapper = su -c
+# rootdir to setup the chroot environment
+# can contain %(repo)s, %(arch)s, %(project)s and %(package)s for replacement, e.g.
+# /srv/oscbuild/%(repo)s-%(arch)s or
+# /srv/oscbuild/%(repo)s-%(arch)s-%(project)s-%(package)s
+#build-root = /var/tmp/build-root
+# compile with N jobs (default: "getconf _NPROCESSORS_ONLN")
+#build-jobs = N
+# build-type to use - values can be (depending on the capabilities of the 'build' script)
+# empty - chroot build
+# kvm - kvm VM build (needs build-device, build-swap, build-memory)
+# xen - xen VM build (needs build-device, build-swap, build-memory)
+# experimental:
+# qemu - qemu VM build
+# lxc - lxc build
+#build-type =
+# build-device is the disk-image file to use as root for VM builds
+# e.g. /var/tmp/FILE.root
+#build-device = /var/tmp/FILE.root
+# build-swap is the disk-image to use as swap for VM builds
+# e.g. /var/tmp/FILE.swap
+#build-swap = /var/tmp/FILE.swap
+# build-memory is the amount of memory used in the VM
+# value in MB - e.g. 512
+#build-memory = 512
+# build-vmdisk-rootsize is the size of the disk-image used as root in a VM build
+# values in MB - e.g. 4096
+#build-vmdisk-rootsize = 4096
+# build-vmdisk-swapsize is the size of the disk-image used as swap in a VM build
+# values in MB - e.g. 1024
+#build-vmdisk-swapsize = 1024
+# Numeric uid:gid to assign to the "abuild" user in the build-root
+# or "caller" to use the current users uid:gid
+# This is convenient when sharing the buildroot with ordinary userids
+# on the host.
+# This should not be 0
+# build-uid =
+# extra packages to install when building packages locally (osc build)
+# this corresponds to osc build's -x option and can be overridden with that
+# -x '' can also be given on the command line to override this setting, or
+# you can have an empty setting here.
+#extra-pkgs = vim gdb strace
+# build platform is used if the platform argument is omitted to osc build
+#build_repository = openSUSE_Factory
+# default project for getpac or bco
+#getpac_default_project = openSUSE:Factory
+# alternate filesystem layout: have multiple subdirs, where colons were.
+#checkout_no_colon = 0
+# local files to ignore with status, addremove, ....
+#exclude_glob = .osc CVS .svn .* _linkerror *~ #*# *.orig *.bak *.changes.*
+# keep passwords in plaintext. If you see this comment, your osc
+# already uses the encrypted password, and only keeps them in plain text
+# for backwards compatibility. Default will change to 0 in future releases.
+# You can remove the plaintext password without harm, if you do not need
+# backwards compatibility.
+#plaintext_passwd = 1
+# limit the age of requests shown with 'osc req list'.
+# this is a default only, can be overridden by 'osc req list -D NNN'
+# Use 0 for unlimted.
+#request_list_days = 0
+# show info useful for debugging
+#debug = 1
+# show HTTP traffic useful for debugging
+#http_debug = 1
+# Skip signature verification of packages used for build.
+#no_verify = 1
+# jump into the debugger in case of errors
+#post_mortem = 1
+# print call traces in case of errors
+#traceback = 1
+# use KDE/Gnome/MacOS/Windows keyring for credentials if available
+#use_keyring = 1
+# check for unversioned/removed files before commit
+#check_filelist = 1
+# check for pending requests after executing an action (e.g. checkout, update, commit)
+#check_for_request_on_action = 0
+# what to do with the source package if the submitrequest has been accepted. If
+# nothing is specified the API default is used
+#submitrequest_on_accept_action = cleanup|update|noupdate
+#review requests interactively (default: off)
+#request_show_review = 1
+# Directory with executables to validate sources, esp before committing
+#source_validator_directory = /usr/lib/osc/source_validators
+
+[http://localhost]
+user=Admin
+pass=opensuse
+# set aliases for this apiurl
+# aliases = foo, bar
+# 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
+#http_headers = Host: foofoobar,
+# User: mumblegack
+# Force using of keyring for this API
+#keyring = 1
--- /dev/null
+http://localhost
--- /dev/null
+<project name="osctest" />
--- /dev/null
+http://localhost
--- /dev/null
+<directory name="already_in_conflict" rev="1" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="1">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282133912" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282133912" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282133912" name="nochange" size="25" />
+</directory>
\ No newline at end of file
--- /dev/null
+<package project="osctest" name="already_in_conflict">
+ <title/>
+ <description>
+
+ </description>
+ <person userid="Admin" role="maintainer"/>
+ <person userid="Admin" role="bugowner"/>
+</package>
\ No newline at end of file
--- /dev/null
+already_in_conflict
\ No newline at end of file
--- /dev/null
+osctest
\ No newline at end of file
--- /dev/null
+This is a simple test.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change.
--- /dev/null
+This is a simple test.
--- /dev/null
+Is it
+I hope so...
--- /dev/null
+This file didn't change.
--- /dev/null
+http://localhost
--- /dev/null
+<directory name="conflict" rev="1" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="1">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282130148" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282130148" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282130148" name="nochange" size="25" />
+</directory>
\ No newline at end of file
--- /dev/null
+conflict
\ No newline at end of file
--- /dev/null
+osctest
\ No newline at end of file
--- /dev/null
+This is a simple test.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change.
--- /dev/null
+This is a simple test.
--- /dev/null
+Is it possible
+to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change.
--- /dev/null
+http://localhost
--- /dev/null
+<directory name="deleted" rev="1" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="1">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282134731" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282134731" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282134731" name="nochange" size="25" />
+</directory>
\ No newline at end of file
--- /dev/null
+deleted
\ No newline at end of file
--- /dev/null
+osctest
\ No newline at end of file
--- /dev/null
+merge
+foo
--- /dev/null
+This is a simple test.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change.
--- /dev/null
+Is it possible to,
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change.
--- /dev/null
+http://localhost
--- /dev/null
+<directory name="limitsize" rev="1" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="1">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+</directory>
--- /dev/null
+osctest
\ No newline at end of file
--- /dev/null
+This is a simple test.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change.
--- /dev/null
+This is a simple test.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change but
+is modified.
--- /dev/null
+http://localhost
--- /dev/null
+<directory name="limitsize" rev="1" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="1">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+</directory>
--- /dev/null
+limitsize_local
--- /dev/null
+osctest
\ No newline at end of file
--- /dev/null
+This is a simple test.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change.
--- /dev/null
+This is a simple test.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change but
+is modified.
--- /dev/null
+http://localhost
--- /dev/null
+<directory name="simple" rev="1" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="1">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+</directory>
\ No newline at end of file
--- /dev/null
+osctest
\ No newline at end of file
--- /dev/null
+This is a simple test.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change.
--- /dev/null
+This is a simple test.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change.
--- /dev/null
+http://localhost
--- /dev/null
+<directory name="new" />
--- /dev/null
+osctest
\ No newline at end of file
--- /dev/null
+http://localhost
--- /dev/null
+<directory name="restore" rev="1" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="1">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+</directory>
--- /dev/null
+osctest
\ No newline at end of file
--- /dev/null
+This is a simple test.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change.
--- /dev/null
+http://localhost
--- /dev/null
+<directory name="simple" rev="1" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="1">
+ <entry md5="ff22941336956098ae9a564289d1bf1b" mtime="1282137256" name="added" size="15" />
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+</directory>
--- /dev/null
+<directory name="simple" rev="2" srcmd5="3ac41c59a5ed169d5ffef4d824700f7d" vrev="2">
+ <entry md5="ff22941336956098ae9a564289d1bf1b" mtime="1282137256" name="added" size="15" />
+ <entry md5="14758f1afd44c09b7992073ccf00b43d" mtime="1282137220" name="foo" size="7" />
+ <entry md5="256d8f76ba7a0a231fb46a84866f25d8" mtime="1282137238" name="merge" size="20" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+</directory>
--- /dev/null
+This is a simple test.
--- /dev/null
+<package project="osctest" name="simple">
+ <title/>
+ <description>
+
+ </description>
+ <person userid="Admin" role="maintainer"/>
+ <person userid="Admin" role="bugowner"/>
+</package>
\ No newline at end of file
--- /dev/null
+simple
\ No newline at end of file
--- /dev/null
+osctest
\ No newline at end of file
--- /dev/null
+This is a test
--- /dev/null
+This is a simple test.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change.
--- /dev/null
+This is a test
--- /dev/null
+This is a simple test.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change.
--- /dev/null
+http://localhost
--- /dev/null
+<directory name="simple" rev="1" srcmd5="3ac41c59a5ed169d5ffef4d824700f7d" vrev="1">
+ <entry md5="d41d8cd98f00b204e9800998ecf8427e" mtime="1282137256" name="added" size="15" />
+ <entry md5="14758f1afd44c09b7992073ccf00b43d" mtime="1282137220" name="foo" size="7" />
+ <entry md5="256d8f76ba7a0a231fb46a84866f25d8" mtime="1282137238" name="merge" size="20" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+</directory>
--- /dev/null
+<directory name="simple" rev="1" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="1">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+</directory>
\ No newline at end of file
--- /dev/null
+<package project="osctest" name="simple">
+ <title/>
+ <description>
+
+ </description>
+ <person userid="Admin" role="maintainer"/>
+ <person userid="Admin" role="bugowner"/>
+</package>
\ No newline at end of file
--- /dev/null
+simple
\ No newline at end of file
--- /dev/null
+osctest
\ No newline at end of file
--- /dev/null
+xxx
+xxx
+yyy
+zzz
+zzz
--- /dev/null
+This file didn't change.
--- /dev/null
+This is a test
--- /dev/null
+xxx
+xxx
+yyy
+zzz
+zzz
--- /dev/null
+This file didn't change.
--- /dev/null
+http://localhost
--- /dev/null
+<directory name="foo" rev="1" srcmd5="b9f060f4b3640e58a1d44abc25ffb9bd" vrev="1">
+ <entry md5="7b1458c733a187d4f3807665ddd02cca" mtime="1282565027" name="_service:exists" size="20" skipped="true" />
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282320303" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282320303" name="merge" size="48" />
+</directory>
--- /dev/null
+osctest
\ No newline at end of file
--- /dev/null
+This is a simple test.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+another service
+foo
--- /dev/null
+This is a simple test.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+http://localhost
--- /dev/null
+<directory name="simple" rev="1" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="1">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+</directory>
\ No newline at end of file
--- /dev/null
+simple
\ No newline at end of file
--- /dev/null
+osctest
\ No newline at end of file
--- /dev/null
+This is a simple test.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change.
--- /dev/null
+This is a simple test.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+This file didn't change but
+is modified.
--- /dev/null
+<directory name="already_in_conflict" rev="2" srcmd5="686b725018c89978678e15daa666ff85" vrev="2">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282133912" name="foo" size="23" />
+ <entry md5="14758f1afd44c09b7992073ccf00b43d" mtime="1282134056" name="merge" size="7" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282133912" name="nochange" size="25" />
+</directory>
--- /dev/null
+<directory name="conflict" rev="2" srcmd5="6463d0bd161765e9a2b7186606c72ca1" vrev="2">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282130148" name="foo" size="23" />
+ <entry md5="89fcd308c6e6919c472e56ec82ace945" mtime="1282130545" name="merge" size="46" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282130148" name="nochange" size="25" />
+</directory>
--- /dev/null
+Is
+it possible to
+merge this file?
+We'll see.
--- /dev/null
+<directory name="simple" rev="2" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="2">
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+</directory>
--- /dev/null
+<directory name="foo" rev="2" srcmd5="018a80019e08143e7ae324c778873d62" vrev="2">
+ <entry md5="ed955c917012307d982b7cdd5799ff1a" mtime="1282320398" name="bigfile" size="69" skipped="true" />
+ <entry md5="d15dbfcb847653913855e21370d83af1" mtime="1282553634" name="exists" size="6" />
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282320303" name="foo" size="23" skipped="true" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282320303" name="merge" size="48" skipped="true" />
+</directory>
--- /dev/null
+<directory name="foo" rev="2" vrev="2" srcmd5="018a80019e08143e7ae324c778873d62">
+ <entry name="bigfile" md5="ed955c917012307d982b7cdd5799ff1a" size="69" mtime="1282320398" />
+ <entry name="exists" md5="d15dbfcb847653913855e21370d83af1" size="6" mtime="1282553634" />
+ <entry name="foo" md5="0d62ceea6020d75154078a20d8c9f9ba" size="23" mtime="1282320303" />
+ <entry name="merge" md5="17b9e9e1a032ed44e7a584dc6303ffa8" size="48" mtime="1282320303" />
+</directory>
--- /dev/null
+<directory name="limitsize" rev="2" srcmd5="e51a3133d3d3eb2a48e06efb79e2d503" vrev="2">
+ <entry md5="ed955c917012307d982b7cdd5799ff1a" mtime="1282320398" name="bigfile" size="69" skipped="true" />
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282320303" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282320303" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+</directory>
--- /dev/null
+<directory name="limitsize" rev="2" vrev="2" srcmd5="e51a3133d3d3eb2a48e06efb79e2d503">
+ <entry name="bigfile" md5="ed955c917012307d982b7cdd5799ff1a" size="69" mtime="1282320398" />
+ <entry name="foo" md5="0d62ceea6020d75154078a20d8c9f9ba" size="23" mtime="1282320303" />
+ <entry name="merge" md5="17b9e9e1a032ed44e7a584dc6303ffa8" size="48" mtime="1282320303" />
+ <entry name="nochange" md5="7efa70f68983fad1cf487f69dedf93e9" size="25" mtime="1282047303" />
+</directory>
--- /dev/null
+<directory name="deleted" rev="2" srcmd5="0e717058d371ab9029336418c8c883bd" vrev="2">
+ <entry md5="2bb5f888a0063a0931c12f35851953e4" mtime="1282135005" name="foo" size="37" />
+ <entry md5="426e11f11438365322f102c02b0a33f0" mtime="1282134896" name="merge" size="50" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282134731" name="nochange" size="25" />
+</directory>
--- /dev/null
+This is a simple test.
+And an update
--- /dev/null
+Is
+it possible to
+merge this file?
+We'll see. Foo
--- /dev/null
+<directory name="limitsize_local" rev="2" srcmd5="e51a3133d3d3eb2a48e06efb79e2d503" vrev="2">
+ <entry md5="ed955c917012307d982b7cdd5799ff1a" mtime="1282320398" name="bigfile" size="69" skipped="true" />
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282320303" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282320303" name="merge" size="48" skipped="true" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+</directory>
--- /dev/null
+<directory name="limitsize_local" rev="2" vrev="2" srcmd5="e51a3133d3d3eb2a48e06efb79e2d503">
+ <entry name="bigfile" md5="ed955c917012307d982b7cdd5799ff1a" size="69" mtime="1282320398" />
+ <entry name="foo" md5="0d62ceea6020d75154078a20d8c9f9ba" size="23" mtime="1282320303" />
+ <entry name="merge" md5="17b9e9e1a032ed44e7a584dc6303ffa8" size="48" mtime="1282320303" />
+ <entry name="nochange" md5="7efa70f68983fad1cf487f69dedf93e9" size="25" mtime="1282047303" />
+</directory>
--- /dev/null
+<package project="osctest" name="metamode">
+ <title>foo</title>
+ <description />
+</package>
--- /dev/null
+<directory name="metamode" rev="1" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="1">
+ <entry md5="b995ef5586bdb37154bdeac0bda18c51" mtime="1283265642" name="_meta" size="95" />
+</directory>
--- /dev/null
+<directory name="simple" rev="2" srcmd5="28fe7af7e9985507cf51196fc67015b7" vrev="2">
+ <entry md5="7ba6ca74b292aaa5d46bc407ac5be166" mtime="1282060455" name="exists" size="7" />
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+</directory>
--- /dev/null
+<directory name="simple" rev="2" srcmd5="9247f30cd5694f5301965a0f20a2ed16" vrev="2">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282054323" name="upstream_added" size="23" />
+</directory>
--- /dev/null
+This is a simple test.
--- /dev/null
+<directory name="new">
+</directory>
--- /dev/null
+<directory name="simple" rev="1" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="1">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+</directory>
--- /dev/null
+<directory name="simple" rev="1" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="1">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+</directory>
--- /dev/null
+This is a simple test.
--- /dev/null
+<directory name="simple" rev="1" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="1">
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282047302" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+</directory>
--- /dev/null
+This is a simple test.
--- /dev/null
+Is it
+possible to
+merge this file?
+I hope so...
--- /dev/null
+<directory name="simple" rev="2" srcmd5="3ac41c59a5ed169d5ffef4d824700f7d" vrev="2">
+ <entry md5="ff22941336956098ae9a564289d1bf1b" mtime="1282137256" name="added" size="15" />
+ <entry md5="14758f1afd44c09b7992073ccf00b43d" mtime="1282137220" name="foo" size="7" />
+ <entry md5="256d8f76ba7a0a231fb46a84866f25d8" mtime="1282137238" name="merge" size="20" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+</directory>
--- /dev/null
+xxx
+xxx
+yyy
+zzz
+zzz
--- /dev/null
+another service
--- /dev/null
+This is a file
+with a lot of
+text. Foo foo
+bar bar bar.
+foobarfoobar
--- /dev/null
+<directory name="foo" rev="2" srcmd5="1c5d541a029694c43d5341cabcb4f40f" vrev="2">
+ <entry md5="a0106bad78c9070662d5cde42ee35f23" mtime="1282564656" name="_service:bar" size="16" skipped="true" />
+ <entry md5="d15dbfcb847653913855e21370d83af1" mtime="1282561867" name="_service:foo" size="6" skipped="true" />
+ <entry md5="ed955c917012307d982b7cdd5799ff1a" mtime="1282320398" name="bigfile" size="69" />
+ <entry md5="0d62ceea6020d75154078a20d8c9f9ba" mtime="1282320303" name="foo" size="23" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282320303" name="merge" size="48" />
+</directory>
--- /dev/null
+<directory name="foo" rev="2" vrev="2" srcmd5="1c5d541a029694c43d5341cabcb4f40f">
+ <entry name="_service:bar" md5="a0106bad78c9070662d5cde42ee35f23" size="16" mtime="1282564656" />
+ <entry name="_service:foo" md5="d15dbfcb847653913855e21370d83af1" size="6" mtime="1282561867" />
+ <entry name="bigfile" md5="ed955c917012307d982b7cdd5799ff1a" size="69" mtime="1282320398" />
+ <entry name="foo" md5="0d62ceea6020d75154078a20d8c9f9ba" size="23" mtime="1282320303" />
+ <entry name="merge" md5="17b9e9e1a032ed44e7a584dc6303ffa8" size="48" mtime="1282320303" />
+</directory>
--- /dev/null
+<directory name="simple" rev="2" srcmd5="2df1eacfe03a3bec2112529e7f4dc39a" vrev="2">
+ <entry md5="bb3a1efda68dff80ec3a2fb599b97ad8" mtime="1282058167" name="foo" size="39" />
+ <entry md5="17b9e9e1a032ed44e7a584dc6303ffa8" mtime="1282047303" name="merge" size="48" />
+ <entry md5="7efa70f68983fad1cf487f69dedf93e9" mtime="1282047303" name="nochange" size="25" />
+</directory>
--- /dev/null
+<added>
+This is a simple test.
+<added>