Brian Harring | 7fcc02e | 2012-08-05 04:10:57 -0700 | [diff] [blame^] | 1 | #!/usr/bin/python |
| 2 | |
| 3 | # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
| 4 | # Use of this source code is governed by a BSD-style license that can be |
| 5 | # found in the LICENSE file. |
| 6 | |
| 7 | """This module allows adding and deleting of projects to the local manifest.""" |
| 8 | |
| 9 | import sys |
| 10 | import optparse |
| 11 | import os |
| 12 | import xml.etree.ElementTree as ElementTree |
| 13 | |
| 14 | from cros_build_lib import Die, FindRepoDir |
| 15 | |
| 16 | |
| 17 | def _ReadManifest(manifest, err_not_found=False): |
| 18 | if os.path.isfile(manifest): |
| 19 | ptree = LocalManifest(open(manifest).read()) |
| 20 | elif err_not_found: |
| 21 | Die('Manifest file, %s, not found' % manifest) |
| 22 | else: |
| 23 | ptree = LocalManifest() |
| 24 | ptree.Parse() |
| 25 | return ptree |
| 26 | |
| 27 | |
| 28 | class LocalManifest: |
| 29 | """Class which provides an abstraction for manipulating the local manifest.""" |
| 30 | |
| 31 | def __init__(self, text=None): |
| 32 | self._text = text or '<manifest>\n</manifest>' |
| 33 | |
| 34 | def Parse(self): |
| 35 | """Parse the manifest.""" |
| 36 | self._root = ElementTree.fromstring(self._text) |
| 37 | |
| 38 | def AddProjectElement(self, element, workon='False', remote=None): |
| 39 | """Add a new project element to the manifest tree. |
| 40 | |
| 41 | Returns: |
| 42 | True on success. |
| 43 | """ |
| 44 | name = element.attrib['name'] |
| 45 | path = element.attrib['path'] |
| 46 | for project in self._root.findall('project'): |
| 47 | if project.attrib['path'] == path or project.attrib['name'] == name: |
| 48 | if project.attrib['path'] == path and project.attrib['name'] == name: |
| 49 | return True |
| 50 | else: |
| 51 | return False |
| 52 | element.attrib['workon'] = workon |
| 53 | if remote is not None: |
| 54 | element.attrib['remote'] = remote |
| 55 | element.tail = '\n' |
| 56 | self._root.append(element) |
| 57 | return True |
| 58 | |
| 59 | def AddProject(self, name, path, workon='False', remote=None): |
| 60 | """Add a workon project if it is not already in the manifest. |
| 61 | |
| 62 | Returns: |
| 63 | True on success. |
| 64 | """ |
| 65 | element = ElementTree.Element('project', name=name, path=path) |
| 66 | return self.AddProjectElement(element, workon=workon, remote=remote) |
| 67 | |
| 68 | def AddWorkonProjectElement(self, element): |
| 69 | return self.AddProjectElement(element, workon='True') |
| 70 | |
| 71 | def AddWorkonProject(self, name, path): |
| 72 | return self.AddProject(name, path, workon='True') |
| 73 | |
| 74 | def AddNonWorkonProjectElement(self, element, remote): |
| 75 | return self.AddProjectElement(element, workon='False', remote=remote) |
| 76 | |
| 77 | def AddNonWorkonProject(self, name, path, remote): |
| 78 | return self.AddProject(name, path, workon='False', remote=remote) |
| 79 | |
| 80 | def GetProject(self, name): |
| 81 | """Accessor method for getting a project node from the manifest tree. |
| 82 | |
| 83 | Returns: |
| 84 | project element node from ElementTree, otherwise, None |
| 85 | """ |
| 86 | |
| 87 | for project in self._root.findall('project'): |
| 88 | if project.attrib['name'] == name: |
| 89 | return project |
| 90 | return None |
| 91 | |
| 92 | def ToString(self): |
| 93 | return ElementTree.tostring(self._root, encoding='UTF-8') |
| 94 | |
| 95 | |
| 96 | def main(argv): |
| 97 | repo_dir = FindRepoDir() |
| 98 | if not repo_dir: |
| 99 | Die("Unable to find repo dir.") |
| 100 | |
| 101 | usage = 'usage: %prog add [options] <name> <path>' |
| 102 | parser = optparse.OptionParser(usage=usage) |
| 103 | parser.add_option('-w', '--workon', action='store_true', dest='workon', |
| 104 | default=False, help='Is this a workon package?') |
| 105 | parser.add_option('-f', '--file', dest='local_manifest', |
| 106 | default='%s/local_manifest.xml' % repo_dir, |
| 107 | help='Non-default manifest file to read.') |
| 108 | parser.add_option('-m', '--main', dest='main_manifest', |
| 109 | default='%s/manifest.xml' % repo_dir, |
| 110 | help='Main manifest file to read.') |
| 111 | parser.add_option('-d', '--default', dest='full_manifest', |
| 112 | default='%s/manifests/full.xml' % repo_dir, |
| 113 | help='Default manifest file to read.') |
| 114 | parser.add_option('-r', '--remote', dest='remote', |
| 115 | default=None) |
| 116 | (options, args) = parser.parse_args(argv[2:]) |
| 117 | if len(args) < 1: |
| 118 | parser.error('Not enough arguments') |
| 119 | if argv[1] not in ['add']: |
| 120 | parser.error('Unsupported command: %s.' % argv[1]) |
| 121 | if not options.workon and options.remote is None: |
| 122 | parser.error('Adding non-workon projects requires a remote.') |
| 123 | name = args[0] |
| 124 | |
| 125 | local_tree = _ReadManifest(options.local_manifest) |
| 126 | main_tree = _ReadManifest(options.main_manifest) |
| 127 | full_tree = _ReadManifest(options.full_manifest) |
| 128 | |
| 129 | # Only add this project to local_manifest.xml if not in manifest.xml |
| 130 | if options.workon: |
| 131 | if main_tree.GetProject(name) is None: |
| 132 | project_element = full_tree.GetProject(name) |
| 133 | if project_element is None: |
| 134 | Die('No project named %s, in the default manifest.' % name) |
| 135 | success = local_tree.AddWorkonProjectElement(project_element) |
| 136 | if not success: |
| 137 | Die('Name "%s" already exists with a different path.' % name) |
| 138 | else: |
| 139 | success = local_tree.AddNonWorkonProject(name, args[1], options.remote) |
| 140 | if not success: |
| 141 | Die('Name "%s" already exists with a different path.' % name) |
| 142 | |
| 143 | try: |
| 144 | print >> open(options.local_manifest, 'w'), local_tree.ToString() |
| 145 | except Exception, e: |
| 146 | Die('Error writing to manifest: %s' % e) |
| 147 | |
| 148 | |
| 149 | if __name__ == '__main__': |
| 150 | main(sys.argv) |