ganadist

gerrit cherry-pick script

Feb 23rd, 2012
222
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 4.67 KB | None | 0 0
  1. #!/usr/bin/env python
  2. # repo cherry-pick script
  3.  
  4. import sys, os
  5. import subprocess
  6. from xml.etree import ElementTree
  7. from StringIO import StringIO
  8. import json
  9.  
  10. GIT = 'git'
  11. SSH = 'ssh'
  12.  
  13. REPO = 'repo'
  14. REPO_START = REPO, 'start'
  15. REPO_ABANDON = REPO, 'abandon'
  16.  
  17. def get_top():
  18.     return os.getenv('TOP') or os.getenv('ANDROID_BUILD_TOP')
  19.  
  20. class Manifest:
  21.     def __init__(self):
  22.         self.pathmap = {}
  23.         self.remotes = {}
  24.         self.default = ''
  25.         self.load()
  26.  
  27.         if self.default in self.remotes:
  28.             self.git_server = self.remotes[self.default].get('fetch')
  29.             self.review_server = self.remotes[self.default].get('review')
  30.         else:
  31.             print 'no default remote server'
  32.             sys.exit(-1)
  33.  
  34.         for scheme in ('git://', 'http://', 'https://'):
  35.             if self.git_server.startswith(scheme):
  36.                 print 'unsupported gerrit transport type.'
  37.                 print 'this script supports only ssh transport type'
  38.                 sys.exit(-1)
  39.  
  40.         if self.git_server.startswith('ssh://'):
  41.             if self.git_server.endswith('/'):
  42.                 self.git_server = self.git_server[:-1]
  43.         elif self.git_server == '..':
  44.             # aosp does
  45.             print 'unsupported gerrit transport type.'
  46.             print 'this script supports only ssh transport type'
  47.             sys.exit(-1)
  48.         elif not self.git_server.endswith(':'):
  49.             self.git_server += ':'
  50.  
  51.         # XXX
  52.         self.review_server = self.git_server
  53.         if self.review_server.startswith('ssh://'):
  54.             self.review_server = self.review_server[6:]
  55.  
  56.     def load(self):
  57.         for filename in ('manifest.xml', 'local_manifest.xml'):
  58.             manifest = os.path.sep.join(('.repo', filename))
  59.             if not os.access(manifest, os.R_OK):
  60.                 continue
  61.             p = ElementTree.parse(open(manifest))
  62.             r = p.getroot()
  63.  
  64.             for remote in r.findall('remote'):
  65.                 self.remotes[remote.get('name')] = remote
  66.  
  67.             for default in r.findall('default'):
  68.                 self.default = default.get('remote')
  69.  
  70.             for project in r.findall('remove-project'):
  71.                 name = project.get('name')
  72.                 if name in self.pathmap:
  73.                     del self.pathmap[name]
  74.  
  75.             for project in r.findall('project'):
  76.                 self.pathmap[project.get('name')] = project.get('path')
  77.  
  78.     def __getitem__(self, k):
  79.         return self.pathmap.get(k)
  80.  
  81.     def __contains__(self, k):
  82.         return k in self.pathmap
  83.  
  84. class CherryPick:
  85.     def __init__(self, branch = None):
  86.         self.manifest = Manifest()
  87.         self.git_server = self.manifest.git_server
  88.         self.review_server = self.manifest.review_server
  89.         self.applied = []
  90.         self.branch = branch
  91.  
  92.     def reset_branch(self, project, directory):
  93.         print 'reset project %s with branch %s'%(project, self.branch)
  94.         cmd = REPO_ABANDON + (self.branch, directory)
  95.         subprocess.call(cmd)
  96.         cmd = REPO_START + (self.branch, directory)
  97.         if subprocess.call(cmd) != 0:
  98.             print 'branch create failed. abort'
  99.             sys.exit(-1)
  100.         self.applied.append(directory)
  101.  
  102.     def apply(self, project, ref):
  103.         if not project in self.manifest:
  104.             print 'no such project %s. abort'%project
  105.             sys.exit(-1)
  106.  
  107.         directory = os.path.sep.join((get_top(), self.manifest[project]))
  108.  
  109.         if self.branch and not directory in self.applied:
  110.             self.reset_branch(project, directory)
  111.  
  112.         print 'fetch item %s'%ref
  113.         cmd = GIT, 'fetch', '/'.join((self.git_server, project)), ref
  114.         if subprocess.call(cmd, cwd = directory):
  115.             print 'fetch failed'
  116.             sys.exit(-1)
  117.  
  118.         print 'apply item %s'%ref
  119.         cmd = GIT, 'cherry-pick', 'FETCH_HEAD'
  120.         if subprocess.call(cmd, cwd = directory):
  121.             print 'apply failed'
  122.             sys.exit(-1)
  123.  
  124.     def query(self, items):
  125.         query = ('change:' + x for x in items)
  126.         gerrit_cmd = ('gerrit', 'query', ' OR '.join(query), '--current-patch-set', '--format', 'json')
  127.         cmd = (SSH, self.review_server, ' '.join(gerrit_cmd))
  128.  
  129.         print 'query items to server'
  130.         result = StringIO(subprocess.Popen(cmd, stdout=subprocess.PIPE, close_fds=True).stdout.read())
  131.         r = {}
  132.         for line in result:
  133.             item = json.loads(line)
  134.             if not 'status' in item:
  135.                 continue
  136.  
  137.             number = item['number']
  138.  
  139.             if not item['open']:
  140.                 print 'item %s is not opened. abort'%number
  141.                 sys.exit(-1)
  142.  
  143.             r[number] = item
  144.         return r
  145.  
  146.     def main(self, items):
  147.         result = self.query(items)
  148.         for number in items:
  149.             item = result[number]
  150.             project = item['project']
  151.             ref = item['currentPatchSet']['ref']
  152.             rev = item['currentPatchSet']['revision']
  153.             self.apply(project, ref)
  154.  
  155. if __name__ == '__main__':
  156.     if len(sys.argv) == 1:
  157.         print 'Usage: cherry-pick item1 item2 item3 ... [branch]'
  158.         sys.exit(-1)
  159.  
  160.     top = get_top()
  161.     if not top:
  162.         print 'TOP or ANDROID_BUILD_TOP is not defined. abort'
  163.         sys.exit(-1)
  164.  
  165.     os.chdir(top)
  166.  
  167.     if sys.argv[-1].isdigit():
  168.         items = sys.argv[1:]
  169.         branch = None
  170.     else:
  171.         items = sys.argv[1:-1]
  172.         branch = sys.argv[-1]
  173.  
  174.     cherryPick = CherryPick(branch)
  175.     cherryPick.main(items)
Advertisement
Add Comment
Please, Sign In to add comment