trivial typo in man page
[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 try:
84     script_dir = os.path.abspath(os.path.dirname(__file__))
85 except NameError:
86     # Pre-2.3 versions of Python don't have __file__.
87     script_dir = os.path.abspath(os.path.dirname(sys.argv[0]))
88
89 bootstrap_dir = os.path.join(script_dir, 'bootstrap')
90
91 pass_through_args = []
92 update_only = None
93
94 requires_an_argument = 'bootstrap.py:  %s requires an argument\n'
95
96 def must_copy(dst, src):
97     if not os.path.exists(dst):
98         return 1
99     return open(dst, 'rb').read() != open(src, 'rb').read()
100
101 search = [script_dir]
102
103 # Note:  We don't use the getopt module to process the command-line
104 # arguments because we'd have to teach it about all of the SCons options.
105
106 command_line_args = sys.argv[1:]
107
108 while command_line_args:
109     arg = command_line_args.pop(0)
110
111     if arg == '--bootstrap_dir':
112         try:
113             bootstrap_dir = command_line_args.pop(0)
114         except IndexError:
115             sys.stderr.write(requires_an_argument % arg)
116             sys.exit(1)
117     elif arg[:16] == '--bootstrap_dir=':
118         bootstrap_dir = arg[16:]
119
120     elif arg == '--bootstrap_force':
121         def must_copy(dst, src):
122             return 1
123
124     elif arg == '--bootstrap_src':
125         try:
126             search.insert(0, command_line_args.pop(0))
127         except IndexError:
128             sys.stderr.write(requires_an_argument % arg)
129             sys.exit(1)
130     elif arg[:16] == '--bootstrap_src=':
131         search.insert(0, arg[16:])
132
133     elif arg == '--bootstrap_update':
134         update_only = 1
135
136     elif arg in ('-C', '--directory'):
137         try:
138             dir = command_line_args.pop(0)
139         except IndexError:
140             sys.stderr.write(requires_an_argument % arg)
141             sys.exit(1)
142         else:
143             os.chdir(dir)
144     elif arg[:2] == '-C':
145         os.chdir(arg[2:])
146     elif arg[:12] == '--directory=':
147         os.chdir(arg[12:])
148
149     elif arg in ('-Y', '--repository'):
150         try:
151             dir = command_line_args.pop(0)
152         except IndexError:
153             sys.stderr.write(requires_an_argument % arg)
154             sys.exit(1)
155         else:
156             search.append(dir)
157         pass_through_args.extend([arg, dir])
158     elif arg[:2] == '-Y':
159         search.append(arg[2:])
160         pass_through_args.append(arg)
161     elif arg[:13] == '--repository=':
162         search.append(arg[13:])
163         pass_through_args.append(arg)
164
165     else:
166         pass_through_args.append(arg)
167
168 def find(file, search=search):
169     for dir in search:
170         f = os.path.join(dir, file)
171         if os.path.exists(f):
172             return os.path.normpath(f)
173     sys.stderr.write("could not find `%s' in search path:\n" % file)
174     sys.stderr.write("\t" + string.join(search, "\n\t") + "\n")
175     sys.exit(2)
176
177 scons_py = os.path.join('src', 'script', 'scons.py')
178 src_engine = os.path.join('src', 'engine')
179 MANIFEST_in = find(os.path.join(src_engine, 'MANIFEST.in'))
180
181 files = [ scons_py ] + map(lambda x: os.path.join(src_engine, x[:-1]),
182                            open(MANIFEST_in).readlines())
183
184 for file in files:
185     src = find(file)
186     dst = os.path.join(bootstrap_dir, file)
187     if must_copy(dst, src):
188         dir = os.path.split(dst)[0]
189         if not os.path.isdir(dir):
190             os.makedirs(dir)
191         try: os.unlink(dst)
192         except: pass
193         open(dst, 'wb').write( open(src, 'rb').read() )
194
195 if update_only:
196     sys.exit(0)
197
198 args = [
199             sys.executable,
200             os.path.join(bootstrap_dir, scons_py)
201        ] + pass_through_args
202
203 sys.stdout.write(string.join(args, " ") + '\n')
204 sys.stdout.flush()
205
206 os.environ['SCONS_LIB_DIR'] = os.path.join(bootstrap_dir, src_engine)
207
208 os.execve(sys.executable, args, os.environ)
209
210 # Local Variables:
211 # tab-width:4
212 # indent-tabs-mode:nil
213 # End:
214 # vim: set expandtab tabstop=4 shiftwidth=4: