getnim/src/getnimpkg/utils.nim

196 lines
6.4 KiB
Nim

import httpclient, json, os, strutils, osproc, uri, sequtils
import nimblepkg/[cli, version]
import zippy/tarballs as zippy_tarballs
import zippy/ziparchives as zippy_zips
import cliparams, common
when defined(windows):
import switcher
proc parseVersion*(versionStr: string): Version =
if versionStr[0] notin {'#', '\0'} + Digits:
let msg = "Invalid version, path or unknown channel.\n" &
"Try 1.0.6, #head, #commitHash, or stable.\n" &
"For example: getnim #head.\n \n"&
"See --help for more examples."
raise newException(GetnimError, msg)
let parts = versionStr.split(".")
if parts.len >= 3 and parts[2].parseInt() mod 2 != 0:
let msg = ("Version $# is a development version of Nim. This means " &
"it hasn't been released so you cannot install it this " &
"way. All unreleased versions of Nim " &
"have an odd patch number in their version.") % versionStr
let exc = newException(GetnimError, msg)
exc.hint = "If you want to install the development version then run " &
"`getnim devel`."
raise exc
result = newVersion(versionStr)
proc doCmdRaw*(cmd: string) =
# To keep output in sequence
stdout.flushFile()
stderr.flushFile()
displayDebug("Executing", cmd)
displayDebug("Work Dir", getCurrentDir())
let (output, exitCode) = execCmdEx(cmd)
displayDebug("Finished", "with exit code " & $exitCode)
displayDebug("Output", output)
if exitCode != QuitSuccess:
raise newException(GetnimError,
"Execution failed with exit code $1\nCommand: $2\nOutput: $3" %
[$exitCode, cmd, output])
proc extract*(path: string, extractDir: string) =
display("Extracting", path.extractFilename(), priority = HighPriority)
if path.splitFile().ext == ".xz":
when defined(windows):
# We don't ship with `unxz` on Windows, instead assume that we get
# a .zip on this platform.
raise newException(
GetnimError, "Unable to extract. Tar.xz files are not supported on Windows."
)
else:
let tarFile = path.changeFileExt("")
removeFile(tarFile) # just in case it exists, if it does `unxz` fails.
if findExe("unxz") == "":
raise newException(
GetnimError, "Unable to extract. Need `unxz` to extract .tar.xz file. See https://github.com/dom96/choosenim/issues/290."
)
doCmdRaw("unxz " & quoteShell(path))
extract(tarFile, extractDir) # We remove the .xz extension
return
let tempDir = getTempDir() / "getnim-extraction"
removeDir(tempDir)
try:
case path.splitFile.ext
of ".zip":
zippy_zips.extractAll(path, tempDir)
of ".tar", ".gz":
if findExe("tar") != "":
# TODO: Workaround for high mem usage of zippy (https://github.com/guzba/zippy/issues/31).
createDir(tempDir)
doCmdRaw("tar xf " & quoteShell(path) & " -C " & quoteShell(tempDir))
else:
zippy_tarballs.extractAll(path, tempDir)
else:
raise newException(
ValueError, "Unsupported format for extraction: " & path
)
except Exception as exc:
raise newException(GetnimError, "Unable to extract. Error was '$1'." %
exc.msg)
# Skip outer directory.
# Same as: https://github.com/dom96/untar/blob/d21f7229b/src/untar.nim
#
# Determine which directory to copy.
var srcDir = tempDir
let contents = toSeq(walkDir(srcDir))
if contents.len == 1:
# Skip the outer directory.
srcDir = contents[0][1]
# Finally copy the directory to what the user specified.
copyDir(srcDir, extractDir)
proc getProxy*(): Proxy =
## Returns ``nil`` if no proxy is specified.
var url = ""
try:
if existsEnv("http_proxy"):
url = getEnv("http_proxy")
elif existsEnv("https_proxy"):
url = getEnv("https_proxy")
except ValueError:
display("Warning:", "Unable to parse proxy from environment: " &
getCurrentExceptionMsg(), Warning, HighPriority)
if url.len > 0:
var parsed = parseUri(url)
if parsed.scheme.len == 0 or parsed.hostname.len == 0:
parsed = parseUri("http://" & url)
let auth =
if parsed.username.len > 0: parsed.username & ":" & parsed.password
else: ""
return newProxy($parsed, auth)
else:
return nil
proc getGccArch*(params: CliParams): int =
## Get gcc arch by getting pointer size x 8
var
outp = ""
errC = 0
when defined(windows):
# Add MingW bin dir to PATH so getGccArch can find gcc.
let pathEnv = getEnv("PATH")
if not isDefaultCCInPath(params) and dirExists(params.getMingwBin()):
putEnv("PATH", params.getMingwBin() & PathSep & pathEnv)
(outp, errC) = execCmdEx("cmd /c echo int main^(^) { return sizeof^(void *^); } | gcc -xc - -o archtest && archtest")
putEnv("PATH", pathEnv)
else:
(outp, errC) = execCmdEx("echo \"int main() { return sizeof(void *); }\" | gcc -xc - -o archtest && ./archtest")
removeFile("archtest".addFileExt(ExeExt))
if errC in [4, 8]:
return errC * 8
else:
# Fallback when arch detection fails. See https://github.com/dom96/choosenim/issues/284
return when defined(windows): 32 else: 64
proc getLatestCommit*(repo, branch: string): string =
## Get latest commit for remote Git repo with ls-remote
##
## Returns "" if Git isn't available
let
git = findExe("git")
if git.len != 0:
var
cmd = when defined(windows): "cmd /c " else: ""
cmd &= git.quoteShell & " ls-remote " & repo & " " & branch
let
(outp, errC) = execCmdEx(cmd)
if errC == 0:
for line in outp.splitLines():
result = line.split('\t')[0]
break
else:
display("Warning", outp & "\ngit ls-remote failed", Warning, HighPriority)
proc getNightliesUrl*(parsedContents: JsonNode, arch: int): (string, string) =
let os =
when defined(windows): "windows"
elif defined(linux): "linux"
elif defined(macosx): "osx"
elif defined(freebsd): "freebsd"
for jn in parsedContents.getElems():
if jn["name"].getStr().contains("devel"):
let tagName = jn{"tag_name"}.getStr("")
for asset in jn["assets"].getElems():
let aname = asset["name"].getStr()
let url = asset{"browser_download_url"}.getStr("")
if os in aname:
when not defined(macosx):
if "x" & $arch in aname:
result = (url, tagName)
else:
result = (url, tagName)
if result[0].len != 0:
break
if result[0].len != 0:
break