def resolve(args, img_dir): """Take a list of manifests and resolve any file dependencies, first against the other published manifests and then against what is installed on the machine.""" out_dir = None echo_manifest = False output_to_screen = False suffix = None verbose = False use_system_to_resolve = True constraint_files = [] extra_external_info = False try: opts, pargs = getopt.getopt(args, "d:e:Emos:Sv") except getopt.GetoptError as e: usage(_("illegal global option -- {0}").format(e.opt)) for opt, arg in opts: if opt == "-d": out_dir = arg elif opt == "-e": constraint_files.append(arg) elif opt == "-E": extra_external_info = True elif opt == "-m": echo_manifest = True elif opt == "-o": output_to_screen = True elif opt == "-s": suffix = arg elif opt == "-S": use_system_to_resolve = False elif opt == "-v": verbose = True if (out_dir or suffix) and output_to_screen: usage(_("-o cannot be used with -d or -s")) manifest_paths = [os.path.abspath(fp) for fp in pargs] for manifest in manifest_paths: if not os.path.isfile(manifest): usage(_("The manifest file {0} could not be found.").format( manifest), retcode=2) if out_dir: out_dir = os.path.abspath(out_dir) if not os.path.isdir(out_dir): usage(_("The output directory {0} is not a directory.").format( out_dir), retcode=2) provided_image_dir = True pkg_image_used = False if img_dir == None: orig_cwd = None try: orig_cwd = os.getcwd() except OSError: # May be unreadable by user or have other problem. pass img_dir, provided_image_dir = api.get_default_image_root( orig_cwd=orig_cwd) if os.environ.get("PKG_IMAGE"): # It's assumed that this has been checked by the above # function call and hasn't been removed from the # environment. pkg_image_used = True if not img_dir: error( _("Could not find image. Use the -R option or set " "$PKG_IMAGE to the\nlocation of an image.")) return 1 system_patterns = misc.EmptyI if constraint_files: system_patterns = [] for f in constraint_files: try: with open(f, "rb") as fh: for l in fh: l = l.strip() if l and not l.startswith("#"): system_patterns.append(l) except EnvironmentError as e: if e.errno == errno.ENOENT: error("{0}: '{1}'".format(e.args[1], e.filename), cmd="resolve") return 1 raise api_errors._convert_error(e) if not system_patterns: error( _("External package list files were provided but " "did not contain any fmri patterns.")) return 1 elif use_system_to_resolve: system_patterns = ["*"] # Becuase building an ImageInterface permanently changes the cwd for # python, it's necessary to do this step after resolving the paths to # the manifests. try: api_inst = api.ImageInterface(img_dir, CLIENT_API_VERSION, progress.QuietProgressTracker(), None, PKG_CLIENT_NAME, exact_match=provided_image_dir) except api_errors.ImageNotFoundException as e: if e.user_specified: if pkg_image_used: error( _("No image rooted at '{0}' " "(set by $PKG_IMAGE)").format(e.user_dir)) else: error(_("No image rooted at '{0}'").format(e.user_dir)) else: error(_("No image found.")) return 1 except api_errors.PermissionsException as e: error(e) return 1 except api_errors.ImageFormatUpdateNeeded as e: # This should be a very rare error case. format_update_error(e) return 1 try: pkg_deps, errs, unused_fmris, external_deps = \ dependencies.resolve_deps(manifest_paths, api_inst, system_patterns, prune_attrs=not verbose) except (actions.MalformedActionError, actions.UnknownActionError) as e: error( _("Could not parse one or more manifests because of " "the following line:\n{0}").format(e.actionstr)) return 1 except dependencies.DependencyError as e: error(e) return 1 except api_errors.ApiException as e: error(e) return 1 ret_code = 0 if output_to_screen: ret_code = pkgdeps_to_screen(pkg_deps, manifest_paths, echo_manifest) elif out_dir: ret_code = pkgdeps_to_dir(pkg_deps, manifest_paths, out_dir, suffix, echo_manifest) else: ret_code = pkgdeps_in_place(pkg_deps, manifest_paths, suffix, echo_manifest) if extra_external_info: if constraint_files and unused_fmris: msg( _("\nThe following fmris matched a pattern in a " "constraint file but were not used in\ndependency " "resolution:")) for pfmri in sorted(unused_fmris): msg("\t{0}".format(pfmri)) if not constraint_files and external_deps: msg(_("\nThe following fmris had dependencies resolve " "to them:")) for pfmri in sorted(external_deps): msg("\t{0}".format(pfmri)) for e in errs: if ret_code == 0: ret_code = 1 emsg(e) return ret_code
def execute(self, dry_run=False): ''' The AbstractCheckpoint class requires this method in sub-classes. Parameters: - the dry_run keyword paramater. The default value is False. If set to True, the log message describes the checkpoint tasks. Returns: - Nothing On failure, errors raised are managed by the engine. ''' # Variable used to store the result of a pkg api plan_uninstall pkg_rval = False # List to hold requested packages to be removed pkg_rm_node = [] # Dictionary and lists used to hold the results of package info check # for packages in the list of packages requested for removal pkg_ret_info = {} pkgs_found = [] pkgs_notfound = [] pkgs_illegal = [] # Variables used to check for valid packages info_local = True info_needed = api.PackageInfo.ALL_OPTIONS # The software node containing packages, directories and files that # need removal soft_list = None self.logger.debug('ICT current task: cleanup install') # parse_doc populates variables necessary to execute the checkpoint self.parse_doc() # For GRUB2 based media there is a .volsetid derived ident file that # identifies the root of the image during GRUB2 configuration. It # needs to be removed from the target if present. # eg. if the contents of .volsetid are "ABC-123" then the ident file # name will be (dot)volsetid: ".ABC-123" volsetid = None if VOLSETID in self.cleanup_list: vpath = os.path.join(self.target_dir, VOLSETID) with open(vpath, 'r') as vpath_fh: volsetid = vpath_fh.read().strip() if volsetid and \ os.path.exists(os.path.join(self.target_dir, '.' + volsetid)): self.cleanup_list.append('.' + volsetid) # Get the list of install specific items that need to be removed. # Check for both IPS packages and files and directories # If no items are designated, an empty list is returned. soft_list = self.doc.get_descendants(name=self.name, class_type=Software) if soft_list: soft_node = soft_list[0] # Get the list of install specific packages that need to # be removed. try: pkg_rm_node = soft_node.get_children(class_type=IPSSpec)[0] except IndexError: # No IPS packages have been specified pass # Get the list of install specific files that need to be removed. try: file_rm_node = soft_node.get_children(class_type=CPIOSpec)[0] self.cleanup_list.extend(file_rm_node.contents) except IndexError: # No additional CPIO contents have been specified pass # Create the mnttab file self.logger.debug('Executing: Create /etc/mnttab file') if not dry_run: mnttab = os.path.join(self.target_dir, ICT.MNTTAB) mnttab_dir = os.path.dirname(mnttab) # Create the directory that holds the mnttab file, # if it does not exist. if not os.access(mnttab_dir, os.F_OK): os.makedirs(mnttab_dir) # Create the mnttab file if it does not exist. if not os.access(mnttab, os.F_OK): open(mnttab, 'w').close() os.chmod(mnttab, S_IREAD | S_IRGRP | S_IROTH) # Remove and miscellaneous directories used as work areas self.logger.debug('Executing: Remove miscellaneous work directories ' 'from /var/tmp') for root, dirs, files in os.walk(os.path.join(self.target_dir, 'var/tmp'), topdown=False): for name in files: self.logger.debug('Removing %s', name) if not dry_run: os.unlink(os.path.join(root, name)) for work_dir in dirs: self.logger.debug('Removing %s', work_dir) if not dry_run: os.rmdir(os.path.join(root, work_dir)) self.logger.debug('Executing: Remove miscellaneous work directories ' 'from /mnt') for root, dirs, files in os.walk(os.path.join(self.target_dir, 'mnt'), topdown=False): for name in files: self.logger.debug('Removing %s', name) if not dry_run: os.unlink(os.path.join(root, name)) for work_dir in dirs: self.logger.debug('Removing %s', work_dir) if not dry_run: os.rmdir(os.path.join(root, work_dir)) if not dry_run: try: api_inst = api.ImageInterface( self.target_dir, PKG5_API_VERSION, InstallCLIProgressTracker(self.logger), None, ICT.PKG_CLIENT_NAME) except api_errors.VersionException, ips_err: raise ValueError("The IPS API version specified, " + str(ips_err.received_version) + " does not agree with " "the expected version, " + str(ips_err.expected_version))