Implements #41.

Also, building of binary packages now takes place before any old packages
are removed. This is to prevent the case where the old package is removed
and a new version of the same package fails to build so the user is left
with no package at all.
This commit is contained in:
Dominik Picheta 2014-06-20 20:10:49 +01:00
commit 10de991d3d
5 changed files with 95 additions and 56 deletions

View file

@ -2,9 +2,9 @@
# BSD License. Look at license.txt for more info.
import httpclient, parseopt, os, strutils, osproc, pegs, tables, parseutils,
strtabs, json, algorithm
strtabs, json, algorithm, sets
import babelpkg/packageinfo, babelpkg/version, babelpkg/common, babelpkg/tools, babelpkg/download
import babelpkg/packageinfo, babelpkg/version, babelpkg/tools, babelpkg/download
type
TOptions = object
@ -180,20 +180,26 @@ proc checkInstallDir(pkgInfo: TPackageInfo,
if thisDir[0] == '.': result = true
if thisDir == "nimcache": result = true
proc copyWithExt(origDir, currentDir, dest: string, pkgInfo: TPackageInfo) =
proc copyWithExt(origDir, currentDir, dest: string,
pkgInfo: TPackageInfo): seq[string] =
## Returns the filenames of the files that have been copied
## (their destination).
result = @[]
for kind, path in walkDir(currentDir):
if kind == pcDir:
copyWithExt(origDir, path, dest, pkgInfo)
result.add copyWithExt(origDir, path, dest, pkgInfo)
else:
for iExt in pkgInfo.installExt:
if path.splitFile.ext == ('.' & iExt):
createDir(changeRoot(origDir, dest, path).splitFile.dir)
copyFileD(path, changeRoot(origDir, dest, path))
result.add copyFileD(path, changeRoot(origDir, dest, path))
proc copyFilesRec(origDir, currentDir, dest: string,
options: TOptions, pkgInfo: TPackageInfo) =
options: TOptions, pkgInfo: TPackageInfo): TSet[string] =
## Copies all the required files, skips files specified in the .babel file
## (TPackageInfo).
## Returns a list of filepaths to files which have been installed.
result = initSet[string]()
let whitelistMode =
pkgInfo.installDirs.len != 0 or
pkgInfo.installFiles.len != 0 or
@ -207,7 +213,7 @@ proc copyFilesRec(origDir, currentDir, dest: string,
else:
quit(QuitSuccess)
createDir(dest / file.splitFile.dir)
copyFileD(src, dest / file)
result.incl copyFileD(src, dest / file)
for dir in pkgInfo.installDirs:
# TODO: Allow skipping files inside dirs?
@ -217,9 +223,9 @@ proc copyFilesRec(origDir, currentDir, dest: string,
continue
else:
quit(QuitSuccess)
copyDirD(origDir / dir, dest / dir)
result.incl copyDirD(origDir / dir, dest / dir)
copyWithExt(origDir, currentDir, dest, pkgInfo)
result.incl copyWithExt(origDir, currentDir, dest, pkgInfo)
else:
for kind, file in walkDir(currentDir):
if kind == pcDir:
@ -229,15 +235,15 @@ proc copyFilesRec(origDir, currentDir, dest: string,
# Create the dir.
createDir(changeRoot(origDir, dest, file))
copyFilesRec(origDir, file, dest, options, pkgInfo)
result.incl copyFilesRec(origDir, file, dest, options, pkgInfo)
else:
let skip = pkgInfo.checkInstallFile(origDir, file)
if skip: continue
copyFileD(file, changeRoot(origDir, dest, file))
result.incl copyFileD(file, changeRoot(origDir, dest, file))
copyFileD(pkgInfo.mypath,
result.incl copyFileD(pkgInfo.mypath,
changeRoot(pkgInfo.mypath.splitFile.dir, dest, pkgInfo.mypath))
proc install(packages: seq[tuple[name: string, verRange: PVersionRange]],
@ -286,19 +292,52 @@ proc buildFromDir(pkgInfo: TPackageInfo, paths: seq[string]) =
doCmd("nimrod $# -d:release --noBabelPath $# \"$#\"" %
[pkgInfo.backend, args, realDir / bin.changeFileExt("nim")])
proc installFromDir(dir: string, latest: bool, options: TOptions, url: string): seq[string] =
## Returns where package has been installed to.
proc saveBabelMeta(pkgDestDir, url: string, filesInstalled: TSet[string]) =
var babelmeta = %{"url": %url}
babelmeta["files"] = newJArray()
for file in filesInstalled:
babelmeta["files"].add(%changeRoot(pkgDestDir, "", file))
writeFile(pkgDestDir / "babelmeta.json", $babelmeta)
proc removePkgDir(dir: string, options: TOptions) =
## Removes files belonging to the package in ``dir``.
try:
var babelmeta = parseFile(dir / "babelmeta.json")
if not babelmeta.hasKey("files"):
raise newException(EJsonParsingError,
"Meta data does not contain required info.")
for file in babelmeta["files"]:
removeFile(dir / file.str)
except EOS, EJsonParsingError:
echo("Error: Unable to read babelmeta.json: ", getCurrentExceptionMsg())
if not options.prompt("Would you like to COMPLETELY overwrite ALL files " &
"in " & dir & "?"):
quit(QuitSuccess)
removeDir(dir)
proc installFromDir(dir: string, latest: bool, options: TOptions,
url: string): seq[string] =
## Returns where package has been installed to, together with paths
## to the packages this package depends on.
## The return value of this function is used by
## ``processDeps`` to gather a list of paths to pass to the nimrod compiler.
var pkgInfo = getPkgInfo(dir)
let realDir = pkgInfo.getRealDir()
# Dependencies need to be processed before the creation of the pkg dir.
let paths = processDeps(pkginfo, options)
echo("Installing ", pkginfo.name, "-", pkginfo.version)
# Build before removing an existing package (if one exists). This way
# if the build fails then the old package will still be installed.
if pkgInfo.bin.len > 0: buildFromDir(pkgInfo, paths)
let versionStr = (if latest: "" else: '-' & pkgInfo.version)
let pkgDestDir = pkgsDir / (pkgInfo.name & versionStr)
if existsDir(pkgDestDir):
if not options.prompt(pkgInfo.name & versionStr & " already exists. Overwrite?"):
quit(QuitSuccess)
removeDir(pkgDestDir)
removePkgDir(pkgDestDir, options)
# Remove any symlinked binaries
for bin in pkgInfo.bin:
# TODO: Check that this binary belongs to the package being installed.
@ -306,24 +345,21 @@ proc installFromDir(dir: string, latest: bool, options: TOptions, url: string):
removeFile(binDir / bin.changeFileExt("bat"))
else:
removeFile(binDir / bin)
echo("Installing ", pkginfo.name, "-", pkginfo.version)
# Dependencies need to be processed before the creation of the pkg dir.
let paths = processDeps(pkginfo, options)
if pkgInfo.bin.len > 0: buildFromDir(pkgInfo, paths)
## Will contain a list of files which have been installed.
var filesInstalled: TSet[string]
createDir(pkgDestDir)
if pkgInfo.bin.len > 0:
createDir(binDir)
# Copy all binaries and files that are not skipped
copyFilesRec(realDir, realDir, pkgDestDir, options, pkgInfo)
filesInstalled = copyFilesRec(realDir, realDir, pkgDestDir, options,
pkgInfo)
# Set file permissions to +x for all binaries built,
# and symlink them on *nix OS' to $babelDir/bin/
for bin in pkgInfo.bin:
if not existsFile(pkgDestDir / bin):
copyFileD(realDir / bin, pkgDestDir / bin)
filesInstalled.incl copyFileD(realDir / bin, pkgDestDir / bin)
let currentPerms = getFilePermissions(pkgDestDir / bin)
setFilePermissions(pkgDestDir / bin, currentPerms + {fpUserExec})
@ -341,11 +377,11 @@ proc installFromDir(dir: string, latest: bool, options: TOptions, url: string):
else:
{.error: "Sorry, your platform is not supported.".}
else:
copyFilesRec(realDir, realDir, pkgDestDir, options, pkgInfo)
filesInstalled = copyFilesRec(realDir, realDir, pkgDestDir, options,
pkgInfo)
# Save a babelmeta.json file.
var babelmeta = %{"url": %url}
writeFile(pkgDestDir / "babelmeta.json", $babelmeta)
saveBabelMeta(pkgDestDir, url, filesInstalled)
result = paths # Return the paths to the dependencies of this package.
result.add pkgDestDir

View file

@ -1,15 +0,0 @@
# Copyright (C) Dominik Picheta. All rights reserved.
# BSD License. Look at license.txt for more info.
import os, osproc
type
EBabel* = object of EBase
proc copyFileD*(fro, to: string) =
echo(fro, " -> ", to)
copyFile(fro, to)
proc copyDirD*(fro, to: string) =
echo(fro, " -> ", to)
copyDir(fro, to)

View file

@ -3,7 +3,7 @@
import parseutils, os, osproc, strutils, tables
import packageinfo, common, version, tools
import packageinfo, version, tools
type
TDownloadMethod* {.pure.} = enum
@ -210,4 +210,4 @@ proc echoPackageVersions*(pkg: TPackage) =
except EOS:
echo(getCurrentExceptionMsg())
of TDownloadMethod.Hg:
echo(" versions: (Remote tag retrieval not supported by " & pkg.downloadMethod & ")")
echo(" versions: (Remote tag retrieval not supported by " & pkg.downloadMethod & ")")

View file

@ -1,7 +1,7 @@
# Copyright (C) Dominik Picheta. All rights reserved.
# BSD License. Look at license.txt for more info.
import parsecfg, json, streams, strutils, parseutils, os
import version, common
import version, tools
type
TPackageInfo* = object
mypath*: string ## The path of this .babel file
@ -323,6 +323,13 @@ proc echoPackage*(pkg: TPackage) =
if pkg.web.len > 0:
echo(" website: " & pkg.web)
proc getDownloadDirName*(pkg: TPackage, verRange: PVersionRange): string =
result = pkg.name
let verSimple = getSimpleString(verRange)
if verSimple != "":
result.add "_"
result.add verSimple
when isMainModule:
doAssert getNameVersion("/home/user/.babel/libs/packagea-0.1") == ("packagea", "0.1")
doAssert getNameVersion("/home/user/.babel/libs/package-a-0.1") == ("package-a", "0.1")
doAssert getNameVersion("/home/user/.babel/libs/package-a-0.1") == ("package-a", "0.1")

View file

@ -2,10 +2,11 @@
# BSD License. Look at license.txt for more info.
#
# Various miscellaneous utility functions reside here.
import osproc, pegs, strutils, os, parseurl
import version, common, packageinfo
import osproc, pegs, strutils, os, parseurl, sets
import version, packageinfo
# TODO: Merge with common.nim?
type
EBabel* = object of EBase
proc doCmd*(cmd: string) =
let exitCode = execCmd(cmd)
@ -47,6 +48,19 @@ proc changeRoot*(origRoot, newRoot, path: string): string =
raise newException(EInvalidValue,
"Cannot change root of path: Path does not begin with original root.")
proc copyFileD*(fro, to: string): string =
## Returns the destination (``to``).
echo(fro, " -> ", to)
copyFile(fro, to)
result = to
proc copyDirD*(fro, to: string): seq[string] =
## Returns the filenames of the files in the directory that were copied.
result = @[]
echo("Copying directory: ", fro, " -> ", to)
for path in walkDirRec(fro):
result.add copyFileD(path, changeRoot(fro, to, path))
proc getDownloadDirName*(url: string, verRange: PVersionRange): string =
## Creates a directory name based on the specified ``url``
result = ""
@ -68,9 +82,6 @@ proc getDownloadDirName*(url: string, verRange: PVersionRange): string =
result.add "_"
result.add verSimple
proc getDownloadDirName*(pkg: TPackage, verRange: PVersionRange): string =
result = pkg.name
let verSimple = getSimpleString(verRange)
if verSimple != "":
result.add "_"
result.add verSimple
proc incl*(s: var TSet[string], v: seq[string] | TSet[string]) =
for i in v:
s.incl i