diff --git a/Docs/FAQ.md b/Docs/FAQ.md index a5a6fbb10..03d108afc 100644 --- a/Docs/FAQ.md +++ b/Docs/FAQ.md @@ -9,10 +9,14 @@ Absolutely. You will get the most out of XcodeGen by adding your project to your >Note that you can run `xcodegen` as a step in your build process on CI. ## What happens when I switch branches -If files were added or removed in the new checkout you will most likely need to run `xcodegen` again so that your project will reference all your files. Unfortunately this is a manual step at the moment, but in the future this could be automated. - -For now you can always add xcodegen as a git `post-checkout` hook. -It's recommended to use `--use-cache` so that the project is not needlessly generated. +If files were added or removed in the new checkout you will most likely need to run `xcodegen` again so that your project will reference all your files. + +It's recommended to set up some [git hooks](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks) to automate the process: +- run `xcodegen generate --use-cache` on the following hooks. This will make sure the project is up to date when checking out, merging and rebasing + - post-checkout + - post-rewrite + - post-merge +- run `xcodegen cache` on `post-commit`. This will make sure that when switching branches the cache will be updated in case you made local changes, or are ammending a commit that added a new file. ## Can I use CocoaPods Yes, you will just need to run `pod install` after the project is generated to integrate Cocoapods changes. diff --git a/Sources/XcodeGenCLI/Commands/CacheCommand.swift b/Sources/XcodeGenCLI/Commands/CacheCommand.swift new file mode 100644 index 000000000..70a14a241 --- /dev/null +++ b/Sources/XcodeGenCLI/Commands/CacheCommand.swift @@ -0,0 +1,44 @@ +import Foundation +import PathKit +import ProjectSpec +import SwiftCLI +import XcodeGenKit +import XcodeProj +import Version + +class CacheCommand: ProjectCommand { + + @Key("--cache-path", description: "Where the cache file will be loaded from and save to. Defaults to ~/.xcodegen/cache/{SPEC_PATH_HASH}") + var cacheFilePath: Path? + + init(version: Version) { + super.init(version: version, + name: "cache", + shortDescription: "Write the project cache") + } + + override func execute(specLoader: SpecLoader, projectSpecPath: Path, project: Project) throws { + + let cacheFilePath = self.cacheFilePath ?? Path("~/.xcodegen/cache/\(projectSpecPath.absolute().string.md5)").absolute() + + var cacheFile: CacheFile? + + // generate cache + do { + cacheFile = try specLoader.generateCacheFile() + } catch { + throw GenerationError.projectSpecParsingError(error) + } + + // write cache + if let cacheFile = cacheFile { + do { + try cacheFilePath.parent().mkpath() + try cacheFilePath.write(cacheFile.string) + success("Wrote cache to \(cacheFilePath)") + } catch { + info("Failed to write cache: \(error.localizedDescription)") + } + } + } +} diff --git a/Sources/XcodeGenCLI/Commands/DumpCommand.swift b/Sources/XcodeGenCLI/Commands/DumpCommand.swift index b3da9dcca..7e054062e 100644 --- a/Sources/XcodeGenCLI/Commands/DumpCommand.swift +++ b/Sources/XcodeGenCLI/Commands/DumpCommand.swift @@ -49,7 +49,7 @@ class DumpCommand: ProjectCommand { try file.parent().mkpath() try file.write(output) } else { - stdout.print(output) + success(output) } } } diff --git a/Sources/XcodeGenCLI/Commands/GenerateCommand.swift b/Sources/XcodeGenCLI/Commands/GenerateCommand.swift index b607b09b3..385846e5d 100644 --- a/Sources/XcodeGenCLI/Commands/GenerateCommand.swift +++ b/Sources/XcodeGenCLI/Commands/GenerateCommand.swift @@ -8,9 +8,6 @@ import Version class GenerateCommand: ProjectCommand { - @Flag("-q", "--quiet", description: "Suppress all informational and success output") - var quiet: Bool - @Flag("-c", "--use-cache", description: "Use a cache for the xcodegen spec. This will prevent unnecessarily generating the project if nothing has changed") var useCache: Bool @@ -46,7 +43,7 @@ class GenerateCommand: ProjectCommand { Path("~/.xcodegen/cache/\(projectSpecPath.absolute().string.md5)").absolute() var cacheFile: CacheFile? - // read cache + // generate cache if useCache || self.cacheFilePath != nil { do { cacheFile = try specLoader.generateCacheFile() @@ -138,22 +135,4 @@ class GenerateCommand: ProjectCommand { try Task.run(bash: command, directory: projectDirectory.absolute().string) } } - - func info(_ string: String) { - if !quiet { - stdout.print(string) - } - } - - func warning(_ string: String) { - if !quiet { - stdout.print(string.yellow) - } - } - - func success(_ string: String) { - if !quiet { - stdout.print(string.green) - } - } } diff --git a/Sources/XcodeGenCLI/Commands/ProjectCommand.swift b/Sources/XcodeGenCLI/Commands/ProjectCommand.swift index 894dbc5ba..9f3b013c8 100644 --- a/Sources/XcodeGenCLI/Commands/ProjectCommand.swift +++ b/Sources/XcodeGenCLI/Commands/ProjectCommand.swift @@ -12,6 +12,9 @@ class ProjectCommand: Command { let name: String let shortDescription: String + @Flag("-q", "--quiet", description: "Suppress all informational and success output") + var quiet: Bool + @Key("-s", "--spec", description: "The path to the project spec file. Defaults to project.yml. (It is also possible to link to multiple spec files by comma separating them. Note that all other flags will be the same.)") var spec: String? @@ -58,4 +61,22 @@ class ProjectCommand: Command { } func execute(specLoader: SpecLoader, projectSpecPath: Path, project: Project) throws {} + + func info(_ string: String) { + if !quiet { + stdout.print(string) + } + } + + func warning(_ string: String) { + if !quiet { + stdout.print(string.yellow) + } + } + + func success(_ string: String) { + if !quiet { + stdout.print(string.green) + } + } } diff --git a/Sources/XcodeGenCLI/XcodeGenCLI.swift b/Sources/XcodeGenCLI/XcodeGenCLI.swift index 42afef037..8d6a69c59 100644 --- a/Sources/XcodeGenCLI/XcodeGenCLI.swift +++ b/Sources/XcodeGenCLI/XcodeGenCLI.swift @@ -15,6 +15,7 @@ public class XcodeGenCLI { description: "Generates Xcode projects", commands: [ generateCommand, + CacheCommand(version: version), DumpCommand(version: version), ] )