Example #1
0
 def run(self):
     ui.debug("Calling:", " ".join(self.cmd))
     try:
         self.process = subprocess.Popen(
             self.cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=self.cwd, env=self.env
         )
     except Exception, e:
         self.exception = e
         return
Example #2
0
def clone_project(worktree, url, src=None, branch=None, remote="origin",
    skip_if_exists=False):
    """ Add a project to a worktree given its url.

    If src is not given, it will be guessed from the url

    If skip_if_exists is False, an error message will be
    raised if the project already exists

    """
    should_add = True
    if not src:
        src = url.split("/")[-1].replace(".git", "")
    if os.path.isabs(src):
        src = os.path.relpath(worktree.root, src)
        src = qibuild.sh.to_posix_path(src)

    project = worktree.get_project(src, raises=False)
    if project:
        if not skip_if_exists:
            mess  = "Could not add project from %s in %s\n" % (url, src)
            mess += "This path is already registered for worktree in %s\n" % worktree.root
            raise Exception(mess)
        else:
            if os.path.exists(project.path):
                ui.debug("Found project in %s, skipping" % src)
                return
            # Some one erase the project manually without telling qiworktree
            should_add = False

    path = os.path.join(worktree.root, src)
    path = qibuild.sh.to_native_path(path)
    if os.path.exists(path):
        if skip_if_exists:
            if qisrc.git.is_submodule(path):
                ui.warning("erasing submodule: ", path)
                qibuild.sh.rm(path)
            else:
                ui.debug("Adding project in %s", src)
                worktree.add_project(src)
                return
        else:
            mess  = "Could not add project from %s in %s\n" % (url, src)
            mess += "This path already exists\n"
            raise Exception(mess)

    ui.info(ui.green, "Git clone: %s -> %s" % (url, path))
    dirname = os.path.dirname(path)
    qibuild.sh.mkdir(dirname, recursive=True)
    git = qisrc.git.Git(path)
    if branch:
        git.clone(url, "-b", branch, "-o", remote)
    else:
        git.clone(url, "-o", remote)
    if should_add:
        worktree.add_project(path)
Example #3
0
def toc_open(worktree_root, args=None, qibuild_cfg=None):
    """ Creates a :py:class:`Toc` object.

    :param worktree: The worktree to be used. (see :py:class:`qisrc.worktree.WorkTree`)
    :param args: an ``argparse.NameSpace`` object containing
     the arguments passed from the comand line.
    :param qibuild_cfg: A (:py:class:`qibuild.config.QiBuildConfig` instance) to use.
     If None, we built a new instance to store in ``toc.config``

    You should always use this function to call Toc methods from
    a qibuild :term:`action`.

    It takes care of all the options you specify from command line,
    and calls Toc constructor accordingly (see :py:meth:`Toc.__init__`)

    """
    # Not that args can come from:
    #    - a worktree parser
    #    - a toc parser
    #    - a build parser
    # (hence all the hasattr...)
    # ...
    # or simply not given :)

    config = None
    if hasattr(args, 'config'):
        config   = args.config

    build_type = None
    if hasattr(args, 'build_type'):
        build_type = args.build_type

    cmake_flags = list()
    if hasattr(args,'cmake_flags'):
        cmake_flags = args.cmake_flags

    cmake_generator = None
    if hasattr(args, 'cmake_generator'):
        cmake_generator = args.cmake_generator

    worktree = qisrc.worktree.open_worktree(worktree_root)
    toc = Toc(worktree,
               config=config,
               build_type=build_type,
               cmake_flags=cmake_flags,
               cmake_generator=cmake_generator,
               qibuild_cfg=qibuild_cfg)

    (active_projects, single) =  _projects_from_args(toc, args)
    toc.active_projects = active_projects
    ui.debug("active projects: %s", ".".join(toc.active_projects))
    ui.debug("single: %s", str(single))
    toc.solve_deps = (not single)
    return toc
