Beispiel #1
0
def generate_to_install_spls(id_repository, mspl, feature_list):
    """
	translate the output of the solver into a system to install (mapping from spl names to use flag selection)
	:param id_repository: the id repository of hyportage
	:param mspl: the mspl of hyportage
	:param feature_list: the solution found by the solver
	:return: a dictionary spl_name -> use flag selection
	"""
    # 1. translate the computed solution into a configuration
    res_core = core_data.dictSet()
    use_flags = []
    for feature in feature_list:
        el = id_repository.data_from_id(feature)
        if el[0] == "package":  # el = ("package", spl_name)
            res_core.add_key(el[1])
        else:  # el = ("use", use, spl_name)
            use_flags.append((el[1], el[2]))
    for use_flag, spl_name in use_flags:
        if spl_name in res_core:
            res_core.add(spl_name, use_flag)

    # 2. compares the computed solution to the actual spl use flag configuration, and generate the final configuration
    res = core_data.dictSet()
    for spl_name, use_selection_core in res_core.iteritems():
        spl = mspl[spl_name]
        if spl.use_selection_core == use_selection_core:
            res[spl_name] = spl.use_selection_full
        else:
            annex_use_flags = spl.use_selection_full - spl.iuses_core
            res[spl_name] = use_selection_core | annex_use_flags
    return res
def load_packages_file(filename):
    res = core_data.dictSet()
    for line in parse_configuration_file(filename):
        if line[0] == "*":
            res.add("system", core_data.pattern_create_from_atom(line[1:]))
        else:
            res.add("profile", core_data.pattern_create_from_atom(line))
    return res
	def __init__(
			self, eapi, name, core, deprecated,
			iuses_default, use_manipulation_default,  fm_local, fm_combined,
			keyword_set, license):
		"""
		The constructor of the class
		:param eapi: the EAPI of the spl/package. This information is necessary to compute the full list of use flags of the package
		:param name: the full name of the package, including its category, version and revision if present
		:param core: the core data of the package, as defined in core_data.py. it's the split of the package name into relevant information for pattern matching
		:param deprecated: boolean stating if the package is deprecated (i.e., is installed but not part of the portage tree anymore)
		:param iuses_default: the use flags declared in the IUSE variable (without the implicit ones from the profile)
		:param use_manipulation_default: the use manipulation declared in the IUSE variable
		:param fm_local: the AST corresponding to the USE_REQUIRED variable
		:param fm_combined: the AST corresponding to the conjunction of the DEPEND, RDEPEND and PDEPEND variables
		:param keyword_set: the keywords of the package
		:param license: the licence of the package
		"""
		#######################
		# core data
		self.eapi                     = eapi
		self.name                     = name
		self.core                     = core
		self.is_deprecated               = deprecated
		#######################
		# feature model
		self.iuses_default            = iuses_default             # list of features declared in this spl by default
		self.use_manipulation_default = use_manipulation_default  # default use selection
		self.fm_local                 = fm_local                  # the part of the feature model related to local features, i.e., portage's REQUIRED_USE
		self.fm_combined              = fm_combined               # the part of the feature model relatd to external dependencies, i.e., portage's DEPEND + RDEPEND + PDEPEND
		##
		self.__dependencies            = None                     # mapping from pattern dependencies to list of features they must have declared
		self.__revert_dependencies     = core_data.dictSet()      # which patterns refer to this SPL, with which features
		self.__required_iuses_local    = None                     # list of local features mentioned in local constraints
		self.__required_iuses          = None                     #
		self.__iuses_full              = None                     # full use flag list
		self.__iuses_visible           = None                     # visible use flag list
		self.__iuses_core              = None                     # use flag that are relevant in the constraints
		self.__use_selection_full      = None                     # selected product of this SPL
		self.__use_selection_core      = None                     # selected product of this SPL, only considering the use flags relevant for the constraints
		#######################
		# SMT
		self.__smt_constraint          = None                     # translation of the full feature model into z3 constraints
		#######################
		# visibility
		self.keyword_set             = keyword_set                # list of architectures valid for this SPL
		self.license                 = license                    # the licence of this SPL
		##
		self.__unmasked                = None                     # if portage states that this spl is masked or not
		self.__unmasked_keyword        = None                     # if the keyword configuration of this package masks it
		self.__unmasked_license        = None                     # if the licence configuration of this package masks it
		self.__installable             = None                     # if this package is installable
		self.__is_stable               = None                     # if this package is stable
		#######################
		# graph traversal
		self.visited = False
		#######################
		# initial setup
		self.generate_dependencies_and_requirements()
	def __init__(self, name):
		"""
		The constructor of the class
		:param group_name: the name of the group
		:param spl: the first spl known to be part of this group
		"""
		self.name = name                            # name of the group
		self.spls = []                              # the spls of this group
		self.slots_mapping = core_data.dictSet()    # mapping listings all spls stored in one slot
		self.__smt_constraint = None                # z3 constraint encoding this group
def load_installed_packages():
    data = core_data.dictSet()
    for directory in os.listdir(input_dir_portage_installed):
        path = os.path.join(input_dir_portage_installed, directory)
        for package in os.listdir(path):
            package_name = directory + "/" + package
            #print("looking at " + package_name)
            complete_path = os.path.join(path, package)
            uses = load_installed_package_uses(complete_path)
            data.set(package_name, uses)
    return data
Beispiel #6
0
###############################
# HYPORTAGE AND CONFIG DATA

# hyportage data
hyportage_db_loaded = False
id_repository = hyportage_ids.id_repository_create()
pattern_repository = hyportage_pattern.pattern_repository_create()
mspl = hyportage_data.mspl_create()
spl_groups = hyportage_data.spl_groups_create()

# configuration data
config_db_loaded = False
config = core_data.Config()
mspl_config = core_data.MSPLConfig()
keyword_list = []
installed_packages = core_data.dictSet()
world = set()

# annex info
simplify_mode = "individual"

###############################
# LOAD FUNCTIONS


def load_config(path=config_db_path_default,
                save_modality=config_db_save_modality_default):
    global config_db_loaded
    global config, mspl_config, keyword_list, installed_packages, world
    utils.phase_start("Loading the hyportage config.")
    if not config_db_loaded:
	def __init__(self):
		super(hyportage_constraint_ast.ASTVisitor, self).__init__()
		self.local = set()
		self.dependencies = core_data.dictSet()
		self.pattern = None
def get_user_configuration(environment):
    # first is loaded the profile, which is then updated with local definitions
    # 1. package.use
    files_package_use = get_user_configuration_files_in_path(
        os.path.join(input_dir_user_configuration, "package.use"))
    pattern_use_selection = core_data.SetManipulationPattern()
    for filename in files_package_use:
        pattern_use_selection.update(load_package_use_file(filename))

    # 2. package.accept_keywords / package.keywords
    files_package_accept_keywords = get_user_configuration_files_in_path(
        os.path.join(input_dir_user_configuration, "package.accept_keywords"))
    pattern_accept_keywords = core_data.SetManipulationPattern()
    for filename in files_package_accept_keywords:
        pattern_accept_keywords.update(load_package_keywords_file(filename))

    files_package_keywords = get_user_configuration_files_in_path(
        os.path.join(input_dir_user_configuration, "package.keywords"))
    pattern_keywords = core_data.SetManipulationPattern()
    for filename in files_package_keywords:
        pattern_keywords.update(load_package_keywords_file(filename))

    # 3. package.mask / package.unmask
    files_package_mask = get_user_configuration_files_in_path(
        os.path.join(input_dir_user_configuration, "package.mask"))
    pattern_mask = core_data.PatternListManipulation()
    for filename in files_package_mask:
        pattern_mask.update(load_package_mask_file(filename))

    files_package_unmask = get_user_configuration_files_in_path(
        os.path.join(input_dir_user_configuration, "package.unmask"))
    pattern_unmask = core_data.PatternListManipulation()
    for filename in files_package_unmask:
        pattern_unmask.update(load_package_mask_file(filename))

    # 6. sets
    location_sets = os.path.join(input_dir_user_configuration, "sets")
    pattern_required = core_data.dictSet()
    if os.path.isdir(location_sets):
        for filename in os.listdir(location_sets):
            for line in parse_configuration_file(
                    os.path.join(location_sets, filename)):
                pattern_required.add(filename,
                                     core_data.pattern_create_from_atom(line))

    # 7. local profile
    location_local_profile = os.path.join(input_dir_user_configuration,
                                          "profile")
    if os.path.isdir(location_local_profile):
        environment, config = load_profile_layer(location_local_profile,
                                                 environment)
        config.update_pattern_use(pattern_use_selection)
        config.update_pattern_required(pattern_required)
        config.update_pattern_mask(pattern_mask)
        config.update_pattern_unmask(pattern_unmask)
        config.update_pattern_accept_keywords(pattern_accept_keywords)
        config.update_pattern_keywords(pattern_keywords)
    else:
        use_selection_config = core_data.UseSelectionConfig(
            pattern_use=pattern_use_selection)
        config = core_data.MSPLConfig(
            use_selection_config=use_selection_config,
            pattern_required=pattern_required,
            pattern_mask=pattern_mask,
            pattern_unmask=pattern_unmask,
            pattern_accept_keywords=pattern_accept_keywords,
            pattern_keywords=pattern_keywords)

    return environment, config
def load_profile_layer(path, environment):
    #######################
    # use* files
    # use.force
    path_use_force = os.path.join(path, "use.force")
    use_force = load_use_file(path_use_force)
    # use.mask
    path_use_mask = os.path.join(path, "use.mask")
    use_mask = load_use_file(path_use_mask)
    # use.stable.force
    path_use_stable_force = os.path.join(path, "use.stable.force")
    use_stable_force = load_use_file(path_use_stable_force)
    # use.stable.mask
    path_use_stable_mask = os.path.join(path, "use.stable.mask")
    use_stable_mask = load_use_file(path_use_stable_mask)
    #######################
    # package.use* files
    # package.use
    path_package_use = os.path.join(path, "package.use")
    package_use = load_package_use_file(path_package_use)
    # package.use.force
    path_package_use_force = os.path.join(path, "package.use.force")
    package_use_force = load_package_use_file(path_package_use_force)
    # package.use.mask
    path_package_use_mask = os.path.join(path, "package.use.mask")
    package_use_mask = load_package_use_file(path_package_use_mask)
    # package.use.stable.force
    path_package_use_stable_force = os.path.join(path,
                                                 "package.use.stable.force")
    package_use_stable_force = load_package_use_file(
        path_package_use_stable_force)
    # package.use.stable.mask
    path_package_use_stable_mask = os.path.join(path,
                                                "package.use.stable.mask")
    package_use_stable_mask = load_package_use_file(
        path_package_use_stable_mask)
    #######################
    # make.defaults file
    path_make_defaults = os.path.join(path, "make.defaults")
    if os.path.exists(path_make_defaults):
        new_environment, info = load_make_defaults(path_make_defaults,
                                                   environment)
        make_defaults_use_selection = info[0]
        make_defaults_use_declaration_eapi4, make_defaults_use_declaration_eapi5 = info[
            1], info[2]
        make_defaults_use_declaration_hidden_from_user = info[3]
        make_defaults_arch, make_defaults_accept_keywords = info[4], info[5]
        make_defaults_use_declaration_eapi4.update(use_force.get_elements())
        make_defaults_use_declaration_eapi4.update(use_mask.get_elements())
        make_defaults_use_declaration_eapi4.update(
            core_data.SetManipulation().add_all(
                new_environment.get('BOOTSTRAP_USE',
                                    "").split()).get_elements())
    else:
        new_environment = environment
        make_defaults_use_selection = core_data.SetManipulation()
        make_defaults_use_declaration_eapi4, make_defaults_use_declaration_eapi5 = set(
        ), set()
        make_defaults_use_declaration_hidden_from_user = set()
        make_defaults_arch, make_defaults_accept_keywords = None, core_data.SetManipulation(
        )
    #######################
    # packages (required patterns)
    path_package_required = os.path.join(path, "packages")
    package_required = core_data.dictSet()
    if os.path.exists(path_package_required):
        for line in parse_configuration_file(path_package_required):
            if line[0] == "*":
                package_required.add(
                    "system", core_data.pattern_create_from_atom(line[1:]))
            else:
                package_required.add("profile",
                                     core_data.pattern_create_from_atom(line))
    #######################
    # package.provided (packages implicitly provided)
    path_package_provided = os.path.join(path, "package.provided")
    if os.path.exists(path_package_provided):
        package_provided = set(parse_configuration_file(path_package_provided))
    else:
        package_provided = set()
    #######################
    # package.mask and package.unmask (packages masking)
    path_package_mask = os.path.join(path, "package.mask")
    package_mask = load_package_mask_file(path_package_mask)
    path_package_unmask = os.path.join(path, "package.unmask")
    package_unmask = load_package_mask_file(path_package_unmask)
    #######################
    # package.keywords or package.accept_keywords
    path_package_keywords = os.path.join(path, "package.keywords")
    package_keywords = load_package_keywords_file(path_package_keywords)
    path_package_accept_keywords = os.path.join(path,
                                                "package.accept_keywords")
    package_accept_keywords = load_package_keywords_file(
        path_package_accept_keywords)

    #######################
    # return the result
    res_use_selection_config = core_data.UseSelectionConfig(
        make_defaults_use_selection, use_force, use_mask, use_stable_force,
        use_stable_mask, package_use, package_use_force, package_use_mask,
        package_use_stable_force, package_use_stable_mask)
    res = core_data.MSPLConfig(make_defaults_arch,
                               make_defaults_use_declaration_eapi4,
                               make_defaults_use_declaration_eapi5,
                               make_defaults_use_declaration_hidden_from_user,
                               res_use_selection_config, package_required,
                               package_provided, package_mask, package_unmask,
                               make_defaults_accept_keywords, package_keywords,
                               package_accept_keywords)
    return new_environment, res
Beispiel #10
0
def generate_installation_files(mspl, path_emerge_script,
                                path_use_flag_configuration,
                                path_mask_configuration,
                                path_keywords_configuration, old_installation,
                                new_installation):
    """
	This function generates two files:
	1. the script file to execute to install and uninstall the spls found by the solver
	2. spl configuration file (usually package.use) from the solution found by the solver
	:param mspl: the mspl of hyportage
	:param path_emerge_script: path to the script file to generate
	:param path_use_flag_configuration: path to the configuration file to generate
	:param path_mask_configuration: the path to the unmask file to generate
	:param path_keywords_configuration: the path to the accept_keywords file to generate
	:param old_installation: the currently installed spls
	:param new_installation: the spls to install, found by the solver
	:return: None (but the script file has been generated)
	"""

    # the spls to emerge are the ones that are not present in the old installation, or that have a new configuration
    added_spl_names = []
    for spl_name, product in new_installation.iteritems():
        if spl_name in old_installation:
            if old_installation[spl_name] != product:
                added_spl_names.append(spl_name)
        else:
            added_spl_names.append(spl_name)

    # the spls to remove are the ones that are not in the new configuration and that are not replaced by a new version
    removed_spl_names = []
    new_spl_goups_info = core_data.dictSet()
    for spl_name in new_installation.iterkeys():
        spl = mspl[spl_name]
        new_spl_goups_info.add(core_data.spl_core_get_spl_group_name(spl.core),
                               spl)
    for spl_name in old_installation.iterkeys():
        spl = mspl[spl_name]
        new_versions = new_spl_goups_info.get(
            core_data.spl_core_get_spl_group_name(spl.core))
        if new_versions is None:
            removed_spl_names.append(spl_name)
        else:
            replaced = False
            for new_spl in new_versions:
                if (spl.slot == new_spl.slot) and (spl.name != new_spl.name):
                    replaced = True
                    break
            if replaced: removed_spl_names.append(spl_name)

    # write the files
    added_spl_names.sort()
    with open(path_emerge_script, 'w') as f:
        f.write("#!/bin/bash\n")
        f.write("\n")
        f.write("# File auto-generated by the hyportage tool\n")
        f.write(
            "# Do not update, any modification on this file will will overwritten by the tool\n"
        )
        f.write("\n")
        if added_spl_names:
            f.write("emerge -p --newuse " +
                    " ".join(["=" + spl_name
                              for spl_name in added_spl_names]) + "\n")
        if removed_spl_names:
            f.write(
                "emerge -p --unmerge " +
                " ".join(["=" + spl_name
                          for spl_name in removed_spl_names]) + "\n")
        f.write("\n")

    with open(path_use_flag_configuration, 'w') as f:
        f.write("# File auto-generated by the hyportage tool\n")
        f.write(
            "# Do not update, any modification on this file will will overwritten by the tool\n"
        )
        f.write("\n")
        for spl_name in added_spl_names:
            use_selection = new_installation[spl_name]
            string = "=" + spl_name + " "
            string = string + " ".join(use_selection)
            use_unselection = mspl[spl_name].iuses_full - use_selection
            if use_unselection:
                string = string + " -" + " -".join(use_unselection) + "\n"
            f.write(string)
        f.write("\n")

    with open(path_mask_configuration, 'w') as f:
        f.write("# File auto-generated by the hyportage tool\n")
        f.write(
            "# Do not update, any modification on this file will will overwritten by the tool\n"
        )
        f.write("\n")
        for spl_name in added_spl_names:
            f.write("=" + spl_name + "\n")
            #if not mspl[spl_name].unmasked:
            #	f.write("=" + spl_name)
        f.write("\n")

    with open(path_keywords_configuration, 'w') as f:
        f.write("# File auto-generated by the hyportage tool\n")
        f.write(
            "# Do not update, any modification on this file will will overwritten by the tool\n"
        )
        f.write("\n")
        for spl_name in added_spl_names:
            #f.write("=" + spl_name + " ~" + hyportage_db.mspl_config.arch + "\n")
            f.write("=" + spl_name + " **\n")
            #if not mspl[spl_name].unmasked_keyword:
            #	f.write("=" + spl_name + " ~" + hyportage_db.mspl_config.arch)
        f.write("\n")
Beispiel #11
0
def solve_spls(id_repository,
               config,
               mspl,
               spl_groups,
               spls,
               annex_constraint,
               exploration_use,
               exploration_mask,
               exploration_keywords,
               explain_modality=False):
    """
	Solves the spls in input locally assuming that there is a command hyvar-rec
	:param id_repository: the id repository of hyportage
	:param config: the config of hyportage
	:param mspl: the mspl of hyportage
	:param spl_groups: the spl groups of hyportage
	:param spls: the spls to solve
	:param annex_constraint: the additional constraint to add in the solver input
	:param exploration_use: boolean saying if the solver can change the use flag default selection
	:param exploration_mask: boolean saying if the solver can change the use mask status of the packages
	:param exploration_keywords: boolean saying if the solver can change the keywords of the packages
	:param explain_modality: boolean saying if a problem should be explained (by default: False)
	:return: the solution found by the solver, if it exists
	"""
    # 1. construct the input data for the solver
    # 1.1. construct the constraint
    constraint = annex_constraint[:]
    spl_group_names = core_data.dictSet()
    #tmp = 0
    for spl in spls:
        spl_group_names.add(core_data.spl_core_get_spl_group_name(spl.core),
                            spl)
        included = (spl.unmasked
                    or exploration_mask) and (spl.unmasked_keyword
                                              or exploration_keywords)
        if included:
            #tmp = tmp + 1
            constraint.extend(spl.smt)
            if exploration_use:
                constraint.extend(spl.smt_use_exploration)
            else:
                constraint.extend(spl.smt_use_selection)
        else:
            #logging.info("spl \"" + spl.name + "\" is not scheduled for possible installation")
            constraint.extend(spl.smt_false)
    for spl_group_name, spls_tmp in spl_group_names.iteritems():
        spl_group = spl_groups[spl_group_name]
        constraint.extend(spl_group.smt)
        for spl in spl_group:
            if spl not in spls_tmp:
                constraint.append(
                    smt_encoding.smt_to_string(
                        smt_encoding.get_spl_smt_not(id_repository, spl.name)))
    #logging.info("included spl: " + str(tmp))
    logging.debug("number of constraints to solve: " + str(len(constraint)))
    # 1.2. construct the preferences
    spl_names = {spl.name for spl in spls}
    preferences = get_preferences_core(id_repository, mspl,
                                       config.installed_packages, spl_names)
    # 1.3. construct the current system
    current_system = [
    ]  #installed_spls_to_solver(id_repository, installed_spls, spl_names)
    data_configuration = {
        "selectedFeatures": current_system,
        "attribute_values": [],
        "context_values": []
    }  # current configuration
    data_smt_constraints = {
        "formulas": constraint,
        "features": [],
        "other_int_symbols": []
    }
    data = {
        "attributes": [],  # attributes of the features (empty in our case)
        "contexts": [],  # contexts to consider (empty in our case)
        "configuration":
        data_configuration,
        "constraints":
        [],  # constraints to fill in hyvarrec format (empty in our case for efficiency)
        "preferences":
        preferences,  # preferences in hyvarrec format
        "smt_constraints":
        data_smt_constraints,
        "hyvar_options": [
            "--features-as-boolean", "--constraints-minimization",
            "--no-default-preferences"
        ]
    }

    # 2. run hyvar-rec
    res = run_hyvar(data)
    if res is None: return None
    logging.debug("HyVarRec output: " + json.dumps(res))

    # 4. managing the solver output
    if res["result"] != "sat":
        if explain_modality:
            # todo handle explain modality when the answer is unsat
            # try to print a better explanation of the constraints
            constraints = get_better_constraint_visualization(
                id_repository, mspl, res["constraints"])
            logging.error("Conflict detected. Explanation:\n" +
                          "\n".join(constraints) + '\n')
        return None

    return generate_to_install_spls(id_repository, mspl, res['features'])