#!/usr/bin/env python '''Install P4V addins''' # Copyright (c) 2006 Qualcomm # Miki Tebeka from re import match from user import home from os.path import join, isfile, dirname, isdir from sys import stdout, path, platform from urllib import quote, unquote from shutil import copy2 from os import mkdir, popen from glob import glob from install import InstallError, load_config, is_boolean, is_process_running class Settings: '''Settings in P4V config file''' def __init__(self, name, value): self.name = name self.value = value self.children = [] def indent_level(line): '''Indent level of line (number of tabs at the beginning)''' return match("^\t*", line).end() def parse_line(line): '''Parse settings line''' fields = line.strip().split("=") if len(fields) == 1: fields.append("") return Settings(fields[0], unquote(fields[1])) # Parsing algorithm: # As long as indentation level stays the same or increases we push items to # the stack # When indentation level decreases we group all items in same indentation # level and add them to the children of the parent def parse_settings(filename): '''Parser P4V settings file. Return list of trees''' stack = [] fo = open(filename, "rt") for line in fo: indent = indent_level(line) new = parse_line(line) # 1'st item if not stack: stack.append((new, indent)) continue last_indent = stack[-1][1] if indent >= last_indent: stack.append((new, indent)) continue items = [] while indent < last_indent: if stack[-1][1] == last_indent: items.insert(0, stack.pop()[0]) continue stack[-1][0].children += items items = [] last_indent = stack[-1][1] stack.append((new, indent)) fo.close() return [s[0] for s in stack] def print_tree(tree, fo=stdout, indent=0): '''Print tree of settings''' if tree.value: print >> fo, ("\t" * indent) + ("%s=%s" % (tree.name, tree.value)) else: name = tree.name if (indent == 0) and (not name.endswith(":")): name += "=" elif name in ("directory", "prompttext"): name += "=" print >> fo, ("\t" * indent) + name for child in tree.children: print_tree(child, fo, indent + 1) def new_addin(id, args): '''Create new adding setting tree''' addin = Settings("macro%d" % id, "@") for key, value in args.items(): if is_boolean(key) and (value not in ("yes", "no")): raise InstallError("%s/%s - bad boolean value" % \ (addin["name"], key)) addin.children.append(Settings(key, quote(value))) return addin def find_node(name, nodes): '''Find a node named "name" in list of noded''' for node in nodes: if node.name == name: return node return None def find_macro(name, macros): for mac in macros: name_node = find_node("name", mac.children) assert(name_node) if name_node.value == name: return mac def install(dest, exclude=None, check_process=0): '''Install new addins''' if check_process and is_process_running("p4v"): raise InstallError("P4V is running, close it") cfg_file = join(home, ".p4qt", "settings") settings = parse_settings(cfg_file) all_addins = load_config() if not exclude: exclude = [] # Find "Macros" macros = find_node("Macros:", settings) if not macros: macros = find_node("Macros", settings) if not macros: raise InstallError("bad configuration file (no 'Macros')") if macros.name.endswith(":"): macros.name = macros.name[:-1] macros.value = "@" # Update addins inst_count = 0 for addin in all_addins: if addin["name"] in exclude: continue inst_count += 1 addin["command"] = join(dest, addin["command"]) if addin.get("directory", "") == "$install": addin["directory"] = dest # Is this just an update? mac = find_macro(addin["name"], macros.children) if not mac: mac = new_addin(len(macros.children), addin) macros.children.append(mac) else: for key in addin.keys(): find_node(key, mac.children).value = addin[key] fo = open(cfg_file, "wt") for s in settings: print_tree(s, fo) fo.close() return inst_count if __name__ == "__main__": from optparse import OptionParser parser = OptionParser("usage: %prog [options] DESTINATION") parser.add_option("-e", help="exclude addin from install", dest="exclude", action="append", metavar="ADDIN") parser.add_option("-c", help="check that p4win is not running", dest="check", default=0, action="store_true") opts, args = parser.parse_args() if len(args) != 1: parser.error("wrong number of arguments") # Will exit dest = args[0] try: install(dest, opts.exclude, opts.check) except Exception, e: raise SystemExit("error: %s" % e)