change_headers.swift 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  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 = ["Crashlytics"]
  21. // Update with directories in which to change imports.
  22. let changeImports = ["GoogleUtilities", "FirebaseAuth", "FirebaseCore", "Firebase",
  23. "FirebaseDatabase", "GoogleDataTransport",
  24. "FirebaseDynamicLinks", "FirebaseInAppMessaging", "FirebaseMessaging",
  25. "FirebaseRemoteConfig", "FirebaseInstallations", "Functions",
  26. "FirebaseAppDistribution", "Example", "Crashlytics", "FirebaseStorage"]
  27. // Skip these directories. Imports should only be repo-relative in libraries
  28. // and unit tests.
  29. let skipDirPatterns = ["/Sample/", "/Pods/", "FirebaseStorage/Tests/Integration",
  30. "FirebaseInAppMessaging/Tests/Integration/",
  31. "Example/InstanceID/App", ".build/", "Functions/Example/FirebaseFunctions"]
  32. // Get a Dictionary mapping a simple header name to a repo-relative path.
  33. func getHeaderMap(_ url: URL) -> [String: String] {
  34. var headerMap = [String: String]()
  35. for root in findHeaders {
  36. let rootURL = url.appendingPathComponent(root)
  37. let enumerator = FileManager.default.enumerator(atPath: rootURL.path)
  38. while let file = enumerator?.nextObject() as? String {
  39. if let fType = enumerator?.fileAttributes?[FileAttributeKey.type] as? FileAttributeType,
  40. fType == .typeRegular {
  41. if let url = URL(string: file) {
  42. let filename = url.lastPathComponent
  43. if filename.hasSuffix(".h") {
  44. headerMap[filename] = root + "/" + file
  45. }
  46. }
  47. }
  48. }
  49. }
  50. return headerMap
  51. }
  52. func getImportFile(_ line: String) -> String? {
  53. return line.components(separatedBy: " ")[1]
  54. .replacingOccurrences(of: "\"", with: "")
  55. .replacingOccurrences(of: "<", with: "")
  56. .replacingOccurrences(of: ">", with: "")
  57. .components(separatedBy: "/").last
  58. }
  59. func transformFile(_ file: String) {
  60. var fileContents = ""
  61. do {
  62. fileContents = try String(contentsOfFile: file, encoding: .utf8)
  63. } catch {
  64. print("Could not read \(file). \(error)")
  65. // Not a source file, give up and return.
  66. return
  67. }
  68. var outBuffer = ""
  69. var inSwiftPackage = false
  70. let lines = fileContents.components(separatedBy: .newlines)
  71. for line in lines {
  72. if line.starts(with: "#if SWIFT_PACKAGE") {
  73. inSwiftPackage = true
  74. } else if inSwiftPackage, line.starts(with: "#else") {
  75. inSwiftPackage = false
  76. } else if line.starts(with: "@import") {
  77. if !inSwiftPackage {
  78. fatalError("@import should not be used in CocoaPods library code: \(file):\(line)")
  79. }
  80. }
  81. if line.starts(with: "#import"),
  82. let importFile = getImportFile(line),
  83. let path = headerMap[importFile] {
  84. outBuffer += "#import \"\(path)\"\n"
  85. } else if line.starts(with: "#include"),
  86. let importFile = getImportFile(line),
  87. let path = headerMap[importFile] {
  88. outBuffer += "#include \"\(path)\"\n"
  89. } else {
  90. outBuffer += line + "\n"
  91. }
  92. }
  93. // Write out the changed file.
  94. do {
  95. try outBuffer.dropLast()
  96. .write(toFile: file, atomically: false, encoding: String.Encoding.utf8)
  97. } catch {
  98. fatalError("Failed to write \(file). \(error)")
  99. }
  100. }
  101. // Search the path upwards to find the root of the firebase-ios-sdk repo.
  102. var url = URL(fileURLWithPath: FileManager().currentDirectoryPath)
  103. while url.path != "/", url.lastPathComponent != "firebase-ios-sdk" {
  104. url = url.deletingLastPathComponent()
  105. }
  106. print(url)
  107. // Build map of all headers.
  108. let headerMap = getHeaderMap(url)
  109. // print(headerMap)
  110. for root in changeImports {
  111. let rootURL = url.appendingPathComponent(root)
  112. let enumerator = FileManager.default.enumerator(atPath: rootURL.path)
  113. whileLoop: while let file = enumerator?.nextObject() as? String {
  114. if let fType = enumerator?.fileAttributes?[FileAttributeKey.type] as? FileAttributeType,
  115. fType == .typeRegular {
  116. if file.starts(with: ".") {
  117. continue
  118. }
  119. if !(file.hasSuffix(".h") ||
  120. file.hasSuffix(".m") ||
  121. file.hasSuffix(".mm") ||
  122. file.hasSuffix(".c")) {
  123. continue
  124. }
  125. if file.range(of: "/Public/") != nil {
  126. continue
  127. }
  128. let fullTransformPath = root + "/" + file
  129. for dirPattern in skipDirPatterns {
  130. if fullTransformPath.range(of: dirPattern) != nil {
  131. continue whileLoop
  132. }
  133. }
  134. transformFile(fullTransformPath)
  135. }
  136. }
  137. }