def pbxobj_set_pbxlist_attr(obj, objclass, attr, value, validator): """ obj.attr is type of [PBXBaseObject] """ assert value is None or func.isseq(value) value = value if not value is None else [] oldvalue = getattr(obj, attr, None) if not oldvalue is None: for oldv in oldvalue: oldv.remove_referrer(obj) if not value is None: rejects = [] if func.isseq(value): value, rejects = func.filter_items(validator, value) else: value, rejects = ([], value) if len(rejects) > 0: logger.warn(u'{obj} ignore invalid {attr}:\n\t{v}'\ .format(obj=obj, attr=attr[len(pbxconsts.PBX_ATTR_PREFIX):], \ v='\n\t'.join([str(v) for v in rejects]))) super(objclass, obj).__setattr__(attr, value) for v in value: v.add_referrer(obj, attr)
def __dispatch(obj): if func.isseq(obj): return __canonical_list(list(obj)) elif func.isdict(obj): return __canonical_dict(obj) else: return __canonical_obj(obj)
def __setattr__(self, name, value): if name == u'pbx_buildConfigurationList': pbxhelper.pbxobj_set_pbxobj_attr(self, PBXProject, name, value, \ lambda o:isinstance(o, baseobject.PBXBaseObject) and o.isa == 'XCConfigurationList') elif name in [u'pbx_mainGroup', u'pbx_productRefGroup']: pbxhelper.pbxobj_set_pbxobj_attr(self, PBXProject, name, value, \ lambda o:isinstance(o, baseobject.PBXBaseObject) and o.isa == 'PBXGroup') elif name == u'pbx_targets': pbxhelper.pbxobj_set_pbxlist_attr(self, PBXProject, name, value, self.is_valid_target) elif name == u'pbx_projectReferences': self.__set_project_references(value) elif name == u'pbx_attributes': if not func.isdict(value): value = dict() super(PBXProject, self).__setattr__(name, value) elif name == u'pbx_knownRegions': if not func.isseq(value): value = [value] super(PBXProject, self).__setattr__(name, value) else: super(PBXProject, self).__setattr__(name, value)
def __set_project_references(self, value): if not func.isseq(value): return value, rejects = func.filter_items(self.is_valid_project_reference, value) if len(rejects) > 0: logger.warn(u'{0} ignore invalid project reference:\n\t{1}'\ .format(self, u'\n\t'.join(map(lambda o: str(o), rejects)))) super(PBXProject, self).__setattr__(u'pbx_projectReferences', value)
def __recursively_check_and_replace(obj, keys, oldval, newval): if isinstance(obj, PBXBaseObject): __recursively_check_and_replace(obj.__dict__, keys, oldval, newval) elif func.isseq(obj): __replace_array_item(obj, keys, oldval, newval) elif func.isdict(obj): k = keys.pop(0) v = obj.get(k) if isinstance(v, PBXBaseObject) and v.guid == oldval.guid: if newval is None: obj.pop(k, None) else: obj[k] = newval newval.add_referrer(self, keypath) v.remove_referrer(self) elif func.isdict(v): assert len(keys) > 0 __recursively_check_and_replace(v, keys, oldval, newval) elif func.isseq(v): __replace_array_item(v, keys, oldval, newval)
def __parse_dict_attr_val(self, dic, pbxkey): for k, v in dic.items(): depkey = u'{0}.{1}'.format(pbxkey, k) if func.isstr(v) and pbxhelper.is_valid_guid(v): obj = self.project().get_object(v) if not obj is None: obj.add_referrer(self, depkey) dic[k] = obj else: dic[k] = v elif func.isseq(v): dic[k] = self.__parse_arr_attr_val(v, depkey) elif func.isdict(v): self.__parse_dict_attr_val(v, depkey)
def add_array_build_settings(self, name, value): """ add values to an existed settings. If the value is already exists, ignore. The value of setting is type of list, eg: HEADER_SEARCH_PATHS = ( /usr/include, /usr/local/include, }; examples: add_array_build_settings('HEADER_SEARCH_PATHS', '../thirdparty') => HEADER_SEARCH_PATHS = ( /usr/include, /usr/local/include, ../thirdparty, }; add_array_build_settings('HEADER_SEARCH_PATHS', \ ['../thirdparty', '/usr/include']) => HEADER_SEARCH_PATHS = ( /usr/include, /usr/local/include, ../thirdparty, }; @param name the setting name @param value str or [str] """ settingval = self.get_build_setting(name, default=[]) arr = [] if func.isseq(value): arr.extend(value) else: arr.append(str(value)) for v in arr: if not v in settingval: settingval.append(v) count = len(settingval) if count == 0: settingval = '' elif count == 1: settingval = str(settingval[0]) self.pbx_buildSettings[name] = settingval
def parse(self, objdict): """ parse object attribute values from 'objdict' """ objdict.pop(u'isa', None) for key in objdict.keys(): value = objdict.pop(key) pbxkey = u'pbx_{name}'.format(name=key) if func.isseq(value): newarr = self.__parse_arr_attr_val(value, pbxkey) setattr(self, pbxkey, newarr) elif func.isdict(value): self.__parse_dict_attr_val(value, pbxkey) setattr(self, pbxkey, value) else: self.__parse_str_attr(pbxkey, value)
def _print_value(self, buff, val, identstr, singleline=False): from xcodeproj.pbxproj import baseobject # self.safely_write(buff, u'') if func.isdict(val): pairs = sorted(val.items(), key=lambda e: e) self._print_pairs(buff, pairs, identstr, singleline) elif func.isseq(val): self._print_list(buff, val, identstr, singleline) elif isinstance(val, baseobject.PBXBaseObject): self.safely_write(buff, pbxhelper.pbxstr_escape(val.guid)) comment = val.comment() if not comment is None: self.safely_write(buff, u' /* {comment} */'.format(comment=comment)) else: self.safely_write(buff, pbxhelper.pbxstr_escape(val))
def __parse_arr_attr_val(self, arr, pbxkey): newarr = [] for val in arr: if func.isstr(val) and pbxhelper.is_valid_guid(val): obj = self.project().get_object(val) if not obj is None: obj.add_referrer(self, pbxkey) newarr.append(obj) else: newarr.append(val) # error? elif func.isseq(val): newarr.append(self.__parse_arr_attr_val(val, pbxkey)) elif func.isdict(val): self.__parse_dict_attr_val(val, pbxkey) newarr.append(val) else: newarr.append(val) return newarr
def __validate_project_references(self, resolved, issues): prodrefs = self.pbx_projectReferences if not prodrefs is None: if not func.isseq(prodrefs): issues.append(u'illegal projectReferences: {ref}'.format(ref=prodrefs)) else: for refdict in list(prodrefs): if not self.is_valid_project_reference(refdict): prodrefs.remove(refdict) for obj in [refdict.get(u'ProductGroup'), refdict.get(u'ProjectRef')]: if not obj is None: obj.remove_referrer(self) issues.append(u'remove invalid projectReference:{ref}'.format(ref=refdict)) continue for obj in [refdict.get(u'ProductGroup'), refdict.get(u'ProjectRef')]: try: obj.validate() except baseobject.PBXValidationError as e: self.remove_project_reference(refdict) resolved.append(u'remove invalid projectReference:{ref}; {ex}'\ .format(ref=obj, ex=e))
def add_str_build_settings(self, name, value, seperator=' '): """ add values to an existed settings. If the value is already exists, ignore. The value of setting is a str, eg: VALID_ARCHS = "armv7 arm64"; examples: add_str_build_settings('VALID_ARCHS', 'armv7s') => VALID_ARCHS = "armv7 arm64 armv7s"; add_str_build_settings('VALID_ARCHS', ['i386', 'x86_64']) => VALID_ARCHS = "armv7 arm64 i386 x86_64"; add_str_build_settings('VALID_ARCHS', ['armv7s', 'arm64']) => VALID_ARCHS = "armv7 arm64 armv7s"; @param name the setting name @param value str or [str] @param seperator the seperator of items in setting value """ arr = [] if func.isseq(value): arr = list(value) elif not value is None: arr = [str(value)] settingval = self.get_build_setting(name, default='') for v in arr: if v is None: continue if settingval == v or func.hasprefix(settingval, v + seperator): continue if func.hassubfix(settingval, seperator + v): continue if seperator + v + seperator in settingval: continue settingval += seperator + v self.pbx_buildSettings[name] = settingval
def deduplicate_paths(self, paths): """ return deduplicate paths complete and normalize the paths, deduplicate the result """ if func.isstr(paths): return paths if not func.isseq(paths): return u'' path_dict = dict() for path in paths: normpath = path while func.hasprefix(normpath, '"') and func.hassubfix( normpath, '"'): normpath = normpath[1:len(normpath) - 1] normpath = pbxpath.normalize_path(normpath) realpath = pbxpath.realpath(self.project(), normpath) if realpath in path_dict: continue if not func.hassubfix(realpath, os.sep + '**'): p = os.path.join(realpath, '**') if p in path_dict: continue else: p = realpath[0:len(realpath) - len(os.sep + '**')] path_dict.pop(p, None) path_dict[realpath] = (path, normpath) return [ p[1] for p in sorted(path_dict.values(), key=lambda p: paths.index(p[0])) ]