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
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