Implements basic support for building with .nimble-link'ed packages.
This commit is contained in:
parent
5f1de1e4ff
commit
97dc0ffb45
8 changed files with 90 additions and 31 deletions
|
|
@ -4,7 +4,7 @@
|
||||||
import system except TResult
|
import system except TResult
|
||||||
|
|
||||||
import httpclient, parseopt, os, osproc, pegs, tables, parseutils,
|
import httpclient, parseopt, os, osproc, pegs, tables, parseutils,
|
||||||
strtabs, json, algorithm, sets, uri
|
strtabs, json, algorithm, sets, uri, future, sequtils
|
||||||
|
|
||||||
import strutils except toLower
|
import strutils except toLower
|
||||||
from unicode import toLower
|
from unicode import toLower
|
||||||
|
|
@ -198,11 +198,12 @@ proc removeRevDep(options: Options, pkg: PackageInfo) =
|
||||||
|
|
||||||
proc install(packages: seq[PkgTuple],
|
proc install(packages: seq[PkgTuple],
|
||||||
options: Options,
|
options: Options,
|
||||||
doPrompt = true): tuple[paths: seq[string], pkg: PackageInfo]
|
doPrompt = true): tuple[deps: seq[PackageInfo], pkg: PackageInfo]
|
||||||
proc processDeps(pkginfo: PackageInfo, options: Options): seq[string] =
|
proc processDeps(pkginfo: PackageInfo, options: Options): seq[PackageInfo] =
|
||||||
## Verifies and installs dependencies.
|
## Verifies and installs dependencies.
|
||||||
##
|
##
|
||||||
## Returns the list of paths to pass to the compiler during build phase.
|
## Returns the list of PackageInfo (for paths) to pass to the compiler
|
||||||
|
## during build phase.
|
||||||
result = @[]
|
result = @[]
|
||||||
assert(not pkginfo.isMinimal, "processDeps needs pkginfo.requires")
|
assert(not pkginfo.isMinimal, "processDeps needs pkginfo.requires")
|
||||||
display("Verifying",
|
display("Verifying",
|
||||||
|
|
@ -233,8 +234,8 @@ proc processDeps(pkginfo: PackageInfo, options: Options): seq[string] =
|
||||||
if not found:
|
if not found:
|
||||||
display("Installing", $resolvedDep, priority = HighPriority)
|
display("Installing", $resolvedDep, priority = HighPriority)
|
||||||
let toInstall = @[(resolvedDep.name, resolvedDep.ver)]
|
let toInstall = @[(resolvedDep.name, resolvedDep.ver)]
|
||||||
let (paths, installedPkg) = install(toInstall, options)
|
let (pkgs, installedPkg) = install(toInstall, options)
|
||||||
result.add(paths)
|
result.add(pkgs)
|
||||||
|
|
||||||
pkg = installedPkg # For addRevDep
|
pkg = installedPkg # For addRevDep
|
||||||
|
|
||||||
|
|
@ -243,7 +244,12 @@ proc processDeps(pkginfo: PackageInfo, options: Options): seq[string] =
|
||||||
else:
|
else:
|
||||||
display("Info:", "Dependency on $1 already satisfied" % $dep,
|
display("Info:", "Dependency on $1 already satisfied" % $dep,
|
||||||
priority = HighPriority)
|
priority = HighPriority)
|
||||||
result.add(pkg.mypath.splitFile.dir)
|
if pkg.isLinked:
|
||||||
|
# TODO (#393): This can be optimised since the .nimble-link files have
|
||||||
|
# a secondary line that specifies the srcDir.
|
||||||
|
pkg = pkg.toFullInfo(options)
|
||||||
|
|
||||||
|
result.add(pkg)
|
||||||
# Process the dependencies of this dependency.
|
# Process the dependencies of this dependency.
|
||||||
result.add(processDeps(pkg.toFullInfo(options), options))
|
result.add(processDeps(pkg.toFullInfo(options), options))
|
||||||
reverseDeps.add((pkg.name, pkg.specialVersion))
|
reverseDeps.add((pkg.name, pkg.specialVersion))
|
||||||
|
|
@ -251,8 +257,7 @@ proc processDeps(pkginfo: PackageInfo, options: Options): seq[string] =
|
||||||
# Check if two packages of the same name (but different version) are listed
|
# Check if two packages of the same name (but different version) are listed
|
||||||
# in the path.
|
# in the path.
|
||||||
var pkgsInPath: StringTableRef = newStringTable(modeCaseSensitive)
|
var pkgsInPath: StringTableRef = newStringTable(modeCaseSensitive)
|
||||||
for p in result:
|
for pkgInfo in result:
|
||||||
let pkgInfo = getPkgInfo(p, options)
|
|
||||||
if pkgsInPath.hasKey(pkgInfo.name) and
|
if pkgsInPath.hasKey(pkgInfo.name) and
|
||||||
pkgsInPath[pkgInfo.name] != pkgInfo.version:
|
pkgsInPath[pkgInfo.name] != pkgInfo.version:
|
||||||
raise newException(NimbleError,
|
raise newException(NimbleError,
|
||||||
|
|
@ -267,7 +272,8 @@ proc processDeps(pkginfo: PackageInfo, options: Options): seq[string] =
|
||||||
for i in reverseDeps:
|
for i in reverseDeps:
|
||||||
addRevDep(options, i, pkginfo)
|
addRevDep(options, i, pkginfo)
|
||||||
|
|
||||||
proc buildFromDir(pkgInfo: PackageInfo, paths: seq[string], args: var seq[string]) =
|
proc buildFromDir(pkgInfo: PackageInfo, paths: seq[string],
|
||||||
|
args: var seq[string]) =
|
||||||
## Builds a package as specified by ``pkgInfo``.
|
## Builds a package as specified by ``pkgInfo``.
|
||||||
if pkgInfo.bin.len == 0:
|
if pkgInfo.bin.len == 0:
|
||||||
raise newException(NimbleError,
|
raise newException(NimbleError,
|
||||||
|
|
@ -369,7 +375,10 @@ proc vcsRevisionInDir(dir: string): string =
|
||||||
discard
|
discard
|
||||||
|
|
||||||
proc installFromDir(dir: string, requestedVer: VersionRange, options: Options,
|
proc installFromDir(dir: string, requestedVer: VersionRange, options: Options,
|
||||||
url: string): tuple[paths: seq[string], pkg: PackageInfo] =
|
url: string): tuple[
|
||||||
|
deps: seq[PackageInfo],
|
||||||
|
pkg: PackageInfo
|
||||||
|
] =
|
||||||
## Returns where package has been installed to, together with paths
|
## Returns where package has been installed to, together with paths
|
||||||
## to the packages this package depends on.
|
## to the packages this package depends on.
|
||||||
## The return value of this function is used by
|
## The return value of this function is used by
|
||||||
|
|
@ -385,7 +394,7 @@ proc installFromDir(dir: string, requestedVer: VersionRange, options: Options,
|
||||||
pkgInfo.specialVersion = $requestedVer.spe
|
pkgInfo.specialVersion = $requestedVer.spe
|
||||||
|
|
||||||
# Dependencies need to be processed before the creation of the pkg dir.
|
# Dependencies need to be processed before the creation of the pkg dir.
|
||||||
result.paths = processDeps(pkgInfo, depsOptions)
|
result.deps = processDeps(pkgInfo, depsOptions)
|
||||||
|
|
||||||
if options.depsOnly:
|
if options.depsOnly:
|
||||||
result.pkg = pkgInfo
|
result.pkg = pkgInfo
|
||||||
|
|
@ -396,7 +405,9 @@ proc installFromDir(dir: string, requestedVer: VersionRange, options: Options,
|
||||||
|
|
||||||
# Build before removing an existing package (if one exists). This way
|
# Build before removing an existing package (if one exists). This way
|
||||||
# if the build fails then the old package will still be installed.
|
# if the build fails then the old package will still be installed.
|
||||||
if pkgInfo.bin.len > 0: buildFromDir(pkgInfo, result.paths, true)
|
if pkgInfo.bin.len > 0:
|
||||||
|
let paths = result.deps.map(dep => dep.getRealDir())
|
||||||
|
buildFromDir(pkgInfo, paths, true)
|
||||||
|
|
||||||
let pkgDestDir = pkgInfo.getPkgDest(options)
|
let pkgDestDir = pkgInfo.getPkgDest(options)
|
||||||
if existsDir(pkgDestDir) and existsFile(pkgDestDir / "nimblemeta.json"):
|
if existsDir(pkgDestDir) and existsFile(pkgDestDir / "nimblemeta.json"):
|
||||||
|
|
@ -462,8 +473,8 @@ proc installFromDir(dir: string, requestedVer: VersionRange, options: Options,
|
||||||
# processDeps).
|
# processDeps).
|
||||||
saveNimbleData(options)
|
saveNimbleData(options)
|
||||||
|
|
||||||
# Return the paths to the dependencies of this package.
|
# Return the dependencies of this package (mainly for paths).
|
||||||
result.paths.add pkgDestDir
|
result.deps.add pkgInfo
|
||||||
result.pkg = pkgInfo
|
result.pkg = pkgInfo
|
||||||
result.pkg.isInstalled = true
|
result.pkg.isInstalled = true
|
||||||
result.pkg.myPath = dest
|
result.pkg.myPath = dest
|
||||||
|
|
@ -496,7 +507,7 @@ proc getDownloadInfo*(pv: PkgTuple, options: Options,
|
||||||
|
|
||||||
proc install(packages: seq[PkgTuple],
|
proc install(packages: seq[PkgTuple],
|
||||||
options: Options,
|
options: Options,
|
||||||
doPrompt = true): tuple[paths: seq[string], pkg: PackageInfo] =
|
doPrompt = true): tuple[deps: seq[PackageInfo], pkg: PackageInfo] =
|
||||||
if packages == @[]:
|
if packages == @[]:
|
||||||
result = installFromDir(getCurrentDir(), newVRAny(), options, "")
|
result = installFromDir(getCurrentDir(), newVRAny(), options, "")
|
||||||
else:
|
else:
|
||||||
|
|
@ -530,7 +541,8 @@ proc install(packages: seq[PkgTuple],
|
||||||
proc build(options: Options) =
|
proc build(options: Options) =
|
||||||
var pkgInfo = getPkgInfo(getCurrentDir(), options)
|
var pkgInfo = getPkgInfo(getCurrentDir(), options)
|
||||||
nimScriptHint(pkgInfo)
|
nimScriptHint(pkgInfo)
|
||||||
let paths = processDeps(pkginfo, options)
|
let deps = processDeps(pkginfo, options)
|
||||||
|
let paths = deps.map(dep => dep.getRealDir())
|
||||||
var args = options.action.compileOptions
|
var args = options.action.compileOptions
|
||||||
buildFromDir(pkgInfo, paths, args)
|
buildFromDir(pkgInfo, paths, args)
|
||||||
|
|
||||||
|
|
@ -544,10 +556,10 @@ proc execBackend(options: Options) =
|
||||||
|
|
||||||
var pkgInfo = getPkgInfo(getCurrentDir(), options)
|
var pkgInfo = getPkgInfo(getCurrentDir(), options)
|
||||||
nimScriptHint(pkgInfo)
|
nimScriptHint(pkgInfo)
|
||||||
let paths = processDeps(pkginfo, options)
|
let deps = processDeps(pkginfo, options)
|
||||||
|
|
||||||
var args = ""
|
var args = ""
|
||||||
for path in paths: args.add("--path:\"" & path & "\" ")
|
for dep in deps: args.add("--path:\"" & dep.getRealDir() & "\" ")
|
||||||
for option in options.action.compileOptions:
|
for option in options.action.compileOptions:
|
||||||
args.add("\"" & option & "\" ")
|
args.add("\"" & option & "\" ")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ when not defined(nimscript):
|
||||||
isNimScript*: bool ## Determines if this pkg info was read from a nims file
|
isNimScript*: bool ## Determines if this pkg info was read from a nims file
|
||||||
isMinimal*: bool
|
isMinimal*: bool
|
||||||
isInstalled*: bool ## Determines if the pkg this info belongs to is installed
|
isInstalled*: bool ## Determines if the pkg this info belongs to is installed
|
||||||
|
isLinked*: bool ## Determines if the pkg this info belongs to has been linked via `develop`
|
||||||
postHooks*: HashSet[string] ## Useful to know so that Nimble doesn't execHook unnecessarily
|
postHooks*: HashSet[string] ## Useful to know so that Nimble doesn't execHook unnecessarily
|
||||||
preHooks*: HashSet[string]
|
preHooks*: HashSet[string]
|
||||||
name*: string
|
name*: string
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,7 @@ proc getNameVersion*(pkgpath: string): tuple[name, version: string] =
|
||||||
##
|
##
|
||||||
## Also works for file paths like:
|
## Also works for file paths like:
|
||||||
## ``/home/user/.nimble/pkgs/package-0.1/package.nimble``
|
## ``/home/user/.nimble/pkgs/package-0.1/package.nimble``
|
||||||
if pkgPath.splitFile.ext == ".nimble" or pkgPath.splitFile.ext == ".babel":
|
if pkgPath.splitFile.ext in [".nimble", ".nimble-link", ".babel"]:
|
||||||
return getNameVersion(pkgPath.splitPath.head)
|
return getNameVersion(pkgPath.splitPath.head)
|
||||||
|
|
||||||
result.name = ""
|
result.name = ""
|
||||||
|
|
@ -281,7 +281,7 @@ proc findNimbleFile*(dir: string; error: bool): string =
|
||||||
if kind in {pcFile, pcLinkToFile}:
|
if kind in {pcFile, pcLinkToFile}:
|
||||||
let ext = path.splitFile.ext
|
let ext = path.splitFile.ext
|
||||||
case ext
|
case ext
|
||||||
of ".babel", ".nimble":
|
of ".babel", ".nimble", ".nimble-link":
|
||||||
result = path
|
result = path
|
||||||
inc hits
|
inc hits
|
||||||
else: discard
|
else: discard
|
||||||
|
|
@ -293,8 +293,16 @@ proc findNimbleFile*(dir: string; error: bool): string =
|
||||||
raise newException(NimbleError,
|
raise newException(NimbleError,
|
||||||
"Specified directory does not contain a .nimble file.")
|
"Specified directory does not contain a .nimble file.")
|
||||||
else:
|
else:
|
||||||
display("Warning:", "No .nimble file found for " & dir, Warning,
|
display("Warning:", "No .nimble or .nimble-link file found for " &
|
||||||
HighPriority)
|
dir, Warning, HighPriority)
|
||||||
|
|
||||||
|
if result.splitFile.ext == ".nimble-link":
|
||||||
|
# Return the path of the real .nimble file.
|
||||||
|
let lines = readFile(result).splitLines()
|
||||||
|
result = lines[0]
|
||||||
|
if not fileExists(result):
|
||||||
|
raiseNimbleError("The .nimble-link file is pointing to a missing" &
|
||||||
|
" file: " & result)
|
||||||
|
|
||||||
proc getInstalledPkgsMin*(libsDir: string, options: Options):
|
proc getInstalledPkgsMin*(libsDir: string, options: Options):
|
||||||
seq[tuple[pkginfo: PackageInfo, meta: MetaData]] =
|
seq[tuple[pkginfo: PackageInfo, meta: MetaData]] =
|
||||||
|
|
@ -309,13 +317,15 @@ proc getInstalledPkgsMin*(libsDir: string, options: Options):
|
||||||
let nimbleFile = findNimbleFile(path, false)
|
let nimbleFile = findNimbleFile(path, false)
|
||||||
if nimbleFile != "":
|
if nimbleFile != "":
|
||||||
let meta = readMetaData(path)
|
let meta = readMetaData(path)
|
||||||
let (name, version) = getNameVersion(nimbleFile)
|
let (name, version) = getNameVersion(path)
|
||||||
var pkg = initPackageInfo(nimbleFile)
|
var pkg = initPackageInfo(nimbleFile)
|
||||||
pkg.name = name
|
pkg.name = name
|
||||||
pkg.version = version
|
pkg.version = version
|
||||||
pkg.specialVersion = version
|
pkg.specialVersion = version
|
||||||
pkg.isMinimal = true
|
pkg.isMinimal = true
|
||||||
pkg.isInstalled = true
|
pkg.isInstalled = true
|
||||||
|
pkg.isLinked =
|
||||||
|
cmpPaths(nimbleFile.splitFile().dir, path) != 0
|
||||||
result.add((pkg, meta))
|
result.add((pkg, meta))
|
||||||
|
|
||||||
proc withinRange*(pkgInfo: PackageInfo, verRange: VersionRange): bool =
|
proc withinRange*(pkgInfo: PackageInfo, verRange: VersionRange): bool =
|
||||||
|
|
@ -369,7 +379,7 @@ proc findAllPkgs*(pkglist: seq[tuple[pkgInfo: PackageInfo, meta: MetaData]],
|
||||||
|
|
||||||
proc getRealDir*(pkgInfo: PackageInfo): string =
|
proc getRealDir*(pkgInfo: PackageInfo): string =
|
||||||
## Returns the directory containing the package source files.
|
## Returns the directory containing the package source files.
|
||||||
if pkgInfo.srcDir != "" and not pkgInfo.isInstalled:
|
if pkgInfo.srcDir != "" and (not pkgInfo.isInstalled or pkgInfo.isLinked):
|
||||||
result = pkgInfo.mypath.splitFile.dir / pkgInfo.srcDir
|
result = pkgInfo.mypath.splitFile.dir / pkgInfo.srcDir
|
||||||
else:
|
else:
|
||||||
result = pkgInfo.mypath.splitFile.dir
|
result = pkgInfo.mypath.splitFile.dir
|
||||||
|
|
@ -515,6 +525,8 @@ when isMainModule:
|
||||||
("package", "#head")
|
("package", "#head")
|
||||||
doAssert getNameVersion("/home/user/.nimble/libs/package-#branch-with-dashes") ==
|
doAssert getNameVersion("/home/user/.nimble/libs/package-#branch-with-dashes") ==
|
||||||
("package", "#branch-with-dashes")
|
("package", "#branch-with-dashes")
|
||||||
|
# readPackageInfo (and possibly more) depends on this not raising.
|
||||||
|
doAssert getNameVersion("/home/user/.nimble/libs/package") == ("package", "")
|
||||||
|
|
||||||
doAssert toValidPackageName("foo__bar") == "foo_bar"
|
doAssert toValidPackageName("foo__bar") == "foo_bar"
|
||||||
doAssert toValidPackageName("jhbasdh!£$@%#^_&*_()qwe") == "jhbasdh_qwe"
|
doAssert toValidPackageName("jhbasdh!£$@%#^_&*_()qwe") == "jhbasdh_qwe"
|
||||||
|
|
|
||||||
|
|
@ -292,6 +292,11 @@ proc readPackageInfo(nf: NimbleFile, options: Options,
|
||||||
result.version = minimalInfo.version
|
result.version = minimalInfo.version
|
||||||
result.isNimScript = true
|
result.isNimScript = true
|
||||||
result.isMinimal = true
|
result.isMinimal = true
|
||||||
|
|
||||||
|
# It's possible this proc will receive a .nimble-link file eventually,
|
||||||
|
# I added this assert to hopefully make this error clear for everyone.
|
||||||
|
let msg = "No version detected. Received nimble-link?"
|
||||||
|
assert result.version.len > 0, msg
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
readPackageInfoFromNims(nf, options, result)
|
readPackageInfoFromNims(nf, options, result)
|
||||||
|
|
@ -386,6 +391,8 @@ proc getInstalledPkgs*(libsDir: string, options: Options):
|
||||||
raise exc
|
raise exc
|
||||||
|
|
||||||
pkg.isInstalled = true
|
pkg.isInstalled = true
|
||||||
|
pkg.isLinked =
|
||||||
|
cmpPaths(nimbleFile.splitFile().dir, path) != 0
|
||||||
result.add((pkg, meta))
|
result.add((pkg, meta))
|
||||||
|
|
||||||
proc isNimScript*(nf: string, options: Options): bool =
|
proc isNimScript*(nf: string, options: Options): bool =
|
||||||
|
|
@ -393,7 +400,9 @@ proc isNimScript*(nf: string, options: Options): bool =
|
||||||
|
|
||||||
proc toFullInfo*(pkg: PackageInfo, options: Options): PackageInfo =
|
proc toFullInfo*(pkg: PackageInfo, options: Options): PackageInfo =
|
||||||
if pkg.isMinimal:
|
if pkg.isMinimal:
|
||||||
return getPkgInfoFromFile(pkg.mypath, options)
|
result = getPkgInfoFromFile(pkg.mypath, options)
|
||||||
|
result.isInstalled = pkg.isInstalled
|
||||||
|
result.isLinked = pkg.isLinked
|
||||||
else:
|
else:
|
||||||
return pkg
|
return pkg
|
||||||
|
|
||||||
|
|
|
||||||
12
tests/develop/dependent/dependent.nimble
Normal file
12
tests/develop/dependent/dependent.nimble
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
# Package
|
||||||
|
|
||||||
|
version = "1.0"
|
||||||
|
author = "Dominik Picheta"
|
||||||
|
description = "dependent"
|
||||||
|
license = "MIT"
|
||||||
|
|
||||||
|
srcDir = "src"
|
||||||
|
|
||||||
|
# Dependencies
|
||||||
|
|
||||||
|
requires "nim >= 0.16.0", "srcdirtest"
|
||||||
3
tests/develop/dependent/src/dependent.nim
Normal file
3
tests/develop/dependent/src/dependent.nim
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
import srcdirtest
|
||||||
|
|
||||||
|
doAssert foo() == "correct"
|
||||||
|
|
@ -1 +1,4 @@
|
||||||
|
proc foo*(): string =
|
||||||
|
return "correct"
|
||||||
|
|
||||||
echo("hello")
|
echo("hello")
|
||||||
|
|
@ -24,6 +24,7 @@ test "can compile with --os:windows":
|
||||||
template cd*(dir: string, body: untyped) =
|
template cd*(dir: string, body: untyped) =
|
||||||
## Sets the current dir to ``dir``, executes ``body`` and restores the
|
## Sets the current dir to ``dir``, executes ``body`` and restores the
|
||||||
## previous working dir.
|
## previous working dir.
|
||||||
|
block:
|
||||||
let lastDir = getCurrentDir()
|
let lastDir = getCurrentDir()
|
||||||
setCurrentDir(dir)
|
setCurrentDir(dir)
|
||||||
body
|
body
|
||||||
|
|
@ -501,3 +502,9 @@ suite "develop feature":
|
||||||
check split.len == 2
|
check split.len == 2
|
||||||
check split[0].endsWith("develop/srcdirtest/srcdirtest.nimble")
|
check split[0].endsWith("develop/srcdirtest/srcdirtest.nimble")
|
||||||
check split[1].endsWith("develop/srcdirtest/src")
|
check split[1].endsWith("develop/srcdirtest/src")
|
||||||
|
|
||||||
|
cd "develop/dependent":
|
||||||
|
let (output, exitCode) = execNimble("c", "-r", "src/dependent")
|
||||||
|
checkpoint output
|
||||||
|
check(output.processOutput.inLines("hello"))
|
||||||
|
check exitCode == QuitSuccess
|
||||||
Loading…
Add table
Add a link
Reference in a new issue