Changeset 05bf790b4d7e…
Parent a003225a0599…
by Quentin Schroeder <quentin@fogcreek.com>
Changes to one file · Browse files at 05bf790b4d7e Showing diff from parent a003225a0599 Diff from another changeset...
|
|
@@ -0,0 +1,189 @@ + ################################
+#
+# This script will migrate repositories from one Kiln Server to another. It should work as long as
+# there are no name clashes between the old server and the new one, but it has only be tested with a
+# completely empty new server.
+#
+# The script should be run on a machine which has sufficient disk space to clone copies of ALL of the
+# repositories from the old kiln server. This means it also requires that Mercurial be installed in order to run.
+
+
+
+
+
+
+
+import sys
+import os
+import urllib
+import urllib2
+import urlparse
+from Queue import Queue
+try:
+ import json
+except ImportError:
+ import simplejson as json
+
+
+
+# Set debug to 0 for errors only, 1 for basic output, 2 for verbose output
+debug = 1
+sourceServer = 'https://my.kilnhg.com'
+sourceToken = 'SECRET'
+destinationServer = 'http://server/fogbugz/kiln'
+destinationToken = 'SECRET'
+
+
+
+def debug_print(message, level=1):
+ if ( debug >= level ):
+ print message
+
+
+
+
+# We cycle through the heirarchy of objects and push them over to the new server.
+# Projects contain Groups, which in turn contain Repositories, so we have a nested loop in that order.
+# Note that this does NOT transfer the Users from the previous server nor any specific
+# permissions on the Projects/Groups/Repositories.
+
+
+# Create a dictionary from old ixRepos to new ones.
+# oldIxRepo = 123
+# newIxRepo = 456
+# repo_map[123] = 456
+repo_map = {}
+
+# A list of pairs indicating the parent associations we will have to recreate. (old_ixrepo, old_parent_ixrepo)
+old_parent_associations = []
+
+# Load all the source projects
+src_projects = json.load(urllib2.urlopen('%s/Api/1.0/project/?token=%s' % (sourceServer, sourceToken)))
+
+###### PROJECT LEVEL LOOP ######
+for src_project in src_projects:
+ debug_print("Working on project '%s'" % (src_project['sName']))
+ debug_print("SOURCE PROJECT DATA:\n"+str(src_project), 2)
+
+ dest_project = None
+ # Try to find the project on the Destination Server
+ dest_projects = json.load(urllib2.urlopen('%s/Api/1.0/Project?token=%s' % (destinationServer, destinationToken)))
+ for a_dest_project in dest_projects:
+ if (a_dest_project['sName'] == src_project['sName']):
+ dest_project = json.load(urllib2.urlopen('%s/Api/1.0/Project/%s?token=%s' % (destinationServer, a_dest_project['ixProject'], destinationToken)))
+ debug_print(" - Found an existing match on the destination server. ixProject = %s" % (dest_project['ixProject']))
+ debug_print(" - DESTINATION PROJECT DATA:\n" + str(dest_project), 2)
+
+ # If we don't find an existing project, then create a new project with the information we grabbed from the old server
+ if (not dest_project):
+ data = urllib.urlencode({'token': destinationToken, 'sName': src_project['sName'], \
+ 'sDescription': src_project['sDescription'], 'permissionDefault': src_project['permissionDefault']})
+ dest_project = json.load(urllib2.urlopen('%s/Api/1.0/Project/Create' % (destinationServer), data))
+ debug_print(" + Created a new Project on the destination server. ixProject = %s" % (dest_project['ixProject']))
+ debug_print(" + DESTINATION PROJECT DATA:\n" + str(dest_project), 2)
+
+
+ ###### REPOSITORY GROUP LEVEL LOOP ######
+ for src_repo_group in src_project['repoGroups']:
+ debug_print(" Working on Group '%s'" % (src_repo_group['sName']))
+ debug_print(" SOURCE REPO GROUP DATA:\n" + str(src_repo_group), 2)
+
+
+ dest_repo_group = None
+ # Try to find the project on the Destination Server
+ dest_repo_groups = dest_project['repoGroups']
+ for a_dest_repo_group in dest_repo_groups:
+ if (a_dest_repo_group['sName'] == src_repo_group['sName']):
+ dest_repo_group = json.load(urllib2.urlopen('%s/Api/1.0/RepoGroup/%s?token=%s' % (destinationServer, a_dest_repo_group['ixRepoGroup'], destinationToken)))
+ debug_print(" - Found an existing match on the destination server. ixRepogroup = %s" % (dest_repo_group['ixRepoGroup']))
+ debug_print(" - DESTINATION REPO GROUP DATA:\n" + str(dest_repo_group), 2)
+
+
+ # If we don't find an existing project, then create a new project with the information we grabbed from the old server
+ if (not dest_repo_group):
+ data = urllib.urlencode({'token': destinationToken, 'sName': src_repo_group['sName'], 'ixProject': dest_project['ixProject']})
+ dest_repo_group = json.load(urllib2.urlopen('%s/Api/1.0/RepoGroup/Create/' % (destinationServer), data))
+ debug_print(" + Created a new Repository Group on the destination server. ixRepoGroup = %s" % (dest_repo_group['ixRepoGroup']))
+ debug_print(" + DESTINATION REPO GROUP DATA:\n" + str(dest_repo_group), 2)
+
+
+
+ # We build a queue of the repositories so that we can easily wait to process any repos that need parents created first
+ q = Queue()
+ for src_repo in src_repo_group['repos']:
+ q.put(src_repo)
+
+
+ ###### REPOSITORY LEVEL LOOP ######
+ while (not q.empty()):
+ src_repo = q.get()
+
+ # If the repo has a parent that has NOT been created in the destination yet, then re-enqueue it for later
+ if ((src_repo['ixParent']) and not (src_repo['ixParent'] in repo_map)):
+ q.put(src_repo)
+ debug_print(" Postponing work on Repository '%s'" % (src_repo['sName']))
+ continue
+
+ debug_print(" Working on Repository '%s'" % (src_repo['sName']))
+
+ # If the old repository had a parent, add the assocation to the old_parent_associations list
+ #if src_repo['ixParent']:
+ # old_parent_associations += [(src_repo['ixRepo'], src_repo['ixParent'])] # add (old_ixrepo, old_parent_ixrepo) to the list
+
+
+ dest_repo = None
+ # Try to find the project on the Destination Server
+ dest_repos = dest_repo_group['repos']
+ for a_dest_repo in dest_repos:
+ if (a_dest_repo['sName'] == src_repo['sName']):
+ dest_repo = json.load(urllib2.urlopen('%s/Api/1.0/Repo/%s?token=%s' % (destinationServer, a_dest_repo['ixRepo'], destinationToken)))
+ debug_print(" - Found an existing match on the destination server. ixRepo = %s" % (dest_repo['ixRepo']))
+ debug_print(" - DESTINATION REPOSITORY DATA:\n" + str(dest_repo), 2)
+
+ # If we don't find an existing repo, then create a new repo with the information we grabbed from the old server
+ if (not dest_repo):
+ if (src_repo['ixParent']):
+ data = urllib.urlencode({'token': destinationToken,
+ 'sName': src_repo['sName'],
+ 'sDescription': src_repo['sDescription'],
+ 'ixRepoGroup': dest_repo_group['ixRepoGroup'],
+ 'permissionDefault': src_repo['permissionDefault'],
+ 'ixParent': repo_map[src_repo['ixParent']],
+ 'fCentral': 'false'
+ })
+ else:
+ data = urllib.urlencode({'token': destinationToken,
+ 'sName': src_repo['sName'],
+ 'sDescription': src_repo['sDescription'],
+ 'ixRepoGroup': dest_repo_group['ixRepoGroup'],
+ 'permissionDefault': src_repo['permissionDefault']
+ })
+ dest_repo = json.load(urllib2.urlopen('%s/Api/1.0/Repo/Create/' % (destinationServer), data))
+ debug_print(" + Created a new Repository on the destination server. ixRepo = %s" % (dest_repo['ixRepo']))
+ debug_print(" + DESTINATION REPOSITORY DATA:\n" + str(dest_repo), 2)
+
+
+ # Record the mapping from the old server to the new server. repo_map[oldIxRepo] = newIxRepo
+ repo_map[src_repo['ixRepo']] = dest_repo['ixRepo']
+
+
+ # Build a unique folder name to clone the repo into
+ folder_name = src_repo['sName'] + "-"+str(src_repo['ixRepo'])
+
+ # Convert empty RepoGroup slug values to the default 'Group'
+ group_name = src_repo_group['sSlug']
+ if (group_name == ''):
+ group_name = 'Group'
+ new_group_name = dest_repo_group['sSlug']
+ if (new_group_name == ''):
+ new_group_name = 'Group'
+
+ # Clone the repo locally, and then push it to the destination server
+ os.system("hg clone " + sourceServer +'/Code/'+ src_project["sSlug"] +'/'+ group_name +'/'+ src_repo["sSlug"] +' "'+ folder_name + '"')
+ os.chdir(folder_name)
+ os.system("hg push " + destinationServer +'/Code/'+ dest_project["sSlug"] +'/'+ new_group_name +'/'+ dest_repo["sSlug"])
+ os.chdir('..')
+
+
+
+debug_print("\nDONE!")
|
Loading...