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