Example #4
0
def main():
    ui.info(ui.red, "This is a an error message\n",
        ui.reset, "And here are the details")
    ui.error("could not build")
    ui.warning("-j ignored for this generator")
    ui.info("building foo")
    ui.debug("debug message")
    ui.info(ui.brown, "this is brown")
    ui.info(ui.bold, ui.brown, "this is bold brown")
    ui.info(ui.red, "red is dead")
    ui.info(ui.darkred, "darkred is really dead")
    ui.info(ui.yellow, "this is yellow")
def _dump_arguments(name, args):
    """ Dump an argparser namespace to log """
    output = ""
    max_len = 0
    for k in args.__dict__.keys():
        if len(k) > max_len:
            max_len = len(k)
    for k, v in args.__dict__.iteritems():
        pad = " " * (max_len - len(k))
        output += "  %s%s = %s\n" % (str(k), pad, str(v))
    if output[-1] == "\n":
        output = output[:-1]
    ui.debug("[%s] arguments:\n%s", name, output)
Example #6
0
def _projects_from_args(toc, args):
    """
    Cases handled:
      - nothing specified: get the project from the cwd
      - args.single: do not resolve dependencies
      - args.all: return all projects
    Returns a tuple (project_names, single):
        project_names: the actual list for project
        single: user specified --single
    """
    toc_p_names = [p.name for p in toc.projects]
    if hasattr(args, "all") and args.all:
        # Pretend the user has asked for all the known projects
        ui.debug("select: All projects have been selected")
        return (toc_p_names, False)

    if hasattr(args, "projects"):
        if args.projects:
            ui.debug("select: projects list from arguments: %s", ",".join(args.projects))
            return ([args.projects, args.single])
        else:
            from_cwd = None
            try:
                from_cwd = qibuild.project.project_from_cwd()
            except:
                pass
            if from_cwd:
                ui.debug("select: projects from cwd: %s", from_cwd)
                return ([from_cwd], args.single)
            else:
                ui.debug("select: default to all projects")
                return (toc_p_names, args.single)
    else:
        return (list(), False)
Example #7
0
    def get_sdk_dirs(self, project_name):
        """ Return a list of sdk needed to build a project.

        Iterate through the dependencies.
        When it is a package (pre-compiled), add the path of
        the package, when it is a project, add the path to the "sdk" dir
        under the build directory of the project.

        If a name is both in source and in package, use the package
        (saves compile time), unless user asked explicitely for a list
        of projects

        """
        dirs = list()

        known_project_names = [p.name for p in self.projects]
        if project_name not in known_project_names:
            raise TocException("%s is not a buildable project" % project_name)

        # Here do not honor self.solve_deps or the software won't compile :)
        dep_solver = DependenciesSolver(projects=self.projects, packages=self.packages,
            active_projects=self.active_projects)
        (r_project_names, _package_names, not_found) = dep_solver.solve([project_name])

        # Nothing to do with with the packages:
        # SDK dirs from toolchain are managed by the toolchain file in
        # self.toolchain

        if not_found:
            # FIXME: right now there are tons of case where you could have missing
            # projects. (using a cross-toolchain, or an Aldebaran SDK)
            # Put this back later.
            # ui.warning("Could not find projects", ", ".join(not_found))
            pass

        # Remove self from the list:
        r_project_names.remove(project_name)


        for project_name in r_project_names:
            project = self.get_project(project_name)
            dirs.append(project.get_sdk_dir())

        ui.debug("sdk_dirs for", project_name, ":", " ".join(dirs))
        return dirs
def run_action(module_name, args=None, forward_args=None):
    """
    Run an action using its module path and a list of arguments

    If forward_args is given, it must be an argparse.Namespace object.
    This namespace will be merged with args before being
    passed to the do() method of module_name.

    """
    if not args:
        args = list()
    ui.debug("running", module_name, " ".join(args))
    action_name  = module_name.split(".")[-1]
    package_name = ".".join(module_name.split(".")[:-1])
    try:
        _tmp = __import__(package_name, globals(), locals(), [action_name])
    except ImportError, err:
        raise InvalidAction(module_name, str(err))
