@@ -90,7 +90,7 @@ public struct AbsolutePath: Hashable, Sendable {
90
90
91
91
self . init ( String ( decodingCString: pwszResult, as: UTF16 . self) )
92
92
#else
93
- self . init ( basePath, RelativePath ( str) )
93
+ try self . init ( basePath, RelativePath ( validating : str) )
94
94
#endif
95
95
}
96
96
}
@@ -102,8 +102,8 @@ public struct AbsolutePath: Hashable, Sendable {
102
102
}
103
103
104
104
/// Convenience initializer that appends a string to a relative path.
105
- public init ( _ absPath: AbsolutePath , _ relStr: String ) {
106
- self . init ( absPath, RelativePath ( relStr) )
105
+ public init ( _ absPath: AbsolutePath , validating relStr: String ) throws {
106
+ try self . init ( absPath, RelativePath ( validating : relStr) )
107
107
}
108
108
109
109
/// Initializes the AbsolutePath from `absStr`, which must be an absolute
@@ -240,23 +240,6 @@ public struct RelativePath: Hashable, Sendable {
240
240
_impl = impl
241
241
}
242
242
243
- /// Private initializer for constructing a relative path without performing
244
- /// normalization or canonicalization. This will construct a path without
245
- /// an anchor and thus may be invalid.
246
- fileprivate init ( unsafeUncheckedPath string: String ) {
247
- self . init ( PathImpl ( string: string) )
248
- }
249
-
250
- /// Initializes the RelativePath from `str`, which must be a relative path
251
- /// (which means that it must not begin with a path separator or a tilde).
252
- /// An empty input path is allowed, but will be normalized to a single `.`
253
- /// character. The input string will be normalized if needed, as described
254
- /// in the documentation for RelativePath.
255
- public init ( _ string: String ) {
256
- // Normalize the relative string and store it as our Path.
257
- self . init ( PathImpl ( normalizingRelativePath: string) )
258
- }
259
-
260
243
/// Convenience initializer that verifies that the path is relative.
261
244
public init ( validating path: String ) throws {
262
245
try self . init ( PathImpl ( validatingRelativePath: path) )
@@ -429,12 +412,6 @@ protocol Path: Hashable {
429
412
/// Creates a path from its normalized string representation.
430
413
init ( string: String )
431
414
432
- /// Creates a path from an absolute string representation and normalizes it.
433
- init ( normalizingAbsolutePath: String )
434
-
435
- /// Creates a path from an relative string representation and normalizes it.
436
- init ( normalizingRelativePath: String )
437
-
438
415
/// Creates a path from a string representation, validates that it is a valid absolute path and normalizes it.
439
416
init ( validatingAbsolutePath: String ) throws
440
417
@@ -534,34 +511,12 @@ private struct WindowsPath: Path, Sendable {
534
511
return String ( cString: representation)
535
512
}
536
513
537
- init ( normalizingAbsolutePath path: String ) {
538
- self . init ( string: Self . repr ( path) . withCString ( encodedAs: UTF16 . self) { pwszPath in
539
- var canonical : PWSTR !
540
- _ = PathAllocCanonicalize ( pwszPath,
541
- ULONG ( PATHCCH_ALLOW_LONG_PATHS . rawValue) ,
542
- & canonical)
543
- return String ( decodingCString: canonical, as: UTF16 . self)
544
- } )
545
- }
546
-
547
514
init ( validatingAbsolutePath path: String ) throws {
548
515
let realpath = Self . repr ( path)
549
516
if !Self. isAbsolutePath ( realpath) {
550
517
throw PathValidationError . invalidAbsolutePath ( path)
551
518
}
552
- self . init ( normalizingAbsolutePath: path)
553
- }
554
-
555
- init ( normalizingRelativePath path: String ) {
556
- if path. isEmpty || path == " . " {
557
- self . init ( string: " . " )
558
- } else {
559
- var buffer : [ WCHAR ] = Array < WCHAR > ( repeating: 0 , count: Int ( MAX_PATH + 1 ) )
560
- _ = path. replacingOccurrences ( of: " / " , with: " \\ " ) . withCString ( encodedAs: UTF16 . self) {
561
- PathCanonicalizeW ( & buffer, $0)
562
- }
563
- self . init ( string: String ( decodingCString: buffer, as: UTF16 . self) )
564
- }
519
+ self . init ( string: realpath)
565
520
}
566
521
567
522
init ( validatingRelativePath path: String ) throws {
@@ -570,11 +525,10 @@ private struct WindowsPath: Path, Sendable {
570
525
} else {
571
526
let realpath : String = Self . repr ( path)
572
527
// Treat a relative path as an invalid relative path...
573
- if Self . isAbsolutePath ( realpath) ||
574
- realpath. first == " ~ " || realpath. first == " \\ " {
528
+ if Self . isAbsolutePath ( realpath) || realpath. first == " \\ " {
575
529
throw PathValidationError . invalidRelativePath ( path)
576
530
}
577
- self . init ( normalizingRelativePath : path )
531
+ self . init ( string : realpath )
578
532
}
579
533
}
580
534
@@ -597,7 +551,7 @@ private struct WindowsPath: Path, Sendable {
597
551
}
598
552
}
599
553
defer { LocalFree ( result) }
600
- return PathImpl ( string: String ( decodingCString: result!, as: UTF16 . self) )
554
+ return Self ( string: String ( decodingCString: result!, as: UTF16 . self) )
601
555
}
602
556
603
557
func appending( relativePath: Self ) -> Self {
@@ -608,7 +562,7 @@ private struct WindowsPath: Path, Sendable {
608
562
}
609
563
}
610
564
defer { LocalFree ( result) }
611
- return PathImpl ( string: String ( decodingCString: result!, as: UTF16 . self) )
565
+ return Self ( string: String ( decodingCString: result!, as: UTF16 . self) )
612
566
}
613
567
}
614
568
#else
@@ -830,7 +784,7 @@ private struct UNIXPath: Path, Sendable {
830
784
831
785
init ( validatingRelativePath path: String ) throws {
832
786
switch path. first {
833
- case " / " , " ~ " :
787
+ case " / " :
834
788
throw PathValidationError . invalidRelativePath ( path)
835
789
default :
836
790
self . init ( normalizingRelativePath: path)
@@ -875,9 +829,9 @@ private struct UNIXPath: Path, Sendable {
875
829
}
876
830
877
831
if self == Self . root {
878
- return PathImpl ( string: " / " + name)
832
+ return Self ( string: " / " + name)
879
833
} else {
880
- return PathImpl ( string: string + " / " + name)
834
+ return Self ( string: string + " / " + name)
881
835
}
882
836
}
883
837
@@ -900,12 +854,12 @@ private struct UNIXPath: Path, Sendable {
900
854
// the beginning of the path only.
901
855
if relativePathString. hasPrefix ( " . " ) {
902
856
if newPathString. hasPrefix ( " / " ) {
903
- return PathImpl ( normalizingAbsolutePath: newPathString)
857
+ return Self ( normalizingAbsolutePath: newPathString)
904
858
} else {
905
- return PathImpl ( normalizingRelativePath: newPathString)
859
+ return Self ( normalizingRelativePath: newPathString)
906
860
}
907
861
} else {
908
- return PathImpl ( string: newPathString)
862
+ return Self ( string: newPathString)
909
863
}
910
864
}
911
865
}
@@ -926,7 +880,7 @@ extension PathValidationError: CustomStringConvertible {
926
880
case . invalidAbsolutePath( let path) :
927
881
return " invalid absolute path ' \( path) ' "
928
882
case . invalidRelativePath( let path) :
929
- return " invalid relative path ' \( path) '; relative path should not begin with ' \( AbsolutePath . root. pathString) ' or '~' "
883
+ return " invalid relative path ' \( path) '; relative path should not begin with ' \( AbsolutePath . root. pathString) ' "
930
884
}
931
885
}
932
886
}
@@ -956,10 +910,16 @@ extension AbsolutePath {
956
910
// might be an empty path (when self and the base are equal).
957
911
let relComps = pathComps. dropFirst ( baseComps. count)
958
912
#if os(Windows)
959
- result = RelativePath ( unsafeUncheckedPath : relComps. joined ( separator: " \\ " ) )
913
+ let pathString = relComps. joined ( separator: " \\ " )
960
914
#else
961
- result = RelativePath ( relComps. joined ( separator: " / " ) )
915
+ let pathString = relComps. joined ( separator: " / " )
962
916
#endif
917
+ do {
918
+ result = try RelativePath ( validating: pathString)
919
+ } catch {
920
+ preconditionFailure ( " invalid relative path computed from \( pathString) " )
921
+ }
922
+
963
923
} else {
964
924
// General case, in which we might well need `..` components to go
965
925
// "up" before we can go "down" the directory tree.
@@ -975,10 +935,15 @@ extension AbsolutePath {
975
935
var relComps = Array ( repeating: " .. " , count: newBaseComps. count)
976
936
relComps. append ( contentsOf: newPathComps)
977
937
#if os(Windows)
978
- result = RelativePath ( unsafeUncheckedPath : relComps. joined ( separator: " \\ " ) )
938
+ let pathString = relComps. joined ( separator: " \\ " )
979
939
#else
980
- result = RelativePath ( relComps. joined ( separator: " / " ) )
940
+ let pathString = relComps. joined ( separator: " / " )
981
941
#endif
942
+ do {
943
+ result = try RelativePath ( validating: pathString)
944
+ } catch {
945
+ preconditionFailure ( " invalid relative path computed from \( pathString) " )
946
+ }
982
947
}
983
948
984
949
assert ( AbsolutePath ( base, result) == self )
@@ -1065,13 +1030,31 @@ private func mayNeedNormalization(absolute string: String) -> Bool {
1065
1030
// MARK: - `AbsolutePath` backwards compatibility, delete after deprecation period.
1066
1031
1067
1032
extension AbsolutePath {
1033
+ @_disfavoredOverload
1068
1034
@available ( * , deprecated, message: " use throwing `init(validating:)` variant instead " )
1069
1035
public init ( _ absStr: String ) {
1070
1036
try ! self . init ( validating: absStr)
1071
1037
}
1072
1038
1039
+ @_disfavoredOverload
1073
1040
@available ( * , deprecated, message: " use throwing `init(validating:relativeTo:)` variant instead " )
1074
1041
public init ( _ str: String , relativeTo basePath: AbsolutePath ) {
1075
1042
try ! self . init ( validating: str, relativeTo: basePath)
1076
1043
}
1044
+
1045
+ @_disfavoredOverload
1046
+ @available ( * , deprecated, message: " use throwing variant instead " )
1047
+ public init ( _ absPath: AbsolutePath , _ relStr: String ) {
1048
+ try ! self . init ( absPath, validating: relStr)
1049
+ }
1050
+ }
1051
+
1052
+ // MARK: - `AbsolutePath` backwards compatibility, delete after deprecation period.
1053
+
1054
+ extension RelativePath {
1055
+ @_disfavoredOverload
1056
+ @available ( * , deprecated, message: " use throwing variant instead " )
1057
+ public init ( _ string: String ) {
1058
+ try ! self . init ( validating: string)
1059
+ }
1077
1060
}
0 commit comments