Skip to content

Commit 6683021

Browse files
committed
synced changes from swift-tools-support-core #88
1 parent 9e52092 commit 6683021

File tree

3 files changed

+50
-51
lines changed

3 files changed

+50
-51
lines changed

swift-tools-support-core/Sources/TSCUtility/Netrc.swift

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import Foundation
22
import TSCBasic
33

4-
54
/// Supplies `Authorization` header, typically to be appended to `URLRequest`
65
public protocol AuthorizationProviding {
76
/// Optional `Authorization` header, likely added to `URLRequest`
@@ -14,21 +13,30 @@ extension AuthorizationProviding {
1413
}
1514
}
1615

16+
#if os(Windows)
17+
// FIXME: - add support for Windows when regex function available
18+
#endif
19+
20+
#if os(Linux)
21+
// FIXME: - add support for Linux when regex function available
22+
#endif
23+
24+
#if os(macOS)
25+
/*
26+
Netrc feature depends upon `NSTextCheckingResult.range(withName name: String) -> NSRange`,
27+
which is only available in macOS 10.13+ at this time.
28+
*/
1729
@available (OSX 10.13, *)
1830
/// Container of parsed netrc connection settings
1931
public struct Netrc: AuthorizationProviding {
20-
21-
/// Representation of `machine` connection settings & `default` connection settings. If `default` connection settings present, they will be last element.
32+
/// Representation of `machine` connection settings & `default` connection settings.
33+
/// If `default` connection settings present, they will be last element.
2234
public let machines: [Machine]
2335

2436
private init(machines: [Machine]) {
2537
self.machines = machines
2638
}
2739

28-
// /// Testing API. Not for productive use.
29-
// /// See: [Remove @testable from codebase](https://github.com/apple/swift-package-manager/commit/b6349d516d2f9b2f26ddae9de2c594ede24af7d6)
30-
// public static var _mock: Netrc? = nil
31-
3240
/// Basic authorization header string
3341
/// - Parameter url: URI of network resource to be accessed
3442
/// - Returns: (optional) Basic Authorization header string to be added to the request
@@ -40,11 +48,10 @@ public struct Netrc: AuthorizationProviding {
4048
return "Basic \(authData.base64EncodedString())"
4149
}
4250

43-
///
51+
/// Reads file at path or default location, and returns parsed Netrc representation
4452
/// - Parameter fileURL: Location of netrc file, defaults to `~/.netrc`
4553
/// - Returns: `Netrc` container with parsed connection settings, or error
4654
public static func load(fromFileAtPath filePath: AbsolutePath? = nil) -> Result<Netrc, Netrc.Error> {
47-
4855
let filePath = filePath ?? AbsolutePath("\(NSHomeDirectory())/.netrc")
4956

5057
guard FileManager.default.fileExists(atPath: filePath.pathString) else { return .failure(.fileNotFound(filePath)) }
@@ -54,12 +61,10 @@ public struct Netrc: AuthorizationProviding {
5461
return Netrc.from(fileContents)
5562
}
5663

57-
5864
/// Regex matching logic for deriving `Netrc` container from string content
5965
/// - Parameter content: String text of netrc file
6066
/// - Returns: `Netrc` container with parsed connection settings, or error
6167
public static func from(_ content: String) -> Result<Netrc, Netrc.Error> {
62-
6368
let content = trimComments(from: content)
6469
let regex = try! NSRegularExpression(pattern: RegexUtil.netrcPattern, options: [])
6570
let matches = regex.matches(in: content, options: [], range: NSRange(content.startIndex..<content.endIndex, in: content))
@@ -75,8 +80,6 @@ public struct Netrc: AuthorizationProviding {
7580
guard machines.count > 0 else { return .failure(.machineNotFound) }
7681
return .success(Netrc(machines: machines))
7782
}
78-
79-
8083
/// Utility method to trim comments from netrc content
8184
/// - Parameter text: String text of netrc file
8285
/// - Returns: String text of netrc file *sans* comments
@@ -96,7 +99,6 @@ public struct Netrc: AuthorizationProviding {
9699

97100
@available (OSX 10.13, *)
98101
public extension Netrc {
99-
100102
enum Error: Swift.Error {
101103
case invalidFilePath
102104
case fileNotFound(AbsolutePath)
@@ -135,9 +137,7 @@ public extension Netrc {
135137

136138
@available (OSX 10.13, *)
137139
fileprivate enum RegexUtil {
138-
139140
@frozen fileprivate enum Token: String, CaseIterable {
140-
141141
case machine, login, password, account, macdef, `default`
142142

143143
func capture(prefix: String = "", in match: NSTextCheckingResult, string: String) -> String? {
@@ -147,15 +147,12 @@ fileprivate enum RegexUtil {
147147
}
148148

149149
static let comments: String = "\\#[\\s\\S]*?.*$"
150-
151150
static let `default`: String = #"(?:\s*(?<default>default))"#
152151
static let accountOptional: String = #"(?:\s*account\s+\S++)?"#
153-
154152
static let loginPassword: String = #"\#(namedTrailingCapture("login", prefix: "lp"))\#(accountOptional)\#(namedTrailingCapture("password", prefix: "lp"))"#
155153
static let passwordLogin: String = #"\#(namedTrailingCapture("password", prefix: "pl"))\#(accountOptional)\#(namedTrailingCapture("login", prefix: "pl"))"#
156-
157154
static let netrcPattern = #"(?:(?:(\#(namedTrailingCapture("machine"))|\#(namedMatch("default"))))(?:\#(loginPassword)|\#(passwordLogin)))"#
158-
155+
159156
static func namedMatch(_ string: String) -> String {
160157
return #"(?:\s*(?<\#(string)>\#(string)))"#
161158
}
@@ -164,3 +161,4 @@ fileprivate enum RegexUtil {
164161
return #"\s*\#(string)\s+(?<\#(prefix + string)>\S++)"#
165162
}
166163
}
164+
#endif

swift-tools-support-core/Tests/TSCUtilityTests/DownloaderTests.swift

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -73,18 +73,19 @@ class DownloaderTests: XCTestCase {
7373
}
7474
#endif
7575
}
76-
76+
77+
#if os(macOS)
7778
@available(OSX 10.13, *)
79+
/// Netrc feature depends upon `NSTextCheckingResult.range(withName name: String) -> NSRange`,
80+
/// which is only available in macOS 10.13+ at this time.
7881
func testAuthenticatedSuccess() {
79-
8082
let netrcContent = "machine protected.downloader-tests.com login anonymous password qwerty"
8183
guard case .success(let netrc) = Netrc.from(netrcContent) else {
8284
return XCTFail("Cannot load netrc content")
8385
}
8486
let authData = "anonymous:qwerty".data(using: .utf8)!
8587
let testAuthHeader = "Basic \(authData.base64EncodedString())"
8688

87-
#if os(macOS)
8889
let configuration = URLSessionConfiguration.default
8990
configuration.protocolClasses = [MockAuthenticatingURLProtocol.self]
9091
let downloader = FoundationDownloader(configuration: configuration)
@@ -137,20 +138,21 @@ class DownloaderTests: XCTestCase {
137138
MockAuthenticatingURLProtocol.sendCompletion(for: url)
138139
wait(for: [successExpectation], timeout: 1.0)
139140
}
140-
#endif
141141
}
142+
#endif
142143

144+
#if os(macOS)
143145
@available(OSX 10.13, *)
146+
/// Netrc feature depends upon `NSTextCheckingResult.range(withName name: String) -> NSRange`,
147+
/// which is only available in macOS 10.13+ at this time.
144148
func testDefaultAuthenticationSuccess() {
145-
146149
let netrcContent = "default login default password default"
147150
guard case .success(let netrc) = Netrc.from(netrcContent) else {
148151
return XCTFail("Cannot load netrc content")
149152
}
150153
let authData = "default:default".data(using: .utf8)!
151154
let testAuthHeader = "Basic \(authData.base64EncodedString())"
152155

153-
#if os(macOS)
154156
let configuration = URLSessionConfiguration.default
155157
configuration.protocolClasses = [MockAuthenticatingURLProtocol.self]
156158
let downloader = FoundationDownloader(configuration: configuration)
@@ -203,8 +205,8 @@ class DownloaderTests: XCTestCase {
203205
MockAuthenticatingURLProtocol.sendCompletion(for: url)
204206
wait(for: [successExpectation], timeout: 1.0)
205207
}
206-
#endif
207208
}
209+
#endif
208210

209211
func testClientError() {
210212
// FIXME: Remove once https://github.com/apple/swift-corelibs-foundation/pull/2593 gets inside a toolchain.

swift-tools-support-core/Tests/TSCUtilityTests/NetrcTests.swift

Lines changed: 23 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
import XCTest
22
import TSCUtility
33

4+
#if os(macOS)
45
@available(macOS 10.13, *)
6+
/// Netrc feature depends upon `NSTextCheckingResult.range(withName name: String) -> NSRange`,
7+
/// which is only available in macOS 10.13+ at this time.
58
class NetrcTests: XCTestCase {
9+
/// should load machines for a given inline format
610
func testLoadMachinesInline() {
7-
// it("should load machines for a given inline format") {
811
let content = "machine example.com login anonymous password qwerty"
912

1013
guard case .success(let netrc) = Netrc.from(content) else { return XCTFail() }
@@ -25,8 +28,8 @@ class NetrcTests: XCTestCase {
2528
XCTAssertNil(netrc.authorization(for: URL(string: "http://www.example2.com/resource.zip")!))
2629
}
2730

31+
/// should load machines for a given multi-line format
2832
func testLoadMachinesMultiLine() {
29-
// it("should load machines for a given multi-line format") {
3033
let content = """
3134
machine example.com
3235
login anonymous
@@ -51,6 +54,7 @@ class NetrcTests: XCTestCase {
5154
XCTAssertNil(netrc.authorization(for: URL(string: "http://www.example2.com/resource.zip")!))
5255
}
5356

57+
/// Should fall back to default machine when not matching host
5458
func testLoadDefaultMachine() {
5559
let content = """
5660
machine example.com
@@ -175,9 +179,8 @@ class NetrcTests: XCTestCase {
175179
guard case .failure(.invalidDefaultMachinePosition) = Netrc.from(content) else { return XCTFail() }
176180
}
177181

182+
/// should load machines for a given multi-line format with comments
178183
func testLoadMachinesMultilineComments() {
179-
180-
// it("should load machines for a given multi-line format with comments") {
181184
let content = """
182185
## This is a comment
183186
# This is another comment
@@ -195,8 +198,8 @@ class NetrcTests: XCTestCase {
195198
XCTAssertEqual(machine?.password, "qwerty")
196199
}
197200

201+
/// should load machines for a given multi-line + whitespaces format
198202
func testLoadMachinesMultilineWhitespaces() {
199-
// it("should load machines for a given multi-line + whitespaces format") {
200203
let content = """
201204
machine example.com login anonymous
202205
password qwerty
@@ -211,8 +214,8 @@ class NetrcTests: XCTestCase {
211214
XCTAssertEqual(machine?.password, "qwerty")
212215
}
213216

217+
/// should load multiple machines for a given inline format
214218
func testLoadMultipleMachinesInline() {
215-
// it("should load multiple machines for a given inline format") {
216219
let content = "machine example.com login anonymous password qwerty machine example2.com login anonymous2 password qwerty2"
217220

218221
guard case .success(let netrc) = Netrc.from(content) else { return XCTFail() }
@@ -227,8 +230,8 @@ class NetrcTests: XCTestCase {
227230
XCTAssertEqual(netrc.machines[1].password, "qwerty2")
228231
}
229232

233+
/// should load multiple machines for a given multi-line format
230234
func testLoadMultipleMachinesMultiline() {
231-
// it("should load multiple machines for a given multi-line format") {
232235
let content = """
233236
machine example.com login anonymous
234237
password qwerty
@@ -251,26 +254,26 @@ class NetrcTests: XCTestCase {
251254
XCTAssertEqual(machine?.password, "qwerty2")
252255
}
253256

257+
/// should throw error when machine parameter is missing
254258
func testErrorMachineParameterMissing() {
255-
// it("should throw error when machine parameter is missing") {
256259
let content = "login anonymous password qwerty"
257260

258261
guard case .failure(.machineNotFound) = Netrc.from(content) else {
259262
return XCTFail("Expected machineNotFound error")
260263
}
261264
}
262265

266+
/// should throw error for an empty machine values
263267
func testErrorEmptyMachineValue() {
264-
// it("should throw error for an empty machine values") {
265268
let content = "machine"
266269

267270
guard case .failure(.machineNotFound) = Netrc.from(content) else {
268271
return XCTFail("Expected machineNotFound error")
269272
}
270273
}
271274

275+
/// should throw error for an empty machine values
272276
func testEmptyMachineValueFollowedByDefaultNoError() {
273-
// it("should throw error for an empty machine values") {
274277
let content = "machine default login id password secret"
275278
guard case .success(let netrc) = Netrc.from(content) else { return XCTFail() }
276279
let authorization = netrc.authorization(for: URL(string: "http://example.com/resource.zip")!)
@@ -279,8 +282,8 @@ class NetrcTests: XCTestCase {
279282
XCTAssertEqual(authorization, "Basic \(authData.base64EncodedString())")
280283
}
281284

285+
/// should return authorization when config contains a given machine
282286
func testReturnAuthorizationForMachineMatch() {
283-
// it("should return authorization when config contains a given machine") {
284287
let content = "machine example.com login anonymous password qwerty"
285288

286289
guard case .success(let netrc) = Netrc.from(content) else { return XCTFail() }
@@ -300,8 +303,8 @@ class NetrcTests: XCTestCase {
300303
XCTAssertNil(netrc.authorization(for: URL(string: "http://www.example2.com/resource.zip")!))
301304
}
302305

306+
/// should not return authorization when config does not contain a given machine
303307
func testNoReturnAuthorizationForNoMachineMatch() {
304-
// it("should not return authorization when config does not contain a given machine") {
305308
let content = "machine example.com login anonymous password qwerty"
306309

307310
guard case .success(let netrc) = Netrc.from(content) else { return XCTFail() }
@@ -312,8 +315,8 @@ class NetrcTests: XCTestCase {
312315
XCTAssertNil(netrc.authorization(for: URL(string: "http://www.example2.com/resource.zip")!))
313316
}
314317

318+
/// Test case: https://www.ibm.com/support/knowledgecenter/en/ssw_aix_72/filesreference/netrc.html
315319
func testIBMDocumentation() {
316-
// test case: https://www.ibm.com/support/knowledgecenter/en/ssw_aix_72/filesreference/netrc.html
317320
let content = "machine host1.austin.century.com login fred password bluebonnet"
318321

319322
guard let netrc = try? Netrc.from(content).get() else {
@@ -324,13 +327,11 @@ class NetrcTests: XCTestCase {
324327
XCTAssertEqual(machine?.name, "host1.austin.century.com")
325328
XCTAssertEqual(machine?.login, "fred")
326329
XCTAssertEqual(machine?.password, "bluebonnet")
327-
328330
}
329331

332+
/// Should not fail on presence of `account`, `macdef`, `default`
333+
/// test case: https://gist.github.com/tpope/4247721
330334
func testNoErrorTrailingAccountMacdefDefault() {
331-
// test case: https://gist.github.com/tpope/4247721
332-
333-
// should not fail on presence of `account`, `macdef`, `default`
334335
let content = """
335336
machine api.heroku.com
336337
@@ -368,10 +369,9 @@ class NetrcTests: XCTestCase {
368369
XCTAssertEqual(netrc.machines[3].password, "[email protected]")
369370
}
370371

372+
/// Should not fail on presence of `account`, `macdef`, `default`
373+
/// test case: https://gist.github.com/tpope/4247721
371374
func testNoErrorMixedAccount() {
372-
// test case: https://gist.github.com/tpope/4247721
373-
374-
// should not fail on presence of `account`, `macdef`, `default`
375375
let content = """
376376
machine api.heroku.com
377377
@@ -409,10 +409,9 @@ class NetrcTests: XCTestCase {
409409
XCTAssertEqual(netrc.machines[3].password, "[email protected]")
410410
}
411411

412+
/// Should not fail on presence of `account`, `macdef`, `default`
413+
/// test case: https://renenyffenegger.ch/notes/Linux/fhs/home/username/_netrc
412414
func testNoErrorMultipleMacdefAndComments() {
413-
// test case: https://renenyffenegger.ch/notes/Linux/fhs/home/username/_netrc
414-
415-
// should not fail on presence of `account`, `macdef`, `default`
416415
let content = """
417416
machine ftp.foobar.baz
418417
login john
@@ -444,6 +443,6 @@ class NetrcTests: XCTestCase {
444443
XCTAssertEqual(netrc.machines[1].name, "other.server.org")
445444
XCTAssertEqual(netrc.machines[1].login, "fred")
446445
XCTAssertEqual(netrc.machines[1].password, "sunshine4ever")
447-
448446
}
449447
}
448+
#endif

0 commit comments

Comments
 (0)