Skip to content

Commit

Permalink
Support concurrent Zip Builder runs (#4409)
Browse files Browse the repository at this point in the history
  • Loading branch information
paulb777 committed Nov 28, 2019
1 parent 009fcae commit 6f8732d
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 29 deletions.
24 changes: 11 additions & 13 deletions ZipBuilder/Sources/ZipBuilder/FileManager+Utils.swift
Original file line number Diff line number Diff line change
Expand Up @@ -70,16 +70,10 @@ public extension FileManager {
return directoryExists(at: url)
}

/// Returns the URL to the Firebase cache directory, and creates it if it doesn't exist.
/// Returns the URL to the source Pod cache directory, and creates it if it doesn't exist.
func sourcePodCacheDirectory(withSubdir subdir: String = "") throws -> URL {
// Get the URL for the cache directory.
let cacheDir: URL = try url(for: .cachesDirectory,
in: .userDomainMask,
appropriateFor: nil,
create: true)

// Get the cache root path, and if it already exists just return the URL.
let cacheRoot = cacheDir.appendingPathComponents(["firebase_oss_framework_cache", subdir])
let cacheDir = FileManager.default.temporaryDirectory(withName: "cache")
let cacheRoot = cacheDir.appendingPathComponents([subdir])
if directoryExists(at: cacheRoot) {
return cacheRoot
}
Expand All @@ -90,12 +84,12 @@ public extension FileManager {
return cacheRoot
}

/// Removes a directory if it exists. This is helpful to clean up error handling for checks that
/// Removes a directory or file if it exists. This is helpful to clean up error handling for checks that
/// shouldn't fail. The only situation this could potentially fail is permission errors or if a
/// folder is open in Finder, and in either state the user needs to close the window or fix the
/// permissions. A fatal error will be thrown in those situations.
func removeDirectoryIfExists(at url: URL) {
guard directoryExists(at: url) else { return }
func removeIfExists(at url: URL) {
guard directoryExists(at: url) || fileExists(atPath: url.path) else { return }

do {
try removeItem(at: url)
Expand All @@ -107,6 +101,9 @@ public extension FileManager {
}
}

// Enable a single unique temporary workspace per execution.
static let unique: String = UUID().uuidString

/// Returns a deterministic path of a temporary directory for the given name. Note: This does
/// *not* create the directory if it doesn't exist, merely generates the name for creation.
func temporaryDirectory(withName name: String) -> URL {
Expand All @@ -122,7 +119,8 @@ public extension FileManager {
}

// Organize all temporary directories into a "FirebaseZipRelease" directory.
let firebaseDir = tempDir.appendingPathComponent("FirebaseZipRelease", isDirectory: true)
let unique = FileManager.unique
let firebaseDir = tempDir.appendingPathComponent("ZipRelease" + unique, isDirectory: true)
return firebaseDir.appendingPathComponent(name, isDirectory: true)
}

Expand Down
2 changes: 1 addition & 1 deletion ZipBuilder/Sources/ZipBuilder/FrameworkBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ struct FrameworkBuilder {
do {
// Remove the previously cached framework if it exists, otherwise the `moveItem` call will
// fail.
fileManager.removeDirectoryIfExists(at: cachedFrameworkDir)
fileManager.removeIfExists(at: cachedFrameworkDir)

// Create the root cache directory if it doesn't exist.
if !fileManager.directoryExists(at: cachedFrameworkRoot) {
Expand Down
7 changes: 7 additions & 0 deletions ZipBuilder/Sources/ZipBuilder/LaunchArgs.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ struct LaunchArgs {
case carthageDir
case customSpecRepos
case existingVersions
case keepBuildArtifacts
case minimumIOSVersion
case outputDir
case releasingSDKs
Expand All @@ -68,6 +69,8 @@ struct LaunchArgs {
case .existingVersions:
return "The file path to a textproto file containing the existing released SDK versions, " +
"of type `ZipBuilder_FirebaseSDKs`."
case .keepBuildArtifacts:
return "A flag to indicate keeping (not deleting) the build artifacts."
case .minimumIOSVersion:
return "The minimum supported iOS version. The default is 9.0."
case .outputDir:
Expand Down Expand Up @@ -108,6 +111,9 @@ struct LaunchArgs {
/// master repo.
let customSpecRepos: [URL]?

/// A flag to keep the build artifacts after this script completes.
let keepBuildArtifacts: Bool

/// The minimum iOS Version to build for.
let minimumIOSVersion: String

Expand Down Expand Up @@ -274,6 +280,7 @@ struct LaunchArgs {
}

updatePodRepo = defaults.bool(forKey: Key.updatePodRepo.rawValue)
keepBuildArtifacts = defaults.bool(forKey: Key.keepBuildArtifacts.rawValue)

// Check for extra invalid options.
let validArgs = Key.allCases.map { $0.rawValue }
Expand Down
4 changes: 2 additions & 2 deletions ZipBuilder/Sources/ZipBuilder/ZipBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ struct ZipBuilder {

// Break the `inputPods` into a variable since it's helpful when debugging builds to just
// install a subset of pods, like the following line:
// let inputPods: [String] = ["", "Core", "Analytics", "Storage"]
// let inputPods: [String] = ["", "Core", "Analytics", "Storage"]
let inputPods = CocoaPod.allCases.map { $0.rawValue }
let podsToInstall = inputPods.map { CocoaPodUtils.VersionedPod(name: $0, version: nil) }

Expand Down Expand Up @@ -734,7 +734,7 @@ struct ZipBuilder {
let copiedLocation = tempDir.appendingPathComponent(framework.lastPathComponent)

// Remove the framework if it exists since it could be out of date.
fileManager.removeDirectoryIfExists(at: copiedLocation)
fileManager.removeIfExists(at: copiedLocation)
do {
try fileManager.copyItem(at: framework, to: copiedLocation)
} catch {
Expand Down
32 changes: 19 additions & 13 deletions ZipBuilder/Sources/ZipBuilder/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,6 @@

import Foundation

// Delete the cache directory, if it exists.
do {
let cacheDir = try FileManager.default.sourcePodCacheDirectory()
FileManager.default.removeDirectoryIfExists(at: cacheDir)
} catch {
fatalError("Could not remove the cache before packaging the release: \(error)")
}

// Get the launch arguments, parsed by user defaults.
let args = LaunchArgs.shared

Expand Down Expand Up @@ -60,12 +52,12 @@ do {
let carthagePath =
location.deletingLastPathComponent().appendingPathComponent("carthage_build")
let fileManager = FileManager.default
fileManager.removeDirectoryIfExists(at: carthagePath)
fileManager.removeIfExists(at: carthagePath)
try fileManager.copyItem(at: location, to: carthagePath)

// Package the Carthage distribution with the current directory structure.
let carthageDir = location.deletingLastPathComponent().appendingPathComponent("carthage")
fileManager.removeDirectoryIfExists(at: carthageDir)
fileManager.removeIfExists(at: carthageDir)
var output = carthageDir.appendingPathComponent(firebaseVersion)
if let rcNumber = args.rcNumber {
output.appendPathComponent("rc\(rcNumber)")
Expand All @@ -81,7 +73,7 @@ do {
outputDir: output)

// Remove the duplicated Carthage build directory.
fileManager.removeDirectoryIfExists(at: carthagePath)
fileManager.removeIfExists(at: carthagePath)
print("Done creating Carthage release! Files written to \(output)")

// Save the directory for later copying.
Expand Down Expand Up @@ -129,7 +121,7 @@ do {
if let outputDir = args.outputDir {
do {
// Clear out the output directory if it exists.
FileManager.default.removeDirectoryIfExists(at: outputDir)
FileManager.default.removeIfExists(at: outputDir)
try FileManager.default.createDirectory(at: outputDir, withIntermediateDirectories: true)

// We want the output to be in the X_Y_Z directory.
Expand All @@ -153,7 +145,21 @@ do {
}
}
} else {
print("Success! Zip file can be found at \(zipped.path)")
// Move zip to parent directory so it doesn't get removed with other artifacts.
let parentLocation =
zipped.deletingLastPathComponent().deletingLastPathComponent().appendingPathComponent(zipped.lastPathComponent)
// Clear out the output file if it exists.
FileManager.default.removeIfExists(at: parentLocation)
do {
try FileManager.default.moveItem(at: zipped, to: parentLocation)
} catch {
fatalError("Could not move Zip file to output directory: \(error)")
}
print("Success! Zip file can be found at \(parentLocation.path)")
}

if !args.keepBuildArtifacts {
FileManager.default.removeIfExists(at: projectDir.deletingLastPathComponent())
}

// Get the time since the start of the build to get the full time.
Expand Down

0 comments on commit 6f8732d

Please sign in to comment.