1
0
mirror of https://github.com/openSUSE/osc.git synced 2024-09-20 01:06:17 +02:00

added initial revision handling:

- extended "osc co prj pac" to checkout a specific revision of pac
    - extended "osc up" to update to a specific revision
    - extended "osc diff" to diff the working copy against a
      specific revision on the server. NOTE: comparing two
      server-side revisions (osc diff -r 11:12) is currently
      not supported!
This commit is contained in:
Marcus Hüwe 2007-07-04 12:55:26 +00:00
parent adf9e633f9
commit 85e66362af
2 changed files with 199 additions and 41 deletions

View File

@ -375,6 +375,12 @@ class Osc(cmdln.Cmdln):
@cmdln.alias('di')
@cmdln.option('-r', '--revision', metavar='rev1[:rev2]',
help='If rev1 is specified it will compare your working copy against '
'the revision (rev1) on the server. '
'If rev1 and rev2 are specified it will compare rev1 against rev2'
'(changes in your working copy are ignored in this case).\n'
'NOTE: if more than 1 package is specified --revision will be ignored!')
def do_diff(self, subcmd, opts, *args):
"""${cmd_name}: Generates a diff
@ -389,28 +395,95 @@ class Osc(cmdln.Cmdln):
args = parseargs(args)
pacs = findpacs(args)
difference_found = False
for p in pacs:
if p.todo == []:
for i in p.filenamelist:
s = p.status(i)
if s == 'M' or s == 'C':
p.todo.append(i)
d = []
rev1, rev2 = parseRevisionOption(opts.revision)
pac = pacs[0]
if rev1 and rev2 and (len(pacs) == 1):
# this is currently not implemented
print >>sys.stderr, 'this feature isn\'t implemented yet'
sys.exit(1)
elif rev1 and (pac.rev != rev1) and (len(pacs) == 1):
# make a temp dir for checking out the project
import tempfile
tmpdir = tempfile.mkdtemp(rev1, pac.name, '/tmp')
curdir = os.getcwd()
os.chdir(tmpdir)
init_package_dir(conf.config['apiurl'], pac.prjname, pac.name, tmpdir, rev1)
os.chdir(curdir)
tmppac = Package(tmpdir)
d = []
for filename in p.todo:
d.append('Index: %s\n' % filename)
changed_files = []
added_files = []
removed_files = []
if pac.todo:
for file in pac.todo:
if file in tmppac.filenamelist:
if dgst(os.path.join(pac.dir, file)) != tmppac.findfilebyname(file).md5:
changed_files.append(file)
else:
added_files.append(file)
else:
changed_files, added_files, removed_files = pac.comparePac(tmppac)
for file in changed_files:
tmppac.updatefile(file, rev1)
d.append('Index: %s\n' % file)
d.append('===================================================================\n')
d.append(get_source_file_diff(p.dir, filename, p.rev))
if d:
print ''.join(d)
difference_found = True
d.append(get_source_file_diff(pac.dir, file, rev1, file, tmppac.dir))
tmppac.delete_localfile(file)
tmppac.delete_storefile(file)
# this tempfile is used as a dummy file for difflib
(fd, filename) = tempfile.mkstemp(dir=tmppac.storedir)
for file in added_files:
d.append('Index: %s\n' % file)
d.append('===================================================================\n')
d.append(get_source_file_diff(pac.dir, file, rev1, \
os.path.basename(filename), \
tmppac.storedir, file))
for file in removed_files:
tmppac.updatefile(file, rev1)
d.append('Index: %s\n' % file)
d.append('===================================================================\n')
d.append(get_source_file_diff(tmppac.storedir, \
os.path.basename(filename), \
rev1, file, tmppac.dir, file))
tmppac.delete_localfile(file)
tmppac.delete_storefile(file)
# clean up
os.unlink(filename)
for dir, dirnames, files in os.walk(tmppac.storedir):
for file in files:
os.unlink(os.path.join(dir, file))
os.rmdir(tmppac.storedir)
os.rmdir(tmppac.dir)
else:
for p in pacs:
if p.todo == []:
for i in p.filenamelist:
s = p.status(i)
if s == 'M' or s == 'C':
p.todo.append(i)
for filename in p.todo:
d.append('Index: %s\n' % filename)
d.append('===================================================================\n')
d.append(get_source_file_diff(p.dir, filename, p.rev))
if d:
print ''.join(d)
difference_found = True
if difference_found:
return 1
def do_repourls(self, subcmd, opts, *args):
"""${cmd_name}: shows URLs of .repo files
@ -434,7 +507,9 @@ class Osc(cmdln.Cmdln):
print url_tmpl % (p.prjname.replace(':', ':/'), platform, p.prjname)
@cmdln.option('-r', '--revision', metavar='rev',
help='checkout the specified revision')
@cmdln.alias('co')
def do_checkout(self, subcmd, opts, *args):
"""${cmd_name}: check out content from the repository
@ -461,11 +536,13 @@ class Osc(cmdln.Cmdln):
except:
pass
rev, dummy = parseRevisionOption(opts.revision)
if filename:
get_source_file(conf.config['apiurl'], project, package, filename)
get_source_file(conf.config['apiurl'], project, package, filename, revision=rev)
elif package:
checkout_package(conf.config['apiurl'], project, package)
checkout_package(conf.config['apiurl'], project, package, rev)
elif project:
# all packages
@ -678,6 +755,10 @@ class Osc(cmdln.Cmdln):
print
@cmdln.option('-r', '--revision', metavar='rev',
help='update to specified revision (this option will be ignored '
'if you are going to update the complete project or more than '
'one package)')
@cmdln.alias('up')
def do_update(self, subcmd, opts, *args):
"""${cmd_name}: Update a working copy
@ -719,6 +800,11 @@ class Osc(cmdln.Cmdln):
pacs = findpacs(args)
if opts.revision and ( len(args) == 1):
rev, dummy = parseRevisionOption(opts.revision)
else:
rev = None
for p in pacs:
if len(pacs) > 1:
@ -728,7 +814,7 @@ class Osc(cmdln.Cmdln):
saved_modifiedfiles = [ f for f in p.filenamelist if p.status(f) == 'M' ]
oldp = p
p.update_filesmeta()
p.update_filesmeta(rev)
p = Package(p.dir)
# which files do no longer exist upstream?
@ -754,13 +840,13 @@ class Osc(cmdln.Cmdln):
status_after_merge = p.mergefile(filename)
print statfrmt(status_after_merge, filename)
elif state == 'M':
p.updatefile(filename)
p.updatefile(filename, rev)
print statfrmt('U', filename)
elif state == '!':
p.updatefile(filename)
p.updatefile(filename, rev)
print 'Restored \'%s\'' % filename
elif state == 'F':
p.updatefile(filename)
p.updatefile(filename, rev)
print statfrmt('A', filename)
elif state == ' ':
pass

