Skip to content

Commit 3ba72d1

Browse files
authored
Add swift package-registry command (#3647)
motivation: manage registries configurations changes: * Add PackageRegistry and PackageRegistryTests targets * Add RegistryConfiguration and RegistryConfigurationTests * Add swift-package-registry command * Add tests
1 parent b01ec65 commit 3ba72d1

File tree

14 files changed

+840
-1
lines changed

14 files changed

+840
-1
lines changed

Package.swift

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,10 +133,16 @@ let package = Package(
133133
name: "LLBuildManifest",
134134
dependencies: ["SwiftToolsSupport-auto", "Basics"]),
135135

136+
.target(
137+
/** Package registry support */
138+
name: "PackageRegistry",
139+
dependencies: ["SwiftToolsSupport-auto", "Basics", "PackageLoading", "PackageModel"]),
140+
136141
.target(
137142
/** Source control operations */
138143
name: "SourceControl",
139144
dependencies: ["SwiftToolsSupport-auto", "Basics"]),
145+
140146
.target(
141147
/** Shim for llbuild library */
142148
name: "SPMLLBuild",
@@ -158,7 +164,7 @@ let package = Package(
158164
.target(
159165
/** Data structures and support for complete package graphs */
160166
name: "PackageGraph",
161-
dependencies: ["SwiftToolsSupport-auto", "Basics", "PackageLoading", "PackageModel", "SourceControl"]),
167+
dependencies: ["SwiftToolsSupport-auto", "Basics", "PackageLoading", "PackageModel", "PackageRegistry", "SourceControl"]),
162168

163169
// MARK: Package Collections
164170

@@ -234,6 +240,10 @@ let package = Package(
234240
/** Interacts with package collections */
235241
name: "swift-package-collection",
236242
dependencies: ["Commands"]),
243+
.target(
244+
/** Interact with package registry */
245+
name: "swift-package-registry",
246+
dependencies: ["Commands"]),
237247
.target(
238248
/** Shim tool to find test names on OS X */
239249
name: "swiftpm-xctest-helper",
@@ -300,6 +310,9 @@ let package = Package(
300310
.testTarget(
301311
name: "PackageCollectionsTests",
302312
dependencies: ["PackageCollections", "SPMTestSupport"]),
313+
.testTarget(
314+
name: "PackageRegistryTests",
315+
dependencies: ["SPMTestSupport", "PackageRegistry"]),
303316
.testTarget(
304317
name: "SourceControlTests",
305318
dependencies: ["SourceControl", "SPMTestSupport"]),

Sources/Basics/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ add_library(Basics
1717
HTPClient+URLSession.swift
1818
HTTPClient.swift
1919
JSON+Extensions.swift
20+
JSONDecoder+Extensions.swift
2021
Sandbox.swift
2122
SwiftVersion.swift
2223
SQLiteBackedCache.swift
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*
2+
This source file is part of the Swift.org open source project
3+
4+
Copyright (c) 2021 Apple Inc. and the Swift project authors
5+
Licensed under Apache License v2.0 with Runtime Library Exception
6+
7+
See http://swift.org/LICENSE.txt for license information
8+
See http://swift.org/CONTRIBUTORS.txt for Swift project authors
9+
*/
10+
11+
import Foundation
12+
13+
extension JSONDecoder {
14+
public func decode<T>(_ type: T.Type, from string: String) throws -> T where T : Decodable {
15+
guard let data = string.data(using: .utf8) else {
16+
let context = DecodingError.Context(codingPath: [], debugDescription: "invalid UTF-8 string")
17+
throw DecodingError.dataCorrupted(context)
18+
}
19+
20+
return try decode(type, from: data)
21+
}
22+
}

Sources/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ add_subdirectory(PackageGraph)
1919
add_subdirectory(PackageLoading)
2020
add_subdirectory(PackageModel)
2121
add_subdirectory(PackagePlugin)
22+
add_subdirectory(PackageRegistry)
2223
add_subdirectory(SPMBuildCore)
2324
add_subdirectory(SPMLLBuild)
2425
add_subdirectory(SourceControl)

Sources/Commands/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ add_library(Commands
1616
show-dependencies.swift
1717
SwiftBuildTool.swift
1818
SwiftPackageCollectionsTool.swift
19+
SwiftPackageRegistryTool.swift
1920
SwiftPackageTool.swift
2021
SwiftRunTool.swift
2122
SwiftTestTool.swift
Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
/*
2+
This source file is part of the Swift.org open source project
3+
4+
Copyright (c) 2021 Apple Inc. and the Swift project authors
5+
Licensed under Apache License v2.0 with Runtime Library Exception
6+
7+
See http://swift.org/LICENSE.txt for license information
8+
See http://swift.org/CONTRIBUTORS.txt for Swift project authors
9+
*/
10+
11+
import ArgumentParser
12+
import Basics
13+
import TSCBasic
14+
import SPMBuildCore
15+
import Build
16+
import PackageModel
17+
import PackageLoading
18+
import PackageGraph
19+
import SourceControl
20+
import TSCUtility
21+
import XCBuildSupport
22+
import Workspace
23+
import Foundation
24+
import PackageRegistry
25+
26+
private enum RegistryConfigurationError: Swift.Error {
27+
case missingScope(String? = nil)
28+
case invalidURL(String)
29+
}
30+
31+
extension RegistryConfigurationError: CustomStringConvertible {
32+
var description: String {
33+
switch self {
34+
case .missingScope(let scope?):
35+
return "no existing entry for scope: \(scope)"
36+
case .missingScope:
37+
return "no existing entry for default scope"
38+
case .invalidURL(let url):
39+
return "invalid URL: \(url)"
40+
}
41+
}
42+
}
43+
44+
public struct SwiftPackageRegistryTool: ParsableCommand {
45+
public static var configuration = CommandConfiguration(
46+
commandName: "package-registry",
47+
_superCommandName: "swift",
48+
abstract: "Interact with package registry and manage related configuration",
49+
discussion: "SEE ALSO: swift package",
50+
version: SwiftVersion.currentVersion.completeDisplayString,
51+
subcommands: [
52+
Set.self,
53+
Unset.self
54+
],
55+
helpNames: [.short, .long, .customLong("help", withSingleDash: true)])
56+
57+
@OptionGroup()
58+
var swiftOptions: SwiftToolOptions
59+
60+
public init() {}
61+
62+
struct Set: SwiftCommand {
63+
static let configuration = CommandConfiguration(
64+
abstract: "Set a custom registry")
65+
66+
@OptionGroup(_hiddenFromHelp: true)
67+
var swiftOptions: SwiftToolOptions
68+
69+
@Flag(help: "Apply settings to all projects for this user")
70+
var global: Bool = false
71+
72+
@Option(help: "Associate the registry with a given scope")
73+
var scope: String?
74+
75+
// TODO: Uncomment once .netrc management is implemented
76+
77+
// @Option(help: "Specify a user name for the remote machine")
78+
// var login: String?
79+
80+
// @Option(help: "Supply a password for the remote machine")
81+
// var password: String?
82+
83+
@Argument(help: "The registry URL")
84+
var url: String
85+
86+
func run(_ swiftTool: SwiftTool) throws {
87+
guard let url = URL(string: self.url),
88+
url.scheme == "https"
89+
else {
90+
throw RegistryConfigurationError.invalidURL(self.url)
91+
}
92+
93+
// TODO: Require login if password is specified
94+
95+
let set: (inout RegistryConfiguration) throws -> Void = { configuration in
96+
if let scope = scope {
97+
configuration.scopedRegistries[scope] = .init(url: url)
98+
} else {
99+
configuration.defaultRegistry = .init(url: url)
100+
}
101+
}
102+
103+
let configuration = try swiftTool.getRegistriesConfig()
104+
if global {
105+
try configuration.updateShared(with: set)
106+
} else {
107+
try configuration.updateLocal(with: set)
108+
}
109+
110+
// TODO: Add login and password to .netrc
111+
}
112+
}
113+
114+
struct Unset: SwiftCommand {
115+
static let configuration = CommandConfiguration(
116+
abstract: "Remove a configured registry")
117+
118+
@OptionGroup(_hiddenFromHelp: true)
119+
var swiftOptions: SwiftToolOptions
120+
121+
@Flag(help: "Apply settings to all projects for this user")
122+
var global: Bool = false
123+
124+
@Option(help: "Associate the registry with a given scope")
125+
var scope: String?
126+
127+
func run(_ swiftTool: SwiftTool) throws {
128+
let unset: (inout RegistryConfiguration) throws -> Void = { configuration in
129+
if let scope = scope {
130+
guard let _ = configuration.scopedRegistries[scope] else {
131+
throw RegistryConfigurationError.missingScope(scope)
132+
}
133+
configuration.scopedRegistries.removeValue(forKey: scope)
134+
} else {
135+
guard let _ = configuration.defaultRegistry else {
136+
throw RegistryConfigurationError.missingScope()
137+
}
138+
configuration.defaultRegistry = nil
139+
}
140+
}
141+
142+
let configuration = try swiftTool.getRegistriesConfig()
143+
if global {
144+
try configuration.updateShared(with: unset)
145+
} else {
146+
try configuration.updateLocal(with: unset)
147+
}
148+
}
149+
}
150+
}
151+
152+
// MARK: -
153+
154+
155+
private extension SwiftTool {
156+
func getRegistriesConfig() throws -> Workspace.Configuration.Registries {
157+
let localRegistriesFile = try Workspace.DefaultLocations.registriesConfigurationFile(forRootPackage: self.getPackageRoot())
158+
159+
let workspace = try getActiveWorkspace()
160+
let sharedRegistriesFile = workspace.location.sharedConfigurationDirectory.map {
161+
Workspace.DefaultLocations.registriesConfigurationFile(at: $0)
162+
}
163+
164+
return try .init(
165+
localRegistriesFile: localRegistriesFile,
166+
sharedRegistriesFile: sharedRegistriesFile,
167+
fileSystem: localFileSystem
168+
)
169+
}
170+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# This source file is part of the Swift.org open source project
2+
#
3+
# Copyright (c) 2021 Apple Inc. and the Swift project authors
4+
# Licensed under Apache License v2.0 with Runtime Library Exception
5+
#
6+
# See http://swift.org/LICENSE.txt for license information
7+
# See http://swift.org/CONTRIBUTORS.txt for Swift project authors
8+
9+
add_library(PackageRegistry
10+
RegistryConfiguration.swift)
11+
target_link_libraries(PackageRegistry PUBLIC
12+
TSCBasic
13+
PackageLoading
14+
PackageModel
15+
TSCUtility)
16+
# NOTE(compnerd) workaround for CMake not setting up include flags yet
17+
set_target_properties(PackageRegistry PROPERTIES
18+
INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_Swift_MODULE_DIRECTORY})
19+
20+
if(USE_CMAKE_INSTALL)
21+
install(TARGETS PackageRegistry
22+
ARCHIVE DESTINATION lib
23+
LIBRARY DESTINATION lib
24+
RUNTIME DESTINATION bin)
25+
endif()
26+
set_property(GLOBAL APPEND PROPERTY SwiftPM_EXPORTS PackageRegistry)

0 commit comments

Comments
 (0)