From 5711c6be0d0f2e74eb69e653b4f0fc377347b458 Mon Sep 17 00:00:00 2001 From: yonaskolb Date: Thu, 7 Nov 2019 23:31:07 +1100 Subject: [PATCH 1/6] Remove project description from generate --- Sources/XcodeGenCLI/GenerateCommand.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/Sources/XcodeGenCLI/GenerateCommand.swift b/Sources/XcodeGenCLI/GenerateCommand.swift index 92763ef4..f4e2fa48 100644 --- a/Sources/XcodeGenCLI/GenerateCommand.swift +++ b/Sources/XcodeGenCLI/GenerateCommand.swift @@ -68,7 +68,6 @@ class GenerateCommand: Command { // load project spec do { project = try specLoader.loadProject(path: projectSpecPath, variables: variables) - info("Loaded project:\n \(project.debugDescription.replacingOccurrences(of: "\n", with: "\n "))") } catch { throw GenerationError.projectSpecParsingError(error) } From 43cd0ec33ea519be46c4aa5f5f137c6209bb3b15 Mon Sep 17 00:00:00 2001 From: yonaskolb Date: Fri, 8 Nov 2019 00:18:52 +1100 Subject: [PATCH 2/6] add dump command --- README.md | 2 +- Sources/ProjectSpec/SpecLoader.swift | 2 +- .../XcodeGenCLI/Commands/DumpCommand.swift | 50 +++++++++++++++++ .../{ => Commands}/GenerateCommand.swift | 45 ++------------- .../XcodeGenCLI/Commands/ProjectCommand.swift | 56 +++++++++++++++++++ Sources/XcodeGenCLI/XcodeGenCLI.swift | 5 +- 6 files changed, 116 insertions(+), 44 deletions(-) create mode 100644 Sources/XcodeGenCLI/Commands/DumpCommand.swift rename Sources/XcodeGenCLI/{ => Commands}/GenerateCommand.swift (77%) create mode 100644 Sources/XcodeGenCLI/Commands/ProjectCommand.swift diff --git a/README.md b/README.md index c9747fcf..800be7f0 100644 --- a/README.md +++ b/README.md @@ -130,7 +130,7 @@ Options: - **--use-cache**: Used to prevent unnecessarily generating the project. If this is set, then a cache file will be written to when a project is generated. If `xcodegen` is later run but the spec and all the files it contains are the same, the project won't be generated. - **--cache-path**: A custom path to use for your cache file. This defaults to `~/.xcodegen/cache/{PROJECT_SPEC_PATH_HASH}` -Use `xcodegen help` to see more detailed usage information. +There are other commands as well. Use `xcodegen help` to see more detailed usage information. ## Editing ```shell diff --git a/Sources/ProjectSpec/SpecLoader.swift b/Sources/ProjectSpec/SpecLoader.swift index e193c55a..54c4cf53 100644 --- a/Sources/ProjectSpec/SpecLoader.swift +++ b/Sources/ProjectSpec/SpecLoader.swift @@ -7,7 +7,7 @@ import Yams public class SpecLoader { var project: Project! - private var projectDictionary: [String: Any]? + public private(set) var projectDictionary: [String: Any]? let version: Version public init(version: Version) { diff --git a/Sources/XcodeGenCLI/Commands/DumpCommand.swift b/Sources/XcodeGenCLI/Commands/DumpCommand.swift new file mode 100644 index 00000000..424493b2 --- /dev/null +++ b/Sources/XcodeGenCLI/Commands/DumpCommand.swift @@ -0,0 +1,50 @@ +import Foundation +import SwiftCLI +import PathKit +import ProjectSpec +import Yams + +class DumpCommand: ProjectCommand { + + override var name: String { "dump" } + override var shortDescription: String { "Dumps the project spec to stdout" } + + private let dumpType = Key("--type", "-t", description: """ + The type of dump to output. Either "json", "yaml", "summary", "swift-dump", "parsed-json", or "parsed-yaml". Defaults to summary. The "parsed" types parse the project into swift and then back again and can be used for testing. + """) + + override func execute(specLoader: SpecLoader, projectSpecPath: Path, project: Project) throws { + let type = dumpType.value ?? .summary + + let output: String + switch type { + case .swiftDump: + var string = "" + dump(project, to: &string) + output = string + case .json: + let data = try JSONSerialization.data(withJSONObject: specLoader.projectDictionary!, options: .prettyPrinted) + output = String(data: data, encoding: .utf8)! + case .yaml: + output = try Yams.dump(object: specLoader.projectDictionary!) + case .parsedJSON: + let data = try JSONSerialization.data(withJSONObject: project.toJSONDictionary(), options: .prettyPrinted) + output = String(data: data, encoding: .utf8)! + case .parsedYaml: + output = try Yams.dump(object: project.toJSONDictionary()) + case .summary: + output = project.debugDescription + } + + stdout.print(output) + } +} + +fileprivate enum DumpType: String, ConvertibleFromString { + case swiftDump = "swift-dump" + case json + case yaml + case parsedJSON = "parsed-json" + case parsedYaml = "parsed-yaml" + case summary +} diff --git a/Sources/XcodeGenCLI/GenerateCommand.swift b/Sources/XcodeGenCLI/Commands/GenerateCommand.swift similarity index 77% rename from Sources/XcodeGenCLI/GenerateCommand.swift rename to Sources/XcodeGenCLI/Commands/GenerateCommand.swift index f4e2fa48..7b77be5b 100644 --- a/Sources/XcodeGenCLI/GenerateCommand.swift +++ b/Sources/XcodeGenCLI/Commands/GenerateCommand.swift @@ -5,10 +5,10 @@ import SwiftCLI import XcodeGenKit import XcodeProj -class GenerateCommand: Command { +class GenerateCommand: ProjectCommand { - let name: String = "generate" - let shortDescription: String = "Generate an Xcode project from a spec" + override var name: String { "generate" } + override var shortDescription: String { "Generate an Xcode project from a spec" } let quiet = Flag( "-q", @@ -17,13 +17,6 @@ class GenerateCommand: Command { defaultValue: false ) - let disableEnvExpansion = Flag( - "-n", - "--no-env", - description: "Disable environment variables expansions", - defaultValue: false - ) - let useCache = Flag( "-c", "--use-cache", @@ -36,42 +29,12 @@ class GenerateCommand: Command { description: "Where the cache file will be loaded from and save to. Defaults to ~/.xcodegen/cache/{SPEC_PATH_HASH}" ) - let spec = Key( - "-s", - "--spec", - description: "The path to the project spec file. Defaults to project.yml" - ) - let projectDirectory = Key("-p", "--project", description: "The path to the directory where the project should be generated. Defaults to the directory the spec is in. The filename is defined in the project spec") - let version: Version - - init(version: Version) { - self.version = version - } - - func execute() throws { - - let projectSpecPath = (spec.value ?? "project.yml").absolute() + override func execute(specLoader: SpecLoader, projectSpecPath: Path, project: Project) throws { let projectDirectory = self.projectDirectory.value?.absolute() ?? projectSpecPath.parent() - if !projectSpecPath.exists { - throw GenerationError.missingProjectSpec(projectSpecPath) - } - - let specLoader = SpecLoader(version: version) - let project: Project - - let variables: [String: String] = disableEnvExpansion.value ? [:] : ProcessInfo.processInfo.environment - - // load project spec - do { - project = try specLoader.loadProject(path: projectSpecPath, variables: variables) - } catch { - throw GenerationError.projectSpecParsingError(error) - } - // validate project dictionary do { try specLoader.validateProjectDictionaryWarnings() diff --git a/Sources/XcodeGenCLI/Commands/ProjectCommand.swift b/Sources/XcodeGenCLI/Commands/ProjectCommand.swift new file mode 100644 index 00000000..de642696 --- /dev/null +++ b/Sources/XcodeGenCLI/Commands/ProjectCommand.swift @@ -0,0 +1,56 @@ +import Foundation +import SwiftCLI +import ProjectSpec +import XcodeGenKit +import PathKit +import Core + +class ProjectCommand: Command { + + let version: Version + var name: String { "ProjectCommand" } + var shortDescription: String { "" } + + let spec = Key( + "-s", + "--spec", + description: "The path to the project spec file. Defaults to project.yml" + ) + + let disableEnvExpansion = Flag( + "-n", + "--no-env", + description: "Disable environment variable expansions", + defaultValue: false + ) + + init(version: Version) { + self.version = version + } + + func execute() throws { + + let projectSpecPath = (spec.value ?? "project.yml").absolute() + + if !projectSpecPath.exists { + throw GenerationError.missingProjectSpec(projectSpecPath) + } + + let specLoader = SpecLoader(version: version) + let project: Project + + let variables: [String: String] = disableEnvExpansion.value ? [:] : ProcessInfo.processInfo.environment + + do { + project = try specLoader.loadProject(path: projectSpecPath, variables: variables) + } catch { + throw GenerationError.projectSpecParsingError(error) + } + + try execute(specLoader: specLoader, projectSpecPath: projectSpecPath, project: project) + } + + func execute(specLoader: SpecLoader, projectSpecPath: Path, project: Project) throws { + + } +} diff --git a/Sources/XcodeGenCLI/XcodeGenCLI.swift b/Sources/XcodeGenCLI/XcodeGenCLI.swift index 5a7e772c..9901f451 100644 --- a/Sources/XcodeGenCLI/XcodeGenCLI.swift +++ b/Sources/XcodeGenCLI/XcodeGenCLI.swift @@ -12,7 +12,10 @@ public class XcodeGenCLI { name: "xcodegen", version: version.string, description: "Generates Xcode projects", - commands: [generateCommand] + commands: [ + generateCommand, + DumpCommand(version: version) + ] ) cli.parser.routeBehavior = .searchWithFallback(generateCommand) } From 155add1431cb14d5ee108f3c43a8be76493db8f1 Mon Sep 17 00:00:00 2001 From: yonaskolb Date: Fri, 8 Nov 2019 00:28:39 +1100 Subject: [PATCH 3/6] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dcffde09..21f8cdd7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ #### Added - Add Carthage static framework dependencies support. [#688](https://github.com/yonaskolb/XcodeGen/pull/688) @giginet +- Added `xcodegen dump` command [#710](https://github.com/yonaskolb/XcodeGen/pull/710) @yonaskolb - Added `--no-env` option to disable environment variables expansion [#704](https://github.com/yonaskolb/XcodeGen/pull/704) @rcari #### Fixed From aa0fd85bfe0d7323f14622f1800f5593cfcdfe0c Mon Sep 17 00:00:00 2001 From: yonaskolb Date: Fri, 8 Nov 2019 00:34:55 +1100 Subject: [PATCH 4/6] add file option --- Sources/XcodeGenCLI/Commands/DumpCommand.swift | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/Sources/XcodeGenCLI/Commands/DumpCommand.swift b/Sources/XcodeGenCLI/Commands/DumpCommand.swift index 424493b2..a9484fa0 100644 --- a/Sources/XcodeGenCLI/Commands/DumpCommand.swift +++ b/Sources/XcodeGenCLI/Commands/DumpCommand.swift @@ -10,11 +10,13 @@ class DumpCommand: ProjectCommand { override var shortDescription: String { "Dumps the project spec to stdout" } private let dumpType = Key("--type", "-t", description: """ - The type of dump to output. Either "json", "yaml", "summary", "swift-dump", "parsed-json", or "parsed-yaml". Defaults to summary. The "parsed" types parse the project into swift and then back again and can be used for testing. + The type of dump to output. Either "json", "yaml", "summary", "swift-dump", "parsed-json", or "parsed-yaml". Defaults to yaml. The "parsed" types parse the project into swift and then back again and can be used for testing. """) + private let file = Key("--file", "-f", description: "The path of a file to write to. If not supplied will output to stdout") + override func execute(specLoader: SpecLoader, projectSpecPath: Path, project: Project) throws { - let type = dumpType.value ?? .summary + let type = dumpType.value ?? .yaml let output: String switch type { @@ -36,7 +38,12 @@ class DumpCommand: ProjectCommand { output = project.debugDescription } - stdout.print(output) + if let file = file.value { + try file.parent().mkpath() + try file.write(output) + } else { + stdout.print(output) + } } } From 44f9ffa51ab3ed66c245042401d5e40998ec8cdf Mon Sep 17 00:00:00 2001 From: yonaskolb Date: Fri, 8 Nov 2019 00:37:29 +1100 Subject: [PATCH 5/6] formatting --- Sources/ProjectSpec/SpecFile.swift | 5 ++--- Sources/XcodeGenCLI/Commands/DumpCommand.swift | 18 +++++++++++++----- .../XcodeGenCLI/Commands/GenerateCommand.swift | 6 +++++- .../XcodeGenCLI/Commands/ProjectCommand.swift | 4 +--- Sources/XcodeGenCLI/XcodeGenCLI.swift | 2 +- Sources/XcodeGenKit/PBXProjGenerator.swift | 2 +- 6 files changed, 23 insertions(+), 14 deletions(-) diff --git a/Sources/ProjectSpec/SpecFile.swift b/Sources/ProjectSpec/SpecFile.swift index dbea372e..f5a87777 100644 --- a/Sources/ProjectSpec/SpecFile.swift +++ b/Sources/ProjectSpec/SpecFile.swift @@ -144,7 +144,7 @@ extension Dictionary where Key == String, Value: Any { return merged } - func expand(variables: [String:String]) -> JSONDictionary { + func expand(variables: [String: String]) -> JSONDictionary { var expanded: JSONDictionary = self if !variables.isEmpty { @@ -189,8 +189,7 @@ extension Dictionary where Key == String, Value: Any { index = result.endIndex } else if substring[index] == "$" && substring[substring.index(index, offsetBy: 1)] == "{" - && substring[substring.index(index, offsetBy: 2)] != "}" - { + && substring[substring.index(index, offsetBy: 2)] != "}" { // This is the start of a variable expansion... let variableStart = index if let variableEnd = substring.firstIndex(of: "}") { diff --git a/Sources/XcodeGenCLI/Commands/DumpCommand.swift b/Sources/XcodeGenCLI/Commands/DumpCommand.swift index a9484fa0..2c28adb7 100644 --- a/Sources/XcodeGenCLI/Commands/DumpCommand.swift +++ b/Sources/XcodeGenCLI/Commands/DumpCommand.swift @@ -9,11 +9,19 @@ class DumpCommand: ProjectCommand { override var name: String { "dump" } override var shortDescription: String { "Dumps the project spec to stdout" } - private let dumpType = Key("--type", "-t", description: """ - The type of dump to output. Either "json", "yaml", "summary", "swift-dump", "parsed-json", or "parsed-yaml". Defaults to yaml. The "parsed" types parse the project into swift and then back again and can be used for testing. - """) + private let dumpType = Key( + "--type", + "-t", + description: """ + The type of dump to output. Either "json", "yaml", "summary", "swift-dump", "parsed-json", or "parsed-yaml". Defaults to yaml. The "parsed" types parse the project into swift and then back again and can be used for testing. + """ + ) - private let file = Key("--file", "-f", description: "The path of a file to write to. If not supplied will output to stdout") + private let file = Key( + "--file", + "-f", + description: "The path of a file to write to. If not supplied will output to stdout" + ) override func execute(specLoader: SpecLoader, projectSpecPath: Path, project: Project) throws { let type = dumpType.value ?? .yaml @@ -47,7 +55,7 @@ class DumpCommand: ProjectCommand { } } -fileprivate enum DumpType: String, ConvertibleFromString { +private enum DumpType: String, ConvertibleFromString { case swiftDump = "swift-dump" case json case yaml diff --git a/Sources/XcodeGenCLI/Commands/GenerateCommand.swift b/Sources/XcodeGenCLI/Commands/GenerateCommand.swift index 7b77be5b..3178aa27 100644 --- a/Sources/XcodeGenCLI/Commands/GenerateCommand.swift +++ b/Sources/XcodeGenCLI/Commands/GenerateCommand.swift @@ -29,7 +29,11 @@ class GenerateCommand: ProjectCommand { description: "Where the cache file will be loaded from and save to. Defaults to ~/.xcodegen/cache/{SPEC_PATH_HASH}" ) - let projectDirectory = Key("-p", "--project", description: "The path to the directory where the project should be generated. Defaults to the directory the spec is in. The filename is defined in the project spec") + let projectDirectory = Key( + "-p", + "--project", + description: "The path to the directory where the project should be generated. Defaults to the directory the spec is in. The filename is defined in the project spec" + ) override func execute(specLoader: SpecLoader, projectSpecPath: Path, project: Project) throws { diff --git a/Sources/XcodeGenCLI/Commands/ProjectCommand.swift b/Sources/XcodeGenCLI/Commands/ProjectCommand.swift index de642696..bfda58c4 100644 --- a/Sources/XcodeGenCLI/Commands/ProjectCommand.swift +++ b/Sources/XcodeGenCLI/Commands/ProjectCommand.swift @@ -50,7 +50,5 @@ class ProjectCommand: Command { try execute(specLoader: specLoader, projectSpecPath: projectSpecPath, project: project) } - func execute(specLoader: SpecLoader, projectSpecPath: Path, project: Project) throws { - - } + func execute(specLoader: SpecLoader, projectSpecPath: Path, project: Project) throws {} } diff --git a/Sources/XcodeGenCLI/XcodeGenCLI.swift b/Sources/XcodeGenCLI/XcodeGenCLI.swift index 9901f451..32936561 100644 --- a/Sources/XcodeGenCLI/XcodeGenCLI.swift +++ b/Sources/XcodeGenCLI/XcodeGenCLI.swift @@ -14,7 +14,7 @@ public class XcodeGenCLI { description: "Generates Xcode projects", commands: [ generateCommand, - DumpCommand(version: version) + DumpCommand(version: version), ] ) cli.parser.routeBehavior = .searchWithFallback(generateCommand) diff --git a/Sources/XcodeGenKit/PBXProjGenerator.swift b/Sources/XcodeGenKit/PBXProjGenerator.swift index e1a5d75b..cd54dc4f 100644 --- a/Sources/XcodeGenKit/PBXProjGenerator.swift +++ b/Sources/XcodeGenKit/PBXProjGenerator.swift @@ -479,7 +479,7 @@ public class PBXProjGenerator { let dependecyLinkage = dependencyTarget.defaultLinkage let link = dependency.link ?? ((dependecyLinkage == .dynamic && target.type != .staticLibrary) || - (dependecyLinkage == .static && target.type.isExecutable)) + (dependecyLinkage == .static && target.type.isExecutable)) if link { let dependencyFile = targetFileReferences[dependencyTarget.name]! From d96f7890e4f35805543b0f87bd53d6937f242321 Mon Sep 17 00:00:00 2001 From: yonaskolb Date: Sun, 10 Nov 2019 11:37:30 +1100 Subject: [PATCH 6/6] Refactor commands --- Sources/XcodeGenCLI/Commands/DumpCommand.swift | 18 ++++++++++++------ .../XcodeGenCLI/Commands/GenerateCommand.swift | 10 +++++++--- .../XcodeGenCLI/Commands/ProjectCommand.swift | 8 +++++--- 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/Sources/XcodeGenCLI/Commands/DumpCommand.swift b/Sources/XcodeGenCLI/Commands/DumpCommand.swift index 2c28adb7..0cc075c4 100644 --- a/Sources/XcodeGenCLI/Commands/DumpCommand.swift +++ b/Sources/XcodeGenCLI/Commands/DumpCommand.swift @@ -6,14 +6,11 @@ import Yams class DumpCommand: ProjectCommand { - override var name: String { "dump" } - override var shortDescription: String { "Dumps the project spec to stdout" } - private let dumpType = Key( "--type", "-t", description: """ - The type of dump to output. Either "json", "yaml", "summary", "swift-dump", "parsed-json", or "parsed-yaml". Defaults to yaml. The "parsed" types parse the project into swift and then back again and can be used for testing. + The type of dump to output. Either \(DumpType.allCases.map { "\"\($0.rawValue)\"" }.joined(separator: ", ")). Defaults to \(DumpType.defaultValue.rawValue). The "parsed" types parse the project into swift and then back again. """ ) @@ -23,8 +20,15 @@ class DumpCommand: ProjectCommand { description: "The path of a file to write to. If not supplied will output to stdout" ) + init(version: Version) { + super.init(version: version, + name: "dump", + shortDescription: "Dumps the resolved project spec to stdout or a file" + ) + } + override func execute(specLoader: SpecLoader, projectSpecPath: Path, project: Project) throws { - let type = dumpType.value ?? .yaml + let type = dumpType.value ?? .defaultValue let output: String switch type { @@ -55,11 +59,13 @@ class DumpCommand: ProjectCommand { } } -private enum DumpType: String, ConvertibleFromString { +private enum DumpType: String, ConvertibleFromString, CaseIterable { case swiftDump = "swift-dump" case json case yaml case parsedJSON = "parsed-json" case parsedYaml = "parsed-yaml" case summary + + static var defaultValue: DumpType { .yaml } } diff --git a/Sources/XcodeGenCLI/Commands/GenerateCommand.swift b/Sources/XcodeGenCLI/Commands/GenerateCommand.swift index 3178aa27..e3e6a690 100644 --- a/Sources/XcodeGenCLI/Commands/GenerateCommand.swift +++ b/Sources/XcodeGenCLI/Commands/GenerateCommand.swift @@ -7,9 +7,6 @@ import XcodeProj class GenerateCommand: ProjectCommand { - override var name: String { "generate" } - override var shortDescription: String { "Generate an Xcode project from a spec" } - let quiet = Flag( "-q", "--quiet", @@ -35,6 +32,13 @@ class GenerateCommand: ProjectCommand { description: "The path to the directory where the project should be generated. Defaults to the directory the spec is in. The filename is defined in the project spec" ) + init(version: Version) { + super.init(version: version, + name: "generate", + shortDescription: "Generate an Xcode project from a spec" + ) + } + override func execute(specLoader: SpecLoader, projectSpecPath: Path, project: Project) throws { let projectDirectory = self.projectDirectory.value?.absolute() ?? projectSpecPath.parent() diff --git a/Sources/XcodeGenCLI/Commands/ProjectCommand.swift b/Sources/XcodeGenCLI/Commands/ProjectCommand.swift index bfda58c4..18c2faa1 100644 --- a/Sources/XcodeGenCLI/Commands/ProjectCommand.swift +++ b/Sources/XcodeGenCLI/Commands/ProjectCommand.swift @@ -8,8 +8,8 @@ import Core class ProjectCommand: Command { let version: Version - var name: String { "ProjectCommand" } - var shortDescription: String { "" } + let name: String + let shortDescription: String let spec = Key( "-s", @@ -24,8 +24,10 @@ class ProjectCommand: Command { defaultValue: false ) - init(version: Version) { + init(version: Version, name: String, shortDescription: String) { self.version = version + self.name = name + self.shortDescription = shortDescription } func execute() throws {