From ec2bf05393d68423143181fb1d3c4705a7330ebf Mon Sep 17 00:00:00 2001 From: Edouard DUPIN Date: Fri, 6 Jan 2017 21:24:42 +0100 Subject: [PATCH] [DEV] sync is nearly ready --- maestro/__init__.py | 2 +- maestro/actions.py | 44 +++- .../{init.py => maestroAction_init.py} | 17 +- .../{status.py => maestroAction_status.py} | 0 maestro/actions/maestroAction_sync.py | 126 +++++++++ maestro/actions/sync.py | 76 ------ maestro/env.py | 91 +++---- maestro/manifest.py | 240 ++++++++++++++++++ maestro/multiprocess.py | 50 +++- setup.py | 3 + 10 files changed, 489 insertions(+), 160 deletions(-) rename maestro/actions/{init.py => maestroAction_init.py} (82%) rename maestro/actions/{status.py => maestroAction_status.py} (100%) create mode 100644 maestro/actions/maestroAction_sync.py delete mode 100644 maestro/actions/sync.py create mode 100644 maestro/manifest.py diff --git a/maestro/__init__.py b/maestro/__init__.py index 058f657..8b4e309 100755 --- a/maestro/__init__.py +++ b/maestro/__init__.py @@ -33,7 +33,7 @@ def import_path_local(path): debug.verbose("maestro files: " + str(path) + " [START]") list_files = os.listdir(path) # filter elements: - tmp_list_maestro_file = filter_name_and_file(path, list_files, "*.py") + tmp_list_maestro_file = filter_name_and_file(path, list_files, env.get_system_base_name() + "*.py") debug.verbose("maestro files: " + str(path) + " : " + str(tmp_list_maestro_file)) # Import the module: for filename in tmp_list_maestro_file: diff --git a/maestro/actions.py b/maestro/actions.py index fce8c04..7ce9120 100644 --- a/maestro/actions.py +++ b/maestro/actions.py @@ -12,20 +12,35 @@ from . import debug import os import sys +from . import env list_actions = [] +__base_action_name = env.get_system_base_name() + "Action_" + def init(files): global list_actions; debug.debug("List of action for maestro: ") for elem_path in files : + base_name = os.path.basename(elem_path) + if len(base_name) <= 3 + len(__base_action_name): + # reject it, too small + continue + base_name = base_name[:-3] + if base_name[:len(__base_action_name)] != __base_action_name: + # reject it, wrong start file + continue + name_action = base_name[len(__base_action_name):] debug.debug(" '" + os.path.basename(elem_path)[:-3] + "' file=" + elem_path) list_actions.append({ - "name":os.path.basename(elem_path)[:-3], + "name":name_action, "path":elem_path, }) - +## +## @brief Get the wall list of action availlable +## @return ([string]) the list of action name +## def get_list_of_action(): global list_actions; out = [] @@ -33,20 +48,37 @@ def get_list_of_action(): out.append(elem["name"]) return out +## +## @brief Get a description of an action +## @param[in] action_name (string) Name of the action +## @return (string/None) A descriptive string or None +## +def get_desc(action_name): + global list_actions; + for elem in list_actions: + if elem["name"] == action_name: + # finish the parsing + sys.path.append(os.path.dirname(elem["path"])) + the_action = __import__(__base_action_name + action_name) + if "get_desc" not in dir(the_action): + debug.error("execute is not implmented for this action ... '" + str(action_name) + "'") + return None + return the_action.get_desc() + return None -def execute(action_to_do, argument_list): +def execute(action_name, argument_list): global list_actions; # TODO: Move here the check if action is availlable for elem in list_actions: - if elem["name"] == action_to_do: + if elem["name"] == action_name: debug.info("action: " + str(elem)); # finish the parsing sys.path.append(os.path.dirname(elem["path"])) - the_action = __import__(action_to_do) + the_action = __import__(__base_action_name + action_name) if "execute" not in dir(the_action): - debug.error("execute is not implmented for this action ... '" + str(action_to_do) + "'") + debug.error("execute is not implmented for this action ... '" + str(action_name) + "'") return False return the_action.execute(argument_list) debug.error("Can not do the action...") diff --git a/maestro/actions/init.py b/maestro/actions/maestroAction_init.py similarity index 82% rename from maestro/actions/init.py rename to maestro/actions/maestroAction_init.py index a07fdd3..1758a85 100644 --- a/maestro/actions/init.py +++ b/maestro/actions/maestroAction_init.py @@ -49,22 +49,19 @@ def execute(arguments): # check if .XXX exist (create it if needed) - base_path = os.path.join(tools.get_run_path(), "." + env.get_system_base_name()) - base_config = os.path.join(base_path, "config.txt") - base_manifest_repo = os.path.join(base_path, "manifest") - if os.path.exists(base_path) == True \ - and os.path.exists(base_config) == True \ - and os.path.exists(base_manifest_repo) == True: - debug.error("System already init: path already exist: '" + str(base_path) + "'") - tools.create_directory(base_path) + if os.path.exists(env.get_maestro_path()) == True \ + and os.path.exists(env.get_maestro_path_config()) == True \ + and os.path.exists(env.get_maestro_path_manifest()) == True: + debug.error("System already init: path already exist: '" + str(env.get_maestro_path()) + "'") + tools.create_directory(env.get_maestro_path()) # check if the git of the manifest if availlable # create the file configuration: data = "repo=" + address_manifest + "\nbranch=" + branch + "\nfile=" + manifest_name - tools.file_write_data(base_config, data) + tools.file_write_data(env.get_maestro_path_config(), data) #clone the manifest repository - cmd = "git clone " + address_manifest + " --branch " + branch + " " + base_manifest_repo + cmd = "git clone " + address_manifest + " --branch " + branch + " " + env.get_maestro_path_manifest() debug.info("clone the manifest") ret = multiprocess.run_command_direct(cmd) diff --git a/maestro/actions/status.py b/maestro/actions/maestroAction_status.py similarity index 100% rename from maestro/actions/status.py rename to maestro/actions/maestroAction_status.py diff --git a/maestro/actions/maestroAction_sync.py b/maestro/actions/maestroAction_sync.py new file mode 100644 index 0000000..c91a4ee --- /dev/null +++ b/maestro/actions/maestroAction_sync.py @@ -0,0 +1,126 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +## +## @author Edouard DUPIN +## +## @copyright 2012, Edouard DUPIN, all right reserved +## +## @license MPL v2.0 (see license file) +## + +from maestro import debug +from maestro import tools +from maestro import env +from maestro import multiprocess +from maestro import manifest +import os + + +def help(): + return "plop" + + + + + +def execute(arguments): + debug.info("execute:") + for elem in arguments: + debug.info(" '" + str(elem.get_arg()) + "'") + if len(arguments) != 0: + debug.error("Sync have not parameter") + + # check if .XXX exist (create it if needed) + if os.path.exists(env.get_maestro_path()) == False \ + or os.path.exists(env.get_maestro_path_config()) == False \ + or os.path.exists(env.get_maestro_path_manifest()) == False: + debug.error("System already init have an error: missing data: '" + str(env.get_maestro_path()) + "'") + + + configuration = manifest.load_config() + + debug.info("update manifest : '" + str(env.get_maestro_path_manifest()) + "'") + # update manifest + cmd = "git fetch --all" + multiprocess.run_command_direct(cmd, cwd=env.get_maestro_path_manifest()) + + file_source_manifest = os.path.join(env.get_maestro_path_manifest(), configuration["file"]) + if os.path.exists(file_source_manifest) == False: + debug.error("Missing manifest file : '" + str(file_source_manifest) + "'") + + mani = manifest.Manifest(file_source_manifest) + + all_project = mani.get_all_configs() + debug.info("synchronize : " + str(len(all_project)) + " projects") + id_element = 0 + for elem in all_project: + id_element += 1 + debug.info("sync : " + str(id_element) + "/" + str(len(all_project)) + " : " + str(elem.name)) + #debug.debug("elem : " + str(elem)) + git_repo_path = os.path.join(env.get_maestro_root_path(), elem.path) + if os.path.exists(git_repo_path) == False: + # this is a new clone ==> this is easy ... + #clone the manifest repository + address_manifest = "" + + cmd = "git clone " + elem.select_remote["fetch"] + "/" + elem.name + " --branch " + elem.branch + " --origin " + elem.select_remote["name"] + " " + git_repo_path + debug.info("clone the repo") + ret = multiprocess.run_command_direct(cmd) + if ret == "": + continue + if ret == False: + # all is good, ready to get the system work corectly + continue + debug.info("'" + ret + "'") + debug.error("Clone repository does not work ... ") + continue + + if os.path.exists(os.path.join(git_repo_path,".git")) == False: + # path already exist but it is not used to as a git repo ==> this is an error + debug.error("path '" + git_repo_path + "' is already existing but not used for a git repository. Clean it and restart") + + # simply update the repository ... + debug.verbose("Fetching project: ") + # fetch the repository + cmd = "git fetch " + elem.select_remote["name"] + debug.verbose("execute : " + cmd) + multiprocess.run_command_direct(cmd, cwd=git_repo_path) + # check if the repository is modify + cmd = "git diff --quiet" + debug.verbose("execute : " + cmd) + ret_diff = multiprocess.run_command(cmd, cwd=git_repo_path) + # get local branch + cmd = "git branch" + debug.verbose("execute : " + cmd) + ret_branch = multiprocess.run_command(cmd, cwd=git_repo_path) + + # get tracking branch + cmd = "git rev-parse --abbrev-ref --symbolic-full-name @{u}" + debug.verbose("execute : " + cmd) + ret_track = multiprocess.run_command(cmd, cwd=git_repo_path) + + is_modify = True + if ret_diff[0] == 0: + is_modify = False + + list_branch = ret_branch[1].split('\n') + list_branch2 = [] + select_branch = "" + for elem_branch in list_branch: + if elem_branch[:2] == "* ": + list_branch2.append([elem_branch[2:], True]) + select_branch = elem_branch[2:] + else: + list_branch2.append([elem_branch[2:], False]) + + + if is_modify == True: + debug.warning("[" + elem.name + "] Not update ==> the repository is modified") + continue + + if ret_track[1] != elem.select_remote["name"] + "/" + elem.branch: + debug.warning("[" + elem.name + "] Not update ==> the current branch does not track the correct branch : track '" + ret_track[1] + "' instead of '" + elem.select_remote["name"] + "/" + elem.branch + "'") + continue + + debug.info("select branch = '" + select_branch + "' is modify : " + str(is_modify) + " track: '" + str(ret_track[1]) + "'") + \ No newline at end of file diff --git a/maestro/actions/sync.py b/maestro/actions/sync.py deleted file mode 100644 index e18a917..0000000 --- a/maestro/actions/sync.py +++ /dev/null @@ -1,76 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -## -## @author Edouard DUPIN -## -## @copyright 2012, Edouard DUPIN, all right reserved -## -## @license MPL v2.0 (see license file) -## - -from maestro import debug -from maestro import tools -from maestro import env -from maestro import multiprocess -import os -from lxml import etree - - -def help(): - return "plop" - -def load_manifest(file): - tree = etree.parse(file) - debug.info("manifest:") - root = tree.getroot() - if root.tag != "manifest": - debug.error("in '" + str(file) + "' have not main xml node='manifest'") - for child in root: - if type(child) == etree._Comment: - debug.info(" comment='" + str(child.text) + "'"); - else: - debug.info(" '" + str(child.tag) + "' values=" + str(child.attrib)); - # inside data child.text - return ""; - - -def execute(arguments): - debug.info("execute:") - for elem in arguments: - debug.info(" '" + str(elem.get_arg()) + "'") - if len(arguments) != 0: - debug.error("Sync have not parameter") - - # check if .XXX exist (create it if needed) - base_path = os.path.join(tools.get_run_path(), "." + env.get_system_base_name()) - base_config = os.path.join(base_path, "config.txt") - base_manifest_repo = os.path.join(base_path, "manifest") - if os.path.exists(base_path) == False \ - or os.path.exists(base_config) == False \ - or os.path.exists(base_manifest_repo) == False: - debug.error("System already init have an error: missing data: '" + str(base_path) + "'") - - config_property = tools.file_read_data(base_config) - - element_config = config_property.split("\n") - if len(element_config) != 3: - debug.error("error in configuration property") - if element_config[0][:5] != "repo=": - debug.error("error in configuration property (2)") - if element_config[1][:7] != "branch=": - debug.error("error in configuration property (3)") - if element_config[2][:5] != "file=": - debug.error("error in configuration property (4)") - configuration = { - "repo":element_config[0][5:], - "branch":element_config[1][7:], - "file":element_config[2][5:] - } - debug.info("configuration property: " + str(configuration)) - - file_source_manifest = os.path.join(base_manifest_repo, configuration["file"]) - if os.path.exists(file_source_manifest) == False: - debug.error("Missing manifest file : '" + str(file_source_manifest) + "'") - - manifest = load_manifest(file_source_manifest) - \ No newline at end of file diff --git a/maestro/env.py b/maestro/env.py index aa16d8f..bdf47dc 100644 --- a/maestro/env.py +++ b/maestro/env.py @@ -11,68 +11,7 @@ # Local import from . import debug - - -force_mode=False - -def set_force_mode(val): - global force_mode - if val==1: - force_mode = 1 - else: - force_mode = 0 - -def get_force_mode(): - global force_mode - return force_mode - -force_optimisation=False - -def set_force_optimisation(val): - global force_optimisation - if val==1: - force_optimisation = 1 - else: - force_optimisation = 0 - -def get_force_optimisation(): - global force_optimisation - return force_optimisation - -isolate_system=False - -def set_isolate_system(val): - global isolate_system - if val==1: - isolate_system = 1 - else: - isolate_system = 0 - -def get_isolate_system(): - global isolate_system - return isolate_system - -parse_depth = 9999999 - -def set_parse_depth(val): - global parse_depth - parse_depth = val - debug.debug("Set depth search element: " + str(parse_depth)) - -def get_parse_depth(): - global parse_depth - return parse_depth - -exclude_search_path = [] - -def set_exclude_search_path(val): - global exclude_search_path - exclude_search_path = val - debug.debug("Set depth search element: " + str(exclude_search_path)) - -def get_exclude_search_path(): - global exclude_search_path - return exclude_search_path +import os system_base_name = "maestro" @@ -86,3 +25,31 @@ def get_system_base_name(): global system_base_name return system_base_name + + +maestro_root_path = os.path.join(os.getcwd()) +maestro_path = os.path.join(maestro_root_path, "." + get_system_base_name()) +maestro_path_config = os.path.join(maestro_path, "config.txt") +maestro_path_manifest = os.path.join(maestro_path, "manifest") + +## +## @brief to use later to know where the ".maestro" parent path is ... +## @return the parent path of the ".maestro" +## +def get_maestro_root_path(): + global maestro_root_path + return maestro_root_path + +def get_maestro_path(): + global maestro_path + return maestro_path + +def get_maestro_path_config(): + global maestro_path_config + return maestro_path_config + +def get_maestro_path_manifest(): + global maestro_path_manifest + return maestro_path_manifest + + diff --git a/maestro/manifest.py b/maestro/manifest.py new file mode 100644 index 0000000..dc047b5 --- /dev/null +++ b/maestro/manifest.py @@ -0,0 +1,240 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +## +## @author Edouard DUPIN +## +## @copyright 2012, Edouard DUPIN, all right reserved +## +## @license MPL v2.0 (see license file) +## +import platform +import sys +import os +import copy +# Local import +from . import debug +from . import tools +from . import env + +from lxml import etree + + +def load_config(): + config_property = tools.file_read_data(env.get_maestro_path_config()) + element_config = config_property.split("\n") + if len(element_config) != 3: + debug.error("error in configuration property") + if element_config[0][:5] != "repo=": + debug.error("error in configuration property (2)") + if element_config[1][:7] != "branch=": + debug.error("error in configuration property (3)") + if element_config[2][:5] != "file=": + debug.error("error in configuration property (4)") + configuration = { + "repo":element_config[0][5:], + "branch":element_config[1][7:], + "file":element_config[2][5:] + } + debug.info("configuration property: " + str(configuration)) + return configuration + + +class RepoConfig(): + def __init__(self): + self.name = "" + self.path = "" + self.remotes = [] # list of all remotes, with the upstream elements (needed for third party integrations) + self.select_remote = "" + self.branch = "" + + +class Manifest(): + def __init__(self, manifest_xml): + self.manifest_xml = manifest_xml + self.projects = [] + self.default = None + self.default_base = { + "remote":"origin", + "revision":"master", + "sync":False, + } + self.remotes = [] + self.includes = [] + # load the manifest + self._load() + # check error in manifest (double path ...) + self._check_double_path([]) + + def _load(self): + tree = etree.parse(self.manifest_xml) + debug.debug("manifest : '" + self.manifest_xml + "'") + root = tree.getroot() + if root.tag != "manifest": + debug.error("(l:" + str(child.sourceline) + ") in '" + str(file) + "' have not main xml node='manifest'") + for child in root: + if type(child) == etree._Comment: + debug.verbose("(l:" + str(child.sourceline) + ") comment='" + str(child.text) + "'"); + continue + if child.tag == "remote": + name = "origin" + fetch = "" + for attr in child.attrib: + if attr == "name": + name = child.attrib[attr] + elif attr == "fetch": + fetch = child.attrib[attr] + else: + debug.error("(l:" + str(child.sourceline) + ") Parsing the manifest : Unknow '" + child.tag + "' attibute : '" + attr + "', availlable:[name,fetch]") + debug.debug("(l:" + str(child.sourceline) + ") find '" + child.tag + "' : name='" + name + "' fetch='" + fetch + "'"); + self.remotes.append({ + "name":name, + "fetch":fetch + }) + continue + if child.tag == "include": + name = "" + for attr in child.attrib: + if attr == "name": + name = child.attrib[attr] + else: + debug.error("(l:" + str(child.sourceline) + ") Parsing the manifest : Unknow '" + child.tag + "' attibute : '" + attr + "', availlable:[name]") + debug.debug("(l:" + str(child.sourceline) + ") find '" + child.tag + "' : name='" + name + "'"); + # check if the file exist ... + new_name_xml = os.path.join(os.path.dirname(self.manifest_xml),name) + if os.path.exists(new_name_xml) == False: + debug.error("(l:" + str(child.sourceline) + ") The file does not exist : '" + new_name_xml + "'") + self.includes.append({ + "name":name, + "path":new_name_xml, + "manifest":None + }) + continue + if child.tag == "default": + remote = "origin" + revision = "master" + sync = False + for attr in child.attrib: + if attr == "remote": + remote = child.attrib[attr] + elif attr == "revision": + revision = child.attrib[attr] + elif attr == "sync-s": + sync = child.attrib[attr] + if sync.lower() == "true" \ + or sync == "1" \ + or sync.lower() == "yes": + sync = True + elif sync.lower() == "false" \ + or sync == "0" \ + or sync.lower() == "no": + sync = False + else: + debug.error("(l:" + str(child.sourceline) + ") Parsing the manifest : Unknow '" + child.tag + "' attbute : '" + attr + "', value:'" + sync + "' availlable:[true,1,yes,false,0,no]") + else: + debug.error("(l:" + str(child.sourceline) + ") Parsing the manifest : Unknow '" + child.tag + "' attibute : '" + attr + "', availlable:[remote,revision,sync-s]") + if self.default != None: + debug.error("(l:" + str(child.sourceline) + ") Parsing the manifest : Node '" + child.tag + "' already set") + self.default = { + "remote":remote, + "revision":revision, + "sync":sync, + } + debug.debug("(l:" + str(child.sourceline) + ") find '" + child.tag + "' : remote='" + remote + "' revision='" + revision + "' sync=" + str(sync)); + continue + if child.tag == "project": + name = "" + path = "" + for attr in child.attrib: + if attr == "name": + name = child.attrib[attr] + elif attr == "path": + path = child.attrib[attr] + else: + debug.error("(l:" + str(child.sourceline) + ") Parsing the manifest: Unknow '" + child.tag + "' attibute : '" + attr + "', availlable:[name,revision,sync-s]") + if name == "": + debug.error("(l:" + str(child.sourceline) + ") Parsing the manifest: '" + child.tag + "' missing attribute: 'name' ==> specify the git to clone ...") + self.projects.append({ + "name":name, + "path":path, + }) + debug.debug("(l:" + str(child.sourceline) + ") find '" + child.tag + "' : name='" + name + "' path='" + path + "'"); + continue + debug.info("(l:" + str(child.sourceline) + ") '" + str(child.tag) + "' values=" + str(child.attrib)); + debug.error("(l:" + str(child.sourceline) + ") Parsing error Unknow NODE : '" + str(child.tag) + "' availlable:[remote,include,default,project]") + # now we parse all sub repo: + for elem in self.includes: + elem["manifest"] = Manifest(elem["path"]) + + + # inside data child.text + + + def _create_path_with_elem(self, element): + path = element["path"] + if path == "": + path = element["name"] + if len(path) >= 4 \ + and path[-4:] == ".git": + path = path[:-4] + return path + + def _check_double_path(self, list_path = [], space=""): + debug.debug(space + "check path : '" + self.manifest_xml + "'") + for elem in self.projects: + path = self._create_path_with_elem(elem) + debug.debug(space + " check path:'" + str(path) + "'") + if path in list_path: + debug.error("Check Manifest error : double use of the path '" + str(path) + "'") + list_path.append(path) + for elem in self.includes: + elem["manifest"]._check_double_path(list_path, space + " ") + + def get_all_configs(self, default=None, upper_remotes=[]): + out = [] + if default == None: + if self.default != None: + tmp_default = copy.deepcopy(self.default) + else: + tmp_default = copy.deepcopy(self.default_base) + # add all local project + for elem in self.projects: + conf = RepoConfig() + conf.name = elem["name"] + conf.path = self._create_path_with_elem(elem) + + # add default remote for the project (search in herited element) + for remote in self.remotes: + if remote["name"] == default["remote"]: + conf.remotes.append(remote) + if len(conf.remotes) == 0: + for remote in upper_remotes: + if remote["name"] == default["remote"]: + conf.remotes.append(remote) + if len(conf.remotes) == 0: + debug.error(" No remote detected: " + str(len(conf.remotes)) + " for " + conf.name + " with default remote name : " + default["remote"] + " self remote: " + str(self.remotes)) + + # select default remote: + conf.select_remote = None + debug.debug(" remotes count: " + str(len(conf.remotes))) + for remote in conf.remotes: + debug.debug(" Ckeck remote : " + remote["name"] + " == " + default["remote"]) + if remote["name"] == default["remote"]: + conf.select_remote = remote + break + if conf.select_remote == None: + debug.error("missing remote for project: " + str(conf.name)) + + conf.branch = default["revision"] + out.append(conf) + # create a temporary variable to transmit the remote to includes + upper_remotes_forward = copy.deepcopy(upper_remotes) + for remote in self.remotes: + upper_remotes_forward.append(remote) + # add all include project + for elem in self.includes: + list_project = elem["manifest"].get_all_configs(tmp_default, upper_remotes_forward) + for elem_proj in list_project: + out.append(elem_proj) + return out + + diff --git a/maestro/multiprocess.py b/maestro/multiprocess.py index 465853c..a4196bf 100644 --- a/maestro/multiprocess.py +++ b/maestro/multiprocess.py @@ -21,16 +21,33 @@ from . import tools from . import env -## -## @brief Execute the command and ruturn generate data -## -def run_command_direct(cmd_line): +def run_command_direct_shell(cmd_line, cwd=None, shell=False): # prepare command line: args = shlex.split(cmd_line) debug.verbose("cmd = " + str(args)) + subprocess.check_call(args, shell=shell) + return "" +## +## @brief Execute the command and ruturn generate data +## +def run_command_direct(cmd_line, cwd=None): + # prepare command line: + args = shlex.split(cmd_line) + debug.verbose("cmd = " + str(args)) + """ + if True: + subprocess.check_call(args) + return "" + """ try: # create the subprocess - p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + #p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + #p = subprocess.check_call(args) + """ + if cwd != None: + debug.info("path = " + cwd) + """ + p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=cwd) except subprocess.CalledProcessError as e: debug.error("subprocess.CalledProcessError : " + str(args)) except: @@ -49,3 +66,26 @@ def run_command_direct(cmd_line): return False + +def run_command(cmd_line, cwd=None): + # prepare command line: + args = shlex.split(cmd_line) + debug.verbose("cmd = " + str(args)) + try: + # create the subprocess + """ + if cwd != None: + debug.info("path = " + cwd) + """ + p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=cwd) + except subprocess.CalledProcessError as e: + debug.error("subprocess.CalledProcessError : " + str(args)) + except: + debug.error("Exception on : " + str(args)) + # launch the subprocess: + output, err = p.communicate() + if sys.version_info >= (3, 0): + output = output.decode("utf-8") + err = err.decode("utf-8") + # Check error : + return [p.returncode, output[:-1], err[:-1]] diff --git a/setup.py b/setup.py index e411bdd..438daab 100755 --- a/setup.py +++ b/setup.py @@ -37,6 +37,9 @@ setup(name='maestro', #data_file=[ # ('/etc/bash_completion.d', ['bash-autocompletion/lutin']), #], + install_requires=[ + 'lxml', + ], include_package_data = True, zip_safe=False)