change_headers.swift 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. #!/usr/bin/swift
  2. /*
  3. * Copyright 2020 LLC Google
  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 = ["FirebaseDatabase", "Example/Shared"]
  21. // Update with directories in which to change imports.
  22. let changeImports = ["GoogleUtilities", "FirebaseAuth", "FirebaseCore", "Firebase",
  23. "FirebaseDatabase",
  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. 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. return headerMap
  50. }
  51. func getImportFile(_ line: String) -> String? {
  52. return line.components(separatedBy: " ")[1]
  53. .replacingOccurrences(of: "\"", with: "")
  54. .replacingOccurrences(of: "<", with: "")
  55. .replacingOccurrences(of: ">", with: "")
  56. .components(separatedBy: "/").last
  57. }
  58. func transformFile(_ file: String) {
  59. var fileContents = ""
  60. do {
  61. fileContents = try String(contentsOfFile: file, encoding: .utf8)
  62. } catch {
  63. print("Could not read \(file). \(error)")
  64. // Not a source file, give up and return.
  65. return
  66. }
  67. var outBuffer = ""
  68. var inSwiftPackage = false
  69. let lines = fileContents.components(separatedBy: .newlines)
  70. for line in lines {
  71. if line.starts(with: "#if SWIFT_PACKAGE") {
  72. inSwiftPackage = true
  73. } else if inSwiftPackage, line.starts(with: "#else") {
  74. inSwiftPackage = false
  75. } else if line.starts(with: "@import") {
  76. if !inSwiftPackage {
  77. fatalError("@import should not be used in CocoaPods library code: \(file):\(line)")
  78. }
  79. }
  80. if line.starts(with: "#import"),
  81. let importFile = getImportFile(line),
  82. let path = headerMap[importFile] {
  83. outBuffer += "#import \"\(path)\"\n"
  84. } else if line.starts(with: "#include"),
  85. let importFile = getImportFile(line),
  86. let path = headerMap[importFile] {
  87. outBuffer += "#include \"\(path)\"\n"
  88. } else {
  89. outBuffer += line + "\n"
  90. }
  91. }
  92. // Write out the changed file.
  93. do {
  94. try outBuffer.dropLast()
  95. .write(toFile: file, atomically: false, encoding: String.Encoding.utf8)
  96. } catch {
  97. fatalError("Failed to write \(file). \(error)")
  98. }
  99. }
  100. // Search the path upwards to find the root of the firebase-ios-sdk repo.
  101. var url = URL(fileURLWithPath: FileManager().currentDirectoryPath)
  102. while url.path != "/", url.lastPathComponent != "firebase-ios-sdk" {
  103. url = url.deletingLastPathComponent()
  104. }
  105. print(url)
  106. // Build map of all headers.
  107. let headerMap = getHeaderMap(url)
  108. // print(headerMap)
  109. for root in changeImports {
  110. let rootURL = url.appendingPathComponent(root)
  111. let enumerator = FileManager.default.enumerator(atPath: rootURL.path)
  112. whileLoop: while let file = enumerator?.nextObject() as? String {
  113. if let fType = enumerator?.fileAttributes?[FileAttributeKey.type] as? FileAttributeType,
  114. fType == .typeRegular {
  115. if file.starts(with: ".") {
  116. continue
  117. }
  118. if !(file.hasSuffix(".h") ||
  119. file.hasSuffix(".m") ||
  120. file.hasSuffix(".mm") ||
  121. file.hasSuffix(".c")) {
  122. continue
  123. }
  124. if file.range(of: "/Public/") != nil {
  125. continue
  126. }
  127. let fullTransformPath = root + "/" + file
  128. for dirPattern in skipDirPatterns {
  129. if fullTransformPath.range(of: dirPattern) != nil {
  130. continue whileLoop
  131. }
  132. }
  133. transformFile(fullTransformPath)
  134. }
  135. }
  136. }