def install_pack(pack): """Installs a single pack""" (pack, sep, pconfig) = pack.partition(":") pack_setup = get_pack_setup(pack) pack_dir = get_pack_dir(pack) if not pack_setup: return False # Create ext/ if it does not exist. if not os.path.isdir(lmh_locate("ext")): os.mkdir(lmh_locate("ext")) if pack_setup.is_installed(pack_dir): err("Pack", pack, "is already installed, use --update to update. ") return False try: return pack_setup.install(pack_dir, pconfig) except classes.UnsupportedAction: err("Pack", pack, "does not support installing. You may want to --update the pack?") return False
def match_repo(repo, root=os.getcwd(), abs=False, existence=True): """Matches a single specefier to a repository. """ # 1) Resolve to absolute path repo (via root) # 2) If it is (inside) a repository, return that repository # 3) If not, try to repeat 1) and 2) with root = data_dir # 4) If that fails, return None # make sure the root is absolute root = os.path.abspath(root) # If repo is empty, make sure we use the current directory. if repo == "": repo = os.getcwd() # try the full repo_path repo_path = os.path.join(root, repo) if is_repo_dir(repo_path, existence) or is_in_repo(repo_path): # figure out the path to the repository root repo_path = find_repo_dir(repo_path, existence) if repo_path: if abs: # return the absolute path to the repo return repo_path else: # return just the repo name, determined by the relative name return os.path.relpath(repo_path, os.path.abspath(lmh_locate("content"))) if not (root == os.path.abspath(lmh_locate("content"))): #if the root is not already the data_dir, try that return match_repo(repo, root=lmh_locate("content"), abs=abs,existence=existence) else: # nothing found return None
def match_repo_name(r): # make an absolute path # this will also work with globs names = os.path.abspath(os.path.join(root, r)) # it is not inside the data directory # so try again next time if not is_in_data(names): return True # find the relative path of it to the root. names = os.path.relpath( os.path.abspath(names), lmh_locate("content") ) # make sure everything ends with a slash # so that we can count properly if names[-1] != "/": names += "/" # Now figure out which level we are at # by counting slashes num_slashes = 0 for c in names: # count the slashes # by increasing the level. if c == "/": num_slashes += 1 # if we have no slashes # we are toplevel # and can pretty much exit everything if names == "./": names = lmh_locate("content", "*", "*") # if we have 1 slash # we are one level deep elif num_slashes == 1: names = lmh_locate("content", names, "*") else: names = lmh_locate("content", names) # now expand with the help of globs names = glob.glob(names) # and check if they exist names = list(filter(is_repo, names)) # if we found something # we should through the item if len(names) > 0: results.update(names) return False else: return True
def find_repo_subdirs(path): """ Returns the absolute path to the all repositories contained in PATH. @param {string} path - Path to check @returns {string[]} """ # path needs to be a directory if not os.path.isdir(path): return [] # We are not inside the data directory # so we need to return nothing if not is_in_data(path): return [] # If we can find the current repository path # we can return it. repo_path = find_repo_dir(path) if repo_path: return [repo_path] # Find the relative path from the root to the current directory name = os.path.relpath(os.path.abspath(path), lmh_locate("content")) # make sure everything ends with a slash # so that we can count properly if name[-1] != "/": name += "/" # Now figure out which level we are at # by counting slashes num_slashes = 0 for c in name: # count the slashes # by increasing the level. if c == "/": num_slashes += 1 # if we have no slashes # we are toplevel if name == "./": name = lmh_locate("content", "*", "*") # if we have 1 slash # we are one level deep elif num_slashes == 1: name = lmh_locate("content", name, "*") # else something is wrong # and we are nowhere else: return [] # now we can match the paths via glob.glob # and check that they exist return list(filter(is_repo, glob.glob(name)))
def match_repo_name(r): # make an absolute path # this will also work with globs names = os.path.abspath(os.path.join(root, r)) # it is not inside the data directory # so try again next time if not is_in_data(names): return True # find the relative path of it to the root. names = os.path.relpath(os.path.abspath(names), lmh_locate("content")) # make sure everything ends with a slash # so that we can count properly if names[-1] != "/": names += "/" # Now figure out which level we are at # by counting slashes num_slashes = 0 for c in names: # count the slashes # by increasing the level. if c == "/": num_slashes += 1 # if we have no slashes # we are toplevel # and can pretty much exit everything if names == "./": names = lmh_locate("content", "*", "*") # if we have 1 slash # we are one level deep elif num_slashes == 1: names = lmh_locate("content", names, "*") else: names = lmh_locate("content", names) # now expand with the help of globs names = glob.glob(names) # and check if they exist names = list(filter(is_repo, names)) # if we found something # we should through the item if len(names) > 0: results.update(names) return False else: return True
def get_metainf_lines(package): """ Gets the lines of the meta-inf file. @param package {string} Package to read meta-inf lines form. @returns {string[]} """ # Find the package root directory. package_dir = find_repo_dir(lmh_locate("content", package)) # Check that repository is installed. if not package_dir: err("Repository", package, "is not installed. Failed to read META-INF. ") return [] # Read the path to meta_inf meta_inf_path = os.path.join(package_dir, "META-INF", "MANIFEST.MF") try: # Try and read the file lines return read_file_lines(meta_inf_path) except: # File is not readable, silently fail. return []
def write_deps(dirname, deps): """Writes dependencies into a given module. """ f = lmh_locate("content", match_repo(dirname), "META-INF", "MANIFEST.MF") n = re.sub(r"dependencies: (.*)", "dependencies: "+",".join(deps), read_file(f)) write_file(f, n) std("Wrote new dependencies to", f)
def get_template(name): """ Gets a template file with the given name """ # TODO: Find out why this is unused and if we still need it. return read_file(lmh_locate("bin", "templates", name))
def is_repo_dir(path, existence=True): """ Checks if a directory contains a MathHub repository. Optimised to exit as soon as possible when the directory is not a repository. @param path {string} Path to check. @param existence {boolean} Do we do a theoretical test only or do we check for existence as well? @returns {boolean} """ if re.match('^[^\/]+\/[^\/]+$', path): # it is already a name. name = path else: # it is not a name, so we need to find the relative_path. name = os.path.relpath(os.path.abspath(path), lmh_locate("content")) # if the name ends with a /, remove it. if name.endswith("/"): name = name[:-1] # if the path does not match, we need to exit. if not re.match('^[^\/]+\/[^\/]+$', name): return False # if we need existence, check it is a git directory if existence: return is_repo(path) # we have passed all the tests return True
def main(argv=sys.argv[1:]): """Calls the main program with given arguments. """ # Load commands + aliases commands = json.loads(read_file(lmh_locate("lib", "data", "commands.json"))) aliases = json.loads(read_file(lmh_locate("lib", "data", "aliases.json"))) parser = create_parser(submods, commands, aliases) if len(argv) == 0: parser.print_help() return # parse arguments (args, unknown) = parser.parse_known_args(argv) # do the quiet stuff. if args.quiet: lmh.lib.io.__supressStd__ = True lmh.lib.io.__supressErr__ = True if args.non_interactive: lmh.lib.io.__supressIn__ = True # No action. if args.action == None: parser.print_help() return # an alias, so change the arguments. if args.action in aliases: # new argvs argv = shlex.split(aliases[args.action]) + unknown # and re-parse (args, unknown) = parser.parse_known_args(argv) try: if not submods[args.action].allow_unknown and len(unknown) > 0: err("Too many arguments. ") return False except Exception as e: err(e) # run normally. return submods[args.action].do(args, unknown)
def do_install(self, pack_dir, sstring): """Installs a git controlled package. """ (source, branch) = get_item_source(sstring, self.dsource, self.dbranch, self.name) try: # git clone first if not git_clone(lmh_locate("ext"), source, pack_dir): return False # do the checkout if branch != "": return git_do(lmh_locate("ext", pack_dir), "checkout", branch) else: return True except: err("git clone failed to clone", source, ". Check your network connection. ") return False
def git_version(): """ Returns the current git version of lmh as a string or None """ try: return do_data(lmh_locate(), "rev-parse", "HEAD")[0].rstrip() except: return None
def match_repo_args(spec, all=False, abs=True): """Matches repository arguments to an actual list of repositories""" if all: return match_repos(lmh_locate("content"), abs=abs) elif len(spec) == 0: return match_repos(".", abs=abs) else: return match_repos(spec, abs=abs)
def locate_files(path): """ Finds all files matching a specific specification. @param path Path to find files in """ # if we are outside data_dir, we return. if path.startswith(os.path.abspath(lmh_locate())) and not path.startswith( os.path.abspath(lmh_locate("content"))): return [] # fill these modules. modules = [] # Make sure we are inside the source directory. if os.path.relpath(lmh_locate("content"), path) == "../..": path = path + "/source" # Make it an absolute path. path = os.path.abspath(path) # if it is a file, we are done. if os.path.isfile(path): return [path] # if it is not a directory, return. if not os.path.isdir(path): return [] # find all files and folders. objects = [os.path.abspath(path + "/" + f) for f in os.listdir(path)] files = filter(lambda f: os.path.isfile(f), objects) folders = filter(lambda f: os.path.isdir(f), objects) # HACK out the tikz directories. folders = filter(lambda f: not f.split("/")[-1] in folder_exclude_list, folders) modules = reduce([os.path.abspath(file) for file in files]) # and go into subdirectories. modules.extend(reduce([locate_files(folder) for folder in folders])) # return the modules. return modules
def my_excepthook(exctype, value, tb): if exctype == KeyboardInterrupt: return e = ''.join(traceback.format_exception(exctype, value, tb)) err(e) err("lmh seems to have crashed with %s"%exctype) err("a report will be generated in ") s = "cwd = {0}\n args = {1}\n".format(cwd, sys.argv) s = s + e write_file(lmh_locate("logs", time.strftime("%Y-%m-%d-%H-%M-%S.log")), s)
def locate_compile_target(path, try_root= True): """ Finds all targets to be compiled. (Files AND Folders inside source/) @param path Path to find files in """ spec = path # if we are not inside the data directory, return. if path.startswith(os.path.abspath(lmh_locate())) and not path.startswith(os.path.abspath(lmh_locate("content"))): # if we have not tried the root, we should try again. if try_root: return locate_compile_target(lmh_locate("content", spec), False) return [] # If we are inside the root, go inside the folder. relpath = os.path.relpath(lmh_locate("content"), os.path.realpath(path)) if relpath == "../..": path = path + "/source" elif not relpath.endswith("../.."): return reduce([(locate_compile_target(p)) for p in find_repo_subdirs(path)]) # Get the absolute path. path = os.path.realpath(path) # If it does not exist, return. if not os.path.isfile(path) and not os.path.isdir(path): # if we have not tried the root, we should try again. if try_root: return locate_compile_target(lmh_locate("content", spec), False) err("Could not find anything matching ", "'"+spec+"'") return [] # find the repository dir. repo_dir = find_repo_dir(path, existence=True) repo_name = os.path.relpath(repo_dir, lmh_locate("content")) if repo_dir == False: # if we have not tried the root, we should try again. if try_root: return locate_compile_target(lmh_locate("content", spec), False) err("Matching item to ", "'"+spec+"'", "are outside of repository. ") return [] # Find the source directory and get a relative path repos_src_dir = os.path.join(repo_dir, "source") path = os.path.relpath(path, repos_src_dir) # if we need to go up, we are not in source if path.startswith("../"): # if we have not tried the root, we should try again. if try_root: return locate_compile_target(lmh_locate("content", spec), False) err("Matching item to", "'"+spec+"'", "are outside of the source directory. ") return [] # return the name of the repository and the path inside the repository. return [(repo_name, path)]
def locate_files(path): """ Finds all files matching a specific specification. @param path Path to find files in """ # if we are outside data_dir, we return. if path.startswith(os.path.abspath(lmh_locate())) and not path.startswith(os.path.abspath(lmh_locate("content"))): return [] # fill these modules. modules = [] # Make sure we are inside the source directory. if os.path.relpath(lmh_locate("content"), path) == "../..": path = path + "/source" # Make it an absolute path. path = os.path.abspath(path) # if it is a file, we are done. if os.path.isfile(path): return [path] # if it is not a directory, return. if not os.path.isdir(path): return [] # find all files and folders. objects = [os.path.abspath(path + "/" + f) for f in os.listdir(path)] files = filter(lambda f:os.path.isfile(f), objects) folders = filter(lambda f:os.path.isdir(f), objects) # HACK out the tikz directories. folders = filter(lambda f:not f.split("/")[-1] in folder_exclude_list, folders) modules = reduce([os.path.abspath(file) for file in files]) # and go into subdirectories. modules.extend(reduce([locate_files(folder) for folder in folders])) # return the modules. return modules
def is_installed(package): """ Checks if a repository is installed locally. @param package {string} Package to check. @returns {boolean} """ return is_repo_dir(lmh_locate("content", package))
def is_in_data(path): """ Checks if a directory is contained within the data directory. @param path {string} Path to check. @returns {boolean} """ return os.path.abspath(path).startswith(lmh_locate("content"))
def my_excepthook(exctype, value, tb): if exctype == KeyboardInterrupt: return e = ''.join(traceback.format_exception(exctype, value, tb)) err(e) err("lmh seems to have crashed with %s" % exctype) err("a report will be generated in ") s = "cwd = {0}\n args = {1}\n".format(cwd, sys.argv) s = s + e write_file(lmh_locate("logs", time.strftime("%Y-%m-%d-%H-%M-%S.log")), s)
def match_repo(repo, root=os.getcwd(), abs=False, existence=True): """Matches a single specefier to a repository. """ # 1) Resolve to absolute path repo (via root) # 2) If it is (inside) a repository, return that repository # 3) If not, try to repeat 1) and 2) with root = data_dir # 4) If that fails, return None # make sure the root is absolute root = os.path.abspath(root) # If repo is empty, make sure we use the current directory. if repo == "": repo = os.getcwd() # try the full repo_path repo_path = os.path.join(root, repo) if is_repo_dir(repo_path, existence) or is_in_repo(repo_path): # figure out the path to the repository root repo_path = find_repo_dir(repo_path, existence) if repo_path: if abs: # return the absolute path to the repo return repo_path else: # return just the repo name, determined by the relative name return os.path.relpath(repo_path, os.path.abspath(lmh_locate("content"))) if not (root == os.path.abspath(lmh_locate("content"))): #if the root is not already the data_dir, try that return match_repo(repo, root=lmh_locate("content"), abs=abs, existence=existence) else: # nothing found return None
def find_and_replace_file(file, match, replace, replace_match = None): """Finds and replaces a single file. """ if len(match) != len(replace): err("Find and Replace patterns are not of the same length. ") return False # Compile thex regexp try: match_regex = [re.compile(m) for m in match] except Exception as e: err(e) err("Unable to compile regular expressions. ") return False # get the repository repo = os.path.relpath(find_repo_dir(file), lmh_locate("content")) # We did nothing yet did = False if replace_match == None: def replace_match(match, replace): # TODO: Migrate this to the parent scope. # did = True # Make a template, replacer_template = {} replacer_template["repo"] = repo for i, g in enumerate(match.groups()): replacer_template["g"+str(i)] = g # And replace in it return Template(replace).substitute(replacer_template) # Read file and search file_content = read_file(file) new_file_content = file_content # Iterate over the regexes and replace for (m, r) in zip(match_regex, replace): new_file_content = re.sub(m, lambda x:replace_match(x, r), new_file_content) if file_content != new_file_content: std(file) # If something has changed, write back the file. write_file(file, new_file_content) if did: std(file) return did
def export(f = None): """Exports the list of currently installed repositories. """ # Get all locally installed directories installed = match_repos(lmh_locate("content")) if(f == None): for mod in installed: std(mod) return True try: write_file(f, os.linesep.join(installed)) return True except: err("Unable to write %s" % f) return False
def export(f=None): """Exports the list of currently installed repositories. """ # Get all locally installed directories installed = match_repos(lmh_locate("content")) if (f == None): for mod in installed: std(mod) return True try: write_file(f, os.linesep.join(installed)) return True except: err("Unable to write %s" % f) return False
def do_install(rep): """ Installs a single repository. """ # pre-installation hook. std("Running pre-installation hook for '"+rep+"' ... ", newline=False) if not hook_pre_install(rep): err("Failed. ") return (False, []) std("Done. ") # Find the remote. std("Finding remote for '"+rep+"' ... ") repoURL = find_source(rep) # Did we find a url? if repoURL == False: std("") err(" Could not find a remote. ") return (False, []) std(" OK, will clone from '"+repoURL+"'") # Clone the repository. if not clone(lmh_locate("content"), repoURL, rep): err("git clone did not exit cleanly, cloning failed. ") err(""" Most likely your network connection is bad. If you are using localmh_docker make sure that you have internet access inside the virtual machine. """) return (False, []) std(" OK. ") # post-installation hook. std("Running post-installation hook for '"+rep+"' ... ", newline=False) if not hook_post_install(rep): err("Failed. ") return (False, []) std("Done. ") # Check for dependencies. return do_deps_install(rep)
def find_cached(files, match, replace = None, replace_match = None): """Finds and replaces inside of files. """ # Make sure match and replace are arrays match = [match] if is_string(match) else match if replace != None: replace = [replace] if is_string(replace) else replace if len(replace) != len(match): err("Find and Replace patterns are not of the same length. ") return False rep = False for file in files: repo = os.path.relpath(find_repo_dir(file), lmh_locate("content")) matcher = [Template(m).substitute(repo=repo) for m in match] if replace != None: rep = find_and_replace_file(file, matcher, replace, replace_match = replace_match) or rep else: rep = find_file(file, matcher) or rep return rep
def do(args, unknown): # If there are no repositories, check everything for dependencies. if len(args.spec) == 0: std("Nothing to install, re-installing all existing repositories. ") return install(*match_repos(lmh_locate("content"))) if not get_config("install::noglobs"): args.spec = ls_remote(*args.spec) if len(args.spec) == 0: err("Nothing to install...") return True if args.no_confirm_install: std("Picked", len(args.spec),"repositories. ") else: std("Picked", len(args.spec),"repositories: ") std(*args.spec) if read_raw("Continue (y/N)?").lower() != "y": err("Installation aborted. ") return False return install(*args.spec)
def is_repo_dir(path, existence = True): """ Checks if a directory contains a MathHub repository. Optimised to exit as soon as possible when the directory is not a repository. @param path {string} Path to check. @param existence {boolean} Do we do a theoretical test only or do we check for existence as well? @returns {boolean} """ if re.match('^[^\/]+\/[^\/]+$', path): # it is already a name. name = path else: # it is not a name, so we need to find the relative_path. name = os.path.relpath( os.path.abspath(path), lmh_locate("content") ) # if the name ends with a /, remove it. if name.endswith("/"): name = name[:-1] # if the path does not match, we need to exit. if not re.match('^[^\/]+\/[^\/]+$', name): return False # if we need existence, check it is a git directory if existence: return is_repo(path) # we have passed all the tests return True
from lmh.lib.packs import classes from lmh.lib.dirs import lmh_locate from lmh.lib.env import wget_executable from lmh.lib.utils import mkdir_p from lmh.lib.config import get_config import subprocess import os.path import os import stat import sys mmt_jar_dir = lmh_locate("ext", "MMT", "deploy") mmt_jar_path = lmh_locate(mmt_jar_dir, "mmt.jar") class MMTPack(classes.Pack): """The special MMT Pack""" def __init__(self, mmt_jar_source): self.mmt_jar_source = mmt_jar_source self.name = "MMT" def do_install(self, pack_dir, sstring): """Updates the MMT package""" return self.do_update(pack_dir,sstring) def do_update(self, pack_dir, sstring): """Install the MMT package""" # Make the directory mkdir_p(mmt_jar_dir)
def movemod(source, dest, modules, no_depcrawl, simulate = False): """Moves modules from source to dest. """ # change directory to MathHub root, makes paths easier if simulate: std("cd "+lmh_locate("content")) else: os.chdir(lmh_locate("content")) finds = [] replaces = [] # Match the repos source = match_repo(source, root=lmh_locate("content")) dest = match_repo(dest, root=lmh_locate("content")) if source == None: err("Source repository does not exist, make sure it is installed. ") return False if dest == None: err("Destination repository does not exist, make sure it is installed. ") return False if source == dest: err("Cannot move modules when source and destination are the same. ") return False # Store original source and destination osource = source odest = dest # Make a list of all the moved files. moved_files = [] local_finds = [] local_replaces = [] def run_lmh_find_moved(find, replace): if simulate: # We will run it over dest only. std("lmh", "find", json.dumps(find), "--replace", json.dumps(replace), "--apply", odest) else: # Append it to to a list. local_finds.append(find) local_replaces.append(replace) for module in modules: dest = odest # Figure out the full path to the source srcpath = source + "/source/" + module # Assemble source paths further srcargs = (source + "/" + module).split("/") srcapath = "\\/".join(srcargs[:-1]) srcbpath = srcargs[-1] # Assemble all the commands oldcall = "\[" + srcapath + "\]\{"+srcbpath+"\}" oldcall_long = "\[(.*)repos=" + srcapath + "(.*)\]\{"+srcbpath+"\}" oldcall_local = "\{"+srcbpath+ "\}" newcall = "[" + dest + "]{"+srcbpath+"}" newcall_long = "[$g1" + dest + "$g2]{"+srcbpath+"}" dest += "/source/" # Move the files if simulate: std("mv "+srcpath + ".*.tex"+ " "+ dest + " 2>/dev/null || true") std("mv "+srcpath + ".tex"+ " "+ dest + " 2>/dev/null || true") else: try: shutil.move(srcpath + ".tex", dest) moved_files.append(os.path.join(dest, os.path.basename(srcpath + ".tex"))) except: pass for pat in glob.glob(srcpath + ".*.tex"): # try to move the file if it exists try: shutil.move(pat, dest) moved_files.append(os.path.join(dest, os.path.basename(pat))) except: pass def run_lmh_find(find, replace): finds.append(find) replaces.append(replace) # Run all the commands m = "("+"|".join(["gimport", "guse", "gadopt"])+")" run_lmh_find(r'\\'+m+oldcall, '\\$g0'+newcall) run_lmh_find(r'\\'+m+oldcall_local, '\\$g0'+newcall) m = "("+ "|".join(["importmhmodule", "usemhmodule", "adoptmhmodule", "usemhvocab"]) + ")" run_lmh_find(r'\\'+m+oldcall_long, '\\$g0'+newcall_long) run_lmh_find(r'\\'+m+oldcall_local, '\\$g0'+newcall_long) # For the moved files, repalce gimport, guse, gadpot run_lmh_find_moved(r"\\("+"|".join(["gimport", "guse", "gadopt"])+")\["+dest[-len("/source/")]+"\]\{(.*)\}", "\\$g1{$g2}") # Update the moved files. run_lmh_find_moved(r"\\("+"|".join(["gimport", "guse", "gadopt"])+")\{(((?!(?<=\{)("+"|".join(modules)+")\}).)*?)\}", "\\$g1{$g2}") # Make the repo paths absolute osource = match_repo(osource, abs=True) odest = match_repo(odest, abs=True) files = reduce([find_files(r, "tex")[0] for r in match_repos(lmh_locate("content"), abs=True)]) if simulate: for (f, r) in zip(finds, replaces): std("lmh find", json.dumps(f), "--replace", json.dumps(r), "--apply") if not no_depcrawl: calc_deps(False, dirname=osource) calc_deps(False, dirname=odest) return True else: std("updating paths in the following files: ") res1 = find_cached(files, finds, replace=replaces) res2 = find_cached(moved_files, local_finds, replace=local_replaces) if not no_depcrawl: res3 = calc_deps(True, osource) res4 = calc_deps(True, odest) else: res3 = True res4 = True return res1 and res2 and res3 and res4
def get_pack_dir(pack): return lmh_locate("ext", pack)
import json import os import os.path from lmh.lib.io import std, err, read_file from lmh.lib.dirs import lmh_locate from lmh.lib.packs import classes # # Package Lookers # """All available packs""" av_packs = json.loads(read_file(lmh_locate("lib", "data", "packs.json"))) # Generate the all group, which is everything except for self. av_packs["groups"]["all"] = list(av_packs["packs"].keys()) av_packs["groups"]["all"].remove("self") # # Resolve the specification for a certain pack # def resolve_package_spec(packages): """Resolves package specification. """ to_install = set() for p in packages: (pname, sep, pconfig) = p.partition(":") if pname in av_packs["packs"]: to_install.add(p)
def find_repo_dir(path, existence=True): """ Returns the absolute path to the repository contained in PATH or False. If you need to only check if you are in a repository, use is_in_repo instead. @param {string} path - Path to check @param {boolean} [existence = True] - Do we need to check for existence? @returns {string|boolean} """ # we figure out the relative path namecheck = os.path.relpath( lmh_locate("content"), os.path.abspath(path), ) # if we go into a directory, we if namecheck.startswith('../../'): path = lmh_locate("content", path) # find the relative path # by going relatively from the path to the data directory. name = os.path.relpath(os.path.abspath(path), lmh_locate("content")) # Check that the path does not leave the DATA directory. # This has to be the first component of the path # or the entire path. if name.startswith("../") or name == "..": return False # the repository name should be everything until the second slash # so go through the path and find it num_slash_correct = False abs_name = lmh_locate("content", "") for (i, c) in enumerate(name): if c == "/": if num_slash_correct: # we have found the second slash # we want to check for existence now. if existence and not is_repo(abs_name): return False # and then return the name. return abs_name else: # we have found the first slash num_slash_correct = True # add the caracter to the name abs_name += c # do we have the correct number of slashes? # if so, we can return the path. if num_slash_correct: # again, we might have to check for existence. if existence and not is_repo(abs_name): return False return abs_name else: return False
from lmh.lib.packs import classes from lmh.lib.dirs import lmh_locate from lmh.lib.env import wget_executable from lmh.lib.utils import mkdir_p from lmh.lib.config import get_config import subprocess import os.path import os import stat import sys mmt_jar_dir = lmh_locate("ext", "MMT", "deploy") mmt_jar_path = lmh_locate(mmt_jar_dir, "mmt.jar") class MMTPack(classes.Pack): """The special MMT Pack""" def __init__(self, mmt_jar_source): self.mmt_jar_source = mmt_jar_source self.name = "MMT" def do_install(self, pack_dir, sstring): """Updates the MMT package""" return self.do_update(pack_dir, sstring) def do_update(self, pack_dir, sstring): """Install the MMT package""" # Make the directory
def create(reponame, type="none", remote = True): """Creates a new repository in the given directory""" # Resolve the repository to create repo = match_repo(reponame, existence=False) if repo == None: err("Can not resolve repository to create. ") return False # Remote creation currently disabled if remote: err("Remote cration currently disabled. ") remote = False # and the full path absrepo = match_repo(reponame, abs=True, existence=False) repo_group = repo.split("/")[0] repo_name = repo.split("/")[1] # Check if it is already installed. # TODO: Use the other is_installed if is_installed(repo): err("Repository", repo, "already installed. ") err("Do you maybe want to push this to the remote?") return False # Make the directory if it does not yet exist. try: mkdir_p(absrepo) except: err("Can not create repository directory") return False if not get_config("init::allow_nonempty"): if not (not os.listdir(absrepo)): err("Target Directory is non-empty. ") err("If you want to enable lmh init on non-empty directories, please run") err(" lmh config init::allow_nonempty true") return False # Template Variables. tpl_vars = { "repo": repo, "repo_group": repo_group, "repo_name": repo_name, "install_dir": lmh_locate() } # Copy the base template if not copy_template_dir(os.path.join(emptyrepo_dir, "none"), absrepo, tpl_vars): err("Unable to create repository base. ") return False # Copy the specific type. if type != "none": type_dir = os.path.join(emptyrepo_dir, type) if os.path.isdir(type_dir): if not copy_template_dir(type_dir, absrepo, tpl_vars): err("Unable to use repository template. ") return False else: err("Unknown repository type: ", type) return False if git_root(absrepo) != absrepo: # Now lets make an init if not git_do(absrepo, "init"): err("Error creating git repository. ") err("The directory has been created successfully, however git init failed. ") err("Please run it manually. ") return False # Create the initial commit. if not (git_do(absrepo, "add", "-A") and git_commit(absrepo, "-m", "Repository created by lmh")): err("Error creating inital commit. ") err("The directory has been created successfully, however git commit failed. ") err("Please run it manually. ") return False # Can we find a remote for this? source = find_source(repo, quiet=True) # Don't do anything remote => we are done. if not remote: if source: if not git_do(absrepo, "remote", "add", "origin", source): err("Can not add origin. ") err("git is suddenly weird. ") return False else: std("Skipping remote creation because --no-remote is given. ") std("Repository created successfully. ") return True # Source does not exist => we will have to create it. if not source: source = create_remote(repo_group, repo_name) if not source: err("local repository created but remote creation failed. ") return False # Add the origin. if not git_do(absrepo, "remote", "add", "origin", source): err("Can not add origin. ") err("git is suddenly weird. ") return False if not git_push(absrepo, "-u", "origin", "master"): err("Repository created but could not push created repository. ") err("Check your network connection and try again using git push. ") return False std("Created new repository successfully. ") return True
""" Configuration functions for lmh """ # TODO: Prefer the file in the home directory. # If it does not exist, create it. # If it does exist, migrate automatically. # This will make sure that each user has their own configuration. import json from lmh.lib.dirs import lmh_locate from lmh.lib.io import std, err, read_file, write_file, term_colors """Available configuration values. """ config_meta = json.loads(read_file(lmh_locate("lib", "data", "config.json"))) """The configuration file for lmh""" config_file = lmh_locate( "bin", "lmh.cfg") # TODO: Store this in the home direcory instead # will allow multiple users to read it. def get_config(key): """ Gets a given configuration setting. If it does not exist in the configuration file, the default will be returned """ # check if the given key exists in the configuration if not key in config_meta: err("Option", key, "does not exist. ") raise KeyError
def locate_compile_target(path, try_root=True): """ Finds all targets to be compiled. (Files AND Folders inside source/) @param path Path to find files in """ spec = path # if we are not inside the data directory, return. if path.startswith(os.path.abspath(lmh_locate())) and not path.startswith( os.path.abspath(lmh_locate("content"))): # if we have not tried the root, we should try again. if try_root: return locate_compile_target(lmh_locate("content", spec), False) return [] # If we are inside the root, go inside the folder. relpath = os.path.relpath(lmh_locate("content"), os.path.realpath(path)) if relpath == "../..": path = path + "/source" elif not relpath.endswith("../.."): return reduce([(locate_compile_target(p)) for p in find_repo_subdirs(path)]) # Get the absolute path. path = os.path.realpath(path) # If it does not exist, return. if not os.path.isfile(path) and not os.path.isdir(path): # if we have not tried the root, we should try again. if try_root: return locate_compile_target(lmh_locate("content", spec), False) err("Could not find anything matching ", "'" + spec + "'") return [] # find the repository dir. repo_dir = find_repo_dir(path, existence=True) repo_name = os.path.relpath(repo_dir, lmh_locate("content")) if repo_dir == False: # if we have not tried the root, we should try again. if try_root: return locate_compile_target(lmh_locate("content", spec), False) err("Matching item to ", "'" + spec + "'", "are outside of repository. ") return [] # Find the source directory and get a relative path repos_src_dir = os.path.join(repo_dir, "source") path = os.path.relpath(path, repos_src_dir) # if we need to go up, we are not in source if path.startswith("../"): # if we have not tried the root, we should try again. if try_root: return locate_compile_target(lmh_locate("content", spec), False) err("Matching item to", "'" + spec + "'", "are outside of the source directory. ") return [] # return the name of the repository and the path inside the repository. return [(repo_name, path)]
def do_update(self, pack_dir, update): return pull(lmh_locate())
def match_repos(repos, root=os.getcwd(), abs=False): """ Matches a list of specefiers to repositories. @param {string[]} repos - Specefiers to match @param {string} root - Root directory to use @param {boolean} [abs=False] - Should absolute paths be returned? @returns string[] - repository paths """ # For each element do the following: # 1) Check if given directory exists relatively from current root. # 1a) If it is a repository or repository subdir, return that # 1b) If it is inside the data_dir, return all repo subdirectories # 2) If it does not exist, resolve it as glob.glob from install_dir # 3) For each of the found directories, run 1) # If the repositories are just a string, we want an array. if is_string(repos): repos = [repos] # it is already an array, so remove doubles please. else: repos = remove_doubles(repos) # the glob expressions we want to use # and the repo directories we will use. results = set() def match_repo_name(r): # make an absolute path # this will also work with globs names = os.path.abspath(os.path.join(root, r)) # it is not inside the data directory # so try again next time if not is_in_data(names): return True # find the relative path of it to the root. names = os.path.relpath( os.path.abspath(names), lmh_locate("content") ) # make sure everything ends with a slash # so that we can count properly if names[-1] != "/": names += "/" # Now figure out which level we are at # by counting slashes num_slashes = 0 for c in names: # count the slashes # by increasing the level. if c == "/": num_slashes += 1 # if we have no slashes # we are toplevel # and can pretty much exit everything if names == "./": names = lmh_locate("content", "*", "*") # if we have 1 slash # we are one level deep elif num_slashes == 1: names = lmh_locate("content", names, "*") else: names = lmh_locate("content", names) # now expand with the help of globs names = glob.glob(names) # and check if they exist names = list(filter(is_repo, names)) # if we found something # we should through the item if len(names) > 0: results.update(names) return False else: return True # now filter the repos repos = list(filter(match_repo_name, repos)) # repeat again with data_dir as root root = lmh_locate("content") repos = list(filter(match_repo_name, repos)) # if we want the relative paths we need to set them properly. if not abs: return [os.path.relpath(d, lmh_locate("content")) for d in results] return list(results)
def find_repo_dir(path, existence=True): """ Returns the absolute path to the repository contained in PATH or False. If you need to only check if you are in a repository, use is_in_repo instead. @param {string} path - Path to check @param {boolean} [existence = True] - Do we need to check for existence? @returns {string|boolean} """ # we figure out the relative path namecheck = os.path.relpath( lmh_locate("content"), os.path.abspath(path), ) # if we go into a directory, we if namecheck.startswith('../../'): path = lmh_locate("content", path) # find the relative path # by going relatively from the path to the data directory. name = os.path.relpath( os.path.abspath(path), lmh_locate("content") ) # Check that the path does not leave the DATA directory. # This has to be the first component of the path # or the entire path. if name.startswith("../") or name == "..": return False # the repository name should be everything until the second slash # so go through the path and find it num_slash_correct = False abs_name = lmh_locate("content", "") for (i, c) in enumerate(name): if c == "/": if num_slash_correct: # we have found the second slash # we want to check for existence now. if existence and not is_repo(abs_name): return False # and then return the name. return abs_name else: # we have found the first slash num_slash_correct = True # add the caracter to the name abs_name += c # do we have the correct number of slashes? # if so, we can return the path. if num_slash_correct: # again, we might have to check for existence. if existence and not is_repo(abs_name): return False return abs_name else: return False
def version(): """ Returns the current version of lmh """ return read_file(lmh_locate("lib", "data", "version"))
def match_repos(repos, root=os.getcwd(), abs=False): """ Matches a list of specefiers to repositories. @param {string[]} repos - Specefiers to match @param {string} root - Root directory to use @param {boolean} [abs=False] - Should absolute paths be returned? @returns string[] - repository paths """ # For each element do the following: # 1) Check if given directory exists relatively from current root. # 1a) If it is a repository or repository subdir, return that # 1b) If it is inside the data_dir, return all repo subdirectories # 2) If it does not exist, resolve it as glob.glob from install_dir # 3) For each of the found directories, run 1) # If the repositories are just a string, we want an array. if is_string(repos): repos = [repos] # it is already an array, so remove doubles please. else: repos = remove_doubles(repos) # the glob expressions we want to use # and the repo directories we will use. results = set() def match_repo_name(r): # make an absolute path # this will also work with globs names = os.path.abspath(os.path.join(root, r)) # it is not inside the data directory # so try again next time if not is_in_data(names): return True # find the relative path of it to the root. names = os.path.relpath(os.path.abspath(names), lmh_locate("content")) # make sure everything ends with a slash # so that we can count properly if names[-1] != "/": names += "/" # Now figure out which level we are at # by counting slashes num_slashes = 0 for c in names: # count the slashes # by increasing the level. if c == "/": num_slashes += 1 # if we have no slashes # we are toplevel # and can pretty much exit everything if names == "./": names = lmh_locate("content", "*", "*") # if we have 1 slash # we are one level deep elif num_slashes == 1: names = lmh_locate("content", names, "*") else: names = lmh_locate("content", names) # now expand with the help of globs names = glob.glob(names) # and check if they exist names = list(filter(is_repo, names)) # if we found something # we should through the item if len(names) > 0: results.update(names) return False else: return True # now filter the repos repos = list(filter(match_repo_name, repos)) # repeat again with data_dir as root root = lmh_locate("content") repos = list(filter(match_repo_name, repos)) # if we want the relative paths we need to set them properly. if not abs: return [os.path.relpath(d, lmh_locate("content")) for d in results] return list(results)
def do(args, unknown): std(lmh_locate()) return True
def find_repo_subdirs(path): """ Returns the absolute path to the all repositories contained in PATH. @param {string} path - Path to check @returns {string[]} """ # path needs to be a directory if not os.path.isdir(path): return [] # We are not inside the data directory # so we need to return nothing if not is_in_data(path): return [] # If we can find the current repository path # we can return it. repo_path = find_repo_dir(path) if repo_path: return [repo_path] # Find the relative path from the root to the current directory name = os.path.relpath( os.path.abspath(path), lmh_locate("content") ) # make sure everything ends with a slash # so that we can count properly if name[-1] != "/": name += "/" # Now figure out which level we are at # by counting slashes num_slashes = 0 for c in name: # count the slashes # by increasing the level. if c == "/": num_slashes += 1 # if we have no slashes # we are toplevel if name == "./": name = lmh_locate("content", "*", "*") # if we have 1 slash # we are one level deep elif num_slashes == 1: name = lmh_locate("content", name, "*") # else something is wrong # and we are nowhere else: return [] # now we can match the paths via glob.glob # and check that they exist return list(filter(is_repo, glob.glob(name)))
import json import os import os.path from lmh.lib.io import std, err, read_file from lmh.lib.dirs import lmh_locate from lmh.lib.packs import classes # # Package Lookers # """All available packs""" av_packs = json.loads(read_file(lmh_locate("lib", "data", "packs.json"))) # Generate the all group, which is everything except for self. av_packs["groups"]["all"] = list(av_packs["packs"].keys()) av_packs["groups"]["all"].remove("self") # # Resolve the specification for a certain pack # def resolve_package_spec(packages): """Resolves package specification. """ to_install = set() for p in packages: (pname, sep, pconfig) = p.partition(":") if pname in av_packs["packs"]:
from lmh.lib.io import is_string from lmh.lib.io import std, err, read_file from lmh.lib.dirs import lmh_locate from lmh.lib.config import get_config from subprocess import Popen import shlex try: import signal except: pass """sty directory""" stydir = lmh_locate("sty") """sTex directory""" stexstydir = lmh_locate("ext", "sTeX", "sty") """LatexML directory""" latexmlstydir = lmh_locate("ext", "LaTeXML", "lib", "LaTeXML", "texmf") def which(program): """ Returns the full path to a program that can be found in the users $PATH variable. Similar to the *nix command which (or the windows command where). """ def is_exe(fpath): return os.path.isfile(fpath) and os.access(fpath, os.X_OK) fpath, fname = os.path.split(program)
""" Configuration functions for lmh """ # TODO: Prefer the file in the home directory. # If it does not exist, create it. # If it does exist, migrate automatically. # This will make sure that each user has their own configuration. import json from lmh.lib.dirs import lmh_locate from lmh.lib.io import std, err, read_file, write_file, term_colors """Available configuration values. """ config_meta = json.loads(read_file(lmh_locate("lib", "data", "config.json"))) """The configuration file for lmh""" config_file = lmh_locate("bin", "lmh.cfg") # TODO: Store this in the home direcory instead # will allow multiple users to read it. def get_config(key): """ Gets a given configuration setting. If it does not exist in the configuration file, the default will be returned """ # check if the given key exists in the configuration if not key in config_meta: err("Option", key, "does not exist. ") raise KeyError
def movemod(source, dest, modules, no_depcrawl, simulate=False): """Moves modules from source to dest. """ # change directory to MathHub root, makes paths easier if simulate: std("cd " + lmh_locate("content")) else: os.chdir(lmh_locate("content")) finds = [] replaces = [] # Match the repos source = match_repo(source, root=lmh_locate("content")) dest = match_repo(dest, root=lmh_locate("content")) if source == None: err("Source repository does not exist, make sure it is installed. ") return False if dest == None: err("Destination repository does not exist, make sure it is installed. " ) return False if source == dest: err("Cannot move modules when source and destination are the same. ") return False # Store original source and destination osource = source odest = dest # Make a list of all the moved files. moved_files = [] local_finds = [] local_replaces = [] def run_lmh_find_moved(find, replace): if simulate: # We will run it over dest only. std("lmh", "find", json.dumps(find), "--replace", json.dumps(replace), "--apply", odest) else: # Append it to to a list. local_finds.append(find) local_replaces.append(replace) for module in modules: dest = odest # Figure out the full path to the source srcpath = source + "/source/" + module # Assemble source paths further srcargs = (source + "/" + module).split("/") srcapath = "\\/".join(srcargs[:-1]) srcbpath = srcargs[-1] # Assemble all the commands oldcall = "\[" + srcapath + "\]\{" + srcbpath + "\}" oldcall_long = "\[(.*)repos=" + srcapath + "(.*)\]\{" + srcbpath + "\}" oldcall_local = "\{" + srcbpath + "\}" newcall = "[" + dest + "]{" + srcbpath + "}" newcall_long = "[$g1" + dest + "$g2]{" + srcbpath + "}" dest += "/source/" # Move the files if simulate: std("mv " + srcpath + ".*.tex" + " " + dest + " 2>/dev/null || true") std("mv " + srcpath + ".tex" + " " + dest + " 2>/dev/null || true") else: try: shutil.move(srcpath + ".tex", dest) moved_files.append( os.path.join(dest, os.path.basename(srcpath + ".tex"))) except: pass for pat in glob.glob(srcpath + ".*.tex"): # try to move the file if it exists try: shutil.move(pat, dest) moved_files.append( os.path.join(dest, os.path.basename(pat))) except: pass def run_lmh_find(find, replace): finds.append(find) replaces.append(replace) # Run all the commands m = "(" + "|".join(["gimport", "guse", "gadopt"]) + ")" run_lmh_find(r'\\' + m + oldcall, '\\$g0' + newcall) run_lmh_find(r'\\' + m + oldcall_local, '\\$g0' + newcall) m = "(" + "|".join([ "importmhmodule", "usemhmodule", "adoptmhmodule", "usemhvocab" ]) + ")" run_lmh_find(r'\\' + m + oldcall_long, '\\$g0' + newcall_long) run_lmh_find(r'\\' + m + oldcall_local, '\\$g0' + newcall_long) # For the moved files, repalce gimport, guse, gadpot run_lmh_find_moved( r"\\(" + "|".join(["gimport", "guse", "gadopt"]) + ")\[" + dest[-len("/source/")] + "\]\{(.*)\}", "\\$g1{$g2}") # Update the moved files. run_lmh_find_moved( r"\\(" + "|".join(["gimport", "guse", "gadopt"]) + ")\{(((?!(?<=\{)(" + "|".join(modules) + ")\}).)*?)\}", "\\$g1{$g2}") # Make the repo paths absolute osource = match_repo(osource, abs=True) odest = match_repo(odest, abs=True) files = reduce([ find_files(r, "tex")[0] for r in match_repos(lmh_locate("content"), abs=True) ]) if simulate: for (f, r) in zip(finds, replaces): std("lmh find", json.dumps(f), "--replace", json.dumps(r), "--apply") if not no_depcrawl: calc_deps(False, dirname=osource) calc_deps(False, dirname=odest) return True else: std("updating paths in the following files: ") res1 = find_cached(files, finds, replace=replaces) res2 = find_cached(moved_files, local_finds, replace=local_replaces) if not no_depcrawl: res3 = calc_deps(True, osource) res4 = calc_deps(True, odest) else: res3 = True res4 = True return res1 and res2 and res3 and res4