Extra checks for unsatisfiable dependencies.

Specifically this refers to the problem with babel-test/packagebin.
PackageBin ends up depending on two different versions of PackageA (0.2
and 0.5). This however cannot be built because the Nimrod compiler can
only use one of these packages.
This commit is contained in:
Dominik Picheta 2013-12-20 13:05:10 +00:00
commit 8585e11a4d
2 changed files with 44 additions and 11 deletions

View file

@ -1,7 +1,7 @@
# Copyright (C) Dominik Picheta. All rights reserved. # Copyright (C) Dominik Picheta. All rights reserved.
# BSD License. Look at license.txt for more info. # BSD License. Look at license.txt for more info.
import httpclient, parseopt, os, strutils, osproc, pegs, tables, parseutils import httpclient, parseopt, os, strutils, osproc, pegs, tables, parseutils, strtabs
import packageinfo, version, common, tools, download, algorithm import packageinfo, version, common, tools, download, algorithm
@ -227,7 +227,7 @@ proc copyFilesRec(origDir, currentDir, dest: string, pkgInfo: TPackageInfo) =
changeRoot(pkgInfo.mypath.splitFile.dir, dest, pkgInfo.mypath)) changeRoot(pkgInfo.mypath.splitFile.dir, dest, pkgInfo.mypath))
proc install(packages: seq[tuple[name: string, verRange: PVersionRange]], proc install(packages: seq[tuple[name: string, verRange: PVersionRange]],
options: TOptions, doPrompt = true): string {.discardable.} options: TOptions, doPrompt = true): seq[string] {.discardable.}
proc processDeps(pkginfo: TPackageInfo, options: TOptions): seq[string] = proc processDeps(pkginfo: TPackageInfo, options: TOptions): seq[string] =
## Verifies and installs dependencies. ## Verifies and installs dependencies.
## ##
@ -244,11 +244,22 @@ proc processDeps(pkginfo: TPackageInfo, options: TOptions): seq[string] =
var pkg: TPackageInfo var pkg: TPackageInfo
if not findPkg(pkglist, dep, pkg): if not findPkg(pkglist, dep, pkg):
echo("None found, installing...") echo("None found, installing...")
let dest = install(@[(dep.name, dep.ver)], options) let paths = install(@[(dep.name, dep.ver)], options)
result.add(dest) result.add(paths)
else: else:
echo("Dependency already satisfied.") echo("Dependency already satisfied.")
result.add(pkg.mypath.splitFile.dir) result.add(pkg.mypath.splitFile.dir)
# Check if two packages of the same name (but different version) are listed
# in the path.
var pkgsInPath: PStringTable = newStringTable(modeCaseSensitive)
for p in result:
let (name, version) = getNameVersion(p)
if pkgsInPath.hasKey(name):
raise newException(EBabel,
"Cannot satisfy the dependency on $1 $2 and $1 $3" %
[name, version, pkgsInPath[name]])
pkgsInPath[name] = version
proc buildFromDir(pkgInfo: TPackageInfo, paths: seq[string]) = proc buildFromDir(pkgInfo: TPackageInfo, paths: seq[string]) =
## Builds a package as specified by ``pkgInfo``. ## Builds a package as specified by ``pkgInfo``.
@ -261,17 +272,17 @@ proc buildFromDir(pkgInfo: TPackageInfo, paths: seq[string]) =
doCmd("nimrod $# -d:release $# \"$#\"" % doCmd("nimrod $# -d:release $# \"$#\"" %
[pkgInfo.backend, args, realDir / bin.changeFileExt("nim")]) [pkgInfo.backend, args, realDir / bin.changeFileExt("nim")])
proc installFromDir(dir: string, latest: bool, options: TOptions): string = proc installFromDir(dir: string, latest: bool, options: TOptions): seq[string] =
## Returns where package has been installed to. ## Returns where package has been installed to.
## The return value of this function is used by ## The return value of this function is used by
## ``processDeps`` to gather a list of paths to pass to the nimrod compiler. ## ``processDeps`` to gather a list of paths to pass to the nimrod compiler.
var pkgInfo = getPkgInfo(dir) var pkgInfo = getPkgInfo(dir)
let realDir = pkgInfo.getRealDir() let realDir = pkgInfo.getRealDir()
let pkgDestDir = pkgsDir / (pkgInfo.name & let versionStr = (if latest: "" else: '-' & pkgInfo.version)
(if latest: "" else: '-' & pkgInfo.version)) let pkgDestDir = pkgsDir / (pkgInfo.name & versionStr)
if existsDir(pkgDestDir): if existsDir(pkgDestDir):
if not options.prompt(pkgInfo.name & " already exists. Overwrite?"): if not options.prompt(pkgInfo.name & versionStr & " already exists. Overwrite?"):
quit(QuitSuccess) quit(QuitSuccess)
removeDir(pkgDestDir) removeDir(pkgDestDir)
# Remove any symlinked binaries # Remove any symlinked binaries
@ -317,7 +328,9 @@ proc installFromDir(dir: string, latest: bool, options: TOptions): string =
{.error: "Sorry, your platform is not supported.".} {.error: "Sorry, your platform is not supported.".}
else: else:
copyFilesRec(realDir, realDir, pkgDestDir, pkgInfo) copyFilesRec(realDir, realDir, pkgDestDir, pkgInfo)
result = pkgDestDir
result = paths # Return the paths to the dependencies of this package.
result.add pkgDestDir
echo(pkgInfo.name & " installed successfully.") echo(pkgInfo.name & " installed successfully.")
@ -338,7 +351,7 @@ proc downloadPkg(pkg: TPackage, verRange: PVersionRange): string =
result = downloadDir result = downloadDir
proc install(packages: seq[tuple[name: string, verRange: PVersionRange]], proc install(packages: seq[tuple[name: string, verRange: PVersionRange]],
options: TOptions, doPrompt = true): string = options: TOptions, doPrompt = true): seq[string] =
if packages == @[]: if packages == @[]:
result = installFromDir(getCurrentDir(), false, options) result = installFromDir(getCurrentDir(), false, options)
else: else:

View file

@ -280,6 +280,22 @@ proc getRealDir*(pkgInfo: TPackageInfo): string =
else: else:
result = pkgInfo.mypath.splitFile.dir result = pkgInfo.mypath.splitFile.dir
proc getNameVersion*(pkgpath: string): tuple[name, version: string] =
## Splits ``pkgpath`` in the format ``/home/user/.babel/libs/package-0.1``
## into ``(packagea, 0.1)``
result.name = ""
result.version = ""
let tail = pkgpath.splitPath.tail
if '-' notin tail:
result.name = tail
return
for i in countdown(tail.len-1, 0):
if tail[i] == '-':
result.name = tail[0 .. i-1]
result.version = tail[i+1 .. -1]
break
proc echoPackage*(pkg: TPackage) = proc echoPackage*(pkg: TPackage) =
echo(pkg.name & ":") echo(pkg.name & ":")
echo(" url: " & pkg.url & " (" & pkg.downloadMethod & ")") echo(" url: " & pkg.url & " (" & pkg.downloadMethod & ")")
@ -287,4 +303,8 @@ proc echoPackage*(pkg: TPackage) =
echo(" description: " & pkg.description) echo(" description: " & pkg.description)
echo(" license: " & pkg.license) echo(" license: " & pkg.license)
if pkg.web.len > 0: if pkg.web.len > 0:
echo(" website: " & pkg.web) echo(" website: " & pkg.web)
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")