Переглянути джерело

Handle Xcode 11.4 changes to Swift module maps (#5294)

* Fix broken outputDirs zipPods option combination
Paul Beusterien 6 роки тому
батько
коміт
0306fc289d

+ 4 - 0
ZipBuilder/README.md

@@ -24,6 +24,10 @@ In order to build the Zip file, you will need:
 You can run the tool with `swift run ReleasePackager [ARGS]` or generate an Xcode project with
 `swift package generate-xcodeproj` and run within Xcode.
 
+Since Apple does not support linking libraries built by future Xcode versions, make sure to builid with the
+earliest Xcode needed by any of the library clients. The Xcode command line tools must also be configured
+for that version. Check with `xcodebuild -version`.
+
 ### Launch Arguments
 
 See `main.swift` and the `LaunchArgs` struct for information on specific launch arguments.

+ 28 - 6
ZipBuilder/Sources/ZipBuilder/FrameworkBuilder.swift

@@ -670,15 +670,37 @@ struct FrameworkBuilder {
             let destSwiftModuleDir = destModuleDir.appendingPathComponent(swiftModule.lastPathComponent)
             for file in files {
               let fileURL = URL(fileURLWithPath: file)
-              do {
-                try fileManager.copyItem(at: fileURL, to:
-                  destSwiftModuleDir.appendingPathComponent(fileURL.lastPathComponent))
-              } catch {
-                fatalError("Could not copy Swift module file from \(fileURL) to " + "\(destSwiftModuleDir): \(error)")
+              let projectDir = swiftModule.appendingPathComponent("Project")
+              if fileURL.lastPathComponent == "Project",
+                fileManager.directoryExists(at: projectDir) {
+                // The Project directory (introduced with Xcode 11.4) already exist, only copy in
+                // new contents.
+                let projectFiles = try fileManager.contentsOfDirectory(at: projectDir,
+                                                                       includingPropertiesForKeys: nil).compactMap { $0.path }
+                let destProjectDir = destSwiftModuleDir.appendingPathComponent("Project")
+                for projectFile in projectFiles {
+                  let projectFileURL = URL(fileURLWithPath: projectFile)
+                  do {
+                    try fileManager.copyItem(at: projectFileURL, to:
+                      destProjectDir.appendingPathComponent(projectFileURL.lastPathComponent))
+                  } catch {
+                    fatalError("Could not copy Project file from \(projectFileURL) to " +
+                      "\(destProjectDir): \(error)")
+                  }
+                }
+              } else {
+                do {
+                  try fileManager.copyItem(at: fileURL, to:
+                    destSwiftModuleDir.appendingPathComponent(fileURL.lastPathComponent))
+                } catch {
+                  fatalError("Could not copy Swift module file from \(fileURL) to " +
+                    "\(destSwiftModuleDir): \(error)")
+                }
               }
             }
           } catch {
-            fatalError("Failed to get Modules directory contents - \(moduleDir): \(error.localizedDescription)")
+            fatalError("Failed to get Modules directory contents - \(moduleDir):" +
+              "\(error.localizedDescription)")
           }
         }
       } catch {

+ 9 - 0
ZipBuilder/Sources/ZipBuilder/LaunchArgs.swift

@@ -40,6 +40,7 @@ struct LaunchArgs {
   /// Keys associated with the launch args. See `Usage` for descriptions of each flag.
   private enum Key: String, CaseIterable {
     case archs
+    case buildDependencies
     case buildRoot
     case carthageDir
     case carthageSkipVersionCheck
@@ -62,6 +63,8 @@ struct LaunchArgs {
       case .archs:
         return "The list of architectures to build for. The default list is " +
           "\(Architecture.allCases.map { $0.rawValue })."
+      case .buildDependencies:
+        return "Whether or not to build dependencies of requested pods. The default is true."
       case .buildRoot:
         return "The root directory for build artifacts. If `nil`, a temporary directory will be " +
           "used."
@@ -109,6 +112,9 @@ struct LaunchArgs {
   /// verify expected version numbers.
   let allSDKsPath: URL?
 
+  /// Build dependencies flag.
+  let buildDependencies: Bool
+
   /// The root directory for build artifacts. If `nil`, a temporary directory will be used.
   let buildRoot: URL?
 
@@ -170,6 +176,8 @@ struct LaunchArgs {
     // Override default values for specific keys.
     //   - Always run `pod repo update` and pod cache clean -all` unless explicitly set to false.
     defaults.register(defaults: [Key.updatePodRepo.rawValue: true])
+    //   - Always build dependencies unless explicitly set to false.
+    defaults.register(defaults: [Key.buildDependencies.rawValue: true])
 
     // Get the project template directory, and fail if it doesn't exist.
     guard let templatePath = defaults.string(forKey: Key.templateDir.rawValue) else {
@@ -336,6 +344,7 @@ struct LaunchArgs {
       minimumIOSVersion = "9.0"
     }
 
+    buildDependencies = defaults.bool(forKey: Key.buildDependencies.rawValue)
     carthageSkipVersionCheck = defaults.bool(forKey: Key.carthageSkipVersionCheck.rawValue)
     dynamic = defaults.bool(forKey: Key.dynamic.rawValue)
     updatePodRepo = defaults.bool(forKey: Key.updatePodRepo.rawValue)

+ 6 - 2
ZipBuilder/Sources/ZipBuilder/ZipBuilder.swift

@@ -153,14 +153,18 @@ struct ZipBuilder {
       ModuleMapBuilder(customSpecRepos: customSpecRepos, selectedPods: installedPods).build()
     }
 
+    let podsToBuild = LaunchArgs.shared.buildDependencies ? installedPods :
+      installedPods.filter { podsToInstall.map { $0.name }.contains($0.key) }
+
     // Generate the frameworks. Each key is the pod name and the URLs are all frameworks to be
     // copied in each product's directory.
-    let (frameworks, carthageFrameworks) = generateFrameworks(fromPods: installedPods, inProjectDir: projectDir)
+    let (frameworks, carthageFrameworks) = generateFrameworks(fromPods: podsToBuild,
+                                                              inProjectDir: projectDir)
 
     for (framework, paths) in frameworks {
       print("Frameworks for pod: \(framework) were compiled at \(paths)")
     }
-    return (installedPods, frameworks, carthageFrameworks)
+    return (podsToBuild, frameworks, carthageFrameworks)
   }
 
   // TODO: This function contains a lot of "copy these paths to this directory, fail if there are

+ 11 - 10
ZipBuilder/Sources/ZipBuilder/main.swift

@@ -51,24 +51,22 @@ if let outputDir = args.outputDir {
   }
 }
 
-var zipped: URL
-if args.zipPods == nil {
-  // Do a Firebase build.
-  FirebaseBuilder(zipBuilder: builder).build(in: projectDir)
-} else {
-  let (installedPods, frameworks, _) = builder.buildAndAssembleZip(podsToInstall: LaunchArgs.shared.zipPods!)
+if let zipPods = args.zipPods {
+  let (installedPods, frameworks, _) = builder.buildAndAssembleZip(podsToInstall: zipPods)
   let staging = FileManager.default.temporaryDirectory(withName: "staging")
   try builder.copyFrameworks(fromPods: Array(installedPods.keys), toDirectory: staging,
                              frameworkLocations: frameworks)
-  zipped = Zip.zipContents(ofDir: staging, name: "Frameworks.zip")
+  let zipped = Zip.zipContents(ofDir: staging, name: "Frameworks.zip")
   print(zipped.absoluteString)
   if let outputDir = args.outputDir {
-    try FileManager.default.copyItem(at: zipped, to: outputDir)
-    print("Success! Zip file can be found at \(outputDir.path)")
+    let outputFile = outputDir.appendingPathComponent("Frameworks.zip")
+    try FileManager.default.copyItem(at: zipped, to: outputFile)
+    print("Success! Zip file can be found at \(outputFile.path)")
   } else {
     // Move zip to parent directory so it doesn't get removed with other artifacts.
     let parentLocation =
-      zipped.deletingLastPathComponent().deletingLastPathComponent().appendingPathComponent(zipped.lastPathComponent)
+      zipped.deletingLastPathComponent().deletingLastPathComponent()
+        .appendingPathComponent(zipped.lastPathComponent)
     // Clear out the output file if it exists.
     FileManager.default.removeIfExists(at: parentLocation)
     do {
@@ -78,6 +76,9 @@ if args.zipPods == nil {
     }
     print("Success! Zip file can be found at \(parentLocation.path)")
   }
+} else {
+  // Do a Firebase Zip Release package build.
+  FirebaseBuilder(zipBuilder: builder).build(in: projectDir)
 }
 
 if !args.keepBuildArtifacts {