comparison tools/pkg-install.py @ 4067:bdcddfdc57d0

Install binary of-* packages * Makefile.in: (OCTAVE_FORGE_PKG_BUILD) call pkg-install.py if building binary packages * src/of-io-1-cross-fixes.patch: new patch * src/of-specfun-1-cross-fixes.patch: new patch * tools/pkg-install.py: new file
author John Donoghue <john.donoghue@ieee.org>
date Sat, 26 Dec 2015 22:00:59 -0500
parents
children fc806c8583a9
comparison
equal deleted inserted replaced
4066:0962acdde3be 4067:bdcddfdc57d0
1 #!/usr/bin/python
2 import sys
3 import os
4 import re
5 import tempfile
6 import shutil
7 import fnmatch
8 import subprocess
9
10 class Env:
11 mkoctfile = "mkoctfile";
12 octave_config = "octave-config";
13 make = "make"
14 verbose = True;
15 prefix = ""
16 pkg = ""
17 arch = ""
18 tmp = "/tmp"
19 apiversion = ""
20 bin_dir = ""
21 m_dir = ""
22 arch_dir = ""
23 config_opts = ""
24
25 def show_usage():
26 print sys.argv(0), "[options] pkg1 [pkg2]"
27
28 def verify_directory(dirname):
29 for f in [ "COPYING", "DESCRIPTION" ]:
30 if os.path.isfile(dirname + "/" + f) == False:
31 raise Exception, "package is missing file " + f
32
33 def get_description(descfile):
34 with open(descfile, 'r') as f:
35 lines = f.read().splitlines()
36 d = dict(s.split(': ',1) for s in lines if s.find(': ') != -1)
37 return d
38
39 def extract_pkg(filename, nm):
40 pkg = []
41 with open(filename, 'r') as f:
42 lines = f.read().splitlines()
43 for l in lines:
44 so = re.search(nm, l, re.M|re.S)
45 if so:
46 pkg.append(str(so.group(1)))
47 return pkg
48
49 def write_index_file(env, desc, index_nm):
50
51 with open(index_nm, 'w') as f:
52 files = os.listdir(env.m_dir)
53 classes = fnmatch.filter(files, "@*")
54
55 # check classes
56 for c in classes:
57 class_name = c
58 class_path = env.m_dir + "/" + c;
59 if os.path.isdir(class_path) == True:
60 class_files = list(class_name + "/" + a for a in os.listdir(class_path))
61 files += class_files
62
63 # arch dependant
64 if os.path.exists(env.arch_dir) == True:
65 archfiles = os.listdir(env.arch_dir)
66 files += archfiles
67
68 functions = []
69 for a in files:
70 if a.endswith(".m"):
71 functions.append( str(a[0:len(a)-2]) )
72 elif a.endswith(".oct"):
73 functions.append( str(a[0:len(a)-4]) )
74
75 f.write(env.pkg + " >> " + desc['Title'] + "\n");
76 f.write(desc['Categories'].replace(",", " ") + "\n")
77 for a in functions:
78 f.write(" " + a + "\n")
79
80 def finish_installation(env, packdir):
81 # octave would run post_install.m here - instead we will copy the post_install.m
82 # somewhere and then on initial startup, run the post_install
83 if os.path.isfile(packdir + "/post_install.m") == True:
84 if env.verbose:
85 print "Copying .. post_install.m"
86 destdir = env.prefix + "/share/octave/site/m/once_only"
87 if os.path.exists(destdir) == False:
88 os.makedirs(destdir)
89 shutil.copy2(packdir + "/post_install.m", destdir + "/" + env.pkg + "-post_install.m")
90
91 def create_pkgadddel (env, packdir, nm):
92 if env.verbose:
93 print "Creating...", nm
94
95 instfid = open(env.m_dir + "/" + nm, "w")
96 if os.path.exists(env.arch_dir) == True:
97 archfid = open(env.arch_dir + "/" + nm, "w")
98 else:
99 archfid = instfid
100
101 # search inst .m files for PKG_ commands
102 instdir = packdir + "/inst"
103 files = list(instdir + "/" + a for a in os.listdir(instdir))
104 m_files = fnmatch.filter(files, "*.m")
105 for f in m_files:
106 for a in extract_pkg(f, '^[#%][#%]* *' + nm + ': *(.*)$'):
107 instfid.write("%s\n" % str(a))
108
109 # search inst .m files for PKG_ commands
110 if os.path.exists(packdir + "/src") == True:
111 srcdir = packdir + "/src"
112 files = list(srcdir + "/" + a for a in os.listdir(srcdir))
113 c_files = fnmatch.filter(files, "*.cc")
114 for f in c_files:
115 for a in extract_pkg(f, '^//* *' + nm + ': *(.*)$'):
116 archfid.write("%s\n" % str(a))
117 for a in extract_pkg(f, '^/\** *' + nm + ': *(.*) *\*/$'):
118 archfid.write("%s\n" % a)
119
120 # add PKG_XXX from packdir if exists
121 if os.path.isfile(packdir + "/" + nm) == True:
122 with open(packdir + "/" + nm, 'r') as f:
123 lines = f.read().splitlines()
124 for a in lines:
125 archfid.write("%s\n" % a)
126
127 # close files
128 if archfid != instfid:
129 archfid.close()
130 if os.stat(env.arch_dir + "/" + nm).st_size == 0:
131 os.remove(env.arch_dir + "/" + nm)
132 instfid.close()
133 if os.stat(env.m_dir + "/" + nm).st_size == 0:
134 os.remove(env.m_dir + "/" + nm)
135
136 def generate_lookfor_cache (env):
137 # TODO create doc-cache
138 pass
139
140 def copyfile(files, destdir):
141 if os.path.exists(destdir) == False:
142 os.mkdir(destdir)
143 for a in files:
144 if os.path.isfile(a):
145 shutil.copy2(a, destdir)
146 if os.path.isdir(a):
147 name= os.path.basename(a)
148 morefiles=(a + "/" + b for b in os.listdir(a))
149 copyfile(morefiles, destdir + "/" + name)
150
151 def copy_files(env, pkgdir):
152 if os.path.exists(env.m_dir) == False:
153 os.makedirs(env.m_dir)
154 instdir = pkgdir + "/inst"
155
156 if env.verbose:
157 print "Copying m files ..."
158
159 files = list(instdir + "/" + a for a in os.listdir(instdir))
160 # filter for arch folder
161 if os.path.exists(instdir + "/" + env.arch) == True:
162 files.remove(instdir + "/" + env.arch)
163
164 copyfile(files, env.m_dir)
165
166 if os.path.exists(instdir + "/" + env.arch) == True:
167 if env.verbose:
168 print "Copying arch files ..."
169 files = list(instdir + "/" + env.arch + "/" + a for a in os.listdir(instdir + "/" + env.arch))
170 if len(files) > 0:
171 if os.path.exists(env.arch_dir) == False:
172 os.makedirs(env.arch_dir)
173 copyfile(files, env.arch_dir)
174 shutil.rmtree(instdir + "/" + env.arch)
175
176 # packinfo
177 if env.verbose:
178 print "Copying packinfo files ..."
179 if os.path.exists(env.m_dir + "/packinfo") == False:
180 os.makedirs(env.m_dir + "/packinfo")
181 copyfile([pkgdir + "/DESCRIPTION"], env.m_dir + "/packinfo")
182 copyfile([pkgdir + "/COPYING"], env.m_dir + "/packinfo")
183 copyfile([pkgdir + "/CITATION"], env.m_dir + "/packinfo")
184 copyfile([pkgdir + "/NEWS"], env.m_dir + "/packinfo")
185 copyfile([pkgdir + "/ONEWS"], env.m_dir + "/packinfo")
186 copyfile([pkgdir + "/ChangeLog"], env.m_dir + "/packinfo")
187
188 # index file
189 if env.verbose:
190 print "Copying/creating INDEX ..."
191 if os.path.isfile(pkgdir + "/INDEX") == True:
192 copyfile([pkgdir + "/INDEX"], env.m_dir + "/packinfo")
193 else:
194 desc = get_description(pkgdir + "/DESCRIPTION")
195 write_index_file(env, desc, env.m_dir + "/packinfo/INDEX")
196
197 copyfile([pkgdir + "on_uninstall.m"], env.m_dir + "/packinfo")
198
199 # doc dir ?
200 docdir = pkgdir + "/doc"
201 if os.path.exists(docdir) == True:
202 if env.verbose:
203 print "Copying doc files ..."
204 files = (docdir + "/" + a for a in os.listdir(docdir))
205 copyfile(files, env.m_dir + "/doc")
206
207 # bin dir ?
208 bindir = pkgdir + "/bin"
209 if os.path.exists(bindir) == True:
210 if env.verbose:
211 print "Copying bin files ..."
212 files = (bindir + "/" + a for a in os.listdir(bindir))
213 copyfile(files, env.m_dir + "/bin")
214
215 def configure_make(env, packdir):
216 if os.path.isdir(packdir + "/inst") == False:
217 os.mkdir(packdir + "/inst")
218
219 if os.path.isdir(packdir + "/src") == True:
220 src = packdir + "/src"
221 os.chdir(src)
222
223 if os.path.isfile(src + "/configure") == True:
224 if env.verbose:
225 print "running ./configure " + env.config_opts
226
227 os.system("./configure " + env.config_opts + "")
228
229 if os.path.isfile(src + "/Makefile") == True:
230 if env.verbose:
231 print "running make ..."
232 if os.system(env.make + " --directory '" + src + "'" ) != 0:
233 raise Exception, "make failed during build - stopping install"
234
235 # copy files to inst and inst arch
236 files = src + "/FILES"
237 instdir = packdir + "/inst"
238 archdir = instdir + "/" + env.arch
239
240 if os.path.isfile(files) == True:
241 pass # TODO yet
242 else:
243 # get .m, .oct and .mex files
244 files = os.listdir(src)
245 m_files = fnmatch.filter(files, "*.m")
246 mex_files = fnmatch.filter(files, "*.mex")
247 oct_files = fnmatch.filter(files, "*.oct")
248 files = m_files + mex_files + oct_files
249 files = list(src + "/" + s for s in files)
250
251 # split files into arch and non arch files
252 archdependant = fnmatch.filter(files, "*.mex") + fnmatch.filter(files,"*.oct")
253 archindependant = list( x for x in files if x not in archdependant )
254
255 # copy the files
256 copyfile(archindependant, instdir)
257 copyfile(archdependant, archdir)
258
259 def add_package_list(env, desc):
260 #pkglist = env.prefix + "/share/octave/octave_packages"
261 #with open(pkglist, 'r') as f:
262 # lines = f.read().splitlines()
263 # currently doing nothing for adding, will let installer do
264 pass
265
266 def uninstall_pkg(pkg,env):
267 pass
268
269 def install_pkg(pkg, env):
270 pkg = os.path.abspath(pkg)
271 currdir = os.getcwd()
272
273 try:
274 ## Check that the directory in prefix exist. If it doesn't: create it!
275 tmpdir = tempfile.mkdtemp("-pkg","tmp", env.tmp)
276 os.chdir(tmpdir)
277
278 # unpack dir
279 if env.verbose:
280 os.system("tar xzvf '" + pkg + "'")
281 else:
282 os.system("tar xzf '" + pkg + "'")
283
284 # get list for files creates
285 files=os.listdir(tmpdir)
286 if len(files) != 1:
287 print "Expected to unpack to only one directory"
288
289 packdir = os.path.abspath(files[0])
290
291 # verify have expected min files
292 verify_directory(packdir)
293
294 # read the description file
295 desc = get_description(packdir + "/DESCRIPTION")
296
297 # make the path names
298 env.pkg = desc['Name'].lower()
299 env.m_dir = env.prefix + "/share/octave/packages/" + env.pkg + "-" + desc['Version'];
300 env.arch_dir = env.prefix + "/lib/octave/packages/" + env.pkg + "-" + desc['Version'] + "/" + env.arch + "-" + env.apiversion
301
302 configure_make (env, packdir)
303
304 # install package files
305 copy_files(env, packdir)
306 create_pkgadddel (env, packdir, "PKG_ADD");
307 create_pkgadddel (env, packdir, "PKG_DEL");
308 finish_installation(env, packdir)
309 generate_lookfor_cache (env);
310
311 # update package list
312 add_package_list(env, desc)
313 finally:
314 if env.verbose:
315 print "cleaning up"
316 os.chdir(currdir)
317 shutil.rmtree(tmpdir)
318
319
320 def pkg (args):
321 arch = ''
322
323 env = Env()
324
325 files = []
326
327 for a in args:
328 print a
329 c=a.split("=")
330 key=c[0]
331 if len(c) > 1:
332 val=c[1]
333 else:
334 val=""
335
336 if key == "-verbose":
337 env.verbose = True;
338 elif key == "--verbose":
339 env.verbose = True;
340 elif val == "":
341 files.append(key)
342
343
344 if os.environ.get("OCTAVE_CONFIG") != None:
345 env.octave_config = os.environ["OCTAVE_CONFIG"]
346 if os.environ.get("MAKE") != None:
347 env.make = os.environ["MAKE"]
348 if os.environ.get("MKOCTFILE") != None:
349 env.mkoctfile = os.environ["MKOCTFILE"]
350 if os.environ.get("TMP") != None:
351 env.tmp = os.environ["TMP"]
352
353 if env.verbose:
354 env.mkoctfile = env.mkoctfile + " --verbose"
355
356 # make sure we have these set up in env
357 os.environ['OCTAVE_CONFIG'] = env.octave_config;
358 os.environ['MAKE'] = env.make;
359 os.environ['MKOCTFILE'] = env.mkoctfile;
360 os.environ['TMP'] = env.tmp;
361 os.environ['OCTAVE'] = 'echo';
362
363 if os.environ.get("CC") == None:
364 os.environ['CC'] = os.popen(env.mkoctfile + " -p CC").read().rstrip("\r\n")
365 if os.environ.get("CXX") == None:
366 os.environ['CXX'] = os.popen(env.mkoctfile + " -p CXX").read().rstrip("\r\n")
367 if os.environ.get("AR") == None:
368 os.environ['AR'] = os.popen(env.mkoctfile + " -p AR").read().rstrip("\r\n")
369 if os.environ.get("RANLIB") == None:
370 os.environ['RANLIB'] = os.popen(env.mkoctfile + " -p RANLIB").read().rstrip("\r\n")
371
372 if os.environ.get("CONFIGURE_OPTIONS") != None:
373 env.config_opts = os.environ['CONFIGURE_OPTIONS']
374
375 # work out what arch is etc from mkoctfile/config
376 if env.prefix == "":
377 env.prefix = os.popen(env.octave_config + " -p PREFIX").read().rstrip("\r\n")
378
379 env.arch = os.popen(env.octave_config + " -p CANONICAL_HOST_TYPE").read().rstrip("\r\n")
380 env.apiversion = os.popen(env.octave_config + " -p API_VERSION").read().rstrip("\r\n")
381 env.bindir = os.popen(env.octave_config + " -p BINDIR").read().rstrip("\r\n")
382
383 if env.verbose:
384 print "mkoctfile=", env.mkoctfile
385 print "arch=", env.arch
386 print "apiversion=", env.apiversion
387 print "prefix=", env.prefix
388 print "files=", files
389 print "verbose=", env.verbose
390
391 for a in files:
392 install_pkg(a, env)
393
394 return 0
395
396 if __name__ == "__main__":
397 if len(sys.argv) > 1:
398 pkg(sys.argv[1:])
399 else:
400 show_usage()