Skip to content

Commit 490c2a3

Browse files
authored
Specstesting Copy files to .cocoapods dir (#9077)
* Copy files to .cocoapods dir.
1 parent 0e855f4 commit 490c2a3

File tree

1 file changed

+149
-1
lines changed

1 file changed

+149
-1
lines changed

ReleaseTooling/Sources/PodspecsTester/InitializeSource.swift

Lines changed: 149 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,27 @@ extension Constants {
2626
static let specRepo = "https://github.com/firebase/SpecsTesting"
2727
static let sdkRepo = "https://github.com/firebase/firebase-ios-sdk"
2828
static let testingTagPrefix = "testing-"
29+
static let cocoapodsDir =
30+
"\(ProcessInfo.processInfo.environment["HOME"]!)/.cocoapods/repos/\(localSpecRepoName)"
31+
static let versionFetchPatterns = [
32+
"json": "\"version\"[[:space:]]*:[[:space:]]*\"(.*)\"",
33+
"podspec": "\\.version[[:space:]]*=[[:space:]]*\'([^~=><].*)\'",
34+
]
2935
}
3036

3137
struct InitializeSpecTesting {
38+
enum VersionFetchError: Error {
39+
case noMatchesCaught
40+
case multipleMatches
41+
case noSubgroupCaught
42+
}
43+
3244
static func setupRepo(sdkRepoURL: URL) {
3345
let manifest = FirebaseManifest.shared
3446
addSpecRepo(repoURL: Constants.specRepo)
3547
addTestingTag(path: sdkRepoURL, manifest: manifest)
3648
updatePodspecs(path: sdkRepoURL, manifest: manifest)
49+
copyPodspecs(from: sdkRepoURL, manifest: manifest)
3750
}
3851

3952
// The SpecsTesting repo will be added to `${HOME}/.cocoapods/`, and all
@@ -53,7 +66,6 @@ struct InitializeSpecTesting {
5366

5467
// Add a testing tag to the head of the branch.
5568
private static func addTestingTag(path sdkRepoPath: URL, manifest: FirebaseManifest.Manifest) {
56-
let manifest = FirebaseManifest.shared
5769
let testingTag = Constants.testingTagPrefix + manifest.version
5870
// Add or update the testing tag to the local sdk repo.
5971
Shell.executeCommand("git tag -af \(testingTag) -m 'spectesting'", workingDir: sdkRepoPath)
@@ -83,4 +95,140 @@ struct InitializeSpecTesting {
8395
}
8496
}
8597
}
98+
99+
// Copy updated specs to the `${HOME}/.cocoapods/` dir.
100+
private static func copyPodspecs(from specsDir: URL, manifest: FirebaseManifest.Manifest) {
101+
let path = specsDir.appendingPathComponent("*.{podspec,podspec.json}").path
102+
let paths = Shell.executeCommandFromScript("ls \(path)", outputToConsole: false)
103+
var candidateSpecs: [String]?
104+
switch paths {
105+
case let .error(code, output):
106+
print("specs are not properly read, \(output)")
107+
case let .success(output):
108+
candidateSpecs = output.trimmingCharacters(in: .whitespacesAndNewlines)
109+
.components(separatedBy: "\n")
110+
}
111+
guard let specs = candidateSpecs else {
112+
print("There are no files ending with `podspec` or `podspec.json` detected.")
113+
return
114+
}
115+
for spec in specs {
116+
let specInfo = fetchPodVersion(from: URL(fileURLWithPath: spec))
117+
// Create directories `${HOME}/.cocoapods/${Pod}/${version}`
118+
let podDirURL = createPodDirctory(
119+
specRepoPath: Constants.cocoapodsDir,
120+
podName: specInfo.name,
121+
version: specInfo.version
122+
)
123+
// Copy updated podspecs to directories `${HOME}/.cocoapods/${Pod}/${version}`
124+
Shell.executeCommand("cp -rf \(spec) \(podDirURL)")
125+
}
126+
}
127+
128+
private static func fetchPodVersion(from path: URL) -> (name: String, version: String) {
129+
var contents: String = ""
130+
var podName: String = ""
131+
var version: String = ""
132+
do {
133+
contents = try String(contentsOfFile: path.path, encoding: .utf8)
134+
} catch {
135+
fatalError("Could not read the podspec. \(error)")
136+
}
137+
// Closed source podspecs, e.g. GoogleAppMeasurement.podspec.json.
138+
if path.pathExtension == "json" {
139+
// Remove both extenstions of `podspec` and `json`.
140+
podName = path.deletingPathExtension().deletingPathExtension().lastPathComponent
141+
} else if path.pathExtension == "podspec" {
142+
podName = path.deletingPathExtension().lastPathComponent
143+
}
144+
145+
guard let versionPattern = Constants.versionFetchPatterns[path.pathExtension] else {
146+
fatalError("Regex pattern for \(path.pathExtension) is not found.")
147+
}
148+
149+
do {
150+
version = try matchVersion(from: contents, withPattern: versionPattern)
151+
} catch VersionFetchError.noMatchesCaught {
152+
fatalError(
153+
"Podspec from '\(path.path)' cannot find a version with the following regex\n\(versionPattern)"
154+
)
155+
} catch VersionFetchError.noSubgroupCaught {
156+
fatalError(
157+
"A subgroup of version from Podspec, '\(path.path)', is not caught from the pattern\n\(versionPattern)"
158+
)
159+
} catch VersionFetchError.multipleMatches {
160+
print("found multiple version matches from \(path.path).")
161+
fatalError(
162+
"There should have only one version matching the regex pattern, please update the pattern\n\(versionPattern)"
163+
)
164+
} catch {
165+
fatalError("Version is not caught properly. \(error)")
166+
}
167+
return (podName, version)
168+
}
169+
170+
private static func matchVersion(from content: String,
171+
withPattern regex: String) throws -> String {
172+
let versionMatches = try content.match(regex: regex)
173+
if versionMatches.isEmpty {
174+
throw VersionFetchError.noMatchesCaught
175+
}
176+
// One subgroup in the regex should be for the version
177+
else if versionMatches[0].count < 2 {
178+
throw VersionFetchError.noSubgroupCaught
179+
}
180+
// There are more than one string matching the regex. There should be only
181+
// one version matching the regex.
182+
else if versionMatches.count > 1 {
183+
print(versionMatches)
184+
throw VersionFetchError.multipleMatches
185+
}
186+
return versionMatches[0][1]
187+
}
188+
189+
private static func createPodDirctory(specRepoPath: String, podName: String,
190+
version: String) -> URL {
191+
guard let specRepoURL = URL(string: specRepoPath) else {
192+
fatalError("\(specRepoPath) does not exist.")
193+
}
194+
let podDirPath = specRepoURL.appendingPathComponent(podName).appendingPathComponent(version)
195+
if !FileManager.default.fileExists(atPath: podDirPath.absoluteString) {
196+
do {
197+
print("create path: \(podDirPath.absoluteString)")
198+
try FileManager.default.createDirectory(atPath: podDirPath.absoluteString,
199+
withIntermediateDirectories: true,
200+
attributes: nil)
201+
} catch {
202+
print(error.localizedDescription)
203+
}
204+
}
205+
return podDirPath
206+
}
207+
}
208+
209+
extension String: Error {
210+
/// Returns an array of matching groups, which contains matched string and
211+
/// subgroups.
212+
///
213+
/// - Parameters:
214+
/// - regex: A string of regex.
215+
/// - Returns: An array of array containing each match and its subgroups.
216+
func match(regex: String) throws -> [[String]] {
217+
do {
218+
let regex = try NSRegularExpression(pattern: regex, options: [])
219+
let nsString = self as NSString
220+
let results = regex.matches(
221+
in: self,
222+
options: [],
223+
range: NSMakeRange(0, nsString.length)
224+
)
225+
return results.map { result in
226+
(0 ..< result.numberOfRanges).map {
227+
nsString.substring(with: result.range(at: $0))
228+
}
229+
}
230+
} catch {
231+
fatalError("regex is invalid\n\(error.localizedDescription)")
232+
}
233+
}
86234
}

0 commit comments

Comments
 (0)