def open_worktree(worktree=None):
    """
    Open a qi worktree.

    :return: a valid :py:class:`WorkTree` instance.
             If worktree is None, guess it from the current working dir.

    """
    if not worktree:
        worktree = guess_worktree()
    if worktree is None:
        raise NotInWorktree()
    if not os.path.exists(worktree):
        mess = "Cannot open a worktree from %s\n" % worktree
        mess += "This path does not exist"
        raise Exception(mess)
    res = WorkTree(worktree)
    ui.debug("Opening worktree in", worktree)
    return res
Example #10
0
    def execute(self):
        """Execute the command, and return a generator for iterating over
        the output written to the standard output and error streams.

        """

        def reader(pipe, pipe_name, queue):
            "To be called in a thread"
            while pipe and not pipe.closed:
                line = pipe.readline()
                if line == "":
                    break
                queue.put((pipe_name, line))
            if not pipe.closed:
                pipe.close()

        ui.debug("Calling:", " ".join(self.cmd))
        process = subprocess.Popen(self.cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=self.cwd, env=self.env)
        queue = Queue.Queue()

        pipe_out = threading.Thread(target=reader, args=(process.stdout, "stdout", queue))
        pipe_err = threading.Thread(target=reader, args=(process.stderr, "stderr", queue))

        pipe_out.start()
        pipe_err.start()

        while True:
            if process.poll() is not None and self.returncode is None:
                self.returncode = process.returncode
            try:
                name, line = queue.get(block=True, timeout=0.01)
                if name == "stderr":
                    yield (None, line)
                else:
                    yield (line, None)
            except Queue.Empty:
                if self.returncode is not None:
                    break

        pipe_out.join()
        pipe_err.join()
Example #11
0
 def install_project_runtime(self, project, destdir, num_jobs=1):
     """Install runtime component of a project to a destdir """
     runtime_components = [
          "binary",
          "data",
          "conf",
          "lib",
          "python",
          "doc"
      ]
     for component in runtime_components:
         self.build_env["DESTDIR"] = destdir
         cmake_args = list()
         cmake_args += ["-DCOMPONENT=%s" % component]
         cmake_args += ["-P", "cmake_install.cmake", "--"]
         cmake_args += num_jobs_to_args(num_jobs, self.cmake_generator)
         ui.debug("Installing", component)
         qibuild.command.call(["cmake"] + cmake_args,
             cwd=project.build_directory,
             env=self.build_env,
             )
Example #12
0
    def __init__(self, in_dir, out_dir="build-doc"):
        self.worktree = qisrc.worktree.open_worktree(in_dir)
        self.in_dir = in_dir
        self.out_dir = out_dir
        # Set during configure_all()
        self.opts = dict()

        self.templates_path = None
        self.sphinxdocs = dict()
        self.doxydocs = dict()

        # Will fill up self.templates_path, self.sphinxdocs and self.doxydocs
        self._load_doc_projects()
        self.deps_tree = self.get_deps_tree()
        ui.debug("QiDocBuilder dep tree: ", pprint.pformat(self.deps_tree))

        if not self.templates_path:
            mess = "Could not find any template repo\n"
            mess += "Please make sure that one of the qiproject.xml looks like:\n"
            mess += '<qiproject template_repo="yes" />\n'
            raise Exception(mess)
        self.doxytags_path = os.path.join(self.out_dir, "doxytags")
