From a43583f9c8771c07436ee4175e216ab802ff6165 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sat, 22 Feb 2020 00:07:53 -0800 Subject: [PATCH] relativePath("foo", "foo") is now ".", not "" (#13452) --- changelog.md | 4 +++- compiler/commands.nim | 2 ++ lib/pure/os.nim | 17 ++++++++++++++--- tests/js/tos.nim | 7 +++++++ tests/stdlib/tos.nim | 12 ++++++++---- tests/test_nimscript.nims | 3 +++ 6 files changed, 37 insertions(+), 8 deletions(-) create mode 100644 tests/js/tos.nim diff --git a/changelog.md b/changelog.md index 0e0b6ce3dd76..d929ea0d941a 100644 --- a/changelog.md +++ b/changelog.md @@ -27,7 +27,9 @@ It was an oversight to be included in v1.0. - `options` now treats `proc` like other pointer types, meaning `nil` proc variables are converted to `None`. - +- `relativePath("foo", "foo")` is now `"."`, not `""`, as `""` means invalid path + and shouldn't be conflated with `"."`; use -d:nimOldRelativePathBehavior to restore the old + behavioe ### Breaking changes in the compiler diff --git a/compiler/commands.nim b/compiler/commands.nim index ca6ef5d94588..cecb07386312 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -865,6 +865,8 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; defineSymbol(conf.symbols, "NimMinor", "0") # always be compatible with 1.0.2 for now: defineSymbol(conf.symbols, "NimPatch", "2") + # old behaviors go here: + defineSymbol(conf.symbols, "nimOldRelativePathBehavior") else: localError(conf, info, "unknown Nim version; currently supported values are: {1.0}") of "benchmarkvm": diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 452c856a6046..aff91fccbd24 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -65,6 +65,8 @@ when weirdTarget and defined(nimErrorProcCanHaveBody): else: {.pragma: noNimScript.} +proc normalizePathAux(path: var string){.inline, raises: [], noSideEffect.} + type ReadEnvEffect* = object of ReadIOEffect ## Effect that denotes a read ## from an environment variable. @@ -359,9 +361,13 @@ proc relativePath*(path, base: string; sep = DirSep): string {. assert relativePath("/Users/me/bar/z.nim", "/Users/me", '/') == "bar/z.nim" assert relativePath("", "/users/moo", '/') == "" assert relativePath("foo", ".", '/') == "foo" + assert relativePath("foo", "foo", '/') == "." if path.len == 0: return "" - let base = if base == ".": "" else: base + var base = if base == ".": "" else: base + var path = path + path.normalizePathAux + base.normalizePathAux when doslikeFileSystem: if isAbsolute(path) and isAbsolute(base): @@ -411,6 +417,9 @@ proc relativePath*(path, base: string; sep = DirSep): string {. if not f.hasNext(path): break ff = f.next(path) + when not defined(nimOldRelativePathBehavior): + if result.len == 0: result.add "." + proc isRelativeTo*(path: string, base: string): bool {.since: (1, 1).} = ## Returns true if `path` is relative to `base`. runnableExamples: @@ -1353,7 +1362,7 @@ when not weirdTarget: raise newException(ValueError, "The specified root is not absolute: " & root) joinPath(root, path) -proc normalizePath*(path: var string) {.rtl, extern: "nos$1", tags: [], noNimScript.} = +proc normalizePath*(path: var string) {.rtl, extern: "nos$1", tags: [].} = ## Normalize a path. ## ## Consecutive directory separators are collapsed, including an initial double slash. @@ -1402,7 +1411,9 @@ proc normalizePath*(path: var string) {.rtl, extern: "nos$1", tags: [], noNimScr else: path = "." -proc normalizedPath*(path: string): string {.rtl, extern: "nos$1", tags: [], noNimScript.} = +proc normalizePathAux(path: var string) = normalizePath(path) + +proc normalizedPath*(path: string): string {.rtl, extern: "nos$1", tags: [].} = ## Returns a normalized path for the current OS. ## ## See also: diff --git a/tests/js/tos.nim b/tests/js/tos.nim new file mode 100644 index 000000000000..7395a0ad7a99 --- /dev/null +++ b/tests/js/tos.nim @@ -0,0 +1,7 @@ +static: doAssert defined(nodejs) + +import os + +block: + doAssert "./foo//./bar/".normalizedPath == "foo/bar" + doAssert relativePath(".//foo/bar", "foo") == "bar" diff --git a/tests/stdlib/tos.nim b/tests/stdlib/tos.nim index 03fc1f1e9c96..02a449b8c528 100644 --- a/tests/stdlib/tos.nim +++ b/tests/stdlib/tos.nim @@ -329,15 +329,19 @@ block ospaths: doAssert relativePath("/Users/me/bar/z.nim", "/Users/me", '/') == "bar/z.nim" doAssert relativePath("", "/users/moo", '/') == "" doAssert relativePath("foo", "", '/') == "foo" - doAssert relativePath("/foo", "/Foo", '/') == (when FileSystemCaseSensitive: "../foo" else: "") - doAssert relativePath("/Foo", "/foo", '/') == (when FileSystemCaseSensitive: "../Foo" else: "") - doAssert relativePath("/foo", "/fOO", '/') == (when FileSystemCaseSensitive: "../foo" else: "") - doAssert relativePath("/foO", "/foo", '/') == (when FileSystemCaseSensitive: "../foO" else: "") + doAssert relativePath("/foo", "/Foo", '/') == (when FileSystemCaseSensitive: "../foo" else: ".") + doAssert relativePath("/Foo", "/foo", '/') == (when FileSystemCaseSensitive: "../Foo" else: ".") + doAssert relativePath("/foo", "/fOO", '/') == (when FileSystemCaseSensitive: "../foo" else: ".") + doAssert relativePath("/foO", "/foo", '/') == (when FileSystemCaseSensitive: "../foO" else: ".") doAssert relativePath("foo", ".", '/') == "foo" doAssert relativePath(".", ".", '/') == "." doAssert relativePath("..", ".", '/') == ".." + doAssert relativePath("foo", "foo") == "." + doAssert relativePath("", "foo") == "" + doAssert relativePath("././/foo", "foo//./") == "." + when doslikeFileSystem: doAssert relativePath(r"c:\foo.nim", r"C:\") == r"foo.nim" doAssert relativePath(r"c:\foo\bar\baz.nim", r"c:\foo") == r"bar\baz.nim" diff --git a/tests/test_nimscript.nims b/tests/test_nimscript.nims index 3efbb0a4c1a8..91b23efbfb2f 100644 --- a/tests/test_nimscript.nims +++ b/tests/test_nimscript.nims @@ -22,4 +22,7 @@ import unicode import uri import macros +block: + doAssert "./foo//./bar/".normalizedPath == "foo/bar".unixToNativePath + echo "Nimscript imports are successful."