OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright (c) 2011 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2011 The Chromium Authors. All rights reserved. |
3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 """Meta checkout manager supporting both Subversion and GIT. | 6 """Meta checkout manager supporting both Subversion and GIT. |
7 | 7 |
8 Files | 8 Files |
9 .gclient : Current client configuration, written by 'config' command. | 9 .gclient : Current client configuration, written by 'config' command. |
10 Format is a Python script defining 'solutions', a list whose | 10 Format is a Python script defining 'solutions', a list whose |
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
138 | 138 |
139 class Dependency(GClientKeywords, gclient_utils.WorkItem): | 139 class Dependency(GClientKeywords, gclient_utils.WorkItem): |
140 """Object that represents a dependency checkout.""" | 140 """Object that represents a dependency checkout.""" |
141 | 141 |
142 def __init__(self, parent, name, url, safesync_url, custom_deps, | 142 def __init__(self, parent, name, url, safesync_url, custom_deps, |
143 custom_vars, deps_file, should_process): | 143 custom_vars, deps_file, should_process): |
144 # Warning: this function can be called from any thread. Both | 144 # Warning: this function can be called from any thread. Both |
145 # self.dependencies and self.requirements are read and modified from | 145 # self.dependencies and self.requirements are read and modified from |
146 # multiple threads at the same time. Sad. | 146 # multiple threads at the same time. Sad. |
147 GClientKeywords.__init__(self) | 147 GClientKeywords.__init__(self) |
148 gclient_utils.WorkItem.__init__(self) | 148 gclient_utils.WorkItem.__init__(self, name) |
149 self.parent = parent | 149 self.parent = parent |
150 self.name = name | |
151 self.url = url | 150 self.url = url |
152 self.parsed_url = None | 151 self.parsed_url = None |
153 # These 2 are only set in .gclient and not in DEPS files. | 152 # These 2 are only set in .gclient and not in DEPS files. |
154 self.safesync_url = safesync_url | 153 self.safesync_url = safesync_url |
155 self.custom_vars = custom_vars or {} | 154 self.custom_vars = custom_vars or {} |
156 self.custom_deps = custom_deps or {} | 155 self.custom_deps = custom_deps or {} |
157 self.deps_hooks = [] | 156 self.deps_hooks = [] |
158 self.dependencies = [] | 157 self.dependencies = [] |
159 self.deps_file = deps_file | 158 self.deps_file = deps_file |
160 # A cache of the files affected by the current operation, necessary for | 159 # A cache of the files affected by the current operation, necessary for |
161 # hooks. | 160 # hooks. |
162 self._file_list = [] | 161 self._file_list = [] |
163 # If it is not set to True, the dependency wasn't processed for its child | 162 # If it is not set to True, the dependency wasn't processed for its child |
164 # dependency, i.e. its DEPS wasn't read. | 163 # dependency, i.e. its DEPS wasn't read. |
165 self.deps_parsed = False | 164 self.deps_parsed = False |
166 # This dependency should be processed, i.e. checked out | 165 # This dependency should be processed, i.e. checked out |
167 self.should_process = should_process | 166 self.should_process = should_process |
168 # This dependency has been processed, i.e. checked out | 167 # This dependency has been processed, i.e. checked out |
169 self.processed = False | 168 self.processed = False |
170 # This dependency had its hook run | 169 # This dependency had its hook run |
171 self.hooks_ran = False | 170 self.hooks_ran = False |
172 # Required dependencies to run before running this one: | |
173 self.requirements = set() | |
174 | 171 |
175 # Post process the url to remove trailing slashes. | 172 # Post process the url to remove trailing slashes. |
176 if isinstance(self.url, basestring): | 173 if isinstance(self.url, basestring): |
177 # urls are sometime incorrectly written as proto://host/path/@rev. Replace | 174 # urls are sometime incorrectly written as proto://host/path/@rev. Replace |
178 # it to proto://host/path@rev. | 175 # it to proto://host/path@rev. |
179 if self.url.count('@') > 1: | 176 if self.url.count('@') > 1: |
180 raise gclient_utils.Error('Invalid url "%s"' % self.url) | 177 raise gclient_utils.Error('Invalid url "%s"' % self.url) |
181 self.url = self.url.replace('/@', '@') | 178 self.url = self.url.replace('/@', '@') |
182 | 179 |
183 self._FindDependencies() | 180 self._FindDependencies() |
(...skipping 10 matching lines...) Expand all Loading... |
194 raise gclient_utils.Error('deps_file name must not be a path, just a ' | 191 raise gclient_utils.Error('deps_file name must not be a path, just a ' |
195 'filename. %s' % self.deps_file) | 192 'filename. %s' % self.deps_file) |
196 | 193 |
197 def _FindDependencies(self): | 194 def _FindDependencies(self): |
198 """Setup self.requirements and find any other dependency who would have self | 195 """Setup self.requirements and find any other dependency who would have self |
199 as a requirement. | 196 as a requirement. |
200 """ | 197 """ |
201 # self.parent is implicitly a requirement. This will be recursive by | 198 # self.parent is implicitly a requirement. This will be recursive by |
202 # definition. | 199 # definition. |
203 if self.parent and self.parent.name: | 200 if self.parent and self.parent.name: |
204 self.requirements.add(self.parent.name) | 201 self._requirements.add(self.parent.name) |
205 | 202 |
206 # For a tree with at least 2 levels*, the leaf node needs to depend | 203 # For a tree with at least 2 levels*, the leaf node needs to depend |
207 # on the level higher up in an orderly way. | 204 # on the level higher up in an orderly way. |
208 # This becomes messy for >2 depth as the DEPS file format is a dictionary, | 205 # This becomes messy for >2 depth as the DEPS file format is a dictionary, |
209 # thus unsorted, while the .gclient format is a list thus sorted. | 206 # thus unsorted, while the .gclient format is a list thus sorted. |
210 # | 207 # |
211 # * _recursion_limit is hard coded 2 and there is no hope to change this | 208 # * _recursion_limit is hard coded 2 and there is no hope to change this |
212 # value. | 209 # value. |
213 # | 210 # |
214 # Interestingly enough, the following condition only works in the case we | 211 # Interestingly enough, the following condition only works in the case we |
215 # want: self is a 2nd level node. 3nd level node wouldn't need this since | 212 # want: self is a 2nd level node. 3nd level node wouldn't need this since |
216 # they already have their parent as a requirement. | 213 # they already have their parent as a requirement. |
217 if self.parent in self.root_parent().dependencies: | 214 if self.parent in self.root_parent().dependencies: |
218 root_deps = self.root_parent().dependencies | 215 root_deps = self.root_parent().dependencies |
219 for i in range(0, root_deps.index(self.parent)): | 216 for i in range(0, root_deps.index(self.parent)): |
220 value = root_deps[i] | 217 value = root_deps[i] |
221 if value.name: | 218 if value.name: |
222 self.requirements.add(value.name) | 219 self._requirements.add(value.name) |
223 | 220 |
224 if isinstance(self.url, self.FromImpl): | 221 if isinstance(self.url, self.FromImpl): |
225 self.requirements.add(self.url.module_name) | 222 self._requirements.add(self.url.module_name) |
226 | 223 |
227 if self.name and self.should_process: | 224 if self.name and self.should_process: |
228 def yield_full_tree(root): | 225 def yield_full_tree(root): |
229 """Depth-first recursion.""" | 226 """Depth-first recursion.""" |
230 yield root | 227 yield root |
231 for i in root.dependencies: | 228 for i in root.dependencies: |
232 for j in yield_full_tree(i): | 229 for j in yield_full_tree(i): |
233 if j.should_process: | 230 if j.should_process: |
234 yield j | 231 yield j |
235 | 232 |
236 for obj in yield_full_tree(self.root_parent()): | 233 for obj in yield_full_tree(self.root_parent()): |
237 if obj is self or not obj.name: | 234 if obj is self or not obj.name: |
238 continue | 235 continue |
239 # Step 1: Find any requirements self may need. | 236 # Step 1: Find any requirements self may need. |
240 if self.name.startswith(posixpath.join(obj.name, '')): | 237 if self.name.startswith(posixpath.join(obj.name, '')): |
241 self.requirements.add(obj.name) | 238 self._requirements.add(obj.name) |
242 # Step 2: Find any requirements self may impose. | 239 # Step 2: Find any requirements self may impose. |
243 if obj.name.startswith(posixpath.join(self.name, '')): | 240 if obj.name.startswith(posixpath.join(self.name, '')): |
244 obj.requirements.add(self.name) | 241 try: |
| 242 # Access to a protected member _requirements of a client class |
| 243 # pylint: disable=W0212 |
| 244 obj.lock.acquire() |
| 245 obj._requirements.add(self.name) |
| 246 finally: |
| 247 obj.lock.release() |
245 | 248 |
246 def LateOverride(self, url): | 249 def LateOverride(self, url): |
247 """Resolves the parsed url from url. | 250 """Resolves the parsed url from url. |
248 | 251 |
249 Manages From() keyword accordingly. Do not touch self.parsed_url nor | 252 Manages From() keyword accordingly. Do not touch self.parsed_url nor |
250 self.url because it may called with other urls due to From().""" | 253 self.url because it may called with other urls due to From().""" |
251 assert self.parsed_url == None or not self.should_process, self.parsed_url | 254 assert self.parsed_url == None or not self.should_process, self.parsed_url |
252 overriden_url = self.get_custom_deps(self.name, url) | 255 overriden_url = self.get_custom_deps(self.name, url) |
253 if overriden_url != url: | 256 if overriden_url != url: |
254 logging.info('%s, %s was overriden to %s' % (self.name, url, | 257 logging.info('%s, %s was overriden to %s' % (self.name, url, |
(...skipping 1107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1362 except (gclient_utils.Error, subprocess2.CalledProcessError), e: | 1365 except (gclient_utils.Error, subprocess2.CalledProcessError), e: |
1363 print >> sys.stderr, 'Error: %s' % str(e) | 1366 print >> sys.stderr, 'Error: %s' % str(e) |
1364 return 1 | 1367 return 1 |
1365 | 1368 |
1366 | 1369 |
1367 if '__main__' == __name__: | 1370 if '__main__' == __name__: |
1368 fix_encoding.fix_encoding() | 1371 fix_encoding.fix_encoding() |
1369 sys.exit(Main(sys.argv[1:])) | 1372 sys.exit(Main(sys.argv[1:])) |
1370 | 1373 |
1371 # vim: ts=2:sw=2:tw=80:et: | 1374 # vim: ts=2:sw=2:tw=80:et: |
OLD | NEW |