Skip to content

Commit 9ab7090

Browse files
committed
Initial commit
0 parents  commit 9ab7090

File tree

5 files changed

+235
-0
lines changed

5 files changed

+235
-0
lines changed

.gitignore

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
.DS_Store
2+
/.build
3+
/Packages
4+
/*.xcodeproj
5+
xcuserdata/
6+
DerivedData/
7+
.swiftpm/config/registries.json
8+
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
9+
.netrc

Package.swift

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// swift-tools-version: 5.6
2+
// The swift-tools-version declares the minimum version of Swift required to build this package.
3+
4+
// Copyright Dave Verwer, Sven A. Schmidt, and other contributors.
5+
//
6+
// Licensed under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
18+
import PackageDescription
19+
20+
let package = Package(
21+
name: "spi-dependency-resolution",
22+
products: [
23+
.library(name: "DependencyResolution", targets: ["DependencyResolution"])
24+
],
25+
dependencies: [],
26+
targets: [
27+
.target(name: "DependencyResolution"),
28+
.testTarget(name: "DependencyResolutionTests",
29+
dependencies: [.target(name: "DependencyResolution")]
30+
)
31+
]
32+
)

README.md

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# spi-dependency-resolution
2+
3+
Support package for SPI-Server, handling dependency resolution.
4+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
// Copyright Dave Verwer, Sven A. Schmidt, and other contributors.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
import Foundation
16+
17+
public struct ResolvedDependency: Codable, Equatable {
18+
public var packageName: String
19+
public var repositoryURL: String
20+
21+
public init(packageName: String, repositoryURL: String) {
22+
self.packageName = packageName
23+
self.repositoryURL = repositoryURL
24+
}
25+
}
26+
27+
28+
public protocol FileManager {
29+
func contents(atPath: String) -> Data?
30+
func fileExists(atPath: String) -> Bool
31+
}
32+
33+
34+
extension Foundation.FileManager: FileManager { }
35+
36+
37+
public func getResolvedDependencies(_ fileManager: FileManager = Foundation.FileManager.default, at path: String) -> [ResolvedDependency]? {
38+
struct PackageResolved: Decodable {
39+
// object:
40+
// pins:
41+
// - package: String
42+
// repositoryURL: URL
43+
// - ...
44+
// version: 1
45+
struct V1: Decodable {
46+
var object: Object
47+
48+
struct Object: Decodable {
49+
var pins: [Pin]
50+
51+
struct Pin: Decodable {
52+
var package: String
53+
var repositoryURL: URL
54+
}
55+
}
56+
}
57+
58+
// object:
59+
// pins:
60+
// - identity: String
61+
// location: URL
62+
// - ...
63+
// version: 1
64+
struct V2: Decodable {
65+
var pins: [Pin]
66+
67+
struct Pin: Decodable {
68+
var identity: String
69+
var location: URL
70+
}
71+
}
72+
}
73+
74+
let filePath = URL(fileURLWithPath: path)
75+
.appendingPathComponent("Package.resolved").path
76+
77+
guard fileManager.fileExists(atPath: filePath),
78+
let json = fileManager.contents(atPath: filePath) else { return nil }
79+
80+
if let packageResolvedV2 = try? JSONDecoder()
81+
.decode(PackageResolved.V2.self, from: json) {
82+
return packageResolvedV2.pins.map {
83+
ResolvedDependency(
84+
packageName: $0.identity,
85+
repositoryURL: $0.location.absoluteString
86+
)
87+
}
88+
}
89+
90+
if let packageResolvedV1 = try? JSONDecoder()
91+
.decode(PackageResolved.V1.self, from: json) {
92+
return packageResolvedV1.object.pins.map {
93+
ResolvedDependency(
94+
packageName: $0.package,
95+
repositoryURL: $0.repositoryURL.absoluteString
96+
)
97+
}
98+
}
99+
100+
return nil
101+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
// Copyright Dave Verwer, Sven A. Schmidt, and other contributors.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
@testable import DependencyResolution
16+
17+
import XCTest
18+
19+
20+
/// Tests for utilities and extesions that don't each need a full separate test class
21+
class DependencyResolutionTests: XCTestCase {
22+
23+
func test_getResolvedDependencies_v1() throws {
24+
// setup
25+
struct TestFileManager: DependencyResolution.FileManager {
26+
func contents(atPath: String) -> Data? {
27+
Data("""
28+
{
29+
"object": {
30+
"pins": [
31+
{
32+
"package": "Yams",
33+
"repositoryURL": "https://github.com/jpsim/Yams.git",
34+
"state": {
35+
"branch": null,
36+
"revision": "01835dc202670b5bb90d07f3eae41867e9ed29f6",
37+
"version": "5.0.1"
38+
}
39+
}
40+
]
41+
},
42+
"version": 1
43+
}
44+
""".utf8)
45+
}
46+
func fileExists(atPath: String) -> Bool { true }
47+
}
48+
49+
// MUT
50+
let deps = getResolvedDependencies(TestFileManager(),
51+
at: "path ignored because we mock it")
52+
53+
// validate
54+
XCTAssertEqual(deps?.count, 1)
55+
}
56+
57+
func test_getResolvedDependencies_v2() throws {
58+
// setup
59+
struct TestFileManager: DependencyResolution.FileManager {
60+
func contents(atPath: String) -> Data? {
61+
Data("""
62+
{
63+
"pins" : [
64+
{
65+
"identity" : "swift-log",
66+
"kind" : "remoteSourceControl",
67+
"location" : "https://github.com/apple/swift-log.git",
68+
"state" : {
69+
"revision" : "6fe203dc33195667ce1759bf0182975e4653ba1c",
70+
"version" : "1.4.4"
71+
}
72+
}
73+
],
74+
"version" : 2
75+
}
76+
""".utf8)
77+
}
78+
func fileExists(atPath: String) -> Bool { true }
79+
}
80+
81+
// MUT
82+
let deps = getResolvedDependencies(TestFileManager(),
83+
at: "path ignored because we mock it")
84+
85+
// validate
86+
XCTAssertEqual(deps?.count, 1)
87+
}
88+
89+
}

0 commit comments

Comments
 (0)