#!/usr/bin/env python
'''Install P4V addins'''
# Copyright (c) 2006 Qualcomm
# Miki Tebeka <mtebeka@qualcomm.com>
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)