def _validate_children()

in tools/plisttool/plisttool.py [0:0]


  def _validate_children(plist, child_plists, child_required_values, target):
    """Validates a target's plist is consistent with its children.

    This function checks each of the given child plists (which are typically
    extensions or sub-apps embedded in another application) and fails the build
    if there are any issues.

    Args:
      plist: The final plist of the target being built.
      child_plists: The plists of child targets that the target being built
          depends on.
      child_required_values: Mapping of any key/value pairs to validate in
          the children.
      target: The name of the target being processed.
    Raises:
      PlistToolError: if there was an inconsistency between a child target's
          plist and the current target's plist, with a message describing what
          was incorrect.
    """
    if child_required_values is None:
      child_required_values = dict()

    prefix = plist['CFBundleIdentifier'] + '.'
    version = plist.get('CFBundleVersion')
    short_version = plist.get('CFBundleShortVersionString')

    for label, p in child_plists.items():
      child_plist = PlistIO.get_dict(p, target)

      child_id = child_plist['CFBundleIdentifier']
      if not child_id.startswith(prefix):
        raise PlistToolError(CHILD_BUNDLE_ID_MISMATCH_MSG % (
            target, label, prefix, child_id))

      # - TN2420 calls out CFBundleVersion and CFBundleShortVersionString
      #   has having to match for watchOS targets.
      #   https://developer.apple.com/library/content/technotes/tn2420/_index.html
      # - The Application Loader (and Xcode) have also given errors for
      #   iOS Extensions that don't share the same values for the two
      #   version keys as they parent App. So we enforce this for all
      #   platforms just to be safe even though it isn't otherwise
      #   documented.
      #   https://stackoverflow.com/questions/30441750/use-same-cfbundleversion-and-cfbundleshortversionstring-in-all-targets

      child_version = child_plist.get('CFBundleVersion')
      if version != child_version:
        raise PlistToolError(CHILD_BUNDLE_VERSION_MISMATCH_MSG % (
            target, 'CFBundleVersion', label, version, child_version))

      child_version = child_plist.get('CFBundleShortVersionString')
      if short_version != child_version:
        raise PlistToolError(CHILD_BUNDLE_VERSION_MISMATCH_MSG % (
            target, 'CFBundleShortVersionString', label, short_version,
            child_version))

      required_info = child_required_values.get(label, [])
      for pair in required_info:
        if not isinstance(pair, list) or len(pair) != 2:
          raise PlistToolError(REQUIRED_CHILD_NOT_PAIR % (target, label, pair))

        [key_path, expected] = pair
        value = GetWithKeyPath(child_plist, key_path)
        if value is None:
          key_path_str = ":".join([str(x) for x in key_path])
          raise PlistToolError(REQUIRED_CHILD_KEYPATH_NOT_FOUND % (
              target, label, key_path_str, expected))

        if value != expected:
          key_path_str = ":".join([str(x) for x in key_path])
          raise PlistToolError(REQUIRED_CHILD_KEYPATH_NOT_MATCHING % (
              target, label, key_path_str, expected, value))

    # Make sure there wasn't anything listed in required that wasn't listed
    # as a child.
    for label in child_required_values.keys():
      if label not in child_plists:
        raise PlistToolError(REQUIRED_CHILD_MISSING_MSG % (target, label))