Coverage for gpkit\build.py: 0%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

142 statements  

1"Finds solvers, sets gpkit settings, and builds gpkit" 

2import os 

3import sys 

4import shutil 

5import subprocess 

6 

7LOGSTR = "" 

8settings = {} 

9 

10 

11def log(*args): 

12 "Print a line and append it to the log string." 

13 global LOGSTR # pylint: disable=global-statement 

14 print(*args) 

15 LOGSTR += " ".join(args) + "\n" 

16 

17 

18def pathjoin(*args): 

19 "Join paths, collating multiple arguments." 

20 return os.sep.join(args) 

21 

22 

23def isfile(path): 

24 "Returns true if there's a file at $path. Logs." 

25 if os.path.isfile(path): 

26 log("# Found %s" % path) 

27 return True 

28 log("# Could not find %s" % path) 

29 return False 

30 

31 

32def replacedir(path): 

33 "Replaces directory at $path. Logs." 

34 log("# Replacing directory", path) 

35 if os.path.isdir(path): 

36 shutil.rmtree(path) 

37 os.makedirs(path) 

38 return path 

39 

40 

41def call(cmd): 

42 "Calls subprocess. Logs." 

43 log("# Calling '%s'" % cmd) 

44 log("##") 

45 log("### CALL BEGINS") 

46 retcode = subprocess.call(cmd, shell=True) 

47 log("### CALL ENDS") 

48 log("##") 

49 return retcode 

50 

51 

52def diff(filename, diff_dict): 

53 "Applies a simple diff to a file. Logs." 

54 with open(filename, "r") as a: 

55 with open(filename+".new", "w") as b: 

56 for line_number, line in enumerate(a): 

57 if line[:-1].strip() in diff_dict: 

58 newline = diff_dict[line[:-1].strip()]+"\n" 

59 log("#\n# Change in %s" 

60 "on line %i" % (filename, line_number + 1)) 

61 log("# --", line[:-1][:70]) 

62 log("# ++", newline[:70]) 

63 b.write(newline) 

64 else: 

65 b.write(line) 

66 shutil.move(filename+".new", filename) 

67 

68 

69class SolverBackend: 

70 "Inheritable class for finding solvers. Logs." 

71 name = look = None 

72 

73 def __init__(self): 

74 log("\n# Looking for `%s`" % self.name) 

75 found_in = self.look() # pylint: disable=not-callable 

76 if found_in: 

77 log("\nFound %s %s" % (self.name, found_in)) 

78 self.installed = True 

79 else: 

80 log("# Did not find\n#", self.name) 

81 self.installed = False 

82 

83 

84class MosekCLI(SolverBackend): 

85 "MOSEK command line interface finder." 

86 name = "mosek_cli" 

87 

88 def look(self): # pylint: disable=too-many-return-statements 

89 "Looks in default install locations for a mosek before version 9." 

90 log("# (A \"success\" is if mskexpopt complains that") 

91 log("# we haven't specified a file for it to open.)") 

92 already_in_path = self.run() 

93 if already_in_path: 

94 return already_in_path 

95 

96 log("# Looks like `mskexpopt` was not found in the default PATH,") 

97 log("# so let's try locating that binary ourselves.") 

98 

99 if sys.platform[:3] == "win": 

100 rootdir = "C:\\Program Files\\Mosek" 

101 mosek_platform = "win64x86" 

102 elif sys.platform[:6] == "darwin": 

103 rootdir = pathjoin(os.path.expanduser("~"), "mosek") 

104 mosek_platform = "osx64x86" 

105 elif sys.platform[:5] == "linux": 

106 rootdir = pathjoin(os.path.expanduser("~"), "mosek") 

107 mosek_platform = "linux64x86" 

108 else: 

109 return log("# Platform unsupported: %s" % sys.platform) 

110 

111 if "MSKHOME" in os.environ: # allow specification of root dir 

