summaryrefslogtreecommitdiffstats
path: root/command.py
diff options
context:
space:
mode:
Diffstat (limited to 'command.py')
-rw-r--r--command.py115
1 files changed, 89 insertions, 26 deletions
diff --git a/command.py b/command.py
index 0c3b360c..96d7848f 100644
--- a/command.py
+++ b/command.py
@@ -22,6 +22,7 @@ import sys
22from error import NoSuchProjectError 22from error import NoSuchProjectError
23from error import InvalidProjectGroupsError 23from error import InvalidProjectGroupsError
24 24
25
25class Command(object): 26class Command(object):
26 """Base class for any command line action in repo. 27 """Base class for any command line action in repo.
27 """ 28 """
@@ -33,6 +34,27 @@ class Command(object):
33 def WantPager(self, opt): 34 def WantPager(self, opt):
34 return False 35 return False
35 36
37 def ReadEnvironmentOptions(self, opts):
38 """ Set options from environment variables. """
39
40 env_options = self._RegisteredEnvironmentOptions()
41
42 for env_key, opt_key in env_options.items():
43 # Get the user-set option value if any
44 opt_value = getattr(opts, opt_key)
45
46 # If the value is set, it means the user has passed it as a command
47 # line option, and we should use that. Otherwise we can try to set it
48 # with the value from the corresponding environment variable.
49 if opt_value is not None:
50 continue
51
52 env_value = os.environ.get(env_key)
53 if env_value is not None:
54 setattr(opts, opt_key, env_value)
55
56 return opts
57
36 @property 58 @property
37 def OptionParser(self): 59 def OptionParser(self):
38 if self._optparse is None: 60 if self._optparse is None:
@@ -49,6 +71,24 @@ class Command(object):
49 """Initialize the option parser. 71 """Initialize the option parser.
50 """ 72 """
51 73
74 def _RegisteredEnvironmentOptions(self):
75 """Get options that can be set from environment variables.
76
77 Return a dictionary mapping environment variable name
78 to option key name that it can override.
79
80 Example: {'REPO_MY_OPTION': 'my_option'}
81
82 Will allow the option with key value 'my_option' to be set
83 from the value in the environment variable named 'REPO_MY_OPTION'.
84
85 Note: This does not work properly for options that are explicitly
86 set to None by the user, or options that are defined with a
87 default value other than None.
88
89 """
90 return {}
91
52 def Usage(self): 92 def Usage(self):
53 """Display usage and terminate. 93 """Display usage and terminate.
54 """ 94 """
@@ -60,7 +100,33 @@ class Command(object):
60 """ 100 """
61 raise NotImplementedError 101 raise NotImplementedError
62 102
63 def GetProjects(self, args, missing_ok=False): 103 def _ResetPathToProjectMap(self, projects):
104 self._by_path = dict((p.worktree, p) for p in projects)
105
106 def _UpdatePathToProjectMap(self, project):
107 self._by_path[project.worktree] = project
108
109 def _GetProjectByPath(self, path):
110 project = None
111 if os.path.exists(path):
112 oldpath = None
113 while path \
114 and path != oldpath \
115 and path != self.manifest.topdir:
116 try:
117 project = self._by_path[path]
118 break
119 except KeyError:
120 oldpath = path
121 path = os.path.dirname(path)
122 else:
123 try:
124 project = self._by_path[path]
125 except KeyError:
126 pass
127 return project
128
129 def GetProjects(self, args, missing_ok=False, submodules_ok=False):
64 """A list of projects that match the arguments. 130 """A list of projects that match the arguments.
65 """ 131 """
66 all_projects = self.manifest.projects 132 all_projects = self.manifest.projects
@@ -71,43 +137,40 @@ class Command(object):
71 groups = mp.config.GetString('manifest.groups') 137 groups = mp.config.GetString('manifest.groups')
72 if not groups: 138 if not groups:
73 groups = 'all,-notdefault,platform-' + platform.system().lower() 139 groups = 'all,-notdefault,platform-' + platform.system().lower()
74 groups = [x for x in re.split('[,\s]+', groups) if x] 140 groups = [x for x in re.split(r'[,\s]+', groups) if x]
75 141
76 if not args: 142 if not args:
77 for project in all_projects.values(): 143 all_projects_list = all_projects.values()
144 derived_projects = {}
145 for project in all_projects_list:
146 if submodules_ok or project.sync_s:
147 derived_projects.update((p.name, p)
148 for p in project.GetDerivedSubprojects())
149 all_projects_list.extend(derived_projects.values())
150 for project in all_projects_list:
78 if ((missing_ok or project.Exists) and 151 if ((missing_ok or project.Exists) and
79 project.MatchesGroups(groups)): 152 project.MatchesGroups(groups)):
80 result.append(project) 153 result.append(project)
81 else: 154 else:
82 by_path = None 155 self._ResetPathToProjectMap(all_projects.values())
83 156
84 for arg in args: 157 for arg in args:
85 project = all_projects.get(arg) 158 project = all_projects.get(arg)
86 159
87 if not project: 160 if not project:
88 path = os.path.abspath(arg).replace('\\', '/') 161 path = os.path.abspath(arg).replace('\\', '/')
89 162 project = self._GetProjectByPath(path)
90 if not by_path: 163
91 by_path = dict() 164 # If it's not a derived project, update path->project mapping and
92 for p in all_projects.values(): 165 # search again, as arg might actually point to a derived subproject.
93 by_path[p.worktree] = p 166 if (project and not project.Derived and
94 167 (submodules_ok or project.sync_s)):
95 if os.path.exists(path): 168 search_again = False
96 oldpath = None 169 for subproject in project.GetDerivedSubprojects():
97 while path \ 170 self._UpdatePathToProjectMap(subproject)
98 and path != oldpath \ 171 search_again = True
99 and path != self.manifest.topdir: 172 if search_again:
100 try: 173 project = self._GetProjectByPath(path) or project
101 project = by_path[path]
102 break
103 except KeyError:
104 oldpath = path
105 path = os.path.dirname(path)
106 else:
107 try:
108 project = by_path[path]
109 except KeyError:
110 pass
111 174
112 if not project: 175 if not project:
113 raise NoSuchProjectError(arg) 176 raise NoSuchProjectError(arg)