Skip to content

Commit 233ce17

Browse files
authored
Merge pull request swiftlang#1456 from millenomi/XDG
2 parents 77a8e7b + 37b8b44 commit 233ce17

File tree

9 files changed

+777
-19
lines changed

9 files changed

+777
-19
lines changed

Foundation.xcodeproj/project.pbxproj

+6
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
/* Begin PBXBuildFile section */
1010
0383A1751D2E558A0052E5D1 /* TestStream.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0383A1741D2E558A0052E5D1 /* TestStream.swift */; };
1111
03B6F5841F15F339004F25AF /* TestURLProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03B6F5831F15F339004F25AF /* TestURLProtocol.swift */; };
12+
1513A8432044893F00539722 /* FileManager_XDG.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1513A8422044893F00539722 /* FileManager_XDG.swift */; };
1213
1520469B1D8AEABE00D02E36 /* HTTPServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1520469A1D8AEABE00D02E36 /* HTTPServer.swift */; };
1314
153E951120111DC500F250BE /* CFKnownLocations.h in Headers */ = {isa = PBXBuildFile; fileRef = 153E950F20111DC500F250BE /* CFKnownLocations.h */; settings = {ATTRIBUTES = (Private, ); }; };
1415
153E951220111DC500F250BE /* CFKnownLocations.c in Sources */ = {isa = PBXBuildFile; fileRef = 153E951020111DC500F250BE /* CFKnownLocations.c */; };
@@ -515,6 +516,7 @@
515516
/* Begin PBXFileReference section */
516517
0383A1741D2E558A0052E5D1 /* TestStream.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestStream.swift; sourceTree = "<group>"; };
517518
03B6F5831F15F339004F25AF /* TestURLProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestURLProtocol.swift; sourceTree = "<group>"; };
519+
1513A8422044893F00539722 /* FileManager_XDG.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileManager_XDG.swift; sourceTree = "<group>"; };
518520
1520469A1D8AEABE00D02E36 /* HTTPServer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HTTPServer.swift; sourceTree = "<group>"; };
519521
153E950F20111DC500F250BE /* CFKnownLocations.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CFKnownLocations.h; sourceTree = "<group>"; };
520522
153E951020111DC500F250BE /* CFKnownLocations.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = CFKnownLocations.c; sourceTree = "<group>"; };
@@ -1822,6 +1824,7 @@
18221824
children = (
18231825
EADE0B5D1BD15DFF00C49C64 /* FileHandle.swift */,
18241826
EADE0B5E1BD15DFF00C49C64 /* FileManager.swift */,
1827+
1513A8422044893F00539722 /* FileManager_XDG.swift */,
18251828
EADE0B7A1BD15DFF00C49C64 /* Process.swift */,
18261829
5BDC3F2F1BCC5DCB00ED97BB /* Bundle.swift */,
18271830
5BDC3F411BCC5DCB00ED97BB /* ProcessInfo.swift */,
@@ -2344,6 +2347,7 @@
23442347
5BECBA3A1D1CAE9A00B39B1F /* NSMeasurement.swift in Sources */,
23452348
5BF7AEB21BCD51F9008F214A /* NSNumber.swift in Sources */,
23462349
61D2F9AF1FECFB3E0033306A /* NativeProtocol.swift in Sources */,
2350+
1513A8432044893F00539722 /* FileManager_XDG.swift in Sources */,
23472351
B9974B991EDF4A22007F15B8 /* HTTPURLProtocol.swift in Sources */,
23482352
5BCD03821D3EE35C00E3FF9B /* TimeZone.swift in Sources */,
23492353
EADE0BBC1BD15E0000C49C64 /* URLCache.swift in Sources */,
@@ -2713,6 +2717,7 @@
27132717
DYLIB_COMPATIBILITY_VERSION = 150;
27142718
DYLIB_CURRENT_VERSION = 1303;
27152719
DYLIB_INSTALL_NAME_BASE = "@rpath";
2720+
ENABLE_TESTABILITY = YES;
27162721
FRAMEWORK_VERSION = A;
27172722
GCC_PREFIX_HEADER = CoreFoundation/Base.subproj/CoreFoundation_Prefix.h;
27182723
HEADER_SEARCH_PATHS = (
@@ -2786,6 +2791,7 @@
27862791
DYLIB_COMPATIBILITY_VERSION = 150;
27872792
DYLIB_CURRENT_VERSION = 1303;
27882793
DYLIB_INSTALL_NAME_BASE = "@rpath";
2794+
ENABLE_TESTABILITY = YES;
27892795
FRAMEWORK_VERSION = A;
27902796
GCC_PREFIX_HEADER = CoreFoundation/Base.subproj/CoreFoundation_Prefix.h;
27912797
HEADER_SEARCH_PATHS = (

Foundation/FileManager.swift

+321-4
Large diffs are not rendered by default.

Foundation/FileManager_XDG.swift

+125
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
// This source file is part of the Swift.org open source project
2+
//
3+
// Copyright (c) 2014 - 2018 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 the list of Swift project authors
8+
//
9+
10+
import CoreFoundation
11+
12+
enum _XDGUserDirectory: String {
13+
case desktop = "DESKTOP"
14+
case download = "DOWNLOAD"
15+
case publicShare = "PUBLICSHARE"
16+
case documents = "DOCUMENTS"
17+
case music = "MUSIC"
18+
case pictures = "PICTURES"
19+
case videos = "VIDEOS"
20+
21+
static let allDirectories: [_XDGUserDirectory] = [
22+
.desktop,
23+
.download,
24+
.publicShare,
25+
.documents,
26+
.music,
27+
.pictures,
28+
.videos,
29+
]
30+
31+
var url: URL {
32+
return url(userConfiguration: _XDGUserDirectory.configuredDirectoryURLs,
33+
osDefaultConfiguration: _XDGUserDirectory.osDefaultDirectoryURLs,
34+
stopgaps: _XDGUserDirectory.stopgapDefaultDirectoryURLs)
35+
}
36+
37+
func url(userConfiguration: [_XDGUserDirectory: URL],
38+
osDefaultConfiguration: [_XDGUserDirectory: URL],
39+
stopgaps: [_XDGUserDirectory: URL]) -> URL {
40+
if let url = userConfiguration[self] {
41+
return url
42+
} else if let url = osDefaultConfiguration[self] {
43+
return url
44+
} else {
45+
return stopgaps[self]!
46+
}
47+
}
48+
49+
static let stopgapDefaultDirectoryURLs: [_XDGUserDirectory: URL] = {
50+
let home = URL(fileURLWithPath: NSHomeDirectory(), isDirectory: true)
51+
return [
52+
.desktop: home.appendingPathComponent("Desktop"),
53+
.download: home.appendingPathComponent("Downloads"),
54+
.publicShare: home.appendingPathComponent("Public"),
55+
.documents: home.appendingPathComponent("Documents"),
56+
.music: home.appendingPathComponent("Music"),
57+
.pictures: home.appendingPathComponent("Pictures"),
58+
.videos: home.appendingPathComponent("Videos"),
59+
]
60+
}()
61+
62+
static func userDirectories(fromConfigurationFileAt url: URL) -> [_XDGUserDirectory: URL]? {
63+
if let configuration = try? String(contentsOf: url, encoding: .utf8) {
64+
return userDirectories(fromConfiguration: configuration)
65+
} else {
66+
return nil
67+
}
68+
}
69+
70+
static func userDirectories(fromConfiguration configuration: String) -> [_XDGUserDirectory: URL] {
71+
var entries: [_XDGUserDirectory: URL] = [:]
72+
let home = URL(fileURLWithPath: NSHomeDirectory(), isDirectory: true)
73+
74+
// Parse it:
75+
let lines = configuration.split(separator: "\n")
76+
for line in lines {
77+
if let range = line.range(of: "=") {
78+
var variable = String(line[line.startIndex ..< range.lowerBound].trimmingCharacters(in: .whitespaces))
79+
80+
let prefix = "XDG_"
81+
let suffix = "_DIR"
82+
if variable.hasPrefix(prefix) && variable.hasSuffix(suffix) {
83+
let endOfPrefix = variable.index(variable.startIndex, offsetBy: prefix.length)
84+
let startOfSuffix = variable.index(variable.endIndex, offsetBy: -suffix.length)
85+
86+
variable = String(variable[endOfPrefix ..< startOfSuffix])
87+
}
88+
89+
guard let directory = _XDGUserDirectory(rawValue: variable) else {
90+
continue
91+
}
92+
93+
let path = String(line[range.upperBound ..< line.endIndex]).trimmingCharacters(in: .whitespaces)
94+
if !path.isEmpty {
95+
entries[directory] = URL(fileURLWithPath: path, isDirectory: true, relativeTo: home)
96+
}
97+
} else {
98+
return [:] // Incorrect syntax.
99+
}
100+
}
101+
102+
return entries
103+
}
104+
105+
static let configuredDirectoryURLs: [_XDGUserDirectory: URL] = {
106+
let configurationHome = _SwiftValue.fetch(nonOptional: _CFXDGCreateConfigHomePath()) as! String
107+
let configurationFile = URL(fileURLWithPath: "user-dirs.dirs", isDirectory: false, relativeTo: URL(fileURLWithPath: configurationHome, isDirectory: true))
108+
109+
return userDirectories(fromConfigurationFileAt: configurationFile) ?? [:]
110+
}()
111+
112+
static let osDefaultDirectoryURLs: [_XDGUserDirectory: URL] = {
113+
let configurationDirs = _SwiftValue.fetch(nonOptional: _CFXDGCreateConfigDirectoriesPaths()) as! [String]
114+
115+
for directory in configurationDirs {
116+
let configurationFile = URL(fileURLWithPath: directory, isDirectory: true).appendingPathComponent("user-dirs.defaults")
117+
118+
if let result = userDirectories(fromConfigurationFileAt: configurationFile) {
119+
return result
120+
}
121+
}
122+
123+
return [:]
124+
}()
125+
}

Foundation/NSPathUtilities.swift

+23-1
Original file line numberDiff line numberDiff line change
@@ -562,7 +562,29 @@ extension FileManager {
562562
}
563563

564564
public func NSSearchPathForDirectoriesInDomains(_ directory: FileManager.SearchPathDirectory, _ domainMask: FileManager.SearchPathDomainMask, _ expandTilde: Bool) -> [String] {
565-
NSUnimplemented()
565+
let knownDomains: [FileManager.SearchPathDomainMask] = [
566+
.userDomainMask,
567+
.networkDomainMask,
568+
.localDomainMask,
569+
.systemDomainMask,
570+
]
571+
572+
var result: [URL] = []
573+
574+
for domain in knownDomains {
575+
if domainMask.contains(domain) {
576+
result.append(contentsOf: FileManager.default.urls(for: directory, in: domain))
577+
}
578+
}
579+
580+
return result.map { (url) in
581+
var path = url.absoluteURL.path
582+
if expandTilde {
583+
path = NSString(string: path).expandingTildeInPath
584+
}
585+
586+
return path
587+
}
566588
}
567589

568590
public func NSHomeDirectory() -> String {

0 commit comments

Comments
 (0)