예제 #1
0
def clean_profile(opts, profile):
    # Load the context
    ctx = Context.load(opts.workspace, profile, opts, strict=True, load_env=False)

    if not ctx:
        if not opts.workspace:
            log(
                "[clean] Error: The current or desired workspace could not be "
                "determined. Please run `catkin clean` from within a catkin "
                "workspace or specify the workspace explicitly with the "
                "`--workspace` option.")
        else:
            log(
                "[clean] Error: Could not clean workspace \"%s\" because it "
                "either does not exist or it has no catkin_tools metadata." %
                opts.workspace)
        return False

    profile = ctx.profile

    # Check if the user wants to do something explicit
    actions = [
        'build', 'devel', 'install', 'logs',
        'packages', 'orphans',
        'deinit',  'setup_files']

    logs_exists = os.path.exists(ctx.log_space_abs)
    build_exists = os.path.exists(ctx.build_space_abs)
    devel_exists = os.path.exists(ctx.devel_space_abs)

    install_path = (
        os.path.join(ctx.destdir, ctx.install_space_abs.lstrip(os.sep))
        if ctx.destdir
        else ctx.install_space_abs)
    install_exists = os.path.exists(install_path)

    # Default is to clean all products for this profile
    no_specific_action = not any([
        v for (k, v) in vars(opts).items()
        if k in actions])
    clean_all = opts.deinit or no_specific_action

    # Initialize action options
    if clean_all:
        opts.logs = opts.build = opts.devel = opts.install = True

    # Make sure the user intends to clena everything
    spaces_to_clean = (opts.logs or opts.build or opts.devel or opts.install)
    spaces_to_clean_msgs = []

    if spaces_to_clean and not (opts.yes or opts.dry_run):
        if opts.logs and logs_exists:
            spaces_to_clean_msgs.append(clr("[clean] Log Space:     @{yf}{}").format(ctx.log_space_abs))
        if opts.build and build_exists:
            spaces_to_clean_msgs.append(clr("[clean] Build Space:   @{yf}{}").format(ctx.build_space_abs))
        if opts.devel and devel_exists:
            spaces_to_clean_msgs.append(clr("[clean] Devel Space:   @{yf}{}").format(ctx.devel_space_abs))
        if opts.install and install_exists:
            spaces_to_clean_msgs.append(clr("[clean] Install Space: @{yf}{}").format(install_path))

        if len(spaces_to_clean_msgs) == 0 and not opts.deinit:
            log("[clean] Nothing to be cleaned for profile:  `{}`".format(profile))
            return True

    if len(spaces_to_clean_msgs) > 0:
        log("")
        log(clr("[clean] @!@{yf}Warning:@| This will completely remove the "
                "following directories. (Use `--yes` to skip this check)"))
        for msg in spaces_to_clean_msgs:
            log(msg)
        try:
            yes = yes_no_loop(
                "\n[clean] Are you sure you want to completely remove the directories listed above?")
            if not yes:
                log(clr("[clean] Not removing any workspace directories for"
                        " this profile."))
                return True
        except KeyboardInterrupt:
            log("\n[clean] No actions performed.")
            sys.exit(0)

    # Initialize flag to be used on the next invocation
    needs_force = False

    try:
        # Remove all installspace files
        if opts.install and install_exists:
            log("[clean] Removing installspace: %s" % install_path)
            if not opts.dry_run:
                safe_rmtree(install_path, ctx.workspace, opts.force)

        # Remove all develspace files
        if opts.devel:
            if devel_exists:
                log("[clean] Removing develspace: %s" % ctx.devel_space_abs)
                if not opts.dry_run:
                    safe_rmtree(ctx.devel_space_abs, ctx.workspace, opts.force)
            # Clear the cached metadata from the last build run
            _, build_metadata_file = get_metadata_paths(ctx.workspace, profile, 'build')
            if os.path.exists(build_metadata_file):
                os.unlink(build_metadata_file)
            # Clear the cached packages data, if it exists
            packages_metadata_path = ctx.package_metadata_path()
            if os.path.exists(packages_metadata_path):
                safe_rmtree(packages_metadata_path, ctx.workspace, opts.force)

        # Remove all buildspace files
        if opts.build and build_exists:
            log("[clean] Removing buildspace: %s" % ctx.build_space_abs)
            if not opts.dry_run:
                safe_rmtree(ctx.build_space_abs, ctx.workspace, opts.force)

        # Setup file removal
        if opts.setup_files:
            if devel_exists:
                log("[clean] Removing setup files from develspace: %s" % ctx.devel_space_abs)
                opts.packages.append('catkin')
                opts.packages.append('catkin_tools_prebuild')
            else:
                log("[clean] No develspace exists, no setup files to clean.")

        # Clean log files
        if opts.logs and logs_exists:
            log("[clean] Removing log space: {}".format(ctx.log_space_abs))
            if not opts.dry_run:
                safe_rmtree(ctx.log_space_abs, ctx.workspace, opts.force)

        # Find orphaned packages
        if ctx.link_devel and not any([opts.build, opts.devel]):
            if opts.orphans:
                if os.path.exists(ctx.build_space_abs):
                    log("[clean] Determining orphaned packages...")

                    # Get all existing packages in source space and the
                    # Suppress warnings since this is looking for packages which no longer exist
                    found_source_packages = [
                        pkg.name for (path, pkg) in
                        find_packages(ctx.source_space_abs, warnings=[]).items()]
                    built_packages = [
                        pkg.name for (path, pkg) in
                        find_packages(ctx.package_metadata_path(), warnings=[]).items()]

                    # Look for orphaned products in the build space
                    orphans = [p for p in built_packages
                               if (p not in found_source_packages and p !=
                                   'catkin_tools_prebuild')]

                    if len(orphans) > 0:
                        opts.packages.extend(list(orphans))
                    else:
                        log("[clean] No orphans in the workspace.")
                else:
                    log("[clean] No buildspace exists, no potential for orphans.")

            # Remove specific packages
            if len(opts.packages) > 0:

                try:
                    # Clean the packages
                    needs_force = clean_packages(
                        ctx,
                        opts.packages,
                        opts.dependents,
                        opts.verbose,
                        opts.dry_run)
                except KeyboardInterrupt:
                    wide_log("[build] User interrupted!")
                    return False

        elif opts.orphans or len(opts.packages) > 0:
            log("[clean] Error: Individual packages can only be cleaned from "
                "workspaces with symbolically-linked develspaces (`catkin "
                "config --link-devel`).")

    except:
        log("[clean] Failed to clean profile `{}`".format(profile))
        needs_force = True
        raise

    finally:
        if needs_force:
            log(clr(
                "[clean] @/@!Note:@| @/Parts of the workspace have been cleaned which will "
                "necessitate re-configuring CMake on the next build.@|"))
            update_metadata(ctx.workspace, ctx.profile, 'build', {'needs_force': True})

    return True
