Skip to content

Commit b935c06

Browse files
committed
Make this work, and testable under Darwin and Linux.
1 parent cd7060e commit b935c06

File tree

5 files changed

+294
-132
lines changed

5 files changed

+294
-132
lines changed

Foundation/FileManager.swift

Lines changed: 131 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@
77
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
88
//
99

10-
#if os(macOS) || os(iOS)
10+
#if canImport(Darwin)
1111
import Darwin
12-
#elseif os(Linux) || CYGWIN
12+
#endif
13+
14+
#if canImport(Glibc)
1315
import Glibc
1416
#endif
1517

@@ -128,23 +130,22 @@ open class FileManager : NSObject {
128130

129131
init?(_ domainMask: SearchPathDomainMask) {
130132
if domainMask == .systemDomainMask {
131-
self = .system
133+
self = .system; return
132134
}
133135
if domainMask == .localDomainMask {
134-
self = .local
136+
self = .local; return
135137
}
136138
if domainMask == .networkDomainMask {
137-
self = .network
139+
self = .network; return
138140
}
139141
if domainMask == .userDomainMask {
140-
self = .user
142+
self = .user; return
141143
}
142144

143145
return nil
144146
}
145147
}
146148

147-
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
148149
private func darwinPathURLs(for domain: _SearchPathDomain, system: String?, local: String?, network: String?, userHomeSubpath: String?) -> [URL] {
149150
switch domain {
150151
case .system:
@@ -174,35 +175,140 @@ open class FileManager : NSObject {
174175
return [ URL(fileURLWithPath: all, isDirectory: true, relativeTo: URL(fileURLWithPath: NSHomeDirectory(), isDirectory: true)) ]
175176
}
176177
}
177-
#endif
178178

179179
#if os(Windows) // Non-Apple OSes that do not implement FHS/XDG are not currently supported.
180180
@available(*, unavailable, message: "Not implemented for this OS")
181181
open func urls(for directory: SearchPathDirectory, in domainMask: SearchPathDomainMask) -> [URL] {
182182
NSUnimplemented()
183183
}
184184
#else
185-
186185
/* -URLsForDirectory:inDomains: is analogous to NSSearchPathForDirectoriesInDomains(), but returns an array of NSURL instances for use with URL-taking APIs. This API is suitable when you need to search for a file or files which may live in one of a variety of locations in the domains specified.
187186
*/
188187
open func urls(for directory: SearchPathDirectory, in domainMask: SearchPathDomainMask) -> [URL] {
189-
190188
guard let domain = _SearchPathDomain(domainMask) else {
191189
fatalError("Values other than .systemDomainMask, .localDomainMask, .userDomainMask, .networkDomainMask are unsupported")
192190
}
193191

194192
// We are going to return appropriate paths on Darwin, but [] on platforms that do not have comparable locations.
195193
// For example, on FHS/XDG systems, applications are not installed in a single path.
196-
197-
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
198-
// For Darwin:
194+
195+
let useDarwinPaths: Bool
196+
if let envVar = ProcessInfo.processInfo.environment["_NSFileManagerUseXDGPathsForDirectoryDomains"] {
197+
useDarwinPaths = !NSString(string: envVar).boolValue
198+
} else {
199+
#if canImport(Darwin)
200+
useDarwinPaths = true
201+
#else
202+
useDarwinPaths = false
203+
#endif
204+
}
205+
206+
if useDarwinPaths {
207+
return darwinURLs(for: directory, in: domain)
208+
} else {
209+
return xdgURLs(for: directory, in: domain)
210+
}
211+
}
212+
#endif
213+
214+
private func xdgURLs(for directory: SearchPathDirectory, in domain: _SearchPathDomain) -> [URL] {
215+
// FHS/XDG-compliant OSes:
216+
switch directory {
217+
case .autosavedInformationDirectory:
218+
let runtimePath = _SwiftValue.fetch(nonOptional: _CFXDGCreateDataHomePath()) as! String
219+
return [ URL(fileURLWithPath: "Autosave Information", isDirectory: true, relativeTo: URL(fileURLWithPath: runtimePath, isDirectory: true)) ]
220+
221+
case .desktopDirectory:
222+
guard domain == .user else { return [] }
223+
return [ _XDGUserDirectory.desktop.url ]
224+
225+
case .documentDirectory:
226+
guard domain == .user else { return [] }
227+
return [ _XDGUserDirectory.documents.url ]
228+
229+
case .cachesDirectory:
230+
guard domain == .user else { return [] }
231+
let path = _SwiftValue.fetch(nonOptional: _CFXDGCreateCacheDirectoryPath()) as! String
232+
return [ URL(fileURLWithPath: path, isDirectory: true) ]
233+
234+
case .applicationSupportDirectory:
235+
guard domain == .user else { return [] }
236+
let path = _SwiftValue.fetch(nonOptional: _CFXDGCreateDataHomePath()) as! String
237+
return [ URL(fileURLWithPath: path, isDirectory: true) ]
238+
239+
case .downloadsDirectory:
240+
guard domain == .user else { return [] }
241+
return [ _XDGUserDirectory.download.url ]
242+
243+
case .userDirectory:
244+
guard domain == .local else { return [] }
245+
return [ URL(fileURLWithPath: "/home", isDirectory: true) ]
246+
247+
case .moviesDirectory:
248+
return [ _XDGUserDirectory.videos.url ]
249+
250+
case .musicDirectory:
251+
guard domain == .user else { return [] }
252+
return [ _XDGUserDirectory.music.url ]
253+
254+
case .picturesDirectory:
255+
guard domain == .user else { return [] }
256+
return [ _XDGUserDirectory.pictures.url ]
257+
258+
case .sharedPublicDirectory:
259+
guard domain == .user else { return [] }
260+
return [ _XDGUserDirectory.publicShare.url ]
261+
262+
case .trashDirectory:
263+
let userTrashURL = URL(fileURLWithPath: ".Trash", isDirectory: true, relativeTo: URL(fileURLWithPath: NSHomeDirectory(), isDirectory: true))
264+
if domain == .user || domain == .local {
265+
return [ userTrashURL ]
266+
} else {
267+
return []
268+
}
269+
270+
// None of these are supported outside of Darwin:
271+
case .applicationDirectory:
272+
fallthrough
273+
case .demoApplicationDirectory:
274+
fallthrough
275+
case .developerApplicationDirectory:
276+
fallthrough
277+
case .adminApplicationDirectory:
278+
fallthrough
279+
case .libraryDirectory:
280+
fallthrough
281+
case .developerDirectory:
282+
fallthrough
283+
case .documentationDirectory:
284+
fallthrough
285+
case .coreServiceDirectory:
286+
fallthrough
287+
case .inputMethodsDirectory:
288+
fallthrough
289+
case .preferencePanesDirectory:
290+
fallthrough
291+
case .applicationScriptsDirectory:
292+
fallthrough
293+
case .allApplicationsDirectory:
294+
fallthrough
295+
case .allLibrariesDirectory:
296+
fallthrough
297+
case .printerDescriptionDirectory:
298+
fallthrough
299+
case .itemReplacementDirectory:
300+
return []
301+
}
302+
}
303+
304+
private func darwinURLs(for directory: SearchPathDirectory, in domain: _SearchPathDomain) -> [URL] {
199305
switch directory {
200306
case .applicationDirectory:
201307
return darwinPathURLs(for: domain, all: "Applications", useLocalDirectoryForSystem: true)
202-
308+
203309
case .demoApplicationDirectory:
204310
return darwinPathURLs(for: domain, all: "Demos", useLocalDirectoryForSystem: true)
205-
311+
206312
case .developerApplicationDirectory:
207313
return darwinPathURLs(for: domain, all: "Developer/Applications", useLocalDirectoryForSystem: true)
208314

@@ -229,7 +335,7 @@ open class FileManager : NSObject {
229335

230336
case .preferencePanesDirectory:
231337
return darwinPathURLs(for: domain, system: "/System/Library/PreferencePanes", local: "/Library/PreferencePanes", network: nil, userHomeSubpath: "Library/PreferencePanes")
232-
338+
233339
case .applicationScriptsDirectory:
234340
// Only the ObjC Foundation can know where this is.
235341
return []
@@ -251,27 +357,27 @@ open class FileManager : NSObject {
251357
case .printerDescriptionDirectory:
252358
guard domain == .system else { return [] }
253359
return [ URL(fileURLWithPath: "/System/Library/Printers/PPD", isDirectory: true) ]
254-
360+
255361
case .desktopDirectory:
256362
guard domain == .user else { return [] }
257363
return [ URL(fileURLWithPath: "Desktop", isDirectory: true, relativeTo: URL(fileURLWithPath: NSHomeDirectory(), isDirectory: true)) ]
258364

259365
case .documentDirectory:
260366
guard domain == .user else { return [] }
261367
return [ URL(fileURLWithPath: "Documents", isDirectory: true, relativeTo: URL(fileURLWithPath: NSHomeDirectory(), isDirectory: true)) ]
262-
368+
263369
case .cachesDirectory:
264370
guard domain == .user else { return [] }
265371
return [ URL(fileURLWithPath: "Library/Caches", isDirectory: true, relativeTo: URL(fileURLWithPath: NSHomeDirectory(), isDirectory: true)) ]
266-
372+
267373
case .applicationSupportDirectory:
268374
guard domain == .user else { return [] }
269375
return [ URL(fileURLWithPath: "Library/Application Support", isDirectory: true, relativeTo: URL(fileURLWithPath: NSHomeDirectory(), isDirectory: true)) ]
270-
376+
271377
case .downloadsDirectory:
272378
guard domain == .user else { return [] }
273379
return [ URL(fileURLWithPath: "Downloads", isDirectory: true, relativeTo: URL(fileURLWithPath: NSHomeDirectory(), isDirectory: true)) ]
274-
380+
275381
case .userDirectory:
276382
return darwinPathURLs(for: domain, system: nil, local: "/Users", network: "/Network/Users", userHomeSubpath: nil)
277383

@@ -282,15 +388,15 @@ open class FileManager : NSObject {
282388
case .musicDirectory:
283389
guard domain == .user else { return [] }
284390
return [ URL(fileURLWithPath: "Music", isDirectory: true, relativeTo: URL(fileURLWithPath: NSHomeDirectory(), isDirectory: true)) ]
285-
391+
286392
case .picturesDirectory:
287393
guard domain == .user else { return [] }
288394
return [ URL(fileURLWithPath: "Pictures", isDirectory: true, relativeTo: URL(fileURLWithPath: NSHomeDirectory(), isDirectory: true)) ]
289-
395+
290396
case .sharedPublicDirectory:
291397
guard domain == .user else { return [] }
292398
return [ URL(fileURLWithPath: "Public", isDirectory: true, relativeTo: URL(fileURLWithPath: NSHomeDirectory(), isDirectory: true)) ]
293-
399+
294400
case .trashDirectory:
295401
let userTrashURL = URL(fileURLWithPath: ".Trash", isDirectory: true, relativeTo: URL(fileURLWithPath: NSHomeDirectory(), isDirectory: true))
296402
if domain == .user || domain == .local {
@@ -303,99 +409,8 @@ open class FileManager : NSObject {
303409
// This directory is only returned by url(for:in:appropriateFor:create:)
304410
return []
305411
}
306-
#elseif !os(Windows)
307-
// FHS/XDG-compliant OSes:
308-
switch directory {
309-
case .autosavedInformationDirectory:
310-
let runtimePath = _SwiftValue.fetch(nonOptional: _CFXDGCreateDataHomePath()) as! String
311-
return [ URL(fileURLWithPath: "Autosave Information", isDirectory: true, relativeTo: URL(fileURLWithPath: runtimePath, isDirectory: true)) ]
312-
313-
case .desktopDirectory:
314-
guard domain == .user else { return [] }
315-
return [ _XDGUserDirectory.desktop.url ]
316-
317-
case .documentDirectory:
318-
guard domain == .user else { return [] }
319-
return [ _XDGUserDirectory.documents.url ]
320-
321-
case .cachesDirectory:
322-
guard domain == .user else { return [] }
323-
let path = _SwiftValue.fetch(nonOptional: _CFXDGCreateCacheDirectoryPath()) as! String
324-
return [ URL(fileURLWithPath: path, isDirectory: true) ]
325-
326-
case .applicationSupportDirectory:
327-
guard domain == .user else { return [] }
328-
let path = _SwiftValue.fetch(nonOptional: _CFXDGCreateDataHomePath()) as! String
329-
return [ URL(fileURLWithPath: path, isDirectory: true) ]
330-
331-
case .downloadsDirectory:
332-
guard domain == .user else { return [] }
333-
return [ _XDGUserDirectory.download.url ]
334-
335-
case .userDirectory:
336-
guard domain == .local else { return [] }
337-
return [ URL(fileURLWithPath: "/home", isDirectory: true) ]
338-
339-
case .moviesDirectory:
340-
return [ _XDGUserDirectory.videos.url ]
341-
342-
case .musicDirectory:
343-
guard domain == .user else { return [] }
344-
return [ _XDGUserDirectory.music.url ]
345-
346-
case .picturesDirectory:
347-
guard domain == .user else { return [] }
348-
return [ _XDGUserDirectory.pictures.url ]
349-
350-
case .sharedPublicDirectory:
351-
guard domain == .user else { return [] }
352-
return [ _XDGUserDirectory.publicShare.url ]
353-
354-
case .trashDirectory:
355-
let userTrashURL = URL(fileURLWithPath: ".Trash", isDirectory: true, relativeTo: URL(fileURLWithPath: NSHomeDirectory(), isDirectory: true))
356-
if domain == .user || domain == .local {
357-
return [ userTrashURL ]
358-
} else {
359-
return []
360-
}
361-
362-
// None of these are supported outside of Darwin:
363-
case .applicationDirectory:
364-
fallthrough
365-
case .demoApplicationDirectory:
366-
fallthrough
367-
case .developerApplicationDirectory:
368-
fallthrough
369-
case .adminApplicationDirectory:
370-
fallthrough
371-
case .libraryDirectory:
372-
fallthrough
373-
case .developerDirectory:
374-
fallthrough
375-
case .documentationDirectory:
376-
fallthrough
377-
case .coreServiceDirectory:
378-
fallthrough
379-
case .inputMethodsDirectory:
380-
fallthrough
381-
case .preferencePanesDirectory:
382-
fallthrough
383-
case .applicationScriptsDirectory:
384-
fallthrough
385-
case .allApplicationsDirectory:
386-
fallthrough
387-
case .allLibrariesDirectory:
388-
fallthrough
389-
case .printerDescriptionDirectory:
390-
fallthrough
391-
case .itemReplacementDirectory:
392-
return []
393-
}
394-
#endif
395-
396412
}
397-
#endif
398-
413+
399414
private enum URLForDirectoryError: Error {
400415
case directoryUnknown
401416
}

Foundation/NSPathUtilities.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -578,7 +578,7 @@ public func NSSearchPathForDirectoriesInDomains(_ directory: FileManager.SearchP
578578
}
579579

580580
return result.map { (url) in
581-
var path = url.path
581+
var path = url.absoluteURL.path
582582
if expandTilde {
583583
path = NSString(string: path).expandingTildeInPath
584584
}

0 commit comments

Comments
 (0)