# sample_data.py -- put sample data for Perforce integration into a # TeamTrack database. # Gareth Rees, Ravenbrook Limited, 2000-09-04. # $Id: //info.ravenbrook.com/project/p4dti/version/0.2/code/replicator/teamtrack_sample_data.py#1 $ import random, socket, teamtrack, time, types # Replicator id and Perforce server id for the generated relations. localhost = socket.gethostname() rid = 'case' sid = 'p4_' + localhost # Record types in the VCACTIONS table. See "TeamTrack schema extensions # for Perforce integration". type_filespec = 1 type_fix = 2 type_change = 3 # The starting point for times generated by the program. epoch = time.mktime((1998,1,1,0,0,0,0,0,0)) # The structure of the sample repository, represented as a list whose # first element is a directory name, and the remaining elements are the # entries in that directory (which may be other directories). repository = [ '//depot/', [ 'project/', [ 'compiler/', [ 'doc/', 'goals', 'requirements', 'plan', 'design' ], [ 'src/', 'assembler.c', 'assembler.h', 'compiler.h', 'lexer.c', 'lexer.h', 'main.c', 'parser.c', 'parser.h', 'register.c', 'register.h' ], [ 'build/', 'cc' ] ], [ 'editor/', [ 'doc/', 'goals', 'requirements', 'plan', 'design' ], [ 'src/', 'input.c', 'input.h', 'output.c', 'output.h', 'buffer.c', 'buffer.h', 'commands.c', 'commands.h', 'main.c' ], [ 'build/', 'vi' ] ] ] ] # Transform the repository structure so that all filespecs include the # full path. def expand_filespecs(parent, self): self[0] = parent + self[0] for i in range(len(self) - 1): if (type(self[i+1]) == type([])): expand_filespecs(self[0], self[i+1]) else: self[i+1] = self[0] + self[i+1] expand_filespecs('', repository) # random_filespecs() returns a random list of filespecs from the # repository. The distribution is skewed so that generally sensible # results are returned. def random_filespecs(): # The deepest directory in the repository (0 is the depot). max_level = 3 # Distribution of lengths of paths in returned filespecs (less 1). levels = [0,1,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3] # Distribution of number of filespecs to return. n_filespecs = [0,0,0,0,1,1,1,1,2,2,3,4,5] # How many filespecs to return? k = random.choice(n_filespecs) # Pick a level at which to choose a directory. if (k > 2): level = max_level else: level = random.choice(levels) # Pick a directory from which to choose the filespecs. dir = repository for i in range(level): dir = random.choice(dir[1:]) n = len(dir) - 1 # Now choose k out of n filespecs from the selected directory. filespecs = [] while n > 0 and k > 0: if (random.uniform(0,1) < float(k)/float(n)): fs = dir[n] if level < max_level: fs = fs[0] + '...' filespecs = [fs] + filespecs k = k - 1 n = n - 1 return filespecs # Delete all records from the TS_VCACTIONS table. def clear(server): records = server.query(teamtrack.table['VCACTIONS'],'') for r in records: server.delete_record(teamtrack.table['VCACTIONS'], r['ID']) # Fill in the replicator id, Perforce server id, and jobname for each # case in the TS_CASES table. def case_fields(server, cases): for case in cases: case['P4DTI_RID'] = rid case['P4DTI_SID'] = sid case['P4DTI_JOBNAME'] = rid + '_' + str(case['ID']) case['P4DTI_REPLICATED'] = 0 case.update() # Add associations between cases and filespecs. def assoc(server, cases): for case in cases: filespecs = random_filespecs() for f in filespecs: r = server.new_record(teamtrack.table['VCACTIONS']) r['TYPE'] = type_filespec r['CHAR1'] = rid r['CHAR2'] = sid r['TABLEID'] = teamtrack.table['CASES'] r['RECID'] = case['ID'] t = random.uniform(epoch, time.time()) r['TIME1'] = t r['TIME2'] = t r['FILENAME'] = "{ 'filespec': '%s' }" % f r.add() # The sample TeamTrack users (from the TeamShare demo) and the Perforce # clients they use to edit files in the sample repository. users = [ { 'name': 'chad', 'id': 3, 'client': 'chad-elm' }, { 'name': 'chris','id': 10, 'client': 'chris-larch' }, { 'name': 'jill','id': 14, 'client': 'jill-pine' }, { 'name': 'joe','id': 2, 'client': 'joe-beech' }, { 'name': 'newton','id': 11, 'client': 'newton-holly' }, { 'name': 'pat','id': 13, 'client': 'pat-lime' }, { 'name': 'sarah','id': 12, 'client': 'sarah-willow' }, ] # Status values for Perforce jobs in the sample repository. statuses = [ 'open', 'analyzed', 'changed', 'checked', 'released', 'closed' ] def fixes_and_changes(server, cases): # Set all cases to "open" for case in cases: case['STATE'] = 0 n_changes = len(cases) * 5 # Number of changes to make p4_change = 0 # Perforce change number for i in range(n_changes): # Pick a time at which the change happens. t = epoch + (float(i) * (time.time() - epoch) / float(n_changes)) # Pick a user who makes the change. u = random.choice(users) # Increase the Perforce change number. p4_change = p4_change + random.choice([1,1,1,1,1,2,2,3,4,5]) # Make a change record. c = server.new_record(teamtrack.table['VCACTIONS']) c['TYPE'] = type_change c['CHAR1'] = rid c['CHAR2'] = sid c['INFO1'] = p4_change c['TIME1'] = t c['TIME2'] = t c['AUTHOR1'] = u['id'] c['INFO2'] = 1 # Submitted changelist. c['FILENAME'] = "{ 'decription': 'Automatically generated change comment for change %d.', 'client': '%s' }" \ % (p4_change, u['client']) c.add() # Pick k out of n cases for the change to affect. n = len(cases) k = random.choice([0,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,3]) while n > 0 and k > 0: if (random.uniform(0,1) < float(k)/float(n)): case = cases[n-1] # Change the status keyword by moving it forward in the # statuses array with probability 90% if case['STATE'] == 0 or random.uniform(0,1) < 0.9: case['STATE'] = case['STATE'] + 1 else: case['STATE'] = case['STATE'] - 1 # Make a fix record. f = server.new_record(teamtrack.table['VCACTIONS']) f['TYPE'] = type_fix f['CHAR1'] = rid f['CHAR2'] = sid f['TABLEID'] = teamtrack.table['CASES'] f['RECID'] = case['ID'] f['INFO1'] = p4_change f['TIME1'] = t f['TIME2'] = t f['AUTHOR1'] = u['id'] f['FILENAME'] = "{ 'status': '%s', 'client': '%s' }" \ % (case['STATE'], u['client']) f.add() k = k - 1 n = n - 1 def run(): print "Connecting to TeamTrack..." server = teamtrack.connect('joe','',localhost) print "Deleting all records from the VCACTIONS table..." clear(server) print "Getting cases..." cases = server.query(teamtrack.table['CASES'], '') print "Filling in P4DTI fields for all cases..." case_fields(server, cases) print "Associating filespecs with each case..." assoc(server, cases) print "Adding fixes and changes..." fixes_and_changes(server, cases)