''' After a CVS2P4 conversion, labels are applied to the entire tree even though they may have been applied to a specific branch in CVS. This is a result of the way CVS handles branches. CVS does not create a new revision for a branch but tags the existing revision with a special branch label. In the worst case scenario, a branch is created and then immediately labeled. There is no way to tell if HEAD or the branch was labeled. Standard CVS workflow prevents this from being a problem but in Perforce, checkout out to the label will get everything in both the branch and HEAD with only one being cannonically correct and no indiciation which is. This script solves that problem for all but this worst case scenario. Algorithm: 1. get the list of converted branches 2. get the list of converted labels 3. for each label a. for each branch (not including the main branch) i. for each file if there is a revision beyond the first then mark this label for this branch b. if there were files in this label and it wasn't marked for any branch then mark it for the main branch 4. for each label marked for a branch a. for each branch i. if this is not the correct branch, remove the label frm all files ''' import sys, optparse, p4 MAIN_BRANCH = 'main' def main(): parser = optparse.OptionParser(usage='usage: %prog [options] product-branch') parser.add_option('-p', '--port', help='set the value of P4PORT (required)') parser.add_option('-u', '--user', help='set the value of P4USER (required)') parser.add_option('-c', '--client', help='set the value of P4CLIENT (required)') parser.add_option('-i', '--ignore-duplicates', action='store_true', help='ignore labels on multiple branches') parser.add_option('-m', '--commit', action='store_true', help='commit the label changes to the Perforce server') parser.add_option('-o', '--owner-force', dest='owner', help='force the final value of the label owner') parser.add_option('-t', '--option-force', dest='options', help='force the final value of the label options') parser.add_option('-l', '--label', action='append', dest='labels', help='list of labels to adjust') (opts, args) = parser.parse_args() if not (opts.port and opts.user and opts.client): parser.error('missing required argument') if len(args) != 1: parser.error('incorrect number of arguments') product = args[0] print 'Connecting to Perforce server ...' client = p4.P4() client.parse_forms() client.port = opts.port client.client = opts.client client.user = opts.user client.connect() print 'Syncing the product branch ...' client.run_sync('//depot/%s/...' % product) print 'Getting branch list ...' branches = list() for d in client.run_dirs('//depot/%s/*' % product): dirlist = d['dir'].split('/') dirlist.reverse() branches.append(dirlist[0]) branches.sort() if opts.labels: print 'Using label list from command line ...' labels = opts.labels else: print 'Getting label list ...' labels = list() for label in client.run_labels(): labels.append(label['label']) labels.sort() print 'Processing labels ...' labelmap = dict() dups = list() for label in labels: print '\t%s: ' % label, files_found = False for branch in branches: files = client.run_files('//depot/%s/%s/...@%s' % (product, branch, label)) if files: files_found = True if branch != MAIN_BRANCH: for f in files: if int(f['rev']) > 1: if label in labelmap: print 'Found label on two branches:', branch, labelmap[label], if opts.ignore_duplicates: print '...skipping...' dups.append(label) else: sys.exit(1) print branch labelmap[label] = branch break if files_found: if label not in labelmap: print MAIN_BRANCH labelmap[label] = MAIN_BRANCH else: print 'no branch' print 'Adjusting labels...' for (label, label_branch) in labelmap.iteritems(): if label in dups: continue print '\t%s...' % label labelspec = client.fetch_label(label) owner = (opts.owner and opts.owner) or labelspec['Owner'] labelspec['Owner'] = opts.user options = (opts.options and opts.options) or labelspec['Options'] labelspec['Options'] = 'unlocked' labelspec['View'] = ['//depot/...'] client.input = labelspec client.run_label('-f', '-i') for branch in branches: print '\t\t%s: ' % branch, if branch == label_branch: print 'leaving' continue print 'removing...', if opts.commit: tagargs = ('-d', '-l', label, '//depot/%s/%s/...' % (product, branch)) else: tagargs = ('-n', '-d', '-l', label, '//depot/%s/%s/...' % (product, branch)) if not client.run_labelsync(*tagargs): print 'no files found to remove' else: print 'done' labelspec['Owner'] = owner labelspec['Options'] = options del labelspec['View'] client.save_label(labelspec) if __name__ == '__main__': main()