# Copyright (c) 2011 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

ANDROID_WHITELISTED_LICENSES = [
  'A(pple )?PSL 2(\.0)?',
  'Apache( Version)? 2(\.0)?',
  '(New )?([23]-Clause )?BSD( [23]-Clause)?( with advertising clause)?',
  'L?GPL ?v?2(\.[01])?( or later)?',
  'MIT(/X11)?(-like)?',
  'MPL 1\.1 ?/ ?GPL 2(\.0)? ?/ ?LGPL 2\.1',
  'MPL 2(\.0)?',
  'Microsoft Limited Public License',
  'Microsoft Permissive License',
  'Public Domain',
  'Python',
  'SGI Free Software License B',
  'University of Illinois\/NCSA Open Source',
  'X11',
]

def LicenseIsCompatibleWithAndroid(input_api, license):
  regex = '^(%s)$' % '|'.join(ANDROID_WHITELISTED_LICENSES)
  tokens = \
    [x.strip() for x in input_api.re.split(' and |,', license) if len(x) > 0]
  has_compatible_license = False
  for token in tokens:
    if input_api.re.match(regex, token, input_api.re.IGNORECASE):
      has_compatible_license = True
      break
  return has_compatible_license

def _CheckThirdPartyReadmesUpdated(input_api, output_api):
  """
  Checks to make sure that README.chromium files are properly updated
  when dependencies in third_party are modified.
  """
  readmes = []
  files = []
  errors = []
  for f in input_api.AffectedFiles():
    local_path = f.LocalPath()
    if input_api.os_path.dirname(local_path) == 'third_party':
      continue
    if (local_path.startswith('third_party' + input_api.os_path.sep) and
        not local_path.startswith('third_party' + input_api.os_path.sep +
                                  'WebKit' + input_api.os_path.sep) and
        not local_path.startswith('third_party' + input_api.os_path.sep +
                                  'mojo' + input_api.os_path.sep) and
        not local_path.startswith('third_party' + input_api.os_path.sep +
                                  'boringssl' + input_api.os_path.sep)):
      files.append(f)
      if local_path.endswith("README.chromium"):
        readmes.append(f)
  if files and not readmes:
    errors.append(output_api.PresubmitPromptWarning(
       'When updating or adding third party code the appropriate\n'
       '\'README.chromium\' file should also be updated with the correct\n'
       'version and package information.', files))
  if not readmes:
    return errors

  name_pattern = input_api.re.compile(
    r'^Name: [a-zA-Z0-9_\-\. \(\)]+\r?$',
    input_api.re.IGNORECASE | input_api.re.MULTILINE)
  shortname_pattern = input_api.re.compile(
    r'^Short Name: [a-zA-Z0-9_\-\.]+\r?$',
    input_api.re.IGNORECASE | input_api.re.MULTILINE)
  version_pattern = input_api.re.compile(
    r'^Version: [a-zA-Z0-9_\-\.:]+\r?$',
    input_api.re.IGNORECASE | input_api.re.MULTILINE)
  release_pattern = input_api.re.compile(
    r'^Security Critical: (yes|no)\r?$',
    input_api.re.IGNORECASE | input_api.re.MULTILINE)
  license_pattern = input_api.re.compile(
    r'^License: (.+)\r?$',
    input_api.re.IGNORECASE | input_api.re.MULTILINE)
  license_android_compatible_pattern = input_api.re.compile(
    r'^License Android Compatible: (yes|no)\r?$',
    input_api.re.IGNORECASE | input_api.re.MULTILINE)

  for f in readmes:
    if 'D' in f.Action():
      _IgnoreIfDeleting(input_api, output_api, f, errors)
      continue

    contents = input_api.ReadFile(f)
    if (not shortname_pattern.search(contents)
        and not name_pattern.search(contents)):
      errors.append(output_api.PresubmitError(
        'Third party README files should contain either a \'Short Name\' or\n'
        'a \'Name\' which is the name under which the package is\n'
        'distributed. Check README.chromium.template for details.',
        [f]))
    if not version_pattern.search(contents):
      errors.append(output_api.PresubmitError(
        'Third party README files should contain a \'Version\' field.\n'
        'If the package is not versioned or the version is not known\n'
        'list the version as \'unknown\'.\n'
        'Check README.chromium.template for details.',
        [f]))
    if not release_pattern.search(contents):
      errors.append(output_api.PresubmitError(
        'Third party README files should contain a \'Security Critical\'\n'
        'field. This field specifies whether the package is built with\n'
        'Chromium. Check README.chromium.template for details.',
        [f]))
    license_match = license_pattern.search(contents)
    if not license_match:
      errors.append(output_api.PresubmitError(
        'Third party README files should contain a \'License\' field.\n'
        'This field specifies the license used by the package. Check\n'
        'README.chromium.template for details.',
        [f]))
    elif not LicenseIsCompatibleWithAndroid(input_api, license_match.group(1)) \
         and not license_android_compatible_pattern.search(contents):
      errors.append(output_api.PresubmitPromptWarning(
        'Cannot determine whether specified license is compatible with\n' +
        'the Android licensing requirements. Please check that the license\n' +
        'name is spelled according to third_party/PRESUBMIT.py. Please see\n' +
        'README.chromium.template for details.',
        [f]))
  return errors


def _IgnoreIfDeleting(input_api, output_api, affected_file, errors):
  third_party_dir = input_api.os_path.dirname(affected_file.LocalPath())
  for f in input_api.AffectedFiles():
    if f.LocalPath().startswith(third_party_dir):
      if 'D' not in f.Action():
        errors.append(output_api.PresubmitError(
          'Third party README should only be removed when the whole\n'
          'directory is being removed.\n', [f, affected_file]))


def CheckChangeOnUpload(input_api, output_api):
  results = []
  results.extend(_CheckThirdPartyReadmesUpdated(input_api, output_api))
  return results
