<commit_before>#!/usr/bin/swift
/*
 * Copyright 2020 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// Utility script for verifying `import` and `include` syntax. This ensures a
// consistent style as well as functionality across multiple package managers.

// For more context, see https://github.com/firebase/firebase-ios-sdk/blob/master/HeadersImports.md.

import Foundation

// Skip these directories. Imports should only be repo-relative in libraries
// and unit tests.
let skipDirPatterns = ["/Sample/", "/Pods/", "FirebaseStorage/Tests/Integration",
                       "FirebaseDynamicLinks/Tests/Integration",
                       "FirebaseInAppMessaging/Tests/Integration/",
                       "Example/InstanceID/App", "SymbolCollisionTest/", "/gen/",
                       "CocoapodsIntegrationTest/", "FirebasePerformance/Tests/TestApp/",
                       "FirebasePerformance/Tests/FIRPerfE2E/"] +
  [
    "CoreOnly/Sources", // Skip Firebase.h.
    "SwiftPMTests", // The SwiftPM imports test module imports.
  ] +

  // The following are temporary skips pending working through a first pass of the repo:
  [
    "FirebaseAppDistribution",
    "FirebaseCore/Sources/Private", // TODO: work through adding this back.
    "Firebase/CoreDiagnostics",
    "FirebaseDatabase/Sources/third_party/Wrap-leveldb", // Pending SwiftPM for leveldb.
    "Example",
    "FirebaseInstallations/Source/Tests/Unit/",
    "Firestore",
    "GoogleUtilitiesComponents",
    "FirebasePerformance/ProtoSupport/",
  ]

// Skip existence test for patterns that start with the following:
let skipImportPatterns = [
  "FBLPromise",
  "OCMock",
  "OCMStubRecorder",
]

private class ErrorLogger {
  var foundError = false
  func log(_ message: String) {
    print(message)
    foundError = true
  }

  func importLog(_ message: String, _ file: String, _ line: Int) {
    log("Import Error: \(file):\(line) \(message)")
  }
}

private func checkFile(_ file: String, logger: ErrorLogger, inRepo repoURL: URL) {
  var fileContents = ""
  do {
    fileContents = try String(contentsOfFile: file, encoding: .utf8)
  } catch {
    logger.log("Could not read \(file). \(error)")
    // Not a source file, give up and return.
    return
  }
  let isPublic = file.range(of: "/Public/") != nil &&
    // TODO: Skip legacy GDTCCTLibrary file that isn't Public and should be moved.
    file.range(of: "GDTCCTLibrary/Public/GDTCOREvent+GDTCCTSupport.h") == nil
  let isPrivate = file.range(of: "/Sources/Private/") != nil ||
    // Delete when FirebaseInstallations fixes directory structure.
    file.range(of: "Source/Library/Private/FirebaseInstallationsInternal.h") != nil ||
    file.range(of: "GDTCORLibrary/Internal/GoogleDataTransportInternal.h") != nil

  // Treat all files with names finishing on "Test" or "Tests" as files with tests.
  let isTestFile = file.contains("Test.m") || file.contains("Tests.m") ||
    file.contains("Test.swift") || file.contains("Tests.swift")
  var inSwiftPackage = false
  var inSwiftPackageElse = false
  let lines = fileContents.components(separatedBy: .newlines)
  var lineNum = 0
  nextLine: for rawLine in lines {
    let line = rawLine.trimmingCharacters(in: .whitespaces)
    lineNum += 1
    if line.starts(with: "#if SWIFT_PACKAGE") {
      inSwiftPackage = true
    } else if inSwiftPackage, line.starts(with: "#else") {
      inSwiftPackage = false
      inSwiftPackageElse = true
    } else if inSwiftPackageElse, line.starts(with: "#endif") {
      inSwiftPackageElse = false
    } else if inSwiftPackage {
      continue
    } else if line.starts(with: "@import") {
      // "@import" is only allowed for Swift Package Manager.
      logger.importLog("@import should not be used in CocoaPods library code", file, lineNum)
    }

    // "The #else of a SWIFT_PACKAGE check should only do CocoaPods module-style imports."
    if line.starts(with: "#import") || line.starts(with: "#include") {
      let importFile = line.components(separatedBy: " ")[1]
      if inSwiftPackageElse {
        if importFile.first != "<" {
          logger
            .importLog("Import in SWIFT_PACKAGE #else should start with \"<\".", file, lineNum)
        }
        continue
      }
      let importFileRaw = importFile.replacingOccurrences(of: "\"", with: "")
        .replacingOccurrences(of: "<", with: "")
        .replacingOccurrences(of: ">", with: "")

      if importFile.first == "\"" {
        // Public Headers should only use simple file names without paths.
        if isPublic {
          if importFile.contains("/") {
            logger.importLog("Public header import should not include \"/\"", file, lineNum)
          }

        } else if !FileManager.default.fileExists(atPath: repoURL.path + "/" + importFileRaw) {
          // Non-public header imports should be repo-relative paths. Unqualified imports are
          // allowed in private headers.
          if !isPrivate || importFile.contains("/") {
            for skip in skipImportPatterns {
              if importFileRaw.starts(with: skip) {
                continue nextLine
              }
            }
            logger.importLog("Import \(importFileRaw) does not exist.", file, lineNum)
          }
        }
      } else if importFile.first == "<", !isPrivate, !isTestFile {
        // Verify that double quotes are always used for intra-module imports.
        if importFileRaw.starts(with: "Firebase") {
          logger
            .importLog("Imports internal to the repo should use double quotes not \"<\"", file,
                       lineNum)
        }
      }
    }
  }
}

private func main() -> Int32 {
  let logger = ErrorLogger()
  // Search the path upwards to find the root of the firebase-ios-sdk repo.
  var url = URL(fileURLWithPath: FileManager().currentDirectoryPath)
  while url.path != "/" {<commit_msg>Treat bridging headers as test-related (#7588)<commit_after>#!/usr/bin/swift
/*
 * Copyright 2020 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// Utility script for verifying `import` and `include` syntax. This ensures a
// consistent style as well as functionality across multiple package managers.

// For more context, see https://github.com/firebase/firebase-ios-sdk/blob/master/HeadersImports.md.

import Foundation

// Skip these directories. Imports should only be repo-relative in libraries
// and unit tests.
let skipDirPatterns = ["/Sample/", "/Pods/", "FirebaseStorage/Tests/Integration",
                       "FirebaseDynamicLinks/Tests/Integration",
                       "FirebaseInAppMessaging/Tests/Integration/",
                       "Example/InstanceID/App", "SymbolCollisionTest/", "/gen/",
                       "CocoapodsIntegrationTest/", "FirebasePerformance/Tests/TestApp/",
                       "FirebasePerformance/Tests/FIRPerfE2E/"] +
  [
    "CoreOnly/Sources", // Skip Firebase.h.
    "SwiftPMTests", // The SwiftPM imports test module imports.
  ] +

  // The following are temporary skips pending working through a first pass of the repo:
  [
    "FirebaseAppDistribution",
    "FirebaseCore/Sources/Private", // TODO: work through adding this back.
    "Firebase/CoreDiagnostics",
    "FirebaseDatabase/Sources/third_party/Wrap-leveldb", // Pending SwiftPM for leveldb.
    "Example",
    "FirebaseInstallations/Source/Tests/Unit/",
    "Firestore",
    "GoogleUtilitiesComponents",
    "FirebasePerformance/ProtoSupport/",
  ]

// Skip existence test for patterns that start with the following:
let skipImportPatterns = [
  "FBLPromise",
  "OCMock",
  "OCMStubRecorder",
]

private class ErrorLogger {
  var foundError = false
  func log(_ message: String) {
    print(message)
    foundError = true
  }

  func importLog(_ message: String, _ file: String, _ line: Int) {
    log("Import Error: \(file):\(line) \(message)")
  }
}

private func checkFile(_ file: String, logger: ErrorLogger, inRepo repoURL: URL) {
  var fileContents = ""
  do {
    fileContents = try String(contentsOfFile: file, encoding: .utf8)
  } catch {
    logger.log("Could not read \(file). \(error)")
    // Not a source file, give up and return.
    return
  }
  let isPublic = file.range(of: "/Public/") != nil &&
    // TODO: Skip legacy GDTCCTLibrary file that isn't Public and should be moved.
    file.range(of: "GDTCCTLibrary/Public/GDTCOREvent+GDTCCTSupport.h") == nil
  let isPrivate = file.range(of: "/Sources/Private/") != nil ||
    // Delete when FirebaseInstallations fixes directory structure.
    file.range(of: "Source/Library/Private/FirebaseInstallationsInternal.h") != nil ||
    file.range(of: "GDTCORLibrary/Internal/GoogleDataTransportInternal.h") != nil

  // Treat all files with names finishing on "Test" or "Tests" as files with tests.
  let isTestFile = file.contains("Test.m") || file.contains("Tests.m") ||
    file.contains("Test.swift") || file.contains("Tests.swift")
  let isBridgingHeader = file.contains("Bridging-Header.h")
  var inSwiftPackage = false
  var inSwiftPackageElse = false
  let lines = fileContents.components(separatedBy: .newlines)
  var lineNum = 0
  nextLine: for rawLine in lines {
    let line = rawLine.trimmingCharacters(in: .whitespaces)
    lineNum += 1
    if line.starts(with: "#if SWIFT_PACKAGE") {
      inSwiftPackage = true
    } else if inSwiftPackage, line.starts(with: "#else") {
      inSwiftPackage = false
      inSwiftPackageElse = true
    } else if inSwiftPackageElse, line.starts(with: "#endif") {
      inSwiftPackageElse = false
    } else if inSwiftPackage {
      continue
    } else if line.starts(with: "@import") {
      // "@import" is only allowed for Swift Package Manager.
      logger.importLog("@import should not be used in CocoaPods library code", file, lineNum)
    }

    // "The #else of a SWIFT_PACKAGE check should only do CocoaPods module-style imports."
    if line.starts(with: "#import") || line.starts(with: "#include") {
      let importFile = line.components(separatedBy: " ")[1]
      if inSwiftPackageElse {
        if importFile.first != "<" {
          logger
            .importLog("Import in SWIFT_PACKAGE #else should start with \"<\".", file, lineNum)
        }
        continue
      }
      let importFileRaw = importFile.replacingOccurrences(of: "\"", with: "")
        .replacingOccurrences(of: "<", with: "")
        .replacingOccurrences(of: ">", with: "")

      if importFile.first == "\"" {
        // Public Headers should only use simple file names without paths.
        if isPublic {
          if importFile.contains("/") {
            logger.importLog("Public header import should not include \"/\"", file, lineNum)
          }

        } else if !FileManager.default.fileExists(atPath: repoURL.path + "/" + importFileRaw) {
          // Non-public header imports should be repo-relative paths. Unqualified imports are
          // allowed in private headers.
          if !isPrivate || importFile.contains("/") {
            for skip in skipImportPatterns {
              if importFileRaw.starts(with: skip) {
                continue nextLine
              }
            }
            logger.importLog("Import \(importFileRaw) does not exist.", file, lineNum)
          }
        }
      } else if importFile.first == "<", !isPrivate, !isTestFile, !isBridgingHeader {
        // Verify that double quotes are always used for intra-module imports.
        if importFileRaw.starts(with: "Firebase") {
          logger
            .importLog("Imports internal to the repo should use double quotes not \"<\"", file,
                       lineNum)
        }
      }
    }
  }
}

private func main() -> Int32 {
  let logger = ErrorLogger()
  // Search the path upwards to find the root of the firebase-ios-sdk repo.
  var url = URL(fileURLWithPath: FileManager().currentDirectoryPath)
  while url.path != "/" {
{'fraction_non_alphanumeric': 0.11455252918287938, 'fraction_numerical': 0.0026459143968871595, 'mean_word_length': 2.82584102411432, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 7, 'https://': 2, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1434175', 'n_tokens_mistral': 3733, 'n_tokens_neox': 3597, 'n_words': 1101}