Skip to content

Commit

Permalink
clean up std/os related modules (#20651)
Browse files Browse the repository at this point in the history
* clean up `std/os` related modules

* use `cmpPaths`

* reset

* cleanup
  • Loading branch information
ringabout authored Oct 25, 2022
1 parent daf35c6 commit 69eaa4f
Show file tree
Hide file tree
Showing 6 changed files with 140 additions and 157 deletions.
65 changes: 0 additions & 65 deletions lib/pure/os.nim
Original file line number Diff line number Diff line change
Expand Up @@ -350,70 +350,6 @@ proc fileNewer*(a, b: string): bool {.rtl, extern: "nos$1", noWeirdTarget.} =
else:
result = getLastModificationTime(a) > getLastModificationTime(b)

when defined(windows) and not weirdTarget:
proc openHandle(path: string, followSymlink=true, writeAccess=false): Handle =
var flags = FILE_FLAG_BACKUP_SEMANTICS or FILE_ATTRIBUTE_NORMAL
if not followSymlink:
flags = flags or FILE_FLAG_OPEN_REPARSE_POINT
let access = if writeAccess: GENERIC_WRITE else: 0'i32

when useWinUnicode:
result = createFileW(
newWideCString(path), access,
FILE_SHARE_DELETE or FILE_SHARE_READ or FILE_SHARE_WRITE,
nil, OPEN_EXISTING, flags, 0
)
else:
result = createFileA(
path, access,
FILE_SHARE_DELETE or FILE_SHARE_READ or FILE_SHARE_WRITE,
nil, OPEN_EXISTING, flags, 0
)

proc sameFile*(path1, path2: string): bool {.rtl, extern: "nos$1",
tags: [ReadDirEffect], noWeirdTarget.} =
## Returns true if both pathname arguments refer to the same physical
## file or directory.
##
## Raises `OSError` if any of the files does not
## exist or information about it can not be obtained.
##
## This proc will return true if given two alternative hard-linked or
## sym-linked paths to the same file or directory.
##
## See also:
## * `sameFileContent proc`_
when defined(windows):
var success = true
var f1 = openHandle(path1)
var f2 = openHandle(path2)

var lastErr: OSErrorCode
if f1 != INVALID_HANDLE_VALUE and f2 != INVALID_HANDLE_VALUE:
var fi1, fi2: BY_HANDLE_FILE_INFORMATION

if getFileInformationByHandle(f1, addr(fi1)) != 0 and
getFileInformationByHandle(f2, addr(fi2)) != 0:
result = fi1.dwVolumeSerialNumber == fi2.dwVolumeSerialNumber and
fi1.nFileIndexHigh == fi2.nFileIndexHigh and
fi1.nFileIndexLow == fi2.nFileIndexLow
else:
lastErr = osLastError()
success = false
else:
lastErr = osLastError()
success = false

discard closeHandle(f1)
discard closeHandle(f2)

if not success: raiseOSError(lastErr, $(path1, path2))
else:
var a, b: Stat
if stat(path1, a) < 0'i32 or stat(path2, b) < 0'i32:
raiseOSError(osLastError(), $(path1, path2))
else:
result = a.st_dev == b.st_dev and a.st_ino == b.st_ino

proc isAdmin*: bool {.noWeirdTarget.} =
## Returns whether the caller's process is a member of the Administrators local
Expand Down Expand Up @@ -447,7 +383,6 @@ proc isAdmin*: bool {.noWeirdTarget.} =
result = geteuid() == 0



proc exitStatusLikeShell*(status: cint): cint =
## Converts exit code from `c_system` into a shell exit code.
when defined(posix) and not weirdTarget:
Expand Down
55 changes: 9 additions & 46 deletions lib/std/dirs.nim
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from paths import Path, ReadDirEffect, WriteDirEffect

from std/private/osdirs import dirExists, createDir, existsOrCreateDir, removeDir,
moveDir, walkPattern, walkFiles, walkDirs, walkDir,
moveDir, walkDir, setCurrentDir,
walkDirRec, PathComponent

export PathComponent
Expand Down Expand Up @@ -76,51 +76,6 @@ proc moveDir*(source, dest: Path) {.inline, tags: [ReadIOEffect, WriteIOEffect].
## * `createDir proc`_
moveDir(source.string, dest.string)

iterator walkPattern*(pattern: Path): Path {.tags: [ReadDirEffect].} =
## Iterate over all the files and directories that match the `pattern`.
##
## On POSIX this uses the `glob`:idx: call.
## `pattern` is OS dependent, but at least the `"*.ext"`
## notation is supported.
##
## See also:
## * `walkFiles iterator`_
## * `walkDirs iterator`_
## * `walkDir iterator`_
## * `walkDirRec iterator`_
for p in walkPattern(pattern.string):
yield Path(p)

iterator walkFiles*(pattern: Path): Path {.tags: [ReadDirEffect].} =
## Iterate over all the files that match the `pattern`.
##
## On POSIX this uses the `glob`:idx: call.
## `pattern` is OS dependent, but at least the `"*.ext"`
## notation is supported.
##
## See also:
## * `walkPattern iterator`_
## * `walkDirs iterator`_
## * `walkDir iterator`_
## * `walkDirRec iterator`_
for p in walkFiles(pattern.string):
yield Path(p)

iterator walkDirs*(pattern: Path): Path {.tags: [ReadDirEffect].} =
## Iterate over all the directories that match the `pattern`.
##
## On POSIX this uses the `glob`:idx: call.
## `pattern` is OS dependent, but at least the `"*.ext"`
## notation is supported.
##
## See also:
## * `walkPattern iterator`_
## * `walkFiles iterator`_
## * `walkDir iterator`_
## * `walkDirRec iterator`_
for p in walkDirs(pattern.string):
yield Path(p)

iterator walkDir*(dir: Path; relative = false, checkDir = false,
onlyRegular = false):
tuple[kind: PathComponent, path: Path] {.tags: [ReadDirEffect].} =
Expand Down Expand Up @@ -179,3 +134,11 @@ iterator walkDirRec*(dir: Path,
for p in walkDirRec(dir.string, yieldFilter, followFilter, relative,
checkDir, onlyRegular):
yield Path(p)

proc setCurrentDir*(newDir: Path) {.inline, tags: [].} =
## Sets the `current working directory`:idx:; `OSError`
## is raised if `newDir` cannot been set.
##
## See also:
## * `getCurrentDir proc`_
osdirs.setCurrentDir(newDir.string)
55 changes: 36 additions & 19 deletions lib/std/paths.nim
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import std/private/osseps
export osseps

import std/envvars
import std/private/osappdirs

import pathnorm

from std/private/ospaths2 import joinPath, splitPath,
Expand All @@ -17,6 +20,13 @@ export ReadDirEffect, WriteDirEffect
type
Path* = distinct string

func `==`*(x, y: Path): bool {.inline.} =
## Compares two paths.
##
## On a case-sensitive filesystem this is done
## case-sensitively otherwise case-insensitively.
result = cmpPaths(x.string, y.string) == 0

template endsWith(a: string, b: set[char]): bool =
a.len > 0 and a[^1] in b

Expand Down Expand Up @@ -208,17 +218,6 @@ func addFileExt*(filename: Path, ext: string): Path {.inline.} =
## * `changeFileExt proc`_
result = Path(addFileExt(filename.string, ext))

func cmpPaths*(pathA, pathB: Path): int {.inline.} =
## Compares two paths.
##
## On a case-sensitive filesystem this is done
## case-sensitively otherwise case-insensitively. Returns:
##
## | 0 if pathA == pathB
## | < 0 if pathA < pathB
## | > 0 if pathA > pathB
result = cmpPaths(pathA.string, pathB.string)

func unixToNativePath*(path: Path, drive=Path("")): Path {.inline.} =
## Converts an UNIX-like path to a native one.
##
Expand Down Expand Up @@ -246,14 +245,6 @@ proc getCurrentDir*(): Path {.inline, tags: [].} =
## * `getProjectPath proc <macros.html#getProjectPath>`_
result = Path(ospaths2.getCurrentDir())

proc setCurrentDir*(newDir: Path) {.inline, tags: [].} =
## Sets the `current working directory`:idx:; `OSError`
## is raised if `newDir` cannot been set.
##
## See also:
## * `getCurrentDir proc`_
ospaths2.setCurrentDir(newDir.string)

proc normalizeExe*(file: var Path) {.borrow.}

proc normalizePath*(path: var Path) {.borrow.}
Expand All @@ -268,3 +259,29 @@ proc absolutePath*(path: Path, root = getCurrentDir()): Path =
## See also:
## * `normalizePath proc`_
result = Path(absolutePath(path.string, root.string))

proc expandTildeImpl(path: string): string {.
tags: [ReadEnvEffect, ReadIOEffect].} =
if len(path) == 0 or path[0] != '~':
result = path
elif len(path) == 1:
result = getHomeDir()
elif (path[1] in {DirSep, AltSep}):
result = joinPath(getHomeDir(), path.substr(2))
else:
# TODO: handle `~bob` and `~bob/` which means home of bob
result = path

proc expandTilde*(path: Path): Path {.inline,
tags: [ReadEnvEffect, ReadIOEffect].} =
## Expands ``~`` or a path starting with ``~/`` to a full path, replacing
## ``~`` with `getHomeDir()`_ (otherwise returns ``path`` unmodified).
##
## Windows: this is still supported despite the Windows platform not having this
## convention; also, both ``~/`` and ``~\`` are handled.
runnableExamples:
import std/appdirs
assert expandTilde(Path("~") / Path("appname.cfg")) == getHomeDir() / Path("appname.cfg")
assert expandTilde(Path("~/foo/bar")) == getHomeDir() / Path("foo/bar")
assert expandTilde(Path("/foo/bar")) == Path("/foo/bar")
result = Path(expandTildeImpl(path.string))
30 changes: 29 additions & 1 deletion lib/std/private/oscommon.nim
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
include system/inclrtl

import ospaths2
import std/[oserrors]

when defined(nimPreviewSlimSystem):
Expand All @@ -9,6 +8,15 @@ when defined(nimPreviewSlimSystem):
const weirdTarget* = defined(nimscript) or defined(js)


type
ReadDirEffect* = object of ReadIOEffect ## Effect that denotes a read
## operation from the directory
## structure.
WriteDirEffect* = object of WriteIOEffect ## Effect that denotes a write
## operation to
## the directory structure.


when weirdTarget:
discard
elif defined(windows):
Expand Down Expand Up @@ -181,3 +189,23 @@ proc symlinkExists*(link: string): bool {.rtl, extern: "nos$1",
else:
var res: Stat
result = lstat(link, res) >= 0'i32 and S_ISLNK(res.st_mode)

when defined(windows) and not weirdTarget:
proc openHandle*(path: string, followSymlink=true, writeAccess=false): Handle =
var flags = FILE_FLAG_BACKUP_SEMANTICS or FILE_ATTRIBUTE_NORMAL
if not followSymlink:
flags = flags or FILE_FLAG_OPEN_REPARSE_POINT
let access = if writeAccess: GENERIC_WRITE else: 0'i32

when useWinUnicode:
result = createFileW(
newWideCString(path), access,
FILE_SHARE_DELETE or FILE_SHARE_READ or FILE_SHARE_WRITE,
nil, OPEN_EXISTING, flags, 0
)
else:
result = createFileA(
path, access,
FILE_SHARE_DELETE or FILE_SHARE_READ or FILE_SHARE_WRITE,
nil, OPEN_EXISTING, flags, 0
)
18 changes: 18 additions & 0 deletions lib/std/private/osdirs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -548,3 +548,21 @@ proc moveDir*(source, dest: string) {.tags: [ReadIOEffect, WriteIOEffect], noWei
# Fallback to copy & del
copyDir(source, dest)
removeDir(source)

proc setCurrentDir*(newDir: string) {.inline, tags: [], noWeirdTarget.} =
## Sets the `current working directory`:idx:; `OSError`
## is raised if `newDir` cannot been set.
##
## See also:
## * `getHomeDir proc`_
## * `getConfigDir proc`_
## * `getTempDir proc`_
## * `getCurrentDir proc`_
when defined(windows):
when useWinUnicode:
if setCurrentDirectoryW(newWideCString(newDir)) == 0'i32:
raiseOSError(osLastError(), newDir)
else:
if setCurrentDirectoryA(newDir) == 0'i32: raiseOSError(osLastError(), newDir)
else:
if chdir(newDir) != 0'i32: raiseOSError(osLastError(), newDir)
Loading

0 comments on commit 69eaa4f

Please sign in to comment.