Skip to content

Commit

Permalink
Implements #41.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
dom96 committed Jun 20, 2014
1 parent 5322268 commit 10de991
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 56 deletions.
92 changes: 64 additions & 28 deletions src/babel.nim
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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?
Expand All @@ -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:
Expand All @@ -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]],
Expand Down Expand Up @@ -286,44 +292,74 @@ 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.
when defined(windows):
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})
Expand All @@ -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
Expand Down
15 changes: 0 additions & 15 deletions src/babelpkg/common.nim

This file was deleted.

4 changes: 2 additions & 2 deletions src/babelpkg/download.nim
Expand Up @@ -3,7 +3,7 @@

import parseutils, os, osproc, strutils, tables

import packageinfo, common, version, tools
import packageinfo, version, tools

type
TDownloadMethod* {.pure.} = enum
Expand Down Expand Up @@ -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 & ")")
11 changes: 9 additions & 2 deletions src/babelpkg/packageinfo.nim
@@ -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
Expand Down Expand Up @@ -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")
29 changes: 20 additions & 9 deletions src/babelpkg/tools.nim
Expand Up @@ -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)
Expand Down Expand Up @@ -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 = ""
Expand All @@ -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

0 comments on commit 10de991

Please sign in to comment.