|
1 # This Source Code Form is subject to the terms of the Mozilla Public |
|
2 # License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 # file, You can obtain one at http://mozilla.org/MPL/2.0/. |
|
4 |
|
5 from __future__ import print_function, unicode_literals |
|
6 |
|
7 import os |
|
8 import platform |
|
9 import sys |
|
10 import time |
|
11 |
|
12 |
|
13 STATE_DIR_FIRST_RUN = ''' |
|
14 mach and the build system store shared state in a common directory on the |
|
15 filesystem. The following directory will be created: |
|
16 |
|
17 {userdir} |
|
18 |
|
19 If you would like to use a different directory, hit CTRL+c and set the |
|
20 MOZBUILD_STATE_PATH environment variable to the directory you would like to |
|
21 use and re-run mach. For this change to take effect forever, you'll likely |
|
22 want to export this environment variable from your shell's init scripts. |
|
23 '''.lstrip() |
|
24 |
|
25 |
|
26 # TODO Bug 794506 Integrate with the in-tree virtualenv configuration. |
|
27 SEARCH_PATHS = [ |
|
28 'python/mach', |
|
29 'python/mozboot', |
|
30 'python/mozbuild', |
|
31 'python/mozversioncontrol', |
|
32 'python/blessings', |
|
33 'python/configobj', |
|
34 'python/jsmin', |
|
35 'python/psutil', |
|
36 'python/which', |
|
37 'build/pymake', |
|
38 'config', |
|
39 'dom/bindings', |
|
40 'dom/bindings/parser', |
|
41 'other-licenses/ply', |
|
42 'xpcom/idl-parser', |
|
43 'testing', |
|
44 'testing/xpcshell', |
|
45 'testing/marionette/client', |
|
46 'testing/marionette/client/marionette', |
|
47 'testing/marionette/transport', |
|
48 'testing/mozbase/mozcrash', |
|
49 'testing/mozbase/mozdevice', |
|
50 'testing/mozbase/mozfile', |
|
51 'testing/mozbase/mozhttpd', |
|
52 'testing/mozbase/mozlog', |
|
53 'testing/mozbase/moznetwork', |
|
54 'testing/mozbase/mozprocess', |
|
55 'testing/mozbase/mozprofile', |
|
56 'testing/mozbase/mozrunner', |
|
57 'testing/mozbase/mozsystemmonitor', |
|
58 'testing/mozbase/mozinfo', |
|
59 'testing/mozbase/moztest', |
|
60 'testing/mozbase/mozversion', |
|
61 'testing/mozbase/manifestdestiny', |
|
62 'xpcom/idl-parser', |
|
63 ] |
|
64 |
|
65 # Individual files providing mach commands. |
|
66 MACH_MODULES = [ |
|
67 'addon-sdk/mach_commands.py', |
|
68 'build/valgrind/mach_commands.py', |
|
69 'dom/bindings/mach_commands.py', |
|
70 'layout/tools/reftest/mach_commands.py', |
|
71 'python/mach_commands.py', |
|
72 'python/mach/mach/commands/commandinfo.py', |
|
73 'python/mozboot/mozboot/mach_commands.py', |
|
74 'python/mozbuild/mozbuild/mach_commands.py', |
|
75 'python/mozbuild/mozbuild/frontend/mach_commands.py', |
|
76 'testing/mach_commands.py', |
|
77 'testing/marionette/mach_commands.py', |
|
78 'testing/mochitest/mach_commands.py', |
|
79 'testing/xpcshell/mach_commands.py', |
|
80 'testing/talos/mach_commands.py', |
|
81 'testing/xpcshell/mach_commands.py', |
|
82 'tools/docs/mach_commands.py', |
|
83 'tools/mercurial/mach_commands.py', |
|
84 'tools/mach_commands.py', |
|
85 ] |
|
86 |
|
87 |
|
88 CATEGORIES = { |
|
89 'build': { |
|
90 'short': 'Build Commands', |
|
91 'long': 'Interact with the build system', |
|
92 'priority': 80, |
|
93 }, |
|
94 'post-build': { |
|
95 'short': 'Post-build Commands', |
|
96 'long': 'Common actions performed after completing a build.', |
|
97 'priority': 70, |
|
98 }, |
|
99 'testing': { |
|
100 'short': 'Testing', |
|
101 'long': 'Run tests.', |
|
102 'priority': 60, |
|
103 }, |
|
104 'devenv': { |
|
105 'short': 'Development Environment', |
|
106 'long': 'Set up and configure your development environment.', |
|
107 'priority': 50, |
|
108 }, |
|
109 'build-dev': { |
|
110 'short': 'Low-level Build System Interaction', |
|
111 'long': 'Interact with specific parts of the build system.', |
|
112 'priority': 20, |
|
113 }, |
|
114 'misc': { |
|
115 'short': 'Potpourri', |
|
116 'long': 'Potent potables and assorted snacks.', |
|
117 'priority': 10, |
|
118 }, |
|
119 'disabled': { |
|
120 'short': 'Disabled', |
|
121 'long': 'These commands are unavailable for your current context, run "mach <command>" to see why.', |
|
122 'priority': 0, |
|
123 } |
|
124 } |
|
125 |
|
126 |
|
127 def bootstrap(topsrcdir, mozilla_dir=None): |
|
128 if mozilla_dir is None: |
|
129 mozilla_dir = topsrcdir |
|
130 |
|
131 # Ensure we are running Python 2.7+. We put this check here so we generate a |
|
132 # user-friendly error message rather than a cryptic stack trace on module |
|
133 # import. |
|
134 if sys.version_info[0] != 2 or sys.version_info[1] < 7: |
|
135 print('Python 2.7 or above (but not Python 3) is required to run mach.') |
|
136 print('You are running Python', platform.python_version()) |
|
137 sys.exit(1) |
|
138 |
|
139 # Global build system and mach state is stored in a central directory. By |
|
140 # default, this is ~/.mozbuild. However, it can be defined via an |
|
141 # environment variable. We detect first run (by lack of this directory |
|
142 # existing) and notify the user that it will be created. The logic for |
|
143 # creation is much simpler for the "advanced" environment variable use |
|
144 # case. For default behavior, we educate users and give them an opportunity |
|
145 # to react. We always exit after creating the directory because users don't |
|
146 # like surprises. |
|
147 try: |
|
148 import mach.main |
|
149 except ImportError: |
|
150 sys.path[0:0] = [os.path.join(mozilla_dir, path) for path in SEARCH_PATHS] |
|
151 import mach.main |
|
152 |
|
153 def populate_context(context, key=None): |
|
154 if key is None: |
|
155 return |
|
156 if key == 'state_dir': |
|
157 state_user_dir = os.path.expanduser('~/.mozbuild') |
|
158 state_env_dir = os.environ.get('MOZBUILD_STATE_PATH', None) |
|
159 if state_env_dir: |
|
160 if not os.path.exists(state_env_dir): |
|
161 print('Creating global state directory from environment variable: %s' |
|
162 % state_env_dir) |
|
163 os.makedirs(state_env_dir, mode=0o770) |
|
164 print('Please re-run mach.') |
|
165 sys.exit(1) |
|
166 state_dir = state_env_dir |
|
167 else: |
|
168 if not os.path.exists(state_user_dir): |
|
169 print(STATE_DIR_FIRST_RUN.format(userdir=state_user_dir)) |
|
170 try: |
|
171 for i in range(20, -1, -1): |
|
172 time.sleep(1) |
|
173 sys.stdout.write('%d ' % i) |
|
174 sys.stdout.flush() |
|
175 except KeyboardInterrupt: |
|
176 sys.exit(1) |
|
177 |
|
178 print('\nCreating default state directory: %s' % state_user_dir) |
|
179 os.mkdir(state_user_dir) |
|
180 print('Please re-run mach.') |
|
181 sys.exit(1) |
|
182 state_dir = state_user_dir |
|
183 |
|
184 return state_dir |
|
185 if key == 'topdir': |
|
186 return topsrcdir |
|
187 raise AttributeError(key) |
|
188 |
|
189 mach = mach.main.Mach(os.getcwd()) |
|
190 mach.populate_context_handler = populate_context |
|
191 |
|
192 for category, meta in CATEGORIES.items(): |
|
193 mach.define_category(category, meta['short'], meta['long'], |
|
194 meta['priority']) |
|
195 |
|
196 for path in MACH_MODULES: |
|
197 mach.load_commands_from_file(os.path.join(mozilla_dir, path)) |
|
198 |
|
199 return mach |