change_headers.swift 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. #!/usr/bin/swift
  2. /*
  3. * Copyright 2020 Google LLC
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. // Utility script for updating to repo-relative headers.
  18. import Foundation
  19. // Update with directories in which to find headers.
  20. let findHeaders = ["FirebaseMessaging"]
  21. // Update with directories in which to change imports.
  22. let changeImports = ["GoogleUtilities", "FirebaseAuth", "FirebaseCore", "Firebase",
  23. "FirebaseDatabase", "GoogleDataTransport",
  24. "FirebaseInAppMessaging", "FirebaseMessaging",
  25. "FirebaseRemoteConfig", "FirebaseInstallations", "FirebaseFunctions",
  26. "FirebaseABTesting",
  27. "FirebaseAppDistribution", "Example", "Crashlytics", "FirebaseStorage"]
  28. // Skip these directories. Imports should only be repo-relative in libraries
  29. // and unit tests.
  30. let skipDirPatterns = ["/Sample/", "/Pods/",
  31. "FirebaseInAppMessaging/Tests/Integration/",
  32. ".build/"]
  33. // Get a Dictionary mapping a simple header name to a repo-relative path.
  34. func getHeaderMap(_ url: URL) -> [String: String] {
  35. var headerMap = [String: String]()
  36. for root in findHeaders {
  37. let rootURL = url.appendingPathComponent(root)
  38. let enumerator = FileManager.default.enumerator(atPath: rootURL.path)
  39. while let file = enumerator?.nextObject() as? String {
  40. if let fType = enumerator?.fileAttributes?[FileAttributeKey.type] as? FileAttributeType,
  41. fType == .typeRegular {
  42. if let url = URL(string: file) {
  43. let filename = url.lastPathComponent
  44. if filename.hasSuffix(".h") {
  45. headerMap[filename] = root + "/" + file
  46. }
  47. }
  48. }
  49. }
  50. }
  51. return headerMap
  52. }
  53. func getImportFile(_ line: String) -> String? {
  54. return line.components(separatedBy: " ")[1]
  55. .replacingOccurrences(of: "\"", with: "")
  56. .replacingOccurrences(of: "<", with: "")
  57. .replacingOccurrences(of: ">", with: "")
  58. .components(separatedBy: "/").last
  59. }
  60. func transformFile(_ file: String) {
  61. var fileContents = ""
  62. do {
  63. fileContents = try String(contentsOfFile: file, encoding: .utf8)
  64. } catch {
  65. print("Could not read \(file). \(error)")
  66. // Not a source file, give up and return.
  67. return
  68. }
  69. var outBuffer = ""
  70. var inSwiftPackage = false
  71. let lines = fileContents.components(separatedBy: .newlines)
  72. for line in lines {
  73. if line.starts(with: "#if SWIFT_PACKAGE") {
  74. inSwiftPackage = true
  75. } else if inSwiftPackage, line.starts(with: "#else") {
  76. inSwiftPackage = false
  77. } else if line.starts(with: "@import") {
  78. if !inSwiftPackage {
  79. fatalError("@import should not be used in CocoaPods library code: \(file):\(line)")
  80. }
  81. }
  82. if line.starts(with: "#import"),
  83. let importFile = getImportFile(line),
  84. let path = headerMap[importFile] {
  85. outBuffer += "#import \"\(path)\"\n"
  86. } else if line.starts(with: "#include"),
  87. let importFile = getImportFile(line),
  88. let path = headerMap[importFile] {
  89. outBuffer += "#include \"\(path)\"\n"
  90. } else {
  91. outBuffer += line + "\n"
  92. }
  93. }
  94. // Write out the changed file.
  95. do {
  96. try outBuffer.dropLast()
  97. .write(toFile: file, atomically: false, encoding: String.Encoding.utf8)
  98. } catch {
  99. fatalError("Failed to write \(file). \(error)")
  100. }
  101. }
  102. // Search the path upwards to find the root of the firebase-ios-sdk repo.
  103. var url = URL(fileURLWithPath: FileManager().currentDirectoryPath)
  104. while url.path != "/", url.lastPathComponent != "firebase-ios-sdk" {
  105. url = url.deletingLastPathComponent()
  106. }
  107. print(url)
  108. // Build map of all headers.
  109. let headerMap = getHeaderMap(url)
  110. // print(headerMap)
  111. for root in changeImports {
  112. let rootURL = url.appendingPathComponent(root)
  113. let enumerator = FileManager.default.enumerator(atPath: rootURL.path)
  114. whileLoop: while let file = enumerator?.nextObject() as? String {
  115. if let fType = enumerator?.fileAttributes?[FileAttributeKey.type] as? FileAttributeType,
  116. fType == .typeRegular {
  117. if file.starts(with: ".") {
  118. continue
  119. }
  120. if !(file.hasSuffix(".h") ||
  121. file.hasSuffix(".m") ||
  122. file.hasSuffix(".mm") ||
  123. file.hasSuffix(".c")) {
  124. continue
  125. }
  126. if file.range(of: "/Public/") != nil {
  127. continue
  128. }
  129. let fullTransformPath = root + "/" + file
  130. for dirPattern in skipDirPatterns {
  131. if fullTransformPath.range(of: dirPattern) != nil {
  132. continue whileLoop
  133. }
  134. }
  135. transformFile(fullTransformPath)
  136. }
  137. }
  138. }