mirror of
https://github.com/openSUSE/osc.git
synced 2024-11-10 06:46:15 +01: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:
parent
adf9e633f9
commit
85e66362af
@ -375,6 +375,12 @@ class Osc(cmdln.Cmdln):
|
|||||||
|
|
||||||
|
|
||||||
@cmdln.alias('di')
|
@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):
|
def do_diff(self, subcmd, opts, *args):
|
||||||
"""${cmd_name}: Generates a diff
|
"""${cmd_name}: Generates a diff
|
||||||
|
|
||||||
@ -391,6 +397,74 @@ class Osc(cmdln.Cmdln):
|
|||||||
pacs = findpacs(args)
|
pacs = findpacs(args)
|
||||||
|
|
||||||
difference_found = False
|
difference_found = False
|
||||||
|
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)
|
||||||
|
|
||||||
|
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(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:
|
for p in pacs:
|
||||||
if p.todo == []:
|
if p.todo == []:
|
||||||
for i in p.filenamelist:
|
for i in p.filenamelist:
|
||||||
@ -398,11 +472,12 @@ class Osc(cmdln.Cmdln):
|
|||||||
if s == 'M' or s == 'C':
|
if s == 'M' or s == 'C':
|
||||||
p.todo.append(i)
|
p.todo.append(i)
|
||||||
|
|
||||||
d = []
|
|
||||||
for filename in p.todo:
|
for filename in p.todo:
|
||||||
d.append('Index: %s\n' % filename)
|
d.append('Index: %s\n' % filename)
|
||||||
d.append('===================================================================\n')
|
d.append('===================================================================\n')
|
||||||
d.append(get_source_file_diff(p.dir, filename, p.rev))
|
d.append(get_source_file_diff(p.dir, filename, p.rev))
|
||||||
|
|
||||||
|
|
||||||
if d:
|
if d:
|
||||||
print ''.join(d)
|
print ''.join(d)
|
||||||
difference_found = True
|
difference_found = True
|
||||||
@ -410,8 +485,6 @@ class Osc(cmdln.Cmdln):
|
|||||||
if difference_found:
|
if difference_found:
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def do_repourls(self, subcmd, opts, *args):
|
def do_repourls(self, subcmd, opts, *args):
|
||||||
"""${cmd_name}: shows URLs of .repo files
|
"""${cmd_name}: shows URLs of .repo files
|
||||||
|
|
||||||
@ -435,6 +508,8 @@ class Osc(cmdln.Cmdln):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@cmdln.option('-r', '--revision', metavar='rev',
|
||||||
|
help='checkout the specified revision')
|
||||||
@cmdln.alias('co')
|
@cmdln.alias('co')
|
||||||
def do_checkout(self, subcmd, opts, *args):
|
def do_checkout(self, subcmd, opts, *args):
|
||||||
"""${cmd_name}: check out content from the repository
|
"""${cmd_name}: check out content from the repository
|
||||||
@ -461,11 +536,13 @@ class Osc(cmdln.Cmdln):
|
|||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
rev, dummy = parseRevisionOption(opts.revision)
|
||||||
|
|
||||||
if filename:
|
if filename:
|
||||||
get_source_file(conf.config['apiurl'], project, package, filename)
|
get_source_file(conf.config['apiurl'], project, package, filename, revision=rev)
|
||||||
|
|
||||||
elif package:
|
elif package:
|
||||||
checkout_package(conf.config['apiurl'], project, package)
|
checkout_package(conf.config['apiurl'], project, package, rev)
|
||||||
|
|
||||||
elif project:
|
elif project:
|
||||||
# all packages
|
# all packages
|
||||||
@ -678,6 +755,10 @@ class Osc(cmdln.Cmdln):
|
|||||||
print
|
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')
|
@cmdln.alias('up')
|
||||||
def do_update(self, subcmd, opts, *args):
|
def do_update(self, subcmd, opts, *args):
|
||||||
"""${cmd_name}: Update a working copy
|
"""${cmd_name}: Update a working copy
|
||||||
@ -719,6 +800,11 @@ class Osc(cmdln.Cmdln):
|
|||||||
|
|
||||||
pacs = findpacs(args)
|
pacs = findpacs(args)
|
||||||
|
|
||||||
|
if opts.revision and ( len(args) == 1):
|
||||||
|
rev, dummy = parseRevisionOption(opts.revision)
|
||||||
|
else:
|
||||||
|
rev = None
|
||||||
|
|
||||||
for p in pacs:
|
for p in pacs:
|
||||||
|
|
||||||
if len(pacs) > 1:
|
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' ]
|
saved_modifiedfiles = [ f for f in p.filenamelist if p.status(f) == 'M' ]
|
||||||
|
|
||||||
oldp = p
|
oldp = p
|
||||||
p.update_filesmeta()
|
p.update_filesmeta(rev)
|
||||||
p = Package(p.dir)
|
p = Package(p.dir)
|
||||||
|
|
||||||
# which files do no longer exist upstream?
|
# which files do no longer exist upstream?
|
||||||
@ -754,13 +840,13 @@ class Osc(cmdln.Cmdln):
|
|||||||
status_after_merge = p.mergefile(filename)
|
status_after_merge = p.mergefile(filename)
|
||||||
print statfrmt(status_after_merge, filename)
|
print statfrmt(status_after_merge, filename)
|
||||||
elif state == 'M':
|
elif state == 'M':
|
||||||
p.updatefile(filename)
|
p.updatefile(filename, rev)
|
||||||
print statfrmt('U', filename)
|
print statfrmt('U', filename)
|
||||||
elif state == '!':
|
elif state == '!':
|
||||||
p.updatefile(filename)
|
p.updatefile(filename, rev)
|
||||||
print 'Restored \'%s\'' % filename
|
print 'Restored \'%s\'' % filename
|
||||||
elif state == 'F':
|
elif state == 'F':
|
||||||
p.updatefile(filename)
|
p.updatefile(filename, rev)
|
||||||
print statfrmt('A', filename)
|
print statfrmt('A', filename)
|
||||||
elif state == ' ':
|
elif state == ' ':
|
||||||
pass
|
pass
|
||||||
|
108
osc/core.py
108
osc/core.py
@ -329,12 +329,12 @@ class Package:
|
|||||||
f.write('\n')
|
f.write('\n')
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
def updatefile(self, n):
|
def updatefile(self, n, revision):
|
||||||
filename = os.path.join(self.dir, n)
|
filename = os.path.join(self.dir, n)
|
||||||
storefilename = os.path.join(self.storedir, n)
|
storefilename = os.path.join(self.storedir, n)
|
||||||
mtime = self.findfilebyname(n).mtime
|
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))
|
os.utime(filename, (-1, mtime))
|
||||||
|
|
||||||
shutil.copy2(filename, storefilename)
|
shutil.copy2(filename, storefilename)
|
||||||
@ -386,8 +386,8 @@ class Package:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
def update_filesmeta(self):
|
def update_filesmeta(self, revision=None):
|
||||||
meta = ''.join(show_files_meta(self.apiurl, self.prjname, self.name))
|
meta = ''.join(show_files_meta(self.apiurl, self.prjname, self.name, revision))
|
||||||
f = open(os.path.join(self.storedir, '_files'), 'w')
|
f = open(os.path.join(self.storedir, '_files'), 'w')
|
||||||
f.write(meta)
|
f.write(meta)
|
||||||
f.close()
|
f.close()
|
||||||
@ -462,6 +462,30 @@ class Package:
|
|||||||
|
|
||||||
return state
|
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):
|
def merge(self, otherpac):
|
||||||
self.todo += otherpac.todo
|
self.todo += otherpac.todo
|
||||||
@ -733,7 +757,7 @@ def urlopen(url, data=None):
|
|||||||
return fd
|
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):
|
if not os.path.isdir(store):
|
||||||
os.mkdir(store)
|
os.mkdir(store)
|
||||||
os.chdir(store)
|
os.chdir(store)
|
||||||
@ -745,7 +769,7 @@ def init_package_dir(apiurl, project, package, dir):
|
|||||||
f.close
|
f.close
|
||||||
|
|
||||||
f = open('_files', 'w')
|
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.close()
|
||||||
|
|
||||||
f = open('_osclib_version', 'w')
|
f = open('_osclib_version', 'w')
|
||||||
@ -986,8 +1010,11 @@ def edit_user_meta(user, change_is_required=True):
|
|||||||
print 'Done.'
|
print 'Done.'
|
||||||
|
|
||||||
|
|
||||||
def show_files_meta(apiurl, prj, pac):
|
def show_files_meta(apiurl, prj, pac, revision=None):
|
||||||
f = http_GET(makeurl(apiurl, ['source', prj, pac]))
|
query = []
|
||||||
|
if revision:
|
||||||
|
query.append('rev=%s' % revision)
|
||||||
|
f = http_GET(makeurl(apiurl, ['source', prj, pac], query=query))
|
||||||
return f.readlines()
|
return f.readlines()
|
||||||
|
|
||||||
|
|
||||||
@ -1043,8 +1070,13 @@ def get_user_meta(apiurl, user):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def get_source_file(apiurl, prj, package, filename, targetfilename=None):
|
def get_source_file(apiurl, prj, package, filename, targetfilename=None, revision = None):
|
||||||
u = makeurl(apiurl, ['source', prj, package, pathname2url(filename)])
|
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)
|
f = http_GET(u)
|
||||||
|
|
||||||
o = open(targetfilename or filename, 'w')
|
o = open(targetfilename or filename, 'w')
|
||||||
@ -1082,10 +1114,26 @@ def binary_file(fn):
|
|||||||
return binary(open(fn, 'r').read(4096))
|
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
|
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
|
file2 = os.path.join(dir, filename) # working copy
|
||||||
|
|
||||||
f1 = open(file1, 'r')
|
f1 = open(file1, 'r')
|
||||||
@ -1097,14 +1145,14 @@ def get_source_file_diff(dir, filename, rev):
|
|||||||
f2.close()
|
f2.close()
|
||||||
|
|
||||||
if binary(s1) or binary (s2):
|
if binary(s1) or binary (s2):
|
||||||
d = ['Binary file %s has changed\n' % filename]
|
d = ['Binary file %s has changed\n' % origfilename]
|
||||||
|
|
||||||
else:
|
else:
|
||||||
d = difflib.unified_diff(\
|
d = difflib.unified_diff(\
|
||||||
s1.splitlines(1), \
|
s1.splitlines(1), \
|
||||||
s2.splitlines(1), \
|
s2.splitlines(1), \
|
||||||
fromfile = '%s (revision %s)' % (filename, rev), \
|
fromfile = '%s (revision %s)' % (origfilename, rev), \
|
||||||
tofile = '%s (working copy)' % filename)
|
tofile = '%s (working copy)' % origfilename)
|
||||||
|
|
||||||
# if file doesn't end with newline, we need to append one in the diff result
|
# if file doesn't end with newline, we need to append one in the diff result
|
||||||
d = list(d)
|
d = list(d)
|
||||||
@ -1136,15 +1184,15 @@ def make_dir(apiurl, project, package):
|
|||||||
return(os.path.join(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()
|
olddir = os.getcwd()
|
||||||
|
|
||||||
os.chdir(make_dir(apiurl, project, package))
|
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)
|
p = Package(os.curdir)
|
||||||
|
|
||||||
for filename in p.filenamelist:
|
for filename in p.filenamelist:
|
||||||
p.updatefile(filename)
|
p.updatefile(filename, revision)
|
||||||
print 'A ', os.path.join(project, package, filename)
|
print 'A ', os.path.join(project, package, filename)
|
||||||
|
|
||||||
os.chdir(olddir)
|
os.chdir(olddir)
|
||||||
@ -1535,3 +1583,27 @@ def wipebinaries(apiurl, project, package=None, arch=None, repo=None):
|
|||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
root = ET.parse(f).getroot()
|
root = ET.parse(f).getroot()
|
||||||
return root.get('code')
|
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
|
||||||
|
Loading…
Reference in New Issue
Block a user