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

- reimplement 'osc pull' so that iw works like intended, i.e. still works if the link is broken

This commit is contained in:
Michael Schroeder 2010-01-11 17:00:24 +01:00
parent 60c3b45194
commit 0cb7afbfdf
2 changed files with 104 additions and 10 deletions

View File

@ -4389,16 +4389,102 @@ Please submit there instead, or use --nodevelproject to force direct submission.
raise oscerr.WrongArgs('osc pull only works on linked packages.')
elif not p.isexpanded():
raise oscerr.WrongArgs('osc pull only works on expanded links.')
linkinfo = p.linkinfo
baserev = linkinfo.baserev
if baserev == None:
raise oscerr.WrongArgs('osc pull only works on links containing a base revision.')
# hack
conf.config['linkcontrol'] = 0
# do the update
pulledrev=p.latest_rev()
if pulledrev == p.rev:
raise oscerr.WrongArgs('Already up-to-date.')
p.update(rev=pulledrev)
store_write_string(p.absdir, '_pulled', '')
# get revisions we need
query = { 'expand': 1, 'emptylink': 1 }
u = makeurl(p.apiurl, ['source', p.prjname, p.name], query=query)
f = http_GET(u)
meta = f.readlines()
root_new = ET.fromstring(''.join(meta))
linkinfo_new = root_new.find('linkinfo')
if linkinfo_new == None:
raise oscerr.APIError('link is not a really a link?')
if linkinfo_new.get('error') != None:
raise oscerr.APIError('link target is broken')
if linkinfo_new.get('srcmd5') == baserev:
print "Already up-to-date."
return
dir_new = { 'apiurl': p.apiurl, 'project': p.prjname, 'package': p.name }
dir_new['srcmd5'] = root_new.get('srcmd5')
dir_new['entries'] = [[n.get('name'), n.get('md5')] for n in root_new.findall('entry')]
dir_oldpatched = { 'apiurl': p.apiurl, 'project': p.prjname, 'package': p.name, 'srcmd5': p.srcmd5 }
dir_oldpatched['entries'] = map(lambda f: [f.name, f.md5], p.filelist)
query = { 'rev': linkinfo.srcmd5 }
u = makeurl(p.apiurl, ['source', linkinfo.project, linkinfo.package], query=query)
f = http_GET(u)
root_old = ET.parse(f).getroot()
dir_old = { 'apiurl': p.apiurl, 'project': linkinfo.project, 'package': linkinfo.package, 'srcmd5': linkinfo.srcmd5 }
dir_old['entries'] = [[n.get('name'), n.get('md5')] for n in root_old.findall('entry')]
# now do 3-way merge
entries_old = dict(dir_old['entries'])
entries_oldpatched = dict(dir_oldpatched['entries'])
entries_new = dict(dir_new['entries'])
entries = {}
entries.update(entries_old)
entries.update(entries_oldpatched)
entries.update(entries_new)
for name in sorted(entries.keys()):
md5_old = entries_old.get(name, '')
md5_new = entries_new.get(name, '')
md5_oldpatched = entries_oldpatched.get(name, '')
if md5_old == md5_new or md5_oldpatched == md5_new:
continue
if md5_old == md5_oldpatched:
if md5_new == '':
print statfrmt('D', name)
p.put_on_deletelist(name)
os.unlink(name)
else:
print statfrmt('U', name)
self.download(name, md5_new, dir_new, name)
continue
# need diff3 to resolve issue
if md5_oldpatched == '':
open(name, 'w').write('')
os.rename(name, name + '.mine')
self.download(name, md5_new, dir_new, name + '.new')
self.download(name, md5_old, dir_old, name + '.old')
if binary_file(name + '.mine') or binary_file(name + '.old') or binary_file(name + '.new'):
shutil.copy2(name + '.new', name)
print statfrmt('C', name)
p.put_on_conflictlist(name)
continue
o = open(name, 'wb')
code = subprocess.call(['diff3', '-m',
'-L', '.mine', name + '.mine',
'-L', '.old', name + '.old',
'-L', '.new', name + '.new',
], stdout=o)
if code == 0:
print statfrmt('G', name)
os.unlink(name + '.mine')
os.unlink(name + '.old')
os.unlink(name + '.new')
elif code == 1:
print statfrmt('C', name)
p.put_on_conflictlist(name)
else:
print statfrmt('?', name)
p.put_on_conflictlist(name)
p.write_deletelist()
p.write_conflictlist()
# store new linkrev
store_write_string(p.absdir, '_pulled', linkinfo_new.get('srcmd5'))
print
if len(p.in_conflict):
print 'Please fix the conflicts (files marked with \'C\' above),'
print 'run \'osc resolved ...\', and commit the changes'
print 'to update the link information.'
else:
print 'Please commit the changes to update the link information.'
@cmdln.option('--create', action='store_true', default=False,
help='create new gpg signing key for this project')

View File

@ -276,6 +276,7 @@ class Linkinfo:
self.srcmd5 = None
self.error = None
self.rev = None
self.baserev = None
def read(self, linkinfo_node):
"""read in the linkinfo metadata from the <linkinfo> element passed as
@ -291,6 +292,7 @@ class Linkinfo:
self.srcmd5 = linkinfo_node.get('srcmd5')
self.error = linkinfo_node.get('error')
self.rev = linkinfo_node.get('rev')
self.baserev = linkinfo_node.get('baserev')
def islink(self):
"""returns True if the linkinfo is not empty, otherwise False"""
@ -745,7 +747,7 @@ class Package:
filename = os.path.join(self.dir, n)
storefilename = os.path.join(self.storedir, n)
myfilename = os.path.join(self.dir, n + '.mine')
if self.islinkrepair():
if self.islinkrepair() or self.ispulled():
upfilename = os.path.join(self.dir, n + '.new')
else:
upfilename = os.path.join(self.dir, n + '.r' + self.rev)
@ -755,7 +757,7 @@ class Package:
# the working copy may be updated, so the .r* ending may be obsolete...
# then we don't care
os.unlink(upfilename)
if self.islinkrepair():
if self.islinkrepair() or self.ispulled():
os.unlink(os.path.join(self.dir, n + '.old'))
except:
pass
@ -858,6 +860,12 @@ class Package:
query['keeplink'] = '1'
if conf.config['linkcontrol']:
query['linkrev'] = self.linkinfo.srcmd5
if self.ispulled():
for line in open(os.path.join(self.storedir, '_pulled'), 'r'):
pulledrev = line.strip()
if pulledrev:
query['repairlink'] = '1'
query['linkrev'] = pulledrev
if self.islinkrepair():
query['repairlink'] = '1'
u = makeurl(self.apiurl, ['source', self.prjname, self.name], query=query)