Exemple #1
0
 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 ''))
Exemple #2
0
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)
Exemple #3
0
def die(msg=None, errlvl=1):
    if msg:
        sys.stderr.write(
            str(
                aformat("Fatal: ", fg='red', attrs=[
                    'bold',
                ]) + ("%s\n" % msg)))
    sys.exit(errlvl)
Exemple #4
0
 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)))
Exemple #5
0
 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 ''))
Exemple #6
0
 def err_msg(mesg):
     if error_status["no_error"]:
         print("")
         error_status["no_error"] = False
     print(aformat("  W ", fg="yellow") + mesg)
Exemple #7
0
    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
Exemple #8
0
    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})
Exemple #9
0
def info(msg):
    print(aformat("Info: ", fg='green') + msg, file=sys.stderr)
Exemple #10
0
def err(msg):
    print(aformat("Error: ", fg='red', attrs=[
        'bold',
    ]) + msg,
          file=sys.stderr)
Exemple #11
0
def warn(msg):
    print(aformat("Warning: ", fg='yellow') + msg, file=sys.stderr)
Exemple #12
0
 def replace(s):
     return "(%s)" % ansi.aformat(s.group()[1:], attrs=[
         "bold",
     ])
Exemple #13
0
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)
Exemple #14
0
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