-
Notifications
You must be signed in to change notification settings - Fork 877
Expand file tree
/
Copy pathGenerateCommand.swift
More file actions
154 lines (127 loc) · 5.23 KB
/
GenerateCommand.swift
File metadata and controls
154 lines (127 loc) · 5.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
import Foundation
import PathKit
import ProjectSpec
import SwiftCLI
import XcodeGenKit
import XcodeProj
import Version
class GenerateCommand: ProjectCommand {
@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
@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?
@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")
var projectDirectory: Path?
@Flag("--only-plists", description: "Generate only plist files")
var onlyPlists: Bool
@Flag("--dry-run", description: "Generate project in memory and print a JSON diff of what would change without writing any files")
var dryRun: Bool
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?.absolute() ?? projectSpecPath.parent()
// validate project dictionary
do {
try specLoader.validateProjectDictionaryWarnings()
} catch {
warning("\(error)")
}
let projectPath = projectDirectory + "\(project.name).xcodeproj"
// run pre gen command before we use the cache as the scripts may change it
if let command = project.options.preGenCommand {
try Task.run(bash: command, directory: projectDirectory.absolute().string)
}
let cacheFilePath = self.cacheFilePath ??
Path("~/.xcodegen/cache/\(projectSpecPath.absolute().string.md5)").absolute()
var cacheFile: CacheFile?
// generate cache
if useCache || self.cacheFilePath != nil {
do {
cacheFile = try specLoader.generateCacheFile()
} catch {
throw GenerationError.projectSpecParsingError(error)
}
}
let projectExists = XcodeProj.pbxprojPath(projectPath).exists
// check cache
if let cacheFile = cacheFile,
projectExists,
cacheFilePath.exists {
do {
let existingCacheFile: String = try cacheFilePath.read()
if cacheFile.string == existingCacheFile {
info("Project \(project.name) has not changed since cache was written")
return
}
} catch {
info("Couldn't load cache at \(cacheFile)")
}
}
// validate project
do {
try project.validateMinimumXcodeGenVersion(version)
try project.validate()
} catch let error as SpecValidationError {
throw GenerationError.validationError(error)
}
// generate plists
info("⚙️ Generating plists...")
let fileWriter = FileWriter(project: project)
do {
try fileWriter.writePlists()
if onlyPlists {
return
}
} catch {
throw GenerationError.writingError(error)
}
// generate project
info("⚙️ Generating project...")
let xcodeProject: XcodeProj
do {
let projectGenerator = ProjectGenerator(project: project)
guard let userName = ProcessInfo.processInfo.environment["USER"] else {
throw GenerationError.missingUsername
}
xcodeProject = try projectGenerator.generateXcodeProject(in: projectDirectory, userName: userName)
} catch {
throw GenerationError.generationError(error)
}
// dry-run: diff and exit without writing
if dryRun {
let existingPbxprojPath = XcodeProj.pbxprojPath(projectPath)
let existingXcodeprojPath = projectExists ? projectPath : nil
let diff = ProjectDiff(from: xcodeProject, against: existingXcodeprojPath)
do {
stdout.print(try diff.jsonString())
} catch {
throw GenerationError.writingError(error)
}
return
}
// write project
info("⚙️ Writing project...")
do {
try fileWriter.writeXcodeProject(xcodeProject, to: projectPath)
success("Created project at \(projectPath)")
} catch {
throw GenerationError.writingError(error)
}
// write cache
if let cacheFile = cacheFile {
do {
try cacheFilePath.parent().mkpath()
try cacheFilePath.write(cacheFile.string)
} catch {
info("Failed to write cache: \(error.localizedDescription)")
}
}
// run post gen command
if let command = project.options.postGenCommand {
try Task.run(bash: command, directory: projectDirectory.absolute().string)
}
}
}