]>
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: | |
21 | print commandStr | |
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 | ||
92 | def clean(self, dir=None, projectFile=None): | |
93 | """ | |
94 | dir = the directory containing the project file | |
95 | projectFile = Some formats need to explicitly specify the project file's name | |
96 | """ | |
97 | ||
98 | args = [self.getProgramPath(), "clean"] | |
99 | if dir: | |
100 | args.append(dir) | |
101 | if self.isAvailable(): | |
102 | result = runInDir(args) | |
103 | return result | |
104 | ||
105 | return False | |
106 | ||
107 | def configure(self, options=None): | |
108 | # if we don't have configure, just report success | |
109 | return True | |
110 | ||
111 | def build(self, dir=None, projectFile=None, targets=None, options=None): | |
112 | if self.isAvailable(): | |
113 | if options: | |
114 | optionList = list(options) | |
115 | else: | |
116 | optionList = [] | |
117 | ||
118 | optionList.insert(0, self.getProgramPath()) | |
119 | ||
120 | result = runInDir(optionList, dir) | |
121 | ||
122 | return result | |
123 | ||
124 | return 1 | |
125 | ||
126 | def install(self, dir=None, options=None): | |
127 | if self.isAvailable(): | |
128 | ||
129 | args = ["make", "install"] | |
130 | if options: | |
131 | args.extend(options) | |
132 | result = runInDir(args, dir) | |
133 | return result | |
134 | ||
135 | return 1 | |
136 | ||
137 | # Concrete subclasses of abstract Builder interface | |
138 | ||
139 | class GNUMakeBuilder(Builder): | |
140 | def __init__(self, commandName="make", formatName="GNUMake"): | |
141 | Builder.__init__(self, commandName=commandName, formatName=formatName) | |
142 | ||
143 | ||
c1098adf VZ |
144 | class XcodeBuilder(Builder): |
145 | def __init__(self, commandName="xcodebuild", formatName="Xcode"): | |
3b2c81c7 RD |
146 | Builder.__init__(self, commandName=commandName, formatName=formatName) |
147 | ||
148 | ||
149 | class AutoconfBuilder(GNUMakeBuilder): | |
150 | def __init__(self, formatName="autoconf"): | |
151 | GNUMakeBuilder.__init__(self, formatName=formatName) | |
152 | ||
153 | def configure(self, dir=None, options=None): | |
154 | #olddir = os.getcwd() | |
155 | #os.chdir(dir) | |
156 | ||
157 | configdir = dir | |
158 | if not dir: | |
159 | configdir = os.getcwd() | |
160 | ||
161 | configure_cmd = "" | |
162 | while os.path.exists(configdir): | |
163 | config_cmd = os.path.join(configdir, "configure") | |
164 | if not os.path.exists(config_cmd): | |
165 | parentdir = os.path.abspath(os.path.join(configdir, "..")) | |
166 | if configdir == parentdir: | |
167 | break | |
168 | ||
169 | configdir = parentdir | |
170 | else: | |
171 | configure_cmd = config_cmd | |
172 | break | |
173 | ||
174 | if not configure_cmd: | |
175 | sys.stderr.write("Could not find configure script at %r. Have you run autoconf?\n" % dir) | |
176 | return 1 | |
177 | ||
178 | optionsStr = string.join(options, " ") if options else "" | |
179 | command = "%s %s" % (configure_cmd, optionsStr) | |
180 | print command | |
181 | result = os.system(command) | |
182 | #os.chdir(olddir) | |
183 | return result | |
184 | ||
185 | ||
186 | class MSVCBuilder(Builder): | |
187 | def __init__(self): | |
188 | Builder.__init__(self, commandName="nmake.exe", formatName="msvc") | |
189 | ||
190 | def isAvailable(self): | |
191 | PATH = os.environ['PATH'].split(os.path.pathsep) | |
192 | for p in PATH: | |
193 | if os.path.exists(os.path.join(p, self.name)): | |
194 | return True | |
195 | return False | |
196 | ||
197 | ||
198 | class MSVCProjectBuilder(Builder): | |
199 | def __init__(self): | |
200 | Builder.__init__(self, commandName="VCExpress.exe", formatName="msvcProject") | |
201 | for key in ["VS90COMNTOOLS", "VC80COMNTOOLS", "VC71COMNTOOLS"]: | |
202 | if os.environ.has_key(key): | |
203 | self.prgoramDir = os.path.join(os.environ[key], "..", "IDE") | |
204 | ||
205 | if self.programDir == None: | |
206 | for version in ["9.0", "8", ".NET 2003"]: | |
207 | msvcDir = "C:\\Program Files\\Microsoft Visual Studio %s\\Common7\\IDE" % version | |
208 | if os.path.exists(msvcDir): | |
209 | self.programDir = msvcDir | |
210 | ||
211 | def isAvailable(self): | |
212 | if self.programDir: | |
213 | path = os.path.join(self.programDir, self.name) | |
214 | if os.path.exists(path): | |
215 | return True | |
216 | else: | |
217 | # I don't have commercial versions of MSVC so I can't test this | |
218 | name = "devenv.com" | |
219 | path = os.path.join(self.programDir, name) | |
220 | if os.path.exists(path): | |
221 | self.name = "devenv.com" | |
222 | return True | |
223 | ||
224 | return False | |
225 | ||
c1098adf | 226 | builders = [GNUMakeBuilder, XcodeBuilder, AutoconfBuilder, MSVCBuilder, MSVCProjectBuilder] |
3b2c81c7 RD |
227 | |
228 | def getAvailableBuilders(): | |
229 | availableBuilders = {} | |
230 | for symbol in builders: | |
231 | thisBuilder = symbol() | |
232 | if thisBuilder.isAvailable(): | |
233 | availableBuilders[thisBuilder.formatName] = symbol | |
234 | ||
235 | return availableBuilders |