nim_lk/src/nimblepkg/packageinstaller.nim

112 lines
4.3 KiB
Nim

# Copyright (C) Dominik Picheta. All rights reserved.
# BSD License. Look at license.txt for more info.
import os, strutils, sets, json
# Local imports
import cli, options, tools
when defined(windows):
import version
when not declared(initHashSet) or not declared(toHashSet):
import common
when defined(windows):
# This is just for Win XP support.
# TODO: Drop XP support?
from winlean import WINBOOL, DWORD
type
OSVERSIONINFO* {.final, pure.} = object
dwOSVersionInfoSize*: DWORD
dwMajorVersion*: DWORD
dwMinorVersion*: DWORD
dwBuildNumber*: DWORD
dwPlatformId*: DWORD
szCSDVersion*: array[0..127, char]
proc GetVersionExA*(VersionInformation: var OSVERSIONINFO): WINBOOL{.stdcall,
dynlib: "kernel32", importc: "GetVersionExA".}
proc setupBinSymlink*(symlinkDest, symlinkFilename: string,
options: Options): seq[string] =
result = @[]
let currentPerms = getFilePermissions(symlinkDest)
setFilePermissions(symlinkDest, currentPerms + {fpUserExec})
when defined(unix):
display("Creating", "symlink: $1 -> $2" %
[symlinkDest, symlinkFilename], priority = MediumPriority)
if existsFile(symlinkFilename):
let msg = "Symlink already exists in $1. Replacing." % symlinkFilename
display("Warning:", msg, Warning, HighPriority)
removeFile(symlinkFilename)
createSymlink(symlinkDest, symlinkFilename)
result.add symlinkFilename.extractFilename
elif defined(windows):
# There is a bug on XP, described here:
# http://stackoverflow.com/questions/2182568/batch-script-is-not-executed-if-chcp-was-called
# But this workaround brakes code page on newer systems, so we need to detect OS version
var osver = OSVERSIONINFO()
osver.dwOSVersionInfoSize = cast[DWORD](sizeof(OSVERSIONINFO))
if GetVersionExA(osver) == WINBOOL(0):
raise newException(NimbleError,
"Can't detect OS version: GetVersionExA call failed")
let fixChcp = osver.dwMajorVersion <= 5
# Create cmd.exe/powershell stub.
let dest = symlinkFilename.changeFileExt("cmd")
display("Creating", "stub: $1 -> $2" % [symlinkDest, dest],
priority = MediumPriority)
var contents = "@"
if options.config.chcp:
if fixChcp:
contents.add "chcp 65001 > nul && "
else: contents.add "chcp 65001 > nul\n@"
contents.add "\"" & symlinkDest & "\" %*\n"
writeFile(dest, contents)
result.add dest.extractFilename
# For bash on Windows (Cygwin/Git bash).
let bashDest = dest.changeFileExt("")
display("Creating", "Cygwin stub: $1 -> $2" %
[symlinkDest, bashDest], priority = MediumPriority)
writeFile(bashDest, "\"" & symlinkDest & "\" \"$@\"\n")
result.add bashDest.extractFilename
else:
{.error: "Sorry, your platform is not supported.".}
proc saveNimbleMeta*(pkgDestDir, url, vcsRevision: string,
filesInstalled, bins: HashSet[string],
isLink: bool = false) =
## Saves the specified data into a ``nimblemeta.json`` file inside
## ``pkgDestDir``.
##
## filesInstalled - A list of absolute paths to files which have been
## installed.
## bins - A list of binary filenames which have been installed for this
## package.
##
## isLink - Determines whether the installed package is a .nimble-link.
var nimblemeta = %{"url": %url}
if vcsRevision.len > 0:
nimblemeta["vcsRevision"] = %vcsRevision
let files = newJArray()
nimblemeta["files"] = files
for file in filesInstalled:
files.add(%changeRoot(pkgDestDir, "", file))
let binaries = newJArray()
nimblemeta["binaries"] = binaries
for bin in bins:
binaries.add(%bin)
nimblemeta["isLink"] = %isLink
writeFile(pkgDestDir / "nimblemeta.json", $nimblemeta)
proc saveNimbleMeta*(pkgDestDir, pkgDir, vcsRevision, nimbleLinkPath: string) =
## Overload of saveNimbleMeta for linked (.nimble-link) packages.
##
## pkgDestDir - The directory where the package has been installed.
## For example: ~/.nimble/pkgs/jester-#head/
##
## pkgDir - The directory where the original package files are.
## For example: ~/projects/jester/
saveNimbleMeta(pkgDestDir, "file://" & pkgDir, vcsRevision,
toHashSet[string]([nimbleLinkPath]), initHashSet[string](), true)