Skip to content

Commit 2544eea

Browse files
committed
refact(Lib/shutil): split to shutil_impl; add n_shutil
1 parent e8d93be commit 2544eea

File tree

5 files changed

+120
-107
lines changed

5 files changed

+120
-107
lines changed

src/pylib/Lib/n_shutil.nim

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
2+
3+
import ../private/trans_imp
4+
impExp shutil_impl,
5+
terminals, copys

src/pylib/Lib/shutil.nim

Lines changed: 2 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -1,109 +1,4 @@
11

2-
import std/terminal
2+
import ./n_shutil
3+
export n_shutil
34

4-
# Nim consider it's the same as os.terminal_size,
5-
# as they are both tuple of Nim
6-
type terminal_size = tuple[columns, lines: int]
7-
proc get_terminal_size*(fallback=(80, 24)): terminal_size =
8-
## .. hint:: this does not simply refer to environment variable,
9-
## call `os.get_terminal_size`. This is a wrapper around
10-
## `terminalSize` of `std/terminal`, which is more steady,
11-
## returning meaningful result even when stdout is not associatd with
12-
## a terminal.
13-
result.columns = terminalWidth()
14-
if result.columns == 0:
15-
result.columns = fallback[0]
16-
result.lines = terminalHeight()
17-
if result.lines == 0:
18-
result.lines = fallback[1]
19-
20-
import std/os
21-
when defined(posix):
22-
import std/posix
23-
import ./sys_impl/auditImpl as sys
24-
import ../pyerrors/oserr
25-
import ../io_abc
26-
27-
const COPY_BUFSIZE = when defined(windows): 64 * 1024 else: 16 * 1024
28-
# Python uses as followings, but it seems too large
29-
# when defined(windows): 1024 * 1024 else: 64 * 1024
30-
31-
proc copyfileobjImpl(s, d: File, length=COPY_BUFSIZE) =
32-
## shutil.copyfileobj but for Nim's `File`, here length must be positive
33-
let bufferSize = length
34-
# The following is modified from Nim-2.1.1/Lib/std/private/osfiles.nim L241
35-
# generic version of copyFile which works for any platform:
36-
37-
# Hints for kernel-level aggressive sequential low-fragmentation read-aheads:
38-
# https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_fadvise.html
39-
when defined(linux) or defined(osx):
40-
discard posix_fadvise(getFileHandle(d), 0.cint, 0.cint, POSIX_FADV_SEQUENTIAL)
41-
discard posix_fadvise(getFileHandle(s), 0.cint, 0.cint, POSIX_FADV_SEQUENTIAL)
42-
var buf = alloc(bufferSize)
43-
while true:
44-
var bytesread = readBuffer(s, buf, bufferSize)
45-
if bytesread > 0:
46-
var byteswritten = writeBuffer(d, buf, bytesread)
47-
if bytesread != byteswritten:
48-
dealloc(buf)
49-
raiseOSError(osLastError())
50-
if bytesread != bufferSize: break
51-
dealloc(buf)
52-
flushFile(d)
53-
54-
proc copyfileobj*(s, d: File, length=COPY_BUFSIZE) =
55-
## shutil.copyfileobj but for Nim's `File`
56-
##
57-
## if `length` is negative, it means copying the data
58-
## without looping over the source data in chunks
59-
if length < 0:
60-
d.write(s.readAll())
61-
return
62-
copyfileobjImpl(s, d, length)
63-
64-
type
65-
Error = object of PyOSError ## python's shutil.Error
66-
SameFileError* = object of Error
67-
template copyFileImpl(src, dst: string; options: CopyFlag) =
68-
## called by copyfile
69-
bind copyFile, copyfileobjImpl
70-
when defined(windows):
71-
# std/os's `copyFile` under Windows calls copyFileW,
72-
# which will copy file attributes too.
73-
# so we use another implementation instead.
74-
let isSymlink = src.symlinkExists
75-
if isSymlink and cfSymlinkAsIs in options:
76-
createSymlink(expandSymlink(source), dest)
77-
return
78-
var
79-
fsrc = open(src)
80-
fdst = open(dst, fmWrite)
81-
defer:
82-
fsrc.close()
83-
fdst.close()
84-
copyfileobjImpl(fsrc, dst)
85-
else:
86-
copyFile(src, dst, options)
87-
88-
template copyGen(pyname, impl) =
89-
proc pyname*[T](src, dst: PathLike[T], follow_symlinks=true) =
90-
sys.audit("shutil.copyfile", src, dst)
91-
let
92-
ssrc = $src
93-
sdst = $dst
94-
cpOptions = if follow_symlinks: {cfSymlinkFollow} else: {cfSymlinkAsIs}
95-
if sameFile(ssrc, sdst):
96-
raise newException(SameFileError, pth)
97-
tryOsOp(src, dst): impl(ssrc, sdst, options=cpOptions)
98-
99-
copyGen copyfile, copyFileImpl
100-
101-
proc copyWithPermissions(src, dst: string,
102-
options={cfSymlinkFollow}) =
103-
let dstFile = if dst.dirExists: dst / src.lastPathPart
104-
else: dst
105-
copyFileWithPermissions(src, dstFile,
106-
false, # we do not `ignorePermissionErrors`
107-
options)
108-
109-
copyGen copy, copyWithPermissions