예제 #2
0
def clean_profile(opts, profile):
    # Load the context
    ctx = Context.load(opts.workspace, profile, opts, strict=True, load_env=False)

    if not ctx:
        if not opts.workspace:
            log(clr("[clean] @!@{rf}Error:@| The current or desired workspace could not be "
                    "determined. Please run `catkin clean` from within a catkin "
                    "workspace or specify the workspace explicitly with the "
                    "`--workspace` option."))
        else:
            log(clr("[clean] @!@{rf}Error:@| Could not clean workspace \"%s\" because it "
                    "either does not exist or it has no catkin_tools metadata." %
                    opts.workspace))
        return False

    profile = ctx.profile

    # Check if the user wants to do something explicit
    actions = ['spaces', 'packages', 'clean_this', 'orphans', 'deinit',  'setup_files']

    paths = {}  # noqa
    paths_exists = {}  # noqa

    paths['install'] = (
        os.path.join(ctx.destdir, ctx.install_space_abs.lstrip(os.sep))
        if ctx.destdir
        else ctx.install_space_abs)
    paths_exists['install'] = os.path.exists(paths['install']) and os.path.isdir(paths['install'])

    for space in Context.SPACES.keys():
        if space in paths:
            continue
        paths[space] = getattr(ctx, '{}_space_abs'.format(space))
        paths_exists[space] = getattr(ctx, '{}_space_exists'.format(space))()

    # Default is to clean all products for this profile
    no_specific_action = not any([
        v for (k, v) in vars(opts).items()
        if k in actions])
    clean_all = opts.deinit or no_specific_action

    # Initialize action options
    if clean_all:
        opts.spaces = [k for k in Context.SPACES.keys() if k != 'source']

    # Make sure the user intends to clean everything
    spaces_to_clean_msgs = []

    if opts.spaces and not (opts.yes or opts.dry_run):
        for space in opts.spaces:
            if getattr(ctx, '{}_space_exists'.format(space))():
                space_name = Context.SPACES[space]['space']
                space_abs = getattr(ctx, '{}_space_abs'.format(space))
                spaces_to_clean_msgs.append(clr("[clean] {:14} @{yf}{}").format(space_name + ':', space_abs))

        if len(spaces_to_clean_msgs) == 0 and not opts.deinit:
            log("[clean] Nothing to be cleaned for profile:  `{}`".format(profile))
            return True

    if len(spaces_to_clean_msgs) > 0:
        log("")
        log(clr("[clean] @!@{yf}Warning:@| This will completely remove the "
                "following directories. (Use `--yes` to skip this check)"))
        for msg in spaces_to_clean_msgs:
            log(msg)
        try:
            yes = yes_no_loop(
                "\n[clean] Are you sure you want to completely remove the directories listed above?")
            if not yes:
                log(clr("[clean] Not removing any workspace directories for"
                        " this profile."))
                return True
        except KeyboardInterrupt:
            log("\n[clean] No actions performed.")
            sys.exit(0)

    # Initialize flag to be used on the next invocation
    needs_force = False

    try:
        for space in opts.spaces:
            if space == 'devel':
                # Remove all develspace files
                if paths_exists['devel']:
                    log("[clean] Removing {}: {}".format(Context.SPACES['devel']['space'], ctx.devel_space_abs))
                    if not opts.dry_run:
                        safe_rmtree(ctx.devel_space_abs, ctx.workspace, opts.force)
                # Clear the cached metadata from the last build run
                _, build_metadata_file = get_metadata_paths(ctx.workspace, profile, 'build')
                if os.path.exists(build_metadata_file):
                    os.unlink(build_metadata_file)
                # Clear the cached packages data, if it exists
                packages_metadata_path = ctx.package_metadata_path()
                if os.path.exists(packages_metadata_path):
                    safe_rmtree(packages_metadata_path, ctx.workspace, opts.force)

            else:
                if paths_exists[space]:
                    space_name = Context.SPACES[space]['space']
                    space_path = paths[space]
                    log("[clean] Removing {}: {}".format(space_name, space_path))
                    if not opts.dry_run:
                        safe_rmtree(space_path, ctx.workspace, opts.force)

        # Setup file removal
        if opts.setup_files:
            if paths_exists['devel']:
                log("[clean] Removing setup files from {}: {}".format(Context.SPACES['devel']['space'], paths['devel']))
                opts.packages.append('catkin')
                opts.packages.append('catkin_tools_prebuild')
            else:
                log("[clean] No {} exists, no setup files to clean.".format(Context.SPACES['devel']['space']))

        # Find orphaned packages
        if ctx.link_devel or ctx.isolate_devel and not ('devel' in opts.spaces or 'build' in opts.spaces):
            if opts.orphans:
                if os.path.exists(ctx.build_space_abs):
                    log("[clean] Determining orphaned packages...")

                    # Get all existing packages in source space and the
                    # Suppress warnings since this is looking for packages which no longer exist
                    found_source_packages = [
                        pkg.name for (path, pkg) in
                        find_packages(ctx.source_space_abs, warnings=[]).items()]
                    built_packages = [
                        pkg.name for (path, pkg) in
                        find_packages(ctx.package_metadata_path(), warnings=[]).items()]

                    # Look for orphaned products in the build space
                    orphans = [p for p in built_packages
                               if (p not in found_source_packages and p !=
                                   'catkin_tools_prebuild')]

                    if len(orphans) > 0:
                        opts.packages.extend(list(orphans))
                    else:
                        log("[clean] No orphans in the workspace.")
                else:
                    log("[clean] No {} exists, no potential for orphans.".format(Context.SPACES['build']['space']))

            # Remove specific packages
            if len(opts.packages) > 0 or opts.clean_this:
                # Determine the enclosing package
                try:
                    ws_path = find_enclosing_workspace(getcwd())
                    # Suppress warnings since this won't necessarily find all packages
                    # in the workspace (it stops when it finds one package), and
                    # relying on it for warnings could mislead people.
                    this_package = find_enclosing_package(
                        search_start_path=getcwd(),
                        ws_path=ws_path,
                        warnings=[])
                except InvalidPackage as ex:
                    sys.exit(clr("[clean] @!@{rf}Error:@| The file {} is an invalid package.xml file."
                                 " See below for details:\n\n{}").format(ex.package_path, ex.msg))

                # Handle context-based package cleaning
                if opts.clean_this:
                    if this_package:
                        opts.packages += [this_package]
                    else:
                        sys.exit(
                            clr("[clean] @!@{rf}Error:@| In order to use --this, the current directory"
                                " must be part of a catkin package."))
                try:
                    # Clean the packages
                    needs_force = clean_packages(
                        ctx,
                        opts.packages,
                        opts.dependents,
                        opts.verbose,
                        opts.dry_run)
                except KeyboardInterrupt:
                    wide_log("[clean] User interrupted!")
                    return False

        elif opts.orphans or len(opts.packages) > 0 or opts.clean_this:
            log(clr("[clean] @!@{rf}Error:@| Individual packages cannot be cleaned from "
                    "workspaces with merged develspaces, use a symbolically-linked "
                    "or isolated develspace instead."))

    except:  # noqa: E722
        # Silencing E722 here since we immediately re-raise the exception.
        log("[clean] Failed to clean profile `{}`".format(profile))
        needs_force = True
        raise

    finally:
        if needs_force:
            log(clr(
                "[clean] @/@!Note:@| @/Parts of the workspace have been cleaned which will "
                "necessitate re-configuring CMake on the next build.@|"))
            update_metadata(ctx.workspace, ctx.profile, 'build', {'needs_force': True})

    return True