]>
Commit | Line | Data |
---|---|---|
3b2c81c7 RD |
1 | import os |
2 | import string | |
3 | import subprocess | |
4 | import sys | |
5 | import time | |
6 | ||
7 | class BuildError(Exception): | |
8 | def __init__(self, value): | |
9 | self.value = value | |
10 | ||
11 | def __repr__(self): | |
12 | return repr(self.value) | |
13 | ||
14 | def runInDir(command, dir=None, verbose=True): | |
15 | if dir: | |
16 | olddir = os.getcwd() | |
17 | os.chdir(dir) | |
18 | ||
19 | commandStr = " ".join(command) | |
20 | if verbose: | |
016a3d4c | 21 | print(commandStr) |
3b2c81c7 RD |
22 | result = os.system(commandStr) |
23 | ||
24 | if dir: | |
25 | os.chdir(olddir) | |
26 | ||
27 | return result | |
28 | ||
29 | class Builder: | |
30 | """ | |
31 | Base class exposing the Builder interface. | |
32 | """ | |
33 | ||
34 | def __init__(self, formatName="", commandName="", programDir=None): | |
35 | """ | |
36 | formatName = human readable name for project format (should correspond with Bakefile names) | |
37 | commandName = name of command line program used to invoke builder | |
38 | programDir = directory program is located in, if not on the path | |
39 | """ | |
40 | ||
41 | self.dir = dir | |
42 | self.name = commandName | |
43 | self.formatName = formatName | |
44 | self.programDir = programDir | |
45 | self.doSetup() | |
46 | ||
47 | def doSetup(self): | |
48 | """ | |
49 | Do anything special needed to configure the environment to build with this builder. | |
50 | """ | |
51 | ||
52 | pass | |
53 | ||
54 | def isAvailable(self): | |
55 | """ | |
56 | Run sanity checks before attempting to build with this format | |
57 | """ | |
58 | # Make sure the builder program exists | |
59 | programPath = self.getProgramPath() | |
60 | if os.path.exists(programPath): | |
61 | return True | |
62 | else: | |
63 | # check the PATH for the program | |
64 | # TODO: How do we check if we're in Cygwin? | |
65 | if sys.platform.startswith("win"): | |
66 | result = os.system(self.name) | |
67 | if result == 0: | |
68 | return True | |
69 | dirs = os.environ["PATH"].split(":") | |
70 | ||
71 | for dir in dirs: | |
72 | if os.path.isfile(os.path.join(dir, self.name)): | |
73 | return True | |
74 | ||
75 | else: | |
76 | result = os.system("which %s" % self.name) | |
77 | ||
78 | if result == 0: | |
79 | return True | |
80 | ||
81 | return False | |
82 | ||
83 | def getProgramPath(self): | |
84 | if self.programDir: | |
85 | path = os.path.join(self.programDir, self.name) | |
86 | if sys.platform.startswith("win"): | |
87 | path = '"%s"' % path | |
88 | return path | |
89 | ||
90 | return self.name | |
91 | ||
9f2b6b31 | 92 | def clean(self, dir=None, projectFile=None, options=None): |
3b2c81c7 RD |
93 | """ |
94 | dir = the directory containing the project file | |
95 | projectFile = Some formats need to explicitly specify the project file's name | |
96 | """ | |
3b2c81c7 | 97 | if self.isAvailable(): |
9f2b6b31 RD |
98 | if options: |
99 | optionList = list(options) | |
100 | else: | |
101 | optionList = [] | |
102 | ||
103 | optionList.insert(0, self.getProgramPath()) | |
104 | optionList.append("clean") | |
105 | ||
106 | result = runInDir(optionList, dir) | |
3b2c81c7 RD |
107 | return result |
108 | ||
109 | return False | |
110 | ||
111 | def configure(self, options=None): | |
112 | # if we don't have configure, just report success | |
113 | return True | |
114 | ||
115 | def build(self, dir=None, projectFile=None, targets=None, options=None): | |
116 | if self.isAvailable(): | |
117 | if options: | |
118 | optionList = list(options) | |
119 | else: | |
120 | optionList = [] | |
121 | ||
122 | optionList.insert(0, self.getProgramPath()) | |
123 | ||
124 | result = runInDir(optionList, dir) | |
125 | ||
126 | return result | |
127 | ||
128 | return 1 | |
129 | ||
130 | def install(self, dir=None, options=None): | |
131 | if self.isAvailable(): | |
132 | ||
133 | args = ["make", "install"] | |
134 | if options: | |
135 | args.extend(options) | |
136 | result = runInDir(args, dir) | |
137 | return result | |
138 | ||
139 | return 1 | |
140 | ||
141 | # Concrete subclasses of abstract Builder interface | |
142 | ||
143 | class GNUMakeBuilder(Builder): | |
144 | def __init__(self, commandName="make", formatName="GNUMake"): | |
145 | Builder.__init__(self, commandName=commandName, formatName=formatName) | |
146 | ||
147 | ||
c1098adf VZ |
148 | class XcodeBuilder(Builder): |
149 | def __init__(self, commandName="xcodebuild", formatName="Xcode"): | |
3b2c81c7 RD |
150 | Builder.__init__(self, commandName=commandName, formatName=formatName) |
151 | ||
152 | ||
153 | class AutoconfBuilder(GNUMakeBuilder): | |
154 | def __init__(self, formatName="autoconf"): | |
155 | GNUMakeBuilder.__init__(self, formatName=formatName) | |
156 | ||
157 | def configure(self, dir=None, options=None): | |
158 | #olddir = os.getcwd() | |
159 | #os.chdir(dir) | |
160 | ||
161 | configdir = dir | |
162 | if not dir: | |
163 | configdir = os.getcwd() | |
164 | ||
165 | configure_cmd = "" | |
166 | while os.path.exists(configdir): | |
167 | config_cmd = os.path.join(configdir, "configure") | |
168 | if not os.path.exists(config_cmd): | |
169 | parentdir = os.path.abspath(os.path.join(configdir, "..")) | |
170 | if configdir == parentdir: | |
171 | break | |
172 | ||
173 | configdir = parentdir | |
174 | else: | |
175 | configure_cmd = config_cmd | |
176 | break | |
177 | ||
178 | if not configure_cmd: | |
179 | sys.stderr.write("Could not find configure script at %r. Have you run autoconf?\n" % dir) | |
180 | return 1 | |
181 | ||
182 | optionsStr = string.join(options, " ") if options else "" | |
183 | command = "%s %s" % (configure_cmd, optionsStr) | |
016a3d4c | 184 | print(command) |
3b2c81c7 RD |
185 | result = os.system(command) |
186 | #os.chdir(olddir) | |
187 | return result | |
188 | ||
189 | ||
190 | class MSVCBuilder(Builder): | |
191 | def __init__(self): | |
192 | Builder.__init__(self, commandName="nmake.exe", formatName="msvc") | |
193 | ||
194 | def isAvailable(self): | |
195 | PATH = os.environ['PATH'].split(os.path.pathsep) | |
196 | for p in PATH: | |
197 | if os.path.exists(os.path.join(p, self.name)): | |
198 | return True | |
199 | return False | |
200 | ||
201 | ||
202 | class MSVCProjectBuilder(Builder): | |
203 | def __init__(self): | |
204 | Builder.__init__(self, commandName="VCExpress.exe", formatName="msvcProject") | |
205 | for key in ["VS90COMNTOOLS", "VC80COMNTOOLS", "VC71COMNTOOLS"]: | |
206 | if os.environ.has_key(key): | |
01456a3f | 207 | self.programDir = os.path.join(os.environ[key], "..", "IDE") |
3b2c81c7 RD |
208 | |
209 | if self.programDir == None: | |
210 | for version in ["9.0", "8", ".NET 2003"]: | |
211 | msvcDir = "C:\\Program Files\\Microsoft Visual Studio %s\\Common7\\IDE" % version | |
212 | if os.path.exists(msvcDir): | |
213 | self.programDir = msvcDir | |
214 | ||
215 | def isAvailable(self): | |
216 | if self.programDir: | |
217 | path = os.path.join(self.programDir, self.name) | |
218 | if os.path.exists(path): | |
219 | return True | |
220 | else: | |
221 | # I don't have commercial versions of MSVC so I can't test this | |
222 | name = "devenv.com" | |
223 | path = os.path.join(self.programDir, name) | |
224 | if os.path.exists(path): | |
225 | self.name = "devenv.com" | |
226 | return True | |
227 | ||
228 | return False | |
229 | ||
c1098adf | 230 | builders = [GNUMakeBuilder, XcodeBuilder, AutoconfBuilder, MSVCBuilder, MSVCProjectBuilder] |
3b2c81c7 RD |
231 | |
232 | def getAvailableBuilders(): | |
233 | availableBuilders = {} | |
234 | for symbol in builders: | |
235 | thisBuilder = symbol() | |
236 | if thisBuilder.isAvailable(): | |
237 | availableBuilders[thisBuilder.formatName] = symbol | |
238 | ||
239 | return availableBuilders |