View File

@ -329,12 +329,12 @@ class Package:
f.write('\n')
f.close()
def updatefile(self, n):
def updatefile(self, n, revision):
filename = os.path.join(self.dir, n)
storefilename = os.path.join(self.storedir, n)
mtime = self.findfilebyname(n).mtime
get_source_file(self.apiurl, self.prjname, self.name, n, targetfilename=filename)
get_source_file(self.apiurl, self.prjname, self.name, n, targetfilename=filename, revision=revision)
os.utime(filename, (-1, mtime))
shutil.copy2(filename, storefilename)
@ -386,8 +386,8 @@ class Package:
def update_filesmeta(self):
meta = ''.join(show_files_meta(self.apiurl, self.prjname, self.name))
def update_filesmeta(self, revision=None):
meta = ''.join(show_files_meta(self.apiurl, self.prjname, self.name, revision))
f = open(os.path.join(self.storedir, '_files'), 'w')
f.write(meta)
f.close()
@ -462,6 +462,30 @@ class Package:
return state
def comparePac(self, pac):
"""
This method compares the local filelist with
the filelist of the passed package to see which files
were added, removed and changed.
"""
changed_files = []
added_files = []
removed_files = []
for file in self.filenamelist:
if not file in self.to_be_deleted:
if file in pac.filenamelist:
if dgst(file) != pac.findfilebyname(file).md5:
changed_files.append(file)
else:
added_files.append(file)
for file in pac.filenamelist:
if (not file in self.filenamelist) or (file in self.to_be_deleted):
removed_files.append(file)
return changed_files, added_files, removed_files
def merge(self, otherpac):
self.todo += otherpac.todo
@ -733,7 +757,7 @@ def urlopen(url, data=None):
return fd
def init_package_dir(apiurl, project, package, dir):
def init_package_dir(apiurl, project, package, dir, revision=None):
if not os.path.isdir(store):
os.mkdir(store)
os.chdir(store)
@ -745,7 +769,7 @@ def init_package_dir(apiurl, project, package, dir):
f.close
f = open('_files', 'w')
f.write(''.join(show_files_meta(apiurl, project, package)))
f.write(''.join(show_files_meta(apiurl, project, package, revision)))
f.close()
f = open('_osclib_version', 'w')
@ -986,8 +1010,11 @@ def edit_user_meta(user, change_is_required=True):
print 'Done.'
def show_files_meta(apiurl, prj, pac):
f = http_GET(makeurl(apiurl, ['source', prj, pac]))
def show_files_meta(apiurl, prj, pac, revision=None):
query = []
if revision:
query.append('rev=%s' % revision)
f = http_GET(makeurl(apiurl, ['source', prj, pac], query=query))
return f.readlines()
@ -1043,8 +1070,13 @@ def get_user_meta(apiurl, user):
return None
def get_source_file(apiurl, prj, package, filename, targetfilename=None):
u = makeurl(apiurl, ['source', prj, package, pathname2url(filename)])
def get_source_file(apiurl, prj, package, filename, targetfilename=None, revision = None):
query = []
if revision:
query.append('rev=%s' % quote_plus(revision))
u = makeurl(apiurl, ['source', prj, package, pathname2url(filename)], query=query)
# print 'url: %s' % u
f = http_GET(u)
o = open(targetfilename or filename, 'w')
@ -1082,10 +1114,26 @@ def binary_file(fn):
return binary(open(fn, 'r').read(4096))
def get_source_file_diff(dir, filename, rev):
def get_source_file_diff(dir, filename, rev, oldfilename = None, olddir = None, origfilename = None):
"""
This methods diffs oldfilename against filename (so filename will
be shown as the new file).
The variable origfilename is used if filename and oldfilename differ
in their names (for instance if a tempfile is used for filename etc.)
"""
import difflib
file1 = os.path.join(dir, store, filename) # stored original
if not oldfilename:
oldfilename = filename
if not olddir:
olddir = os.path.join(dir, store)
if not origfilename:
origfilename = filename
file1 = os.path.join(olddir, oldfilename) # old/stored original
file2 = os.path.join(dir, filename) # working copy
f1 = open(file1, 'r')
@ -1097,14 +1145,14 @@ def get_source_file_diff(dir, filename, rev):
f2.close()
if binary(s1) or binary (s2):
d = ['Binary file %s has changed\n' % filename]
d = ['Binary file %s has changed\n' % origfilename]
else:
d = difflib.unified_diff(\
s1.splitlines(1), \
s2.splitlines(1), \
fromfile = '%s (revision %s)' % (filename, rev), \
tofile = '%s (working copy)' % filename)
fromfile = '%s (revision %s)' % (origfilename, rev), \
tofile = '%s (working copy)' % origfilename)
# if file doesn't end with newline, we need to append one in the diff result
d = list(d)
@ -1136,15 +1184,15 @@ def make_dir(apiurl, project, package):
return(os.path.join(project, package))
def checkout_package(apiurl, project, package):
def checkout_package(apiurl, project, package, revision=None):
olddir = os.getcwd()
os.chdir(make_dir(apiurl, project, package))
init_package_dir(apiurl, project, package, store)
init_package_dir(apiurl, project, package, store, revision)
p = Package(os.curdir)
for filename in p.filenamelist:
p.updatefile(filename)
p.updatefile(filename, revision)
print 'A ', os.path.join(project, package, filename)
os.chdir(olddir)
@ -1535,3 +1583,27 @@ def wipebinaries(apiurl, project, package=None, arch=None, repo=None):
sys.exit(1)
root = ET.parse(f).getroot()
return root.get('code')
def parseRevisionOption(string):
"""
retrun a tuple which contains the revisions
"""
if string:
if ':' in string:
splitted_rev = string.split(':')
try:
for i in splitted_rev:
int(i)
return splitted_rev
except ValueError:
print >>sys.stderr, 'your revision \'%s\' will be ignored' % string
return None, None
else:
if string.isdigit():
return string, None
else:
print >>sys.stderr, 'your revision \'%s\' will be ignored' % string
return None, None
else:
return None, None