Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(327)

Side by Side Diff: gclient.py

Issue 3107009: Move ExecutionQueue and WorkItem to gclient_utils.py (Closed)
Patch Set: Update unit test Created 10 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | gclient_utils.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/python 1 #!/usr/bin/python
2 # Copyright (c) 2010 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2010 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 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
52 __version__ = "0.5.2" 52 __version__ = "0.5.2"
53 53
54 import logging 54 import logging
55 import optparse 55 import optparse
56 import os 56 import os
57 import posixpath 57 import posixpath
58 import pprint 58 import pprint
59 import re 59 import re
60 import subprocess 60 import subprocess
61 import sys 61 import sys
62 import threading
63 import urlparse 62 import urlparse
64 import urllib 63 import urllib
65 64
66 import breakpad 65 import breakpad
67 66
68 import gclient_scm 67 import gclient_scm
69 import gclient_utils 68 import gclient_utils
70 from third_party.repo.progress import Progress 69 from third_party.repo.progress import Progress
71 70
72 71
73 def attr(attr, data): 72 def attr(attr, data):
74 """Sets an attribute on a function.""" 73 """Sets an attribute on a function."""
75 def hook(fn): 74 def hook(fn):
76 setattr(fn, attr, data) 75 setattr(fn, attr, data)
77 return fn 76 return fn
78 return hook 77 return hook
79 78
80 79
81 ## GClient implementation. 80 ## GClient implementation.
82 81
83 class WorkItem(object):
84 """One work item."""
85 requirements = []
86 name = None
87
88 def run(self):
89 pass
90
91
92 class ExecutionQueue(object):
93 """Dependencies sometime needs to be run out of order due to From() keyword.
94
95 This class manages that all the required dependencies are run before running
96 each one.
97
98 Methods of this class are multithread safe.
99 """
100 def __init__(self, progress):
101 self.lock = threading.Lock()
102 # List of Dependency.
103 self.queued = []
104 # List of strings representing each Dependency.name that was run.
105 self.ran = []
106 # List of items currently running.
107 self.running = []
108 self.progress = progress
109 if self.progress:
110 self.progress.update()
111
112 def enqueue(self, d):
113 """Enqueue one Dependency to be executed later once its requirements are
114 satisfied.
115 """
116 assert isinstance(d, WorkItem)
117 try:
118 self.lock.acquire()
119 self.queued.append(d)
120 total = len(self.queued) + len(self.ran) + len(self.running)
121 finally:
122 self.lock.release()
123 if self.progress:
124 self.progress._total = total + 1
125 self.progress.update(0)
126
127 def flush(self, *args, **kwargs):
128 """Runs all enqueued items until all are executed."""
129 while self._run_one_item(*args, **kwargs):
130 pass
131 queued = []
132 running = []
133 try:
134 self.lock.acquire()
135 if self.queued:
136 queued = self.queued
137 self.queued = []
138 if self.running:
139 running = self.running
140 self.running = []
141 finally:
142 self.lock.release()
143 if self.progress:
144 self.progress.end()
145 if queued:
146 raise gclient_utils.Error('Entries still queued: %s' % str(queued))
147 if running:
148 raise gclient_utils.Error('Entries still queued: %s' % str(running))
149
150 def _run_one_item(self, *args, **kwargs):
151 """Removes one item from the queue that has all its requirements completed
152 and execute it.
153
154 Returns False if no item could be run.
155 """
156 i = 0
157 d = None
158 try:
159 self.lock.acquire()
160 while i != len(self.queued) and not d:
161 d = self.queued.pop(i)
162 for r in d.requirements:
163 if not r in self.ran:
164 self.queued.insert(i, d)
165 d = None
166 break
167 i += 1
168 if not d:
169 return False
170 self.running.append(d)
171 finally:
172 self.lock.release()
173 d.run(*args, **kwargs)
174 try:
175 self.lock.acquire()
176 # TODO(maruel): http://crbug.com/51711
177 #assert not d.name in self.ran
178 if not d.name in self.ran:
179 self.ran.append(d.name)
180 self.running.remove(d)
181 if self.progress:
182 self.progress.update(1)
183 finally:
184 self.lock.release()
185 return True
186
187 82
188 class GClientKeywords(object): 83 class GClientKeywords(object):
189 class FromImpl(object): 84 class FromImpl(object):
190 """Used to implement the From() syntax.""" 85 """Used to implement the From() syntax."""
191 86
192 def __init__(self, module_name, sub_target_name=None): 87 def __init__(self, module_name, sub_target_name=None):
193 """module_name is the dep module we want to include from. It can also be 88 """module_name is the dep module we want to include from. It can also be
194 the name of a subdirectory to include from. 89 the name of a subdirectory to include from.
195 90
196 sub_target_name is an optional parameter if the module name in the other 91 sub_target_name is an optional parameter if the module name in the other
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
232 127
233 def Lookup(self, var_name): 128 def Lookup(self, var_name):
234 """Implements the Var syntax.""" 129 """Implements the Var syntax."""
235 if var_name in self._custom_vars: 130 if var_name in self._custom_vars:
236 return self._custom_vars[var_name] 131 return self._custom_vars[var_name]
237 elif var_name in self._local_scope.get("vars", {}): 132 elif var_name in self._local_scope.get("vars", {}):
238 return self._local_scope["vars"][var_name] 133 return self._local_scope["vars"][var_name]
239 raise gclient_utils.Error("Var is not defined: %s" % var_name) 134 raise gclient_utils.Error("Var is not defined: %s" % var_name)
240 135
241 136
242 class Dependency(GClientKeywords, WorkItem): 137 class Dependency(GClientKeywords, gclient_utils.WorkItem):
243 """Object that represents a dependency checkout.""" 138 """Object that represents a dependency checkout."""
244 DEPS_FILE = 'DEPS' 139 DEPS_FILE = 'DEPS'
245 140
246 def __init__(self, parent, name, url, safesync_url, custom_deps, 141 def __init__(self, parent, name, url, safesync_url, custom_deps,
247 custom_vars, deps_file, should_process): 142 custom_vars, deps_file, should_process):
248 GClientKeywords.__init__(self) 143 GClientKeywords.__init__(self)
249 self.parent = parent 144 self.parent = parent
250 self.name = name 145 self.name = name
251 self.url = url 146 self.url = url
252 self.parsed_url = None 147 self.parsed_url = None
(...skipping 555 matching lines...) Expand 10 before | Expand all | Expand 10 after
808 Args: 703 Args:
809 command: The command to use (e.g., 'status' or 'diff') 704 command: The command to use (e.g., 'status' or 'diff')
810 args: list of str - extra arguments to add to the command line. 705 args: list of str - extra arguments to add to the command line.
811 """ 706 """
812 if not self.dependencies: 707 if not self.dependencies:
813 raise gclient_utils.Error('No solution specified') 708 raise gclient_utils.Error('No solution specified')
814 revision_overrides = self._EnforceRevisions() 709 revision_overrides = self._EnforceRevisions()
815 pm = None 710 pm = None
816 if command == 'update' and not self._options.verbose: 711 if command == 'update' and not self._options.verbose:
817 pm = Progress('Syncing projects', 1) 712 pm = Progress('Syncing projects', 1)
818 work_queue = ExecutionQueue(pm) 713 work_queue = gclient_utils.ExecutionQueue(pm)
819 for s in self.dependencies: 714 for s in self.dependencies:
820 work_queue.enqueue(s) 715 work_queue.enqueue(s)
821 work_queue.flush(self._options, revision_overrides, command, args, 716 work_queue.flush(self._options, revision_overrides, command, args,
822 work_queue) 717 work_queue)
823 718
824 # Once all the dependencies have been processed, it's now safe to run the 719 # Once all the dependencies have been processed, it's now safe to run the
825 # hooks. 720 # hooks.
826 if not self._options.nohooks: 721 if not self._options.nohooks:
827 self.RunHooksRecursively(self._options) 722 self.RunHooksRecursively(self._options)
828 723
(...skipping 24 matching lines...) Expand all
853 entry_fixed, self.root_dir())) 748 entry_fixed, self.root_dir()))
854 gclient_utils.RemoveDirectory(e_dir) 749 gclient_utils.RemoveDirectory(e_dir)
855 # record the current list of entries for next time 750 # record the current list of entries for next time
856 self._SaveEntries() 751 self._SaveEntries()
857 return 0 752 return 0
858 753
859 def PrintRevInfo(self): 754 def PrintRevInfo(self):
860 if not self.dependencies: 755 if not self.dependencies:
861 raise gclient_utils.Error('No solution specified') 756 raise gclient_utils.Error('No solution specified')
862 # Load all the settings. 757 # Load all the settings.
863 work_queue = ExecutionQueue(None) 758 work_queue = gclient_utils.ExecutionQueue(None)
864 for s in self.dependencies: 759 for s in self.dependencies:
865 work_queue.enqueue(s) 760 work_queue.enqueue(s)
866 work_queue.flush(self._options, {}, None, [], work_queue) 761 work_queue.flush(self._options, {}, None, [], work_queue)
867 762
868 def GetURLAndRev(dep): 763 def GetURLAndRev(dep):
869 """Returns the revision-qualified SCM url for a Dependency.""" 764 """Returns the revision-qualified SCM url for a Dependency."""
870 if dep.parsed_url is None: 765 if dep.parsed_url is None:
871 return None 766 return None
872 if isinstance(dep.parsed_url, self.FileImpl): 767 if isinstance(dep.parsed_url, self.FileImpl):
873 original_url = dep.parsed_url.file_location 768 original_url = dep.parsed_url.file_location
(...skipping 447 matching lines...) Expand 10 before | Expand all | Expand 10 after
1321 return CMDhelp(parser, argv) 1216 return CMDhelp(parser, argv)
1322 except gclient_utils.Error, e: 1217 except gclient_utils.Error, e:
1323 print >> sys.stderr, 'Error: %s' % str(e) 1218 print >> sys.stderr, 'Error: %s' % str(e)
1324 return 1 1219 return 1
1325 1220
1326 1221
1327 if '__main__' == __name__: 1222 if '__main__' == __name__:
1328 sys.exit(Main(sys.argv[1:])) 1223 sys.exit(Main(sys.argv[1:]))
1329 1224
1330 # vim: ts=2:sw=2:tw=80:et: 1225 # vim: ts=2:sw=2:tw=80:et:
OLDNEW
« no previous file with comments | « no previous file | gclient_utils.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698