def _ParseKey(target_object, key): """Parses the key value according target object type. Args: target_object: the target object. key: string, the key of object. Returns: If object is dict, returns key itself. If object is list, returns int(key). Raises: ios_errors.PlistError: when object is list and key is not int, or object is not list/dict. """ if isinstance(target_object, dict): return key if isinstance(target_object, list): try: return int(key) except ValueError: raise ios_errors.PlistError( 'The key %s is invaild index of list(array) object %s.' % (key, target_object)) raise ios_errors.PlistError('The object %s is not dict or list.' % target_object)
def _SetPlistFieldByPlistBuddy(plist_path, field, value): """Set field with provided value in .plist file. Args: plist_path: string, the path of plist file. field: string, the field consist of property key names delimited by colons. List(array) items are specified by a zero-based integer index. Examples :CFBundleShortVersionString :CFBundleDocumentTypes:2:CFBundleTypeExtensions value: a object, the value of the field to be added. It can be integer, bool, string, array, dict. Raises: ios_errors.PlistError: the field does not exist in the .plist file's dict. """ command = [ PLIST_BUDDY, '-c', 'Set :"%s" "%s"' % (field, value), plist_path ] try: subprocess.check_output(command, stderr=subprocess.STDOUT) except subprocess.CalledProcessError as e: raise ios_errors.PlistError('Failed to set field %s in plist %s: %s' % (field, plist_path, e.output))
def _GetPlistFieldByPlistBuddy(plist_path, field): """View specific field in the .plist file by PlistBuddy tool. Args: plist_path: string, the path of plist file. field: string, the field consist of property key names delimited by colons. List(array) items are specified by a zero-based integer index. Examples :CFBundleShortVersionString :CFBundleDocumentTypes:2:CFBundleTypeExtensions Returns: the object of the plist's field. Raises: ios_errors.PlistError: the field does not exist in the plist dict. """ command = [PLIST_BUDDY, '-c', 'Print :"%s"' % field, plist_path] try: return subprocess.check_output(command, stderr=subprocess.STDOUT, text=True).strip() except subprocess.CalledProcessError as e: raise ios_errors.PlistError('Failed to get field %s in plist %s: %s', field, plist_path, e.output)
def _GetObjectWithField(target_object, field): """Gets sub object of the object with field. Args: target_object: the target object. field: string, the field consist of property key names delimited by colons. List(array) items are specified by a zero-based integer index. Examples :CFBundleShortVersionString :CFBundleDocumentTypes:2:CFBundleTypeExtensions Returns: a object of the target object's field. If field is empty, returns the target object itself. Raises: ios_errors.PlistError: the field does not exist in the object or the field is invaild. """ if not field: return target_object current_object = target_object for key in field.split(':'): try: current_object = current_object[_ParseKey(current_object, key)] except ios_errors.PlistError as e: raise e except (KeyError, IndexError): raise ios_errors.PlistError( 'The field %s can not be found in the target object. ' 'The object content is %s' % (field, current_object)) return current_object
def DeletePlistField(self, field): """Delete field in .plist file. Args: field: string, the field consist of property key names delimited by colons. List(array) items are specified by a zero-based integer index. Examples :CFBundleShortVersionString :CFBundleDocumentTypes:2:CFBundleTypeExtensions Raises: ios_errors.PlistError: the field does not exist in the .plist file's dict. """ with open(self._plist_file_path, 'rb') as plist_file: plist_root_object = plistlib.load(plist_file) keys_in_field = field.rsplit(':', 1) if len(keys_in_field) == 1: key = field target_object = plist_root_object else: key = keys_in_field[1] target_object = _GetObjectWithField(plist_root_object, keys_in_field[0]) try: del target_object[_ParseKey(target_object, key)] except ios_errors.PlistError as e: raise e except (KeyError, IndexError): raise ios_errors.PlistError( 'Failed to delete key %s from object %s.' % (key, target_object)) with open(self._plist_file_path, 'wb') as plist_file: plistlib.dump(plist_root_object, plist_file)
def SetPlistField(self, field, value): """Set field with provided value in .plist file. Args: field: string, the field consist of property key names delimited by colons. List(array) items are specified by a zero-based integer index. Examples :CFBundleShortVersionString :CFBundleDocumentTypes:2:CFBundleTypeExtensions value: a object, the value of the field to be added. It can be integer, bool, string, array, dict. Raises: ios_errors.PlistError: the field does not exist in the .plist file's dict. """ if self._plistlib_module is None: _SetPlistFieldByPlistBuddy(self._plist_file_path, field, value) return if not field: self._plistlib_module.writePlist(value, self._plist_file_path) return if os.path.exists(self._plist_file_path): plist_root_object = self._plistlib_module.readPlist( self._plist_file_path) else: plist_root_object = {} keys_in_field = field.rsplit(':', 1) if len(keys_in_field) == 1: key = field target_object = plist_root_object else: key = keys_in_field[1] target_object = _GetObjectWithField(plist_root_object, keys_in_field[0]) try: target_object[_ParseKey(target_object, key)] = value except ios_errors.PlistError as e: raise e except (KeyError, IndexError): raise ios_errors.PlistError( 'Failed to set key %s from object %s.' % (key, target_object)) self._plistlib_module.writePlist(plist_root_object, self._plist_file_path)
def _DeletePlistFieldByPlistBuddy(plist_path, field): """Delete field in .plist file. Args: plist_path: string, the path of plist file. field: string, the field consist of property key names delimited by colons. List(array) items are specified by a zero-based integer index. Examples :CFBundleShortVersionString :CFBundleDocumentTypes:2:CFBundleTypeExtensions Raises: ios_errors.PlistError: the field does not exist in the .plist file's dict. """ command = [PLIST_BUDDY, '-c', 'Delete :"%s"' % field, plist_path] try: subprocess.check_output(command, stderr=subprocess.STDOUT) except subprocess.CalledProcessError as e: raise ios_errors.PlistError( 'Failed to delete field %s in plist %s: %s' % (field, plist_path, e.output))