Skip to content

Commit 79dbcff

Browse files
authored
add support for local netrc file (#3790)
motivation: SE-0292 defines that local .etrc files should be honored changes: * add lookup for local .netrc file before defaulting to user hom directory * deprecate Workspace.Configuration.Netrc since it now redundant * add tests
1 parent 7550d27 commit 79dbcff

File tree

5 files changed

+105
-36
lines changed

5 files changed

+105
-36
lines changed

Sources/Basics/FileSystem+Extensions.swift

+4
Original file line numberDiff line numberDiff line change
@@ -129,4 +129,8 @@ extension FileSystem {
129129
public func writeFileContents(_ path: AbsolutePath, string: String) throws {
130130
return try self.writeFileContents(path, bytes: .init(encodingAsUTF8: string))
131131
}
132+
133+
public func writeFileContents(_ path: AbsolutePath, provider: () -> String) throws {
134+
return try self.writeFileContents(path, string: provider())
135+
}
132136
}

Sources/Commands/SwiftTool.swift

+17-13
Original file line numberDiff line numberDiff line change
@@ -498,34 +498,38 @@ public class SwiftTool {
498498
func getAuthorizationProvider() throws -> AuthorizationProvider? {
499499
var providers = [AuthorizationProvider]()
500500
// netrc file has higher specificity than keychain so use it first
501-
if let workspaceNetrc = try self.getNetrcConfig()?.get() {
502-
providers.append(workspaceNetrc)
501+
if let netrcConfigFile = try self.getNetrcConfigFile() {
502+
providers.append(try NetrcAuthorizationProvider(path: netrcConfigFile, fileSystem: localFileSystem))
503503
}
504504

505505
// TODO: add --no-keychain option to allow opt-out
506506
//#if canImport(Security)
507507
// providers.append(KeychainAuthorizationProvider(observabilityScope: self.observabilityScope))
508508
//#endif
509509

510-
return providers.isEmpty ? nil : CompositeAuthorizationProvider(providers, observabilityScope: self.observabilityScope)
510+
return providers.isEmpty ? .none : CompositeAuthorizationProvider(providers, observabilityScope: self.observabilityScope)
511511
}
512512

513-
func getNetrcConfig() -> Workspace.Configuration.Netrc? {
514-
guard options.netrc else { return nil }
513+
func getNetrcConfigFile() throws -> AbsolutePath? {
514+
guard options.netrc else {
515+
return .none
516+
}
515517

516518
if let configuredPath = options.netrcFilePath {
517519
guard localFileSystem.exists(configuredPath) else {
518-
self.observabilityScope.emit(error: "Did not find .netrc file at \(configuredPath).")
519-
return nil
520+
throw StringError("Did not find .netrc file at \(configuredPath).")
520521
}
522+
return configuredPath
523+
}
521524

522-
return .init(path: configuredPath, fileSystem: localFileSystem)
523-
} else {
524-
let defaultPath = localFileSystem.homeDirectory.appending(component: ".netrc")
525-
guard localFileSystem.exists(defaultPath) else { return nil }
526-
527-
return .init(path: defaultPath, fileSystem: localFileSystem)
525+
// TODO: replace multiroot-data-file with explicit overrides
526+
let localPath = try (options.multirootPackageDataFile ?? self.getPackageRoot()).appending(component: ".netrc")
527+
if localFileSystem.exists(localPath) {
528+
return localPath
528529
}
530+
531+
let userHomePath = localFileSystem.homeDirectory.appending(component: ".netrc")
532+
return localFileSystem.exists(userHomePath) ? userHomePath : .none
529533
}
530534

531535
private func getSharedCacheDirectory() throws -> AbsolutePath? {

Sources/Workspace/Workspace.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,7 @@ public class Workspace {
385385
),
386386
mirrors: config?.mirrors,
387387
authorizationProvider: netrcFilePath.map {
388-
try Configuration.Netrc(path: $0, fileSystem: fileSystem).get()
388+
try NetrcAuthorizationProvider(path: $0, fileSystem: fileSystem)
389389
},
390390
customToolsVersion: currentToolsVersion,
391391
customManifestLoader: manifestLoader,

Sources/Workspace/WorkspaceConfiguration.swift

-22
Original file line numberDiff line numberDiff line change
@@ -343,28 +343,6 @@ extension Workspace.Configuration {
343343
}
344344
}
345345

346-
// MARK: - Authentication
347-
348-
extension Workspace.Configuration {
349-
public struct Netrc {
350-
private let path: AbsolutePath
351-
private let fileSystem: FileSystem
352-
353-
public init(path: AbsolutePath, fileSystem: FileSystem) {
354-
self.path = path
355-
self.fileSystem = fileSystem
356-
}
357-
358-
public func get() throws -> AuthorizationProvider {
359-
return try Self.load(self.path, fileSystem: self.fileSystem)
360-
}
361-
362-
private static func load(_ path: AbsolutePath, fileSystem: FileSystem) throws -> AuthorizationProvider {
363-
try NetrcAuthorizationProvider(path: path, fileSystem: fileSystem)
364-
}
365-
}
366-
}
367-
368346
// MARK: - Registries
369347

370348
extension Workspace.Configuration {
+83
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
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 Basics
12+
@testable import Commands
13+
import SPMTestSupport
14+
import TSCBasic
15+
import XCTest
16+
17+
final class SwiftToolTests: XCTestCase {
18+
func testNetrcLocations() throws {
19+
fixture(name: "DependencyResolution/External/XCFramework") { packageRoot in
20+
let fs = localFileSystem
21+
22+
// custom .netrc file
23+
24+
do {
25+
let customPath = fs.homeDirectory.appending(component: UUID().uuidString)
26+
try fs.writeFileContents(customPath) {
27+
"machine mymachine.labkey.org login [email protected] password custom"
28+
}
29+
30+
31+
let options = try SwiftToolOptions.parse(["--package-path", packageRoot.pathString, "--netrc-file", customPath.pathString])
32+
let tool = try SwiftTool(options: options)
33+
XCTAssertEqual(try tool.getNetrcConfigFile().map(resolveSymlinks), resolveSymlinks(customPath))
34+
let auth = try tool.getAuthorizationProvider()?.authentication(for: URL(string: "https://mymachine.labkey.org")!)
35+
XCTAssertEqual(auth?.user, "[email protected]")
36+
XCTAssertEqual(auth?.password, "custom")
37+
38+
// delete it
39+
try localFileSystem.removeFileTree(customPath)
40+
XCTAssertThrowsError(try tool.getNetrcConfigFile(), "error expected") { error in
41+
XCTAssertEqual(error as? StringError, StringError("Did not find .netrc file at \(customPath)."))
42+
}
43+
}
44+
45+
// local .netrc file
46+
47+
do {
48+
let localPath = packageRoot.appending(component: ".netrc")
49+
try fs.writeFileContents(localPath) {
50+
return "machine mymachine.labkey.org login [email protected] password local"
51+
}
52+
53+
let options = try SwiftToolOptions.parse(["--package-path", packageRoot.pathString])
54+
let tool = try SwiftTool(options: options)
55+
56+
XCTAssertEqual(try tool.getNetrcConfigFile().map(resolveSymlinks), resolveSymlinks(localPath))
57+
let auth = try tool.getAuthorizationProvider()?.authentication(for: URL(string: "https://mymachine.labkey.org")!)
58+
XCTAssertEqual(auth?.user, "[email protected]")
59+
XCTAssertEqual(auth?.password, "local")
60+
}
61+
62+
// user .netrc file
63+
64+
do {
65+
// make sure there isn't a local one
66+
try localFileSystem.removeFileTree(packageRoot.appending(component: ".netrc"))
67+
68+
let userHomePath = fs.homeDirectory.appending(component: ".netrc")
69+
try fs.writeFileContents(userHomePath) {
70+
return "machine mymachine.labkey.org login [email protected] password user"
71+
}
72+
73+
let options = try SwiftToolOptions.parse(["--package-path", packageRoot.pathString])
74+
let tool = try SwiftTool(options: options)
75+
76+
XCTAssertEqual(try tool.getNetrcConfigFile().map(resolveSymlinks), resolveSymlinks(userHomePath))
77+
let auth = try tool.getAuthorizationProvider()?.authentication(for: URL(string: "https://mymachine.labkey.org")!)
78+
XCTAssertEqual(auth?.user, "[email protected]")
79+
XCTAssertEqual(auth?.password, "user")
80+
}
81+
}
82+
}
83+
}

0 commit comments

Comments
 (0)