blob: 3764a409e2dfc84e78ec4f4deffd7c2cc0d2c444 [file] [log] [blame]
Brian Harring7fcc02e2012-08-05 04:10:57 -07001#!/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
9import sys
10import optparse
11import os
12import xml.etree.ElementTree as ElementTree
13
14from cros_build_lib import Die, FindRepoDir
15
16
17def _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
28class 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
96def 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
149if __name__ == '__main__':
150 main(sys.argv)