Add emacs and vim editing settings to the bottom of *.py files.
[scons.git] / bootstrap.py
1 #
2 # __COPYRIGHT__
3 #
4 # Permission is hereby granted, free of charge, to any person obtaining
5 # a copy of this software and associated documentation files (the
6 # "Software"), to deal in the Software without restriction, including
7 # without limitation the rights to use, copy, modify, merge, publish,
8 # distribute, sublicense, and/or sell copies of the Software, and to
9 # permit persons to whom the Software is furnished to do so, subject to
10 # the following conditions:
11 #
12 # The above copyright notice and this permission notice shall be included
13 # in all copies or substantial portions of the Software.
14 #
15 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
16 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
17 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 #
23
24 import os
25 import os.path
26 import string
27 import sys
28
29 __doc__ = """bootstrap.py
30
31 This script supports "bootstrap" execution of the current SCons in
32 this local source tree by copying of all necessary Python scripts and
33 modules from underneath the src/ subdirectory into a subdirectory (named
34 "bootstrap/" by default), and then executing the copied SCons with the
35 supplied command-line arguments.
36
37 There are a handful of options that are specific to this bootstrap.py
38 script and which are *not* passed on to the underlying SCons script.
39 All of these begin with the string "bootstrap_":
40
41     --bootstrap_dir=DIR
42
43         Sets the name of the directory into which the SCons files will
44         be copied.  The default is "bootstrap" in the local subdirectory.
45
46     --bootstrap_force
47
48         Forces a copy of all necessary files.  By default, the
49         bootstrap.py script only updates the bootstrap copy if the
50         content of the source copy is different.
51
52     --bootstrap_src=DIR
53
54         Searches for the SCons files relative to the specified DIR,
55         then relative to the directory in which this bootstrap.py
56         script is found.
57
58     --bootstrap_update
59
60         Only updates the bootstrap subdirectory, and then exits.
61
62 In addition to the above options, the bootstrap.py script understands
63 the following SCons options:
64
65     -C, --directory
66
67         Changes to the specified directory before invoking SCons.
68         Because we change directory right away to the specified directory,
69         the SCons script itself doesn't need to, so this option gets
70         "eaten" by the bootstrap.py script.
71
72     -Y, --repository
73
74         These options are used under Aegis to specify a search path
75         for the source files that may not have been copied in to the
76         Aegis change.
77
78 This is essentially a minimal build of SCons to bootstrap ourselves into
79 executing it for the full build of all the packages, as specified in our
80 local SConstruct file.
81 """
82
83 bootstrap_dir = 'bootstrap'
84 try:
85     script_dir = os.path.split(__file__)[0]
86 except NameError:
87     # Pre-2.3 versions of Python don't have __file__.
88     script_dir = os.path.split(sys.argv[0])[0]
89     if not script_dir:
90         script_dir = os.getcwd()
91     elif not os.path.is_abs(script_dir):
92         script_dir = os.path.join(os.getcwd(), script_dir)
93 if script_dir:
94     bootstrap_dir = os.path.join(script_dir, bootstrap_dir)
95 pass_through_args = []
96 update_only = None
97
98 requires_an_argument = 'bootstrap.py:  %s requires an argument\n'
99
100 def must_copy(dst, src):
101     if not os.path.exists(dst):
102         return 1
103     return open(dst, 'rb').read() != open(src, 'rb').read()
104
105 search = [os.path.dirname(sys.argv[0])]
106 if search[0] == '': search[0] = '.'
107
108 # Note:  We don't use the getopt module to process the command-line
109 # arguments because we'd have to teach it about all of the SCons options.
110
111 command_line_args = sys.argv[1:]
112
113 while command_line_args:
114     arg = command_line_args.pop(0)
115
116     if arg == '--bootstrap_dir':
117         try:
118             bootstrap_dir = command_line_args.pop(0)
119         except IndexError:
120             sys.stderr.write(requires_an_argument % arg)
121             sys.exit(1)
122     elif arg[:16] == '--bootstrap_dir=':
123         bootstrap_dir = arg[16:]
124
125     elif arg == '--bootstrap_force':
126         def must_copy(dst, src):
127             return 1
128
129     elif arg == '--bootstrap_src':
130         try:
131             search.insert(0, command_line_args.pop(0))
132         except IndexError:
133             sys.stderr.write(requires_an_argument % arg)
134             sys.exit(1)
135     elif arg[:16] == '--bootstrap_src=':
136         search.insert(0, arg[16:])
137
138     elif arg == '--bootstrap_update':
139         update_only = 1
140
141     elif arg in ('-C', '--directory'):
142         try:
143             dir = command_line_args.pop(0)
144         except IndexError:
145             sys.stderr.write(requires_an_argument % arg)
146             sys.exit(1)
147         else:
148             os.chdir(dir)
149     elif arg[:2] == '-C':
150         os.chdir(arg[2:])
151     elif arg[:12] == '--directory=':
152         os.chdir(arg[12:])
153
154     elif arg in ('-Y', '--repository'):
155         try:
156             dir = command_line_args.pop(0)
157         except IndexError:
158             sys.stderr.write(requires_an_argument % arg)
159             sys.exit(1)
160         else:
161             search.append(dir)
162         pass_through_args.extend([arg, dir])
163     elif arg[:2] == '-Y':
164         search.append(arg[2:])
165         pass_through_args.append(arg)
166     elif arg[:13] == '--repository=':
167         search.append(arg[13:])
168         pass_through_args.append(arg)
169
170     else:
171         pass_through_args.append(arg)
172
173 def find(file, search=search):
174     for dir in search:
175         f = os.path.join(dir, file)
176         if os.path.exists(f):
177             return os.path.normpath(f)
178     sys.stderr.write("could not find `%s' in search path:\n" % file)
179     sys.stderr.write("\t" + string.join(search, "\n\t") + "\n")
180     sys.exit(2)
181
182 scons_py = os.path.join('src', 'script', 'scons.py')
183 src_engine = os.path.join('src', 'engine')
184 MANIFEST_in = find(os.path.join(src_engine, 'MANIFEST.in'))
185
186 files = [ scons_py ] + map(lambda x: os.path.join(src_engine, x[:-1]),
187                            open(MANIFEST_in).readlines())
188
189 for file in files:
190     src = find(file)
191     dst = os.path.join(bootstrap_dir, file)
192     if must_copy(dst, src):
193         dir = os.path.split(dst)[0]
194         if not os.path.isdir(dir):
195             os.makedirs(dir)
196         try: os.unlink(dst)
197         except: pass
198         open(dst, 'wb').write( open(src, 'rb').read() )
199
200 if update_only:
201     sys.exit(0)
202
203 args = [
204             os.path.split(sys.executable)[1],
205             os.path.join(bootstrap_dir, scons_py)
206        ] + pass_through_args
207
208 sys.stdout.write(string.join(args, " ") + '\n')
209 sys.stdout.flush()
210
211 os.environ['SCONS_LIB_DIR'] = os.path.join(bootstrap_dir, src_engine)
212
213 os.execve(sys.executable, args, os.environ)
214
215 # Local Variables:
216 # tab-width:4
217 # indent-tabs-mode:nil
218 # End:
219 # vim: set expandtab tabstop=4 shiftwidth=4: