def get_var_list(self): if self.var_list is None: self.var_list = ConfigVarList() self.var_list.set_var("iid_name").append(self.name) if self.guid: self.var_list.set_var("iid_guid").append(self.guid) if self.remark: self.var_list.set_var("iid_remark").append(self.remark) self.var_list.set_var("iid_inherite").extend(self._inherit_list()) self.var_list.set_var("iid_folder_list").extend(self._folder_list()) self.var_list.set_var("iid_depend_list").extend(self._depend_list()) for action_type in self.action_types: self.var_list.set_var("iid_action_list_"+action_type).extend(self._action_list(action_type)) source_vars_obj = self.var_list.set_var("iid_source_var_list") source_list = self._source_list() for i, source in enumerate(source_list): source_var = "iid_source_"+str(i) source_vars_obj.append(source_var) self.var_list.set_var(source_var).extend(source) return self.var_list
class InstallItem(object): __slots__ = ('iid', 'name', 'guid', 'remark', "description", 'inherit', '__set_for_os', '__items', '__resolved_inherit', 'var_list', 'required_by') os_names = ('common', 'Mac', 'Mac32', 'Mac64', 'Win', 'Win32', 'Win64') allowed_item_keys = ('name', 'guid','install_sources', 'install_folders', 'inherit', 'depends', 'actions', 'remark') allowed_top_level_keys = os_names[1:] + allowed_item_keys action_types = ('pre_copy', 'pre_copy_to_folder', 'pre_copy_item', 'post_copy_item', 'post_copy_to_folder', 'post_copy', 'pre_remove', 'pre_remove_from_folder', 'pre_remove_item', 'remove_item', 'post_remove_item', 'post_remove_from_folder', 'post_remove') file_types = ('!dir_cont', '!files', '!file', '!dir') resolve_inheritance_stack = list() _get_for_os = [ os_names[0]] # _get_for_os is a class member since we usually want to get for same oses for all InstallItems @staticmethod def create_items_section(): retVal = defaultdict(unique_list) return retVal @staticmethod def merge_item_sections(this_items, the_other_items): common_items = set(this_items.keys() + the_other_items.keys()) try: for item in common_items: this_items[item].extend(the_other_items[item]) except TypeError: print("TypeError for", item) raise @staticmethod def begin_get_for_all_oses(): """ adds all known os names to the list of os that will influence all get functions such as depend_list, source_list etc. This is a static method so it will influence all InstallItem objects. This method is useful in code that does reporting or analyzing, where there is need to have access to all oses not just the current or target os. """ InstallItem._get_for_os = [] InstallItem._get_for_os.extend(InstallItem.os_names) @staticmethod def reset_get_for_all_oses(): """ resets the list of os that will influence all get functions such as depend_list, source_list etc. This is a static method so it will influence all InstallItem objects. This method is useful in code that does reporting or analyzing, where there is need to have access to all oses not just the current or target os. """ InstallItem._get_for_os = [InstallItem.os_names[0]] @staticmethod def begin_get_for_specific_os(for_os): """ adds another os name to the list of os that will influence all get functions such as depend_list, source_list etc. This is a static method so it will influence all InstallItem objects. """ InstallItem._get_for_os.append(for_os) @staticmethod def end_get_for_specific_os(): """ removed the last added os name to the list of os that will influence all get functions such as depend_list, source_list etc. This is a static method so it will influence all InstallItem objects. """ InstallItem._get_for_os.pop() def merge_all_item_sections(self, otherInstallItem): for os_ in InstallItem.os_names: InstallItem.merge_item_sections(self.__items[os_], otherInstallItem.__items[os_]) def __init__(self): self.__resolved_inherit = False self.iid = None self.name = "" self.guid = None self.remark = "" self.description = "" self.inherit = unique_list() self.__set_for_os = [InstallItem.os_names[0]] # reading for all platforms ('common') or for which specific platforms ('Mac', 'Win')? self.__items = defaultdict(InstallItem.create_items_section) self.var_list = None self.required_by = unique_list() def read_from_yaml_by_idd(self, IID, all_items_node): my_node = all_items_node[IID] self.iid = IID self.description = str(my_node.start_mark) self.read_from_yaml(my_node) self.iid = IID # restore the IID & description that might have been overwritten by inheritance self.description = str(my_node.start_mark) def read_from_yaml(self, my_node): element_names = set([akey for akey in my_node.iterkeys()]) if not element_names.issubset(self.allowed_top_level_keys): raise KeyError("illegal keys {}; IID: {}, {}".format(list(element_names.difference(self.allowed_top_level_keys)), self.iid, self.description)) if 'inherit' in my_node: inherite_node = my_node['inherit'] for inheritoree in inherite_node: self.add_inherit(inheritoree.value) if 'name' in my_node: self.name = my_node['name'].value if 'guid' in my_node: self.guid = my_node['guid'].value.lower() if 'remark' in my_node: self.remark = my_node['remark'].value if 'install_sources' in my_node: for source in my_node['install_sources']: self.add_source(source.value, source.tag) if 'install_folders' in my_node: for folder in my_node['install_folders']: self.add_folder(folder.value) if 'depends' in my_node: for source in my_node['depends']: self.add_depend(source.value) if 'actions' in my_node: self.read_actions(my_node['actions']) for os_ in InstallItem.os_names[1:]: if os_ in my_node: self.begin_set_for_specific_os(os_) self.read_from_yaml(my_node[os_]) self.end_set_for_specific_os() def get_var_list(self): if self.var_list is None: self.var_list = ConfigVarList() self.var_list.set_var("iid_iid").append(self.iid) if self.name: self.var_list.set_var("iid_name").append(self.name) if self.guid: self.var_list.set_var("iid_guid").append(self.guid) if self.remark: self.var_list.set_var("iid_remark").append(self.remark) self.var_list.set_var("iid_inherit").extend(self._inherit_list()) self.var_list.set_var("iid_folder_list").extend(self._folder_list()) self.var_list.set_var("iid_depend_list").extend(self._depend_list()) for action_type in self.action_types: action_list_for_type = self._action_list(action_type) if len(action_list_for_type) > 0: self.var_list.set_var("iid_action_list_" + action_type).extend(action_list_for_type) source_vars_obj = self.var_list.set_var("iid_source_var_list") source_list = self._source_list() for i, source in enumerate(source_list): source_var = "iid_source_" + str(i) source_vars_obj.append(source_var) self.var_list.set_var(source_var).extend(source) return self.var_list def __enter__(self): var_stack.push_scope(self.get_var_list()) return self def __exit__(self, etype, value, traceback): var_stack.pop_scope() def begin_set_for_specific_os(self, for_os): self.__set_for_os.append(for_os) def end_set_for_specific_os(self): self.__set_for_os.pop() def __add_item_by_os_and_category(self, item_os, item_category, item_value): """ Add an item to one of the oses and category e.g.: __add_item_by_os_and_category("Win", "install_sources", "x.dll") __add_item_by_os_and_category("common", "install_sources", "AudioTrack.bundle") """ self.__items[item_os][item_category].append(item_value) def __add_item_to_default_os_by_category(self, item_category, item_value): """ Add an item to currently default os and category, e.g.: begin_set_for_specific_os("Win") __add_item_to_default_os_by_category("install_sources", "x.dll") self.end_set_for_specific_os() __add_item_to_default_os_by_category("install_sources", "AudioTrack.bundle") The default os is the one at the top of the __set_for_os stack. __set_for_os starts with "common" as the first o. """ self.__add_item_by_os_and_category(self.__set_for_os[-1], item_category, item_value) def __get_item_list_by_os_and_category(self, item_os, item_category): retVal = list() if item_os in self.__items and item_category in self.__items[item_os]: retVal.extend(self.__items[item_os][item_category]) return retVal def __get_item_list_for_default_oses_by_category(self, item_category): retVal = unique_list() for os_name in InstallItem._get_for_os: retVal.extend(self.__get_item_list_by_os_and_category(os_name, item_category)) return retVal def add_inherit(self, inherit_idd): self.inherit.append(inherit_idd) def _inherit_list(self): retVal = self.inherit return retVal def add_source(self, new_source, file_type='!dir'): if file_type not in InstallItem.file_types: file_type = '!dir' if new_source.startswith("/"): # absolute path new_source = new_source[1:] elif new_source.startswith("$("): # explicitly relative to some variable pass else: # implicitly relative to $(SOURCE_PREFIX) new_source = "$(SOURCE_PREFIX)/"+new_source self.__add_item_to_default_os_by_category('install_sources', (new_source, file_type, self.__set_for_os[-1])) def _source_list(self): return self.__get_item_list_for_default_oses_by_category('install_sources') def add_folder(self, new_folder): self.__add_item_to_default_os_by_category('install_folders', new_folder) def _folder_list(self): return self.__get_item_list_for_default_oses_by_category('install_folders') def add_depend(self, new_depend): self.__add_item_to_default_os_by_category('depends', new_depend) def _depend_list(self): return self.__get_item_list_for_default_oses_by_category('depends') def add_action(self, action_type, new_action): if action_type not in InstallItem.action_types: raise KeyError("actions type must be one of: " + str(InstallItem.action_types) + " not " + action_type) self.__add_item_to_default_os_by_category(action_type, new_action) def read_actions(self, action_nodes): for action_type, new_actions in action_nodes: for action in new_actions: self.add_action(action_type, action.value) def _action_list(self, action_type): if action_type not in InstallItem.action_types: raise KeyError("actions type must be one of: " + str(InstallItem.action_types) + " not " + action_type) return self.__get_item_list_for_default_oses_by_category(action_type) def all_action_list(self): """ Get a list of all types of actions, can be used to find how many actions there are. """ retVal = list() for action_type in InstallItem.action_types: retVal.extend(self.__get_item_list_for_default_oses_by_category(action_type)) return retVal def get_recursive_depends(self, items_map, out_set, orphan_set): if self.iid not in out_set: out_set.append(self.iid) # print("get_recursive_depends: added", self.iid) for depend in self._depend_list(): try: # if IID is a guid iids_from_guid will translate to iid's, or return the IID otherwise dependees = iids_from_guid(items_map, depend) for dependee in dependees: items_map[dependee].required_by.append(self.iid) if dependee not in out_set: # avoid cycles, save time items_map[dependee].get_recursive_depends(items_map, out_set, orphan_set) except KeyError: orphan_set.append(depend) #else: # print("get_recursive_depends: already added", self.iid) def repr_for_yaml_items(self, for_which_os): retVal = None if self.__items[for_which_os]: retVal = OrderedDict() if self.__items[for_which_os]['install_sources']: source_list = list() for source in self.__items[for_which_os]['install_sources']: if source[1] != '!dir': source_list.append(augmentedYaml.YamlDumpWrap(value=source[0], tag=source[1])) else: source_list.append(source[0]) retVal['install_sources'] = source_list if self.__items[for_which_os]['install_folders']: retVal['install_folders'] = list(self.__items[for_which_os]['install_folders']) if self.__items[for_which_os]['depends']: retVal['depends'] = list(self.__items[for_which_os]['depends']) for action in InstallItem.action_types: if action in self.__items[for_which_os] and self.__items[for_which_os][action]: actions_dict = retVal.setdefault('actions', OrderedDict()) actions_dict[action] = list(self.__items[for_which_os][action]) return retVal def repr_for_yaml(self): retVal = OrderedDict() retVal['name'] = self.name if self.guid: retVal['guid'] = self.guid if self.remark: retVal['remark'] = self.remark if self.inherit: retVal['inherit'] = self._inherit_list() common_items = self.repr_for_yaml_items(InstallItem.os_names[0]) if common_items: retVal.update(common_items) for os_ in InstallItem.os_names[1:]: os_items = self.repr_for_yaml_items(os_) if os_items: retVal[os_] = os_items return retVal def merge_from_another_InstallItem(self, otherInstallItem): """ merge the contents of another InstallItem """ # self.iid = iid is not merged # self.name = name is not merged # self.guid = guid is not merged # name of the other item is added to the remark if not self.remark: self.remark = self.name self.remark += ", " + otherInstallItem.name self.inherit.update(otherInstallItem.inherit) self.merge_all_item_sections(otherInstallItem) def resolve_inheritance(self, InstallItemsDict): if not self.__resolved_inherit: if self.iid in self.resolve_inheritance_stack: raise Exception("circular resolve_inheritance of " + self.iid) self.resolve_inheritance_stack.append(self.iid) for ancestor in self._inherit_list(): if ancestor not in InstallItemsDict: raise KeyError(self.iid + " inherites from " + ancestor + " which is not in InstallItemsDict") ancestor_item = InstallItemsDict[ancestor] ancestor_item.resolve_inheritance(InstallItemsDict) self.merge_all_item_sections(ancestor_item) self.resolve_inheritance_stack.pop()