112 rootdir = os.environ["MSKHOME"] 

113 log("# Using MSKHOME environment variable (value %s) instead of" 

114 " OS-default MOSEK home directory" % rootdir) 

115 if not os.path.isdir(rootdir): 

116 return log("# expected MOSEK directory not found: %s" % rootdir) 

117 

118 possible_versions = [f for f in os.listdir(rootdir) 

119 if len(f) == 1 and f < "9"] 

120 if not possible_versions: 

121 return log("# no version folders (e.g. '7', '8') found" 

122 " in mosek directory \"%s\"" % rootdir) 

123 version = sorted(possible_versions)[-1] 

124 tools_dir = pathjoin(rootdir, version, "tools") 

125 lib_dir = pathjoin(tools_dir, "platform", mosek_platform) 

126 bin_dir = pathjoin(lib_dir, "bin") 

127 settings["mosek_bin_dir"] = bin_dir 

128 os.environ['PATH'] = os.environ['PATH'] + os.pathsep + bin_dir 

129 log("# Adding %s to the PATH" % bin_dir) 

130 

131 return self.run("in " + bin_dir) 

132 

133 def run(self, where="in the default PATH"): 

134 "Attempts to run mskexpopt." 

135 try: 

136 if call("mskexpopt") in (1052, 28): # 28 for MacOSX 

137 return where 

138 except: # pylint: disable=bare-except 

139 pass # exception type varies by operating system 

140 return None 

141 

142 

143class CVXopt(SolverBackend): 

144 "CVXopt finder." 

145 name = "cvxopt" 

146 

147 def look(self): 

148 "Attempts to import cvxopt." 

149 try: 

150 log("# Trying to import cvxopt...") 

151 import cvxopt # pylint: disable=unused-import 

152 return "in the default PYTHONPATH" 

153 except ImportError: 

154 pass 

155 

156 

157class MosekConif(SolverBackend): 

158 "MOSEK exponential cone solver finder." 

159 name = "mosek_conif" 

160 

161 def look(self): 

162 "Attempts to import a mosek supporting exponential cones." 

163 try: 

164 log("# Trying to import mosek...") 

165 import mosek 

166 if hasattr(mosek.conetype, "pexp"): 

167 return "in the default PYTHONPATH" 

168 return None 

169 except ImportError: 

170 pass 

171 

172def build(): 

173 "Builds GPkit" 

174 import gpkit 

175 log("# Building GPkit version %s" % gpkit.__version__) 

176 log("# Moving to the directory from which GPkit was imported.") 

177 start_dir = os.getcwd() 

178 os.chdir(gpkit.__path__[0]) 

179 

180 log("\nAttempting to find and build solvers:") 

181 solvers = [MosekCLI(), MosekConif(), CVXopt()] 

182 installed_solvers = [solver.name for solver in solvers if solver.installed] 

183 if not installed_solvers: 

184 log("Can't find any solvers!\n") 

185 if "GPKITSOLVERS" in os.environ: 

186 log("Replaced found solvers (%s) with environment var GPKITSOLVERS" 

187 " (%s)" % (installed_solvers, os.environ["GPKITSOLVERS"])) 

188 settings["installed_solvers"] = os.environ["GPKITSOLVERS"] 

189 else: 

190 settings["installed_solvers"] = ", ".join(installed_solvers) 

191 log("\nFound the following solvers: " + settings["installed_solvers"]) 

192 

193 # Write settings 

194 envpath = "env" 

195 replacedir(envpath) 

196 with open(pathjoin(envpath, "settings"), "w") as f: 

197 for setting, value in sorted(settings.items()): 

198 f.write("%s : %s\n" % (setting, value)) 

199 with open(pathjoin(envpath, "build.log"), "w") as f: 

200 f.write(LOGSTR) 

201 

202 os.chdir(start_dir) 

203 

204if __name__ == "__main__": 

205 build()