Mercurial > mxe-octave
view tools/pkg-install.py @ 5210:4eae7db624e8
* tools/pkg-install.py: add rebuild command
author | John Donoghue |
---|---|
date | Tue, 19 Nov 2019 07:57:29 -0500 |
parents | eb8b37422e16 |
children | b6ca48619aa6 |
line wrap: on
line source
#!/usr/bin/python import sys import os import re import tempfile import shutil import fnmatch import subprocess import glob class Env: mkoctfile = "mkoctfile"; octave_config = "octave-config"; make = "make" verbose = True; prefix = ""; pkg = ""; use_pkg_prefix = True; arch = ""; tmp = "/tmp"; apiversion = ""; bin_dir = ""; m_dir = ""; arch_dir = ""; cleanup = False; def show_usage(): print sys.argv(0), "[options] pkg1 [pkg2]" def verify_directory(dirname): for f in [ "COPYING", "DESCRIPTION" ]: if os.path.isfile(dirname + "/" + f) == False: raise Exception, "package is missing file " + f def get_description(descfile): with open(descfile, 'r') as f: lines = f.read().splitlines() pat_match = re.compile("(?P<name>[-\w]+):\s*(?P<value>\w.*)") lineval = "" d={} for l in lines: if len(l) > 0: if (l[0] == ' ' or l[0] == '\t'): lineval = lineval + l else: lineval = l e = pat_match.match(lineval) if e: d[e.group("name")] = e.group("value") return d def extract_pkg(filename, nm): pkg = [] with open(filename, 'r') as f: lines = f.read().splitlines() for l in lines: so = re.search(nm, l, re.M|re.S) if so: pkg.append(str(so.group(1))) return pkg def write_index_file(env, desc, index_nm): with open(index_nm, 'w') as f: files = os.listdir(env.m_dir) classes = fnmatch.filter(files, "@*") # check classes for c in classes: class_name = c class_path = env.m_dir + "/" + c; if os.path.isdir(class_path) == True: class_files = list(class_name + "/" + a for a in os.listdir(class_path)) files += class_files # arch dependant if os.path.exists(env.arch_dir) == True: archfiles = os.listdir(env.arch_dir) files += archfiles functions = [] for a in files: if a.endswith(".m"): functions.append( str(a[0:len(a)-2]) ) elif a.endswith(".oct"): functions.append( str(a[0:len(a)-4]) ) f.write(env.pkg + " >> " + desc['Title'] + "\n"); f.write(desc['Categories'].replace(",", " ") + "\n") for a in functions: f.write(" " + a + "\n") def finish_installation(env, packdir): # octave would run post_install.m here - instead we will copy the post_install.m # somewhere and then on initial startup, run the post_install if os.path.isfile(packdir + "/post_install.m") == True: if env.verbose: print "Copying .. post_install.m" destdir = env.prefix + "/share/octave/site/m/once_only" if os.path.exists(destdir) == False: os.makedirs(destdir) shutil.copy2(packdir + "/post_install.m", destdir + "/" + env.pkg + "-post_install.m") def create_pkgadddel (env, packdir, nm): if env.verbose: print "Creating...", nm instfid = open(env.m_dir + "/" + nm, "a") if os.path.exists(env.arch_dir) == True: archfid = open(env.arch_dir + "/" + nm, "w") else: archfid = instfid # search inst .m files for PKG_ commands instdir = packdir + "/inst" files = list(instdir + "/" + a for a in os.listdir(instdir)) m_files = fnmatch.filter(files, "*.m") for f in m_files: for a in extract_pkg(f, '^[#%][#%]* *' + nm + ': *(.*)$'): instfid.write("%s\n" % str(a)) # search src .cc files for PKG_ commands if os.path.exists(packdir + "/src") == True: srcdir = packdir + "/src" files = list(srcdir + "/" + a for a in os.listdir(srcdir)) cc_files = fnmatch.filter(files, "*.cc") cpp_files = fnmatch.filter(files, "*.cpp") cxx_files = fnmatch.filter(files, "*.cxx") for f in cc_files + cpp_files + cxx_files: for a in extract_pkg(f, '^//* *' + nm + ': *(.*)$'): archfid.write("%s\n" % str(a)) for a in extract_pkg(f, '^/\** *' + nm + ': *(.*) *\*/$'): archfid.write("%s\n" % a) # add PKG_XXX from packdir if exists if os.path.isfile(packdir + "/" + nm) == True: with open(packdir + "/" + nm, 'r') as f: lines = f.read().splitlines() for a in lines: archfid.write("%s\n" % a) # close files if archfid != instfid: archfid.close() if os.stat(env.arch_dir + "/" + nm).st_size == 0: os.remove(env.arch_dir + "/" + nm) instfid.close() if os.stat(env.m_dir + "/" + nm).st_size == 0: os.remove(env.m_dir + "/" + nm) def generate_lookfor_cache (env): # TODO create doc-cache pass def copyfile(files, destdir): if os.path.exists(destdir) == False: os.mkdir(destdir) for a in files: if os.path.isfile(a): shutil.copy2(a, destdir) if os.path.isdir(a): name= os.path.basename(a) morefiles=(a + "/" + b for b in os.listdir(a)) copyfile(morefiles, destdir + "/" + name) def copy_files(env, pkgdir): if os.path.exists(env.m_dir) == False: os.makedirs(env.m_dir) instdir = pkgdir + "/inst" if env.verbose: print "Copying m files ..." files = list(instdir + "/" + a for a in os.listdir(instdir)) # filter for arch folder if os.path.exists(instdir + "/" + env.arch) == True: files.remove(instdir + "/" + env.arch) copyfile(files, env.m_dir) if os.path.exists(instdir + "/" + env.arch) == True: if env.verbose: print "Copying arch files ..." files = list(instdir + "/" + env.arch + "/" + a for a in os.listdir(instdir + "/" + env.arch)) if len(files) > 0: if os.path.exists(env.arch_dir) == False: os.makedirs(env.arch_dir) copyfile(files, env.arch_dir) shutil.rmtree(instdir + "/" + env.arch) # packinfo if env.verbose: print "Copying packinfo files ..." if os.path.exists(env.m_dir + "/packinfo") == False: os.makedirs(env.m_dir + "/packinfo") copyfile([pkgdir + "/DESCRIPTION"], env.m_dir + "/packinfo") copyfile([pkgdir + "/COPYING"], env.m_dir + "/packinfo") copyfile([pkgdir + "/CITATION"], env.m_dir + "/packinfo") copyfile([pkgdir + "/NEWS"], env.m_dir + "/packinfo") copyfile([pkgdir + "/ONEWS"], env.m_dir + "/packinfo") copyfile([pkgdir + "/ChangeLog"], env.m_dir + "/packinfo") # index file if env.verbose: print "Copying/creating INDEX ..." if os.path.isfile(pkgdir + "/INDEX") == True: copyfile([pkgdir + "/INDEX"], env.m_dir + "/packinfo") else: desc = get_description(pkgdir + "/DESCRIPTION") write_index_file(env, desc, env.m_dir + "/packinfo/INDEX") copyfile([pkgdir + "on_uninstall.m"], env.m_dir + "/packinfo") # doc dir ? docdir = pkgdir + "/doc" if os.path.exists(docdir) == True: if env.verbose: print "Copying doc files ..." files = (docdir + "/" + a for a in os.listdir(docdir)) copyfile(files, env.m_dir + "/doc") # bin dir ? bindir = pkgdir + "/bin" if os.path.exists(bindir) == True: if env.verbose: print "Copying bin files ..." files = (bindir + "/" + a for a in os.listdir(bindir)) copyfile(files, env.m_dir + "/bin") def configure_make(env, packdir): if os.path.isdir(packdir + "/inst") == False: os.mkdir(packdir + "/inst") if os.path.isdir(packdir + "/src") == True: src = packdir + "/src" os.chdir(src) if os.path.isfile(src + "/configure") == True: if env.verbose: print "running ./configure " + env.config_opts if os.system("./configure " + env.config_opts + "") != 0: raise Exception, "configure failed - stopping install" if os.path.isfile(src + "/Makefile") == True: if env.verbose: print "running make ..." if os.system(env.make + " --directory '" + src + "'" ) != 0: raise Exception, "make failed during build - stopping install" # copy files to inst and inst arch files = src + "/FILES" instdir = packdir + "/inst" archdir = instdir + "/" + env.arch if os.path.isfile(files) == True: pass # TODO yet else: # get .m, .oct and .mex files files = os.listdir(src) m_files = fnmatch.filter(files, "*.m") mex_files = fnmatch.filter(files, "*.mex") oct_files = fnmatch.filter(files, "*.oct") files = m_files + mex_files + oct_files files = list(src + "/" + s for s in files) # split files into arch and non arch files archdependant = fnmatch.filter(files, "*.mex") + fnmatch.filter(files,"*.oct") archindependant = list( x for x in files if x not in archdependant ) # copy the files copyfile(archindependant, instdir) copyfile(archdependant, archdir) def add_package_list(env, desc): #pkglist = env.prefix + "/share/octave/octave_packages" #with open(pkglist, 'r') as f: # lines = f.read().splitlines() # currently doing nothing for adding, will let installer do pass def uninstall_pkg(pkg,env): # uninstall existing directories files=glob.glob(env.prefix + "/share/octave/packages/" + env.pkg + "-" + "*") for f in files: print "removing dir " + f shutil.rmtree(f) files=glob.glob(env.prefix + "/lib/octave/packages/" + env.pkg + "-" + "*") for f in files: print "removing dir " + f shutil.rmtree(f) pass def install_pkg(pkg, env): pkg = os.path.abspath(pkg) currdir = os.getcwd() try: ## Check that the directory in prefix exist. If it doesn't: create it! tmpdir = tempfile.mkdtemp("-pkg","tmp", env.tmp) os.chdir(tmpdir) # unpack dir if env.verbose: os.system("tar xzvf '" + pkg + "'") else: os.system("tar xzf '" + pkg + "'") # get list for files creates files=os.listdir(tmpdir) if len(files) != 1: print "Expected to unpack to only one directory" packdir = os.path.abspath(files[0]) # verify have expected min files verify_directory(packdir) # read the description file desc = get_description(packdir + "/DESCRIPTION") # make the path names env.pkg = desc['Name'].lower() env.m_dir = env.prefix + "/share/octave/packages/" + env.pkg + "-" + desc['Version']; env.arch_dir = env.prefix + "/lib/octave/packages/" + env.pkg + "-" + desc['Version'] + "/" + env.arch + "-" + env.apiversion configure_make (env, packdir) # uninstall old packages uninstall_pkg(pkg, env) # install package files copy_files(env, packdir) create_pkgadddel (env, packdir, "PKG_ADD"); create_pkgadddel (env, packdir, "PKG_DEL"); finish_installation(env, packdir) generate_lookfor_cache (env); # update package list add_package_list(env, desc) finally: if env.verbose: print "cleaning up" os.chdir(currdir) if env.cleanup: shutil.rmtree(tmpdir) def fix_depends(deps): deplist = [s.strip() for s in deps.split(",") if len(s.strip()) > 0] deppat = re.compile('\s*(?P<name>[-\w]+)\s*(\(\s*(?P<op>[<>=]+)\s*(?P<ver>\d+\.\d+(\.\d+)*)\s*\))*\s*') deps = [] for d in deplist: e = deppat.match(d) name = e.group("name") ver = e.group("ver") if ver: op = e.group("op") else: op = ">=" ver = "0.0.0" deps.append({"package": name, "operator": op, "version": ver}) return deps def rebuild_pkg(env): currdir = os.getcwd() try: oct_dir = env.prefix + "/share/octave" pkg_dir = oct_dir + "/packages" arch_dir = env.prefix + "/lib/octave/packages" pkg_list_file = oct_dir + "/octave_packages" descs=glob.glob(pkg_dir + "/*/packinfo/DESCRIPTION") with open(pkg_list_file, "w") as f: f.write("# Created by pkg-install.py\n") f.write("# name: global_packages\n") f.write("# type: cell\n"); f.write("# rows: 1\n") f.write("# columns: {}\n".format(len(descs))) for d in descs: pkg = d[len(pkg_dir):-len("/packinfo/DESCRIPTION")] if env.verbose: print "Rebuilding {}".format(pkg) desc = get_description(d) desc["Name"] = desc["Name"].lower() desc["Depends"] = fix_depends(desc.get("Depends","")) f.write("# name: <cell-element>\n"); f.write("# type: scalar struct\n"); f.write("# ndims: 2\n"); f.write(" 1 1\n"); f.write("# length: 13\n"); pkg_fields = [ "Name", "Version", "Date", "Author", "Maintainer", \ "Title", "Description", "Depends", "Autoload", "License" ] for field in pkg_fields: name = field.lower() value = desc.get(field, None) if value is None: if name == "autoload": value = "no" else: value = "not set" f.write("# name: {}\n".format(name)) if name == "depends": f.write("# type: cell\n") f.write("# rows: 1\n") f.write("# columns: {}\n".format(len(value))) dep_fields = [ "package", "operator", "version" ] for dep in value: f.write("# name: <cell-element>\n") f.write("# type: scalar struct\n") f.write("# ndims: 2\n") f.write(" 1 1\n"); f.write("# length: 3\n"); for df in dep_fields: val = dep.get(df) f.write("# name: {}\n".format(df)) f.write("# type: sq_string\n") f.write("# elements: 1\n") f.write("# length: {}\n".format(len(str(val)))) f.write("{}\n".format(str(val))) f.write("\n\n"); f.write("\n\n"); else: f.write("# type: sq_string\n") f.write("# elements: 1\n") f.write("# length: {}\n".format(len(str(value)))) f.write("{}\n".format(str(value))) f.write("\n\n"); f.write("# name: loaded\n") f.write("# type: bool\n") f.write("0\n") f.write("\n\n"); name = "dir" if env.use_pkg_prefix: value = "__OH__/share/octave/packages" + pkg else: value = pkg_dir + pkg f.write("# name: {}\n".format(name)) f.write("# type: sq_string\n") f.write("# elements: 1\n") f.write("# length: {}\n".format(len(str(value)))) f.write("{}\n".format(str(value))) f.write("\n\n"); name = "archprefix" if env.use_pkg_prefix: value = "__OH__/lib/octave/packages" + pkg else: value = arch_dir + pkg f.write("# name: {}\n".format(name)) f.write("# type: sq_string\n") f.write("# elements: 1\n") f.write("# length: {}\n".format(len(str(value)))) f.write("{}\n".format(str(value))) f.write("\n\n"); finally: os.chdir(currdir) def pkg (args): arch = '' operation = "install" env = Env() files = [] operation = args[0] if operation != "install" and operation != "rebuild": raise Exception, "Expected pkg operation 'install' or 'rebuild'" args = args[1:] for a in args: c=a.split("=") key=c[0] if len(c) > 1: val=c[1] else: val="" if key == "-verbose": env.verbose = True; elif key == "--verbose": env.verbose = True; elif key == "--no-pkg-prefix": env.use_pkg_prefix = False; elif key == "-no-cleanup": env.cleanup = False; elif val == "": files.append(key) if os.environ.get("OCTAVE_CONFIG") != None: env.octave_config = os.environ["OCTAVE_CONFIG"] if os.environ.get("MAKE") != None: env.make = os.environ["MAKE"] if os.environ.get("MKOCTFILE") != None: env.mkoctfile = os.environ["MKOCTFILE"] if os.environ.get("TMP") != None: env.tmp = os.environ["TMP"] if env.verbose: env.mkoctfile = env.mkoctfile + " --verbose" # make sure we have these set up in env os.environ['OCTAVE_CONFIG'] = env.octave_config; os.environ['MAKE'] = env.make; os.environ['MKOCTFILE'] = env.mkoctfile; os.environ['TMP'] = env.tmp; os.environ['OCTAVE'] = 'echo'; if os.environ.get("CC") == None: os.environ['CC'] = os.popen(env.mkoctfile + " -p CC").read().rstrip("\r\n") if os.environ.get("CXX") == None: os.environ['CXX'] = os.popen(env.mkoctfile + " -p CXX").read().rstrip("\r\n") if os.environ.get("AR") == None: os.environ['AR'] = os.popen(env.mkoctfile + " -p AR").read().rstrip("\r\n") if os.environ.get("RANLIB") == None: os.environ['RANLIB'] = os.popen(env.mkoctfile + " -p RANLIB").read().rstrip("\r\n") if os.environ.get("CONFIGURE_OPTIONS") != None: env.config_opts = os.environ['CONFIGURE_OPTIONS'] # work out what arch is etc from mkoctfile/config if env.prefix == "": env.prefix = os.popen(env.octave_config + " -p OCTAVE_HOME").read().rstrip("\r\n") if env.prefix == "": env.prefix = os.popen(env.octave_config + " -p PREFIX").read().rstrip("\r\n") env.arch = os.popen(env.octave_config + " -p CANONICAL_HOST_TYPE").read().rstrip("\r\n") env.apiversion = os.popen(env.octave_config + " -p API_VERSION").read().rstrip("\r\n") env.bindir = os.popen(env.octave_config + " -p BINDIR").read().rstrip("\r\n") if env.verbose: print "operation=", operation print "mkoctfile=", env.mkoctfile print "arch=", env.arch print "apiversion=", env.apiversion print "prefix=", env.prefix print "files=", files print "verbose=", env.verbose if operation == "install": for a in files: install_pkg(a, env) # rebuild pkg list afterwards rebuild_pkg(env) else: rebuild_pkg(env) return 0 if __name__ == "__main__": if len(sys.argv) > 1: pkg(sys.argv[1:]) else: show_usage()