src/pylib/Lib/shutil_impl/copys.nim

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
2+
import std/os
3+
when defined(posix):
4+
import std/posix
5+
import ../../pyerrors/oserr
6+
import ../../io_abc
7+
import ./sys
8+
9+
const COPY_BUFSIZE = when defined(windows): 64 * 1024 else: 16 * 1024
10+
# Python uses as followings, but it seems too large
11+
# when defined(windows): 1024 * 1024 else: 64 * 1024
12+
13+
proc copyfileobjImpl(s, d: File, length=COPY_BUFSIZE) =
14+
## shutil.copyfileobj but for Nim's `File`, here length must be positive
15+
let bufferSize = length
16+
# The following is modified from Nim-2.1.1/Lib/std/private/osfiles.nim L241
17+
# generic version of copyFile which works for any platform:
18+
19+
# Hints for kernel-level aggressive sequential low-fragmentation read-aheads:
20+
# https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_fadvise.html
21+
when defined(linux) or defined(osx):
22+
discard posix_fadvise(getFileHandle(d), 0.cint, 0.cint, POSIX_FADV_SEQUENTIAL)
23+
discard posix_fadvise(getFileHandle(s), 0.cint, 0.cint, POSIX_FADV_SEQUENTIAL)
24+
var buf = alloc(bufferSize)
25+
while true:
26+
var bytesread = readBuffer(s, buf, bufferSize)
27+
if bytesread > 0:
28+
var byteswritten = writeBuffer(d, buf, bytesread)
29+
if bytesread != byteswritten:
30+
dealloc(buf)
31+
raiseOSError(osLastError())
32+
if bytesread != bufferSize: break
33+
dealloc(buf)
34+
flushFile(d)
35+
36+
proc copyfileobj*(s, d: File, length=COPY_BUFSIZE) =
37+
## shutil.copyfileobj but for Nim's `File`
38+
##
39+
## if `length` is negative, it means copying the data
40+
## without looping over the source data in chunks
41+
if length < 0:
42+
d.write(s.readAll())
43+
return
44+
copyfileobjImpl(s, d, length)
45+
46+
type
47+
Error = object of PyOSError ## python's shutil.Error
48+
SameFileError* = object of Error
49+
template copyFileImpl(src, dst: string; options: CopyFlag) =
50+
## called by copyfile
51+
bind copyFile, copyfileobjImpl
52+
when defined(windows):
53+
# std/os's `copyFile` under Windows calls copyFileW,
54+
# which will copy file attributes too.
55+
# so we use another implementation instead.
56+
let isSymlink = src.symlinkExists
57+
if isSymlink and cfSymlinkAsIs in options:
58+
createSymlink(expandSymlink(source), dest)
59+
return
60+
var
61+
fsrc = open(src)
62+
fdst = open(dst, fmWrite)
63+
defer:
64+
fsrc.close()
65+
fdst.close()
66+
copyfileobjImpl(fsrc, dst)
67+
else:
68+
copyFile(src, dst, options)
69+
70+
template copyGen(pyname, impl) =
71+
proc pyname*[T](src, dst: PathLike[T], follow_symlinks=true) =
72+
sys.audit("shutil.copyfile", src, dst)
73+
let
74+
ssrc = $src
75+
sdst = $dst
76+
cpOptions = if follow_symlinks: {cfSymlinkFollow} else: {cfSymlinkAsIs}
77+
if sameFile(ssrc, sdst):
78+
raise newException(SameFileError, pth)
79+
tryOsOp(src, dst): impl(ssrc, sdst, options=cpOptions)
80+
81+
copyGen copyfile, copyFileImpl
82+
83+
proc copyWithPermissions(src, dst: string,
84+
options={cfSymlinkFollow}) =
85+
let dstFile = if dst.dirExists: dst / src.lastPathPart
86+
else: dst
87+
copyFileWithPermissions(src, dstFile,
88+
false, # we do not `ignorePermissionErrors`
89+
options)
90+
91+
copyGen copy, copyWithPermissions

src/pylib/Lib/shutil_impl/sys.nim

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
2+
import ../sys_impl/auditImpl
3+
export audit
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
2+
import std/terminal
3+
4+
# Nim consider it's the same as os.terminal_size,
5+
# as they are both tuple of Nim
6+
type terminal_size = tuple[columns, lines: int]
7+
proc get_terminal_size*(fallback=(80, 24)): terminal_size =
8+
## .. hint:: this does not simply refer to environment variable,
9+
## call `os.get_terminal_size`. This is a wrapper around
10+
## `terminalSize` of `std/terminal`, which is more steady,
11+
## returning meaningful result even when stdout is not associatd with
12+
## a terminal.
13+
result.columns = terminalWidth()
14+
if result.columns == 0:
15+
result.columns = fallback[0]
16+
result.lines = terminalHeight()
17+
if result.lines == 0:
18+
result.lines = fallback[1]
19+

0 commit comments

Comments
 (0)