def msg(action, xmlid, record, tags=""): token = aformat("..", fg="black", attrs=[ "bold", ]) trunc = lambda s, l, index=-1: shorten( s, l, index=index, token=token, token_length=2) color = { "grab": { "fg": "cyan" }, "skip": { "fg": "blue" }, "mark": { "fg": "red" }, "name": { "fg": "red" }, } action_colored = aformat(action, **color[action]) print(" %s: %-56s %-10s (%s,%4d)%s" % (action_colored, trunc(self.tuple2xmlid(xmlid), 64), tags, record._model, record._ref, (": %s" % r.name) if 'name' in r.fields else ''))
def line(line_def, **kwargs): """Highlights a character in the line""" def replace(s): return "(%s)" % ansi.aformat(s.group()[1:], attrs=[ "bold", ]) return ansi.aformat(re.sub('@.?', replace, line_def), **kwargs)
def die(msg=None, errlvl=1): if msg: sys.stderr.write( str( aformat("Fatal: ", fg='red', attrs=[ 'bold', ]) + ("%s\n" % msg))) sys.exit(errlvl)
def msg(action, message): token = aformat("..", fg="black", attrs=[ "bold", ]) trunc = lambda s, l, index=-1: shorten( s, l, index=index, token=token, token_length=2) color = { "lint": { "fg": "red" }, "info": { "fg": "white" }, "warn": { "fg": "yellow" }, } action_colored = aformat(action, **color[action]) print(" %-4s: %-72s" % (action_colored, trunc(message, 72, index=-1)))
def msg(action, xmlid, filename, record): token = aformat("..", fg="black", attrs=[ "bold", ]) trunc = lambda s, l, index=-1: shorten( s, l, index=index, token=token, token_length=2) color = { "nop": { "fg": "blue" }, "new": { "fg": "green" }, "chg": { "fg": "yellow" }, } action_colored = aformat(action, **color[action]) print(" %-4s: %-32s in %-32s (%s,%4d)%s" % (action_colored, trunc(self.tuple2xmlid(xmlid), 32, index=8), trunc(filename, 32, index=8), record._model, record._ref, (": %s" % r.name) if 'name' in r.fields else ''))
def err_msg(mesg): if error_status["no_error"]: print("") error_status["no_error"] = False print(aformat(" W ", fg="yellow") + mesg)
def map_data(self): error_status = {'no_error': True} def err_msg(mesg): if error_status["no_error"]: print("") error_status["no_error"] = False print(aformat(" W ", fg="yellow") + mesg) tracked_files = {} start = time.time() print(aformat("Loading current module's XMLs data... ", attrs=[ "bold", ]), end="") sys.stdout.flush() res = {} xml_files = self.meta.get('data', []) module_dependencies = [ "base", ] for xml_file in xml_files: if not os.path.exists(self.file_path(xml_file)): err_msg("file %r referenced in data section of " "``__openerp__.py`` does not exists !" % xml_file) continue if xml_file.endswith(".csv"): err_msg("%s: skipping CSV file." % xml_file) continue xml = load(self.file_path(xml_file)) tracked_files[xml_file] = { 'xml_file_content': xml, } ## XXXvlab: will not catch complex situation file_deps = set() for elt in xml.getchildren(): if elt.tag != "data": continue for record in elt.getchildren(): if record.tag == "comment": continue if 'id' not in record.attrib: err_msg( "!! Error while reading %s: No id found !\n%s" % (record.tag, xml2string(record, xml_declaration=False))) continue attrib_id = record.attrib['id'] deps = set() if record.tag == "menuitem": deps |= set( xmlid2tuple(record.attrib[a], self.module_name) for a in ['action', 'parent'] if record.attrib.get(a, False)) ## Get deps deps |= set([ xmlid2tuple(xmlid, self.module_name) for xmlid in record.xpath(".//@ref") ]) evals = record.xpath(".//@eval") if evals: ## must get ref() usages ! xmlids = [] for e in evals: try: xmlids.extend(common.get_refs_in_eval(e)) except Exception, exc: err_msg( "%s: %s %s: Exception while evaluating: %r, %s" % (xml_file, record.tag, attrib_id, e, exc.msg)) continue deps |= set( xmlid2tuple(xmlid, self.module_name) for xmlid in xmlids) ## Check deps for module, xmlid in deps: if module != self.module_name: ## Check that we depens of this module if module not in module_dependencies: module_dependencies.append(module) else: t = self.xmlid2tuple(xmlid) if t not in res and not t[1].startswith("model_"): err_msg("%s: %s %s references %s.%s which is not defined (yet?)." \ % (xml_file, record.tag, attrib_id, module, xmlid)) ## Check for duplicate xmlid: local_xml_id = self.xmlid2tuple(attrib_id) if local_xml_id in res: err_msg("%s: %s %s already defined in file %s." \ % (xml_file, record.tag, attrib_id, res[local_xml_id]['filename'])) res[self.xmlid2tuple(attrib_id)] = { 'filename': xml_file, 'record_xml': record, 'deps': deps, } file_deps |= deps ## Check cyclicity if cycle_exists( self.xmlid2tuple(attrib_id), lambda n: list(res.get(n, {'deps': []})['deps'])): err_msg("%s: %s %s introduce a cyclic reference." % (xml_file, record.tag, attrib_id)) tracked_files[xml_file]["deps"] = file_deps
def _record_import(self, ooop_records, label, tag, follow_o2m=True): tracked_xml_ids, _, tracked_files = self.map_data() print( aformat("Collecting records in %s" % self.db_identifier, attrs=[ "bold", ])) content = self.to_xml(ooop_records, follow_o2m=follow_o2m, tag=tag) xmls = [(r, xmlize(c), d) for r, c, d in content] def msg(action, xmlid, filename, record): token = aformat("..", fg="black", attrs=[ "bold", ]) trunc = lambda s, l, index=-1: shorten( s, l, index=index, token=token, token_length=2) color = { "nop": { "fg": "blue" }, "new": { "fg": "green" }, "chg": { "fg": "yellow" }, } action_colored = aformat(action, **color[action]) print(" %-4s: %-32s in %-32s (%s,%4d)%s" % (action_colored, trunc(self.tuple2xmlid(xmlid), 32, index=8), trunc(filename, 32, index=8), record._model, record._ref, (": %s" % r.name) if 'name' in r.fields else '')) print(aformat("Reviewing collected records", attrs=[ "bold", ])) records_written = [] filenames = {} for record, xml, deps in xmls: records_written.append(record) module, xml_id = self.xml_id_mgr.lookup(record) ## This is the real xmlid that will be written and should ## be checked xmlid = self.xmlid2tuple(xml_id) if xmlid in tracked_xml_ids: elt = tracked_xml_ids[xmlid]['record_xml'] filename = tracked_xml_ids[xmlid]['filename'] if xml2string(elt) == xml2string(xml): msg("nop", xmlid, filename, record) continue msg("chg", xmlid, filename, record) if filename not in filenames: filenames[filename] = \ tracked_files[filename]['xml_file_content'] ## find 'data' element (parent) of tracked xml elt = tracked_xml_ids[xmlid]['record_xml'] data = elt.getparent() data.replace(elt, xml) tracked_xml_ids[xmlid]['record_xml'] = xml tracked_xml_ids[xmlid]['replaced'] = \ tracked_xml_ids[xmlid].get('replaced', 0) + 1 else: filename = self._get_file_name_for_record(record, xmls, label) msg("new", xmlid, filename, record) if filename not in filenames: filenames[filename] = \ tracked_files[filename]['xml_file_content'] \ if filename in tracked_files else \ common._empty_data_xml() ## find 'data' xml element. data = filenames[filename].getchildren()[0] data.append(xml) if filenames: print(aformat("Writing changes", attrs=[ "bold", ])) else: print(aformat("No changes to write to files.", attrs=[ "bold", ])) for filename, data in filenames.items(): self.add_xml(filename, xml2string(data)) for r in records_written: self._trigger_event(r, 'write') ## Should probably directly write in the linted form... self.lint(args={"-c": True})
def info(msg): print(aformat("Info: ", fg='green') + msg, file=sys.stderr)
def err(msg): print(aformat("Error: ", fg='red', attrs=[ 'bold', ]) + msg, file=sys.stderr)
def warn(msg): print(aformat("Warning: ", fg='yellow') + msg, file=sys.stderr)
def replace(s): return "(%s)" % ansi.aformat(s.group()[1:], attrs=[ "bold", ])
def run(obj=None, arguments=None): global LOGGER if obj is None: obj = get_stack_module() subcmds = get_subcmds(obj) if arguments is None: exname = kf.basename(sys.argv[0]) name = kf.basename(exname, ['.py', '.pyc']) env = {"exname": exname, "name": name, "surcmd": exname} else: env = arguments["__env__"] doc = get_help(obj, env=env, subcmds=subcmds) if arguments is None: try: arguments = docopt(doc, version=getattr(obj, '__version__', False), options_first=True, help=False) except DocoptExit as e: msg.err("Invalid command line for %r" % env["surcmd"]) raise e manage_std_options(arguments, doc) if arguments["help"]: command = arguments["COMMAND"] if command is None: print(doc) else: if command not in subcmds: print("Action %r not found." % command) exit(1) print(get_help_subcmd(command, subcmds[command], env)) exit(0) assert "ACTION" in arguments action = arguments["ACTION"] if action not in subcmds: msg.err("Action '%s' does not exists." % action) print("Use `%(surcmd)s --help` to get full help." % env) exit(1) subcmd = subcmds[action] ## XXXvlab: this would be nice if only one doc would have worked, ## it might be possible but didn't have much time to dig docopt_doc = get_help_subcmd(action, subcmd, env, only_sub=True) real_doc = get_help_subcmd(action, subcmd, env) options_first = True if get_subcmds(subcmd) else False try: args = docopt(docopt_doc, argv=arguments["ARGS"], help=False, version=getattr(subcmd, '__version__', False), options_first=options_first) except DocoptLanguageError as e: msg.die("Doc syntax error %s, please check:\n%s" % (e.message, real_doc)) exit(1) except DocoptExit: ## XXXvlab: hum we can't give the correct doc and have to ## do bad things to make it work. So I have to substitute ## the help printing message. msg.err("Invalid command line for command '%s %s'" % (env["surcmd"], action)) print(get_help_subcmd(action, subcmd, env)) exit(1) manage_std_options(args, real_doc) env = subcmd_env(env, action) args["__env__"] = env p, kw = match_prototype(subcmd, args) debug_mode = os.environ.get("%s_DEBUG" % args["__env__"]["name"].upper(), False) if debug_mode is not False and not LOGGER: logger = logging.getLogger('') ch = logging.StreamHandler() ch.setLevel(logging.DEBUG) # add formatter to ch formatter = logging.Formatter( '%(asctime)s %(levelname)-5s [%(name)s] %(message)s') ch.setFormatter(formatter) # add ch to logger logger.addHandler(ch) if ":" in debug_mode: ## at least one statement for statement in debug_mode.split(","): if ":" not in statement: msg.err("Invalid debug string.") exit(253) logger, level = statement.rsplit(":", 1) logging.getLogger(logger).setLevel(getattr(logging, level)) else: logger.setLevel(logging.DEBUG) LOGGER = True try: ret = subcmd(*p, **kw) except KeyboardInterrupt: if is_debug_mode(args): msg.err("Keyboard interrupt received while running '%s':" % (env["surcmd"], )) print( format_last_exception( prefix=aformat(" | ", fg="black", attrs=[ "bold", ]))) else: print() msg.err("Keyboard Interrupt. Bailing out.") exit(254) except Exception as e: ## pylint: disable=broad-except if is_debug_mode(args): msg.err("Exception while running '%s':" % (env["surcmd"], )) print( format_last_exception( prefix=aformat(" | ", fg="black", attrs=[ "bold", ]))) else: message = "%s" % e msg.err(message) exit(255) exit(ret)
def get_help(obj, env, subcmds): """Interpolate complete help doc of given object Assumption that given object as a specific interface: obj.__doc__ is the basic help object. obj.get_actions_titles() returns the subcommand if any. """ doc = txt.dedent(obj.__doc__ or "") env = env.copy() ## get a local copy doc = doc.strip() if not re.search(r"^usage:\s*$", doc, flags=re.IGNORECASE | re.MULTILINE): doc += txt.dedent(""" Usage: %(std_usage)s Options: %(std_options)s""") help_line = (" %%-%ds %%s" % (max([5] + [len(a) for a in subcmds]), )) env["actions"] = "\n".join( help_line % (name, get_help(subcmd, subcmd_env(env, name), {}).split("\n")[0]) for name, subcmd in subcmds.items()) env["actions_help"] = "" if not env["actions"] else ( "ACTION could be one of:\n\n" "%(actions)s\n\n" "See '%(surcmd)s help ACTION' for more information " "on a specific command." % env) if "%(std_usage)s" in doc: env["std_usage"] = txt.indent( ("%(surcmd)s --help\n" "%(surcmd)s --version" + (("\n%(surcmd)s help [COMMAND]" "\n%(surcmd)s ACTION [ARGS...]") if subcmds else "")) % env, _find_prefix(doc, "%(std_usage)s"), first="") if "%(std_options)s" in doc: env["std_options"] = txt.indent( "--help Show this screen.\n" "--version Show version.", _find_prefix(doc, "%(std_options)s"), first="") if subcmds and "%(actions_help)s" not in doc: doc += "\n\n%(actions_help)s" try: output = doc % env except KeyError as e: msg.err("Doc interpolation of %s needed missing key %r" % (aformat(env["surcmd"], attrs=[ "bold", ]), e.args[0])) exit(1) except Exception as e: msg.err("Documentation of %s is not valid. Please check it:\n%s" % (aformat(env["surcmd"], attrs=[ "bold", ]), doc)) exit(1) return output