-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathosutils.nim
116 lines (100 loc) · 3.22 KB
/
osutils.nim
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#
# Nawabs -- The Anti package manager for Nim
# (c) Copyright 2017 Andreas Rumpf
#
# See the file "license.txt", included in this
# distribution, for details about the copyright.
## OS utilities like 'exec' and 'withDir'.
import os, strutils, osproc, std/sha1
proc error*(msg: string) =
when defined(debug):
writeStackTrace()
quit "[Error] " & msg
proc exec*(cmd: string; attempts=0) =
for i in 0..attempts:
if execShellCmd(cmd) == 0: return
if i < attempts: os.sleep(4000)
error "exernal program failed: " & cmd
template withDir*(dir, body) =
let oldDir = getCurrentDir()
try:
setCurrentDir(dir)
body
finally:
setCurrentDir(oldDir)
proc isUrl*(x: string): bool =
x.startsWith("git://") or x.startsWith("https://") or x.startsWith("http://")
proc cloneUrl*(url, dest: string; cloneUsingHttps: bool) =
var modUrl =
if url.startsWith("git://") and cloneUsingHttps:
"https://" & url[6 .. ^1]
else: url
# github + https + trailing url slash causes a
# checkout/ls-remote to fail with Repository not found
var isgithub = false
if modUrl.contains("github.com") and modUrl.endswith("/"):
modUrl = modUrl[0 .. ^2]
isgithub = true
let (_, exitCode) = execCmdEx("git ls-remote --quiet --tags " & modUrl)
var xcode = exitCode
if isgithub and exitCode != QuitSuccess:
# retry multiple times to avoid annoying github timeouts:
for i in 0..10:
os.sleep(4000)
xcode = execCmdEx("git ls-remote --quiet --tags " & modUrl)[1]
if xcode == QuitSuccess: break
if xcode == QuitSuccess:
# retry multiple times to avoid annoying github timeouts:
let cmd = "git clone " & modUrl & " " & dest
for i in 0..10:
if execShellCmd(cmd) == 0: return
os.sleep(4000)
error "exernal program failed: " & cmd
elif not isgithub:
let (_, exitCode) = execCmdEx("hg identify " & modUrl)
if exitCode == QuitSuccess:
exec "hg clone " & modUrl & " " & dest
else:
error "Unable to identify url: " & modUrl
else:
error "Unable to identify url: " & modUrl
proc exe*(f: string): string =
result = addFileExt(f, ExeExt)
when defined(windows):
result = result.replace('/','\\')
proc tryExec*(cmd: string): bool =
echo(cmd)
result = execShellCmd(cmd) == 0
proc safeRemove*(filename: string) =
if fileExists(filename): removeFile(filename)
proc copyExe*(source, dest: string) =
safeRemove(dest)
copyFile(dest=dest, source=source)
inclFilePermissions(dest, {fpUserExec})
proc fileChanged*(file, hashdir: string): bool =
try:
var currentHash = secureHashFile(file)
var f: File
let hashFile = hashdir / $secureHash(expandFilename(file)) & ".sha1"
if open(f, hashFile, fmRead):
let oldHash = parseSecureHash(f.readLine())
close(f)
result = oldHash != currentHash
else:
result = true
if result:
if open(f, hashFile, fmWrite):
f.writeLine($currentHash)
close(f)
except IOError, OSError:
result = true
template rule*(d, body: untyped) =
const deps {.inject.} = d
var change = false
for x in deps:
if fileChanged(x):
change = true
# we must not break here so that every file gets a fresh timestamp
# anyway
if change:
body