Example #13
0
def run_tests(project, build_env, pattern=None, verbose=False, slow=False, dry_run=False, valgrind=False):
    """ Called by :py:meth:`qibuild.toc.Toc.test_project`

    :param test_name: If given, only run this test

    Always write some XML files in build-<config>/test-results
    (even if they were no tests to run at all)

    :return: a boolean to indicate if test was sucessful

    """
    build_dir = project.build_directory
    results_dir = os.path.join(project.build_directory, "test-results")

    all_tests = parse_ctest_test_files(build_dir)
    tests = list()
    slow_tests = list()
    if pattern:
        tests = [x for x in all_tests if re.search(pattern, x[0])]
        if not tests:
            mess  = "No tests matching %s\n" % pattern
            mess += "Known tests are:\n"
            for x in all_tests:
                mess += "  * " + x[0] + "\n"
            raise Exception(mess)
    else:
        for test in all_tests:
            (name, cmd_, properties) = test
            cost = properties.get("COST")
            if not slow and cost and float(cost) > 50:
                ui.debug("Skipping test", name, "because cost",
                         "(%s)"% cost, "is greater than 50")
                slow_tests.append(name)
                continue
            tests.append(test)

    if not tests:
        # Create a fake test result to keep CI jobs happy:
        fake_test_res = TestResult("compilation")
        fake_test_res.ok = True
        xml_out = os.path.join(results_dir, "compilation.xml")
        write_xml(xml_out, fake_test_res)
        ui.warning("No tests found for project", project.name)
        return

    if dry_run:
        ui.info(ui.green, "List of tests for", project.name)
        for (test_name, _, _) in tests:
            ui.info(ui.green, " * ", ui.reset, test_name)
        return

    ui.info(ui.green, "Testing", project.name, "...")
    ok = True
    fail_tests = list()
    for (i, test) in enumerate(tests):
        (test_name, cmd, properties) = test
        ui.info(ui.green, " * ", ui.reset, ui.bold,
                "(%2i/%2i)" % (i+1, len(tests)),
                ui.blue, test_name.ljust(25), end="")
        if verbose:
            print
        sys.stdout.flush()
        test_res = run_test(build_dir, test_name, cmd, properties, build_env,
                            valgrind=valgrind, verbose=verbose)
        if test_res.ok:
            ui.info(ui.green, "[OK]")
        else:
            ok = False
            ui.info(ui.red, "[FAIL]")
            if not verbose:
                print test_res.out
            fail_tests.append(test_name)
        xml_out = os.path.join(results_dir, test_name + ".xml")
        if not os.path.exists(xml_out):
            write_xml(xml_out, test_res)

    if ok:
        ui.info("Ran %i tests" % len(tests))
        if slow_tests and not slow:
            ui.info("Note: %i" % len(slow_tests),
                    "slow tests did not run, use --slow to run them")
        ui.info("All pass. Congrats!")
        return True

    ui.error("Ran %i tests, %i failures" %
                  (len(tests), len(fail_tests)))
    for fail_test in fail_tests:
        ui.info(ui.bold, " -", ui.blue, fail_test)
    return False
Example #14
0
    def install_project(self, project, destdir, prefix="/",
                        runtime=False, num_jobs=1,
                        split_debug=False):
        """ Install the project

        :param project: project name.
        :param destdir: destination. Note that when using `qibuild install`,
          we will first call `cmake` to make sure `CMAKE_INSTALL_PREFIX` is
          ``/``. But this function simply calls ``cmake --target install``
          in the simple case.
        :param runtime: Whether to install the project as a runtime
           package or not.
           (see :ref:`cmake-install` section for the details)
        :package split_debug: split the debug symbols out of the binaries
            useful for `qibuild deploy`

        """
        build_dir = project.build_directory
        # DESTDIR=/tmp/foo and CMAKE_PREFIX="/usr/local" means
        # dest = /tmp/foo/usr/local
        destdir = qibuild.sh.to_native_path(destdir)
        self.build_env["DESTDIR"] = destdir
        # Must make sure prefix is not seen as an absolute path here:
        dest = os.path.join(destdir, prefix[1:])
        dest = qibuild.sh.to_native_path(dest)
        cmake_cache = os.path.join(build_dir, "CMakeCache.txt")
        if not os.path.exists(cmake_cache):
            mess  = """Could not install project {project.name}
It appears the project has not been configured.
({cmake_cache} does not exist)
Try configuring and building the project first.
"""
            mess = mess.format(config=self.active_config,
                project=project, cmake_cache=cmake_cache)
            raise Exception(mess)

        cprefix = qibuild.cmake.get_cached_var(build_dir, "CMAKE_INSTALL_PREFIX")
        if cprefix != prefix:
            qibuild.cmake.cmake(project.directory, project.build_directory,
                ['-DCMAKE_INSTALL_PREFIX=%s' % prefix],
                clean_first=False,
                env=self.build_env)
        else:
            mess = "Skipping configuration of project %s\n" % project.name
            mess += "CMAKE_INSTALL_PREFIX is already correct"
            ui.debug(mess)

        if not self.using_visual_studio and not self.cmake_generator == "Xcode":
            self.build_project(project, target="preinstall", num_jobs=num_jobs,
                               fix_shared_libs=False)

        if runtime:
            self.install_project_runtime(project, destdir, num_jobs=num_jobs)
        else:
            self.build_project(project, target="install", fix_shared_libs=False)

        if split_debug:
            if self.using_visual_studio:
                raise Exception("split debug not supported on Visual Studio")
            objcopy = qibuild.cmake.get_cached_var(project.build_directory, "CMAKE_OBJCOPY")
            if objcopy is None:
                objcopy = qibuild.command.find_program("objcopy", env=self.build_env)

            if not objcopy:
                mess  = """\
Could not split debug symbols from binaries for project {project.name}.
Could not find objcopy executable.\
"""
                qibuild.ui.warning(mess.format(project=project))
            else:
                qibuild.gdb.split_debug(destdir, objcopy=objcopy)
Example #15
0
def call(cmd, cwd=None, env=None, ignore_ret_code=False, quiet=None):
    """ Execute a command line.

    If ignore_ret_code is False:
        raise CommandFailedException if returncode is None.
    Else:
        simply returns the returncode of the process

    Note: first arg of the cmd is assumed to be something
    inside %PATH%. (or in env[PATH] if env is not None)

    Note: the shell= argument of the subprocess.Popen
    call will always be False.

    can raise:
      * CommandFailedException if ignore_ret_code is False
        and returncode is non zero
      * NotInPath  if first arg of cmd is not in %PATH%
      * And a normal exception if cwd is given and is not
        an existing directory.

    """
    exe_full_path = find_program(cmd[0], env=env)
    if not exe_full_path:
        raise NotInPath(cmd[0], env=env)
    cmd[0] = exe_full_path

    if cwd:
        if not os.path.exists(cwd):
            # We know we are likely to have a problem on windows here,
            # so always raise.
            raise Exception("Trying to to run %s in non-existing %s" % (" ".join(cmd), cwd))

    ui.debug("Calling:", " ".join(cmd))
    ring_buffer = RingBuffer(300)

    returncode = 0
    if quiet:
        quiet_command = quiet
    else:
        quiet_command = CONFIG.get("quiet", False)
    # This code won't work on windows with python < 2.7,
    # so quiet will be ignored
    if sys.platform.startswith("win") and sys.version_info < (2, 7):
        quiet_command = False
    if not quiet_command:
        returncode = subprocess.call(cmd, env=env, cwd=cwd)
    else:
        cmdline = CommandLine(cmd, cwd=cwd, env=env)
        for (out, err) in cmdline.execute():
            if out is not None:
                ring_buffer.append(out)
            if err is not None:
                ring_buffer.append(err)
        returncode = cmdline.returncode

    if ignore_ret_code:
        return returncode

    if returncode != 0:
        if quiet_command:
            lines = ring_buffer.get()
            for line in lines:
                sys.stdout.write(line)
                sys.stdout.flush()
        # Raise correct exception
        raise CommandFailedException(cmd, returncode, cwd)