Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

clean up std/os related modules #20651

Merged
merged 5 commits into from
Oct 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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