diff --git a/src/nimble.nim b/src/nimble.nim index 5eaf8009..e5c9b89f 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -21,7 +21,7 @@ import nimblepkg/packageinfotypes, nimblepkg/packageinfo, nimblepkg/version, nimblepkg/nimscriptwrapper, nimblepkg/developfile, nimblepkg/paths, nimblepkg/nimbledatafile, nimblepkg/packagemetadatafile, nimblepkg/displaymessages, nimblepkg/sha1hashes, nimblepkg/syncfile, - nimblepkg/deps, nimblepkg/nimblesat, nimblepkg/forge_aliases + nimblepkg/deps, nimblepkg/nimblesat, nimblepkg/forge_aliases, nimblepkg/nimenv const nimblePathsFileName* = "nimble.paths" @@ -754,35 +754,6 @@ proc processLockedDependencies(pkgInfo: PackageInfo, options: Options): return res.toHashSet -proc compileNim(realDir: string) = - let command = when defined(windows): "build_all.bat" else: "./build_all.sh" - cd realDir: - display("Info:", "compiling nim in $1" % realDir, priority = HighPriority) - tryDoCmdEx(command) - -proc useNimFromDir(options: var Options, realDir: string, tryCompiling = false) = - const binaryName = when defined(windows): "nim.exe" else: "nim" - - let - nim = realDir / "bin" / binaryName - fileExists = fileExists(options.nimBin) - - if not fileExists(nim): - if tryCompiling and options.prompt("Develop version of nim was found but it is not compiled. Compile it now?"): - compileNim(realDir) - else: - raise nimbleError("Trying to use nim from $1 " % realDir, - "If you are using develop mode nim make sure to compile it.") - - options.nimBin = nim - let separator = when defined(windows): ";" else: ":" - - putEnv("PATH", realDir / "bin" & separator & getEnv("PATH")) - if fileExists: - display("Info:", "switching to $1 for compilation" % options.nim, priority = HighPriority) - else: - display("Info:", "using $1 for compilation" % options.nim, priority = HighPriority) - proc install(packages: seq[PkgTuple], options: Options, doPrompt, first, fromLockFile: bool, preferredPackages: seq[PackageInfo] = @[]): PackageDependenciesInfo = @@ -817,6 +788,9 @@ proc install(packages: seq[PkgTuple], options: Options, var downloadPath = "" if options.useSatSolver and subdir == "": #Ignore the cache if subdir is set downloadPath = getCacheDownloadDir(url, pv.ver, options) + # if pv.name.isNim: + # downloadPath = "/Volumes/Store/Projects/nim/nimble/temptest/nimtest" + let (downloadDir, downloadVersion, vcsRevision) = if not isAlias: @@ -831,8 +805,8 @@ proc install(packages: seq[PkgTuple], options: Options, try: var opt = options if pv.name.isNim: - compileNim(downloadDir) - opt.useNimFromDir(downloadDir, true) + compileNim(opt, downloadDir, pv.ver) + opt.useNimFromDir(downloadDir, pv.ver, true) result = installFromDir(downloadDir, pv.ver, opt, url, first, fromLockFile, vcsRevision, preferredPackages = preferredPackages) @@ -2403,16 +2377,17 @@ proc setNimBin*(options: var Options) = if lockFile.fileExists and not options.disableLockFile and not options.useSystemNim: for name, dep in lockFile.getLockedDependencies.lockedDepsFor(options): if name.isNim: + let v = dep.version.toVersionRange() if isInstalled(name, dep, options): - options.useNimFromDir(getDependencyDir(name, dep, options)) + options.useNimFromDir(getDependencyDir(name, dep, options), v) elif not options.offline: let depsOnly = options.depsOnly options.depsOnly = false let downloadResult = downloadDependency(name, dep, options, false) - compileNim(downloadResult.downloadDir) - options.useNimFromDir(downloadResult.downloadDir) + compileNim(options, downloadResult.downloadDir, v) + options.useNimFromDir(downloadResult.downloadDir, v) let pkgInfo = installDependency(initTable[string, LockFileDep](), downloadResult, options, @[]) - options.useNimFromDir(pkgInfo.getRealDir) + options.useNimFromDir(pkgInfo.getRealDir, v) options.depsOnly = depsOnly break @@ -2429,13 +2404,13 @@ proc setNimBin*(options: var Options) = let installedPkgs = getInstalledPkgsMin(options.getPkgsDir(), options) var pkg = initPackageInfo() if findPkg(installedPkgs, nimVersion, pkg): - options.useNimFromDir(pkg.getRealDir) + options.useNimFromDir(pkg.getRealDir, pkg.basicInfo.version.toVersionRange()) else: # It still no nim found then download and install one to allow parsing of # other packages. if options.nimBin.len == 0 and not options.offline and options.prompt("No nim found. Download it now?"): for pkg in install(nimVersion, options): - options.useNimFromDir(pkg.getRealDir) + options.useNimFromDir(pkg.getRealDir, pkg.basicInfo.version.toVersionRange()) if options.nimBin.len == 0: raise nimbleError("Unable to find nim") @@ -2446,7 +2421,7 @@ proc setNimBin*(options: var Options) = pkgInfo = getPkgInfo(getCurrentDir(), options) for pkg in pkgInfo.processDevelopDependencies(options): if pkg.name.isNim: - options.useNimFromDir(pkg.getRealDir, true) + options.useNimFromDir(pkg.getRealDir, pkg.basicInfo.version.toVersionRange(), true) return options.pkgInfoCache.clear() except NimbleError: @@ -2464,11 +2439,11 @@ proc setNimBin*(options: var Options) = let installedPkgs = getInstalledPkgsMin(options.getPkgsDir(), options) var pkg = initPackageInfo() if findPkg(installedPkgs, require, pkg): - options.useNimFromDir(pkg.getRealDir) + options.useNimFromDir(pkg.getRealDir, require.ver) else: if not options.offline and options.prompt("No nim version matching $1. Download it now?" % $require.ver): for pkg in install(require, options): - options.useNimFromDir(pkg.getRealDir) + options.useNimFromDir(pkg.getRealDir, require.ver) else: let msg = "Unsatisfied dependency: " & require.name & " (" & $require.ver & ")" raise nimbleError(msg) diff --git a/src/nimblepkg/nimblesat.nim b/src/nimblepkg/nimblesat.nim index 7fa2ad8c..e655cbf3 100644 --- a/src/nimblepkg/nimblesat.nim +++ b/src/nimblepkg/nimblesat.nim @@ -105,22 +105,22 @@ proc hasVersion*(packagesVersions: Table[string, PackageVersions], name: string, return true false -proc getNimVersion*(pvs: seq[PkgTuple]): Version = - proc getVersion(ver: VersionRange): Version = - case ver.kind: - of verLater, verEarlier, verEqLater, verEqEarlier, verEq: - ver.ver - of verSpecial: - ver.spe - of verIntersect, verTilde, verCaret: - getVersion(ver.verILeft) - of verAny: - newVersion "0.0.0" +proc getNimVersion*(ver: VersionRange): Version = + case ver.kind: + of verLater, verEarlier, verEqLater, verEqEarlier, verEq: + ver.ver + of verSpecial: + ver.spe + of verIntersect, verTilde, verCaret: + getNimVersion(ver.verILeft) + of verAny: + newVersion "0.0.0" +proc getNimVersion*(pvs: seq[PkgTuple]): Version = result = newVersion("0.0.0") for pv in pvs: if pv.name == "nim": - result = getVersion(pv.ver) + result = getNimVersion(pv.ver) proc findDependencyForDep(g: DepGraph; dep: string): int {.inline.} = assert g.packageToDependency.hasKey(dep), dep & " not found" diff --git a/src/nimblepkg/nimenv.nim b/src/nimblepkg/nimenv.nim new file mode 100644 index 00000000..0cd61a13 --- /dev/null +++ b/src/nimblepkg/nimenv.nim @@ -0,0 +1,110 @@ +import std/[strscans, os, strutils, strformat] +import version, nimblesat, cli, common, options + +when defined(windows): + const + BatchFile = """ + @echo off + set PATH="$1";%PATH% + """ +else: + const + ShellFile = "export PATH=$1:$$PATH\n" + +const ActivationFile = + when defined(windows): "activate.bat" else: "activate.sh" + +proc infoAboutActivation(nimDest, nimVersion: string) = + when defined(windows): + display("Info", nimDest & "installed; activate with 'nim-" & nimVersion & "activate.bat'") + else: + display("Info", nimDest & "installed; activate with 'source nim-" & nimVersion & "activate.sh'") + +proc compileNim*(options: Options, nimDest: string, v: VersionRange) = + let keepCsources = options.useSatSolver #SAT Solver has a cache instead of a temp dir for downloads + template exec(command: string) = + let cmd = command # eval once + if os.execShellCmd(cmd) != 0: + display("Error", "Failed to execute: $1" % cmd, Error, HighPriority) + return + let nimVersion = v.getNimVersion() + let workspace = nimDest.parentDir() + if dirExists(workspace / nimDest): + if not fileExists(nimDest / ActivationFile): + display("Info", &"Directory {nimDest} already exists; remove or rename and try again") + else: + infoAboutActivation nimDest, $nimVersion + return + + var major, minor, patch: int + if not nimVersion.isSpecial: + if not scanf($nimVersion, "$i.$i.$i", major, minor, patch): + display("Error", "cannot parse version requirement", Error) + return + let csourcesVersion = + #TODO We could test special against the special versionn-x branch to get the right csources + if nimVersion.isSpecial or (major == 1 and minor >= 9) or major >= 2: + # already uses csources_v2 + "csources_v2" + elif major == 0: + "csources" # has some chance of working + else: + "csources_v1" + cd workspace: + echo "Entering CSOURCES", csourcesVersion, " exists ", dirExists(csourcesVersion) + if not dirExists(csourcesVersion): + exec "git clone https://github.com/nim-lang/" & csourcesVersion + + cd workspace / csourcesVersion: + when defined(windows): + exec "build.bat" + else: + let makeExe = findExe("make") + if makeExe.len == 0: + exec "sh build.sh" + else: + exec "make" + let nimExe0 = ".." / csourcesVersion / "bin" / "nim".addFileExt(ExeExt) + cd nimDest: + let nimExe = "bin" / "nim".addFileExt(ExeExt) + copyFileWithPermissions nimExe0, nimExe + exec nimExe & " c --noNimblePath --skipUserCfg --skipParentCfg --hints:off koch" + let kochExe = when defined(windows): "koch.exe" else: "./koch" + exec kochExe & " boot -d:release --skipUserCfg --skipParentCfg --hints:off" + exec kochExe & " tools --skipUserCfg --skipParentCfg --hints:off" + # unless --keep is used delete the csources because it takes up about 2GB and + # is not necessary afterwards: + if not keepCsources: + removeDir workspace / csourcesVersion / "c_code" + let pathEntry = workspace / nimDest / "bin" + #remove nimble so it doesnt interfer with the current one: + removeFile "bin" / "nimble".addFileExt(ExeExt) + when defined(windows): + writeFile "activate.bat", BatchFile % pathEntry.replace('/', '\\') + else: + writeFile "activate.sh", ShellFile % pathEntry + infoAboutActivation nimDest, $nimVersion + + +proc useNimFromDir*(options: var Options, realDir: string, v: VersionRange, tryCompiling = false) = + const binaryName = when defined(windows): "nim.exe" else: "nim" + + let + nim = realDir / "bin" / binaryName + fileExists = fileExists(options.nimBin) + + if not fileExists(nim): + if tryCompiling and options.prompt("Develop version of nim was found but it is not compiled. Compile it now?"): + compileNim(options, realDir, v) + else: + raise nimbleError("Trying to use nim from $1 " % realDir, + "If you are using develop mode nim make sure to compile it.") + + options.nimBin = nim + let separator = when defined(windows): ";" else: ":" + + putEnv("PATH", realDir / "bin" & separator & getEnv("PATH")) + if fileExists: + display("Info:", "switching to $1 for compilation" % options.nim, priority = HighPriority) + else: + display("Info:", "using $1 for compilation" % options.nim, priority = HighPriority) diff --git a/src/nimblepkg/options.nim b/src/nimblepkg/options.nim index c4bf80b0..be410181 100644 --- a/src/nimblepkg/options.nim +++ b/src/nimblepkg/options.nim @@ -390,6 +390,11 @@ proc getPkgsLinksDir*(options: Options): string = proc getBinDir*(options: Options): string = options.getNimbleDir() / nimbleBinariesDirName +proc setPackageCache(options: var Options, baseDir: string) = + if options.useSatSolver: + options.pkgCachePath = baseDir / "pkgcache" + display("Info:", "Package cache path " & options.pkgCachePath, priority = HighPriority) + proc setNimbleDir*(options: var Options) = var nimbleDir = options.config.nimbleDir @@ -407,6 +412,7 @@ proc setNimbleDir*(options: var Options) = # --nimbleDir: takes priority... nimbleDir = options.nimbleDir propagate = true + setPackageCache(options, nimbleDir) else: # ...followed by the environment variable. let env = getEnv("NIMBLE_DIR") @@ -414,6 +420,7 @@ proc setNimbleDir*(options: var Options) = display("Info:", "Using the environment variable: NIMBLE_DIR='" & env & "'", Success, priority = HighPriority) nimbleDir = env + setPackageCache(options, nimbleDir) else: # ...followed by project local deps mode if dirExists(nimbledeps) or (options.localdeps and not options.developLocaldeps): @@ -422,6 +429,7 @@ proc setNimbleDir*(options: var Options) = nimbleDir = nimbledeps options.localdeps = true propagate = true + setPackageCache(options, options.config.nimbleDir) #We want to use the nimbleDir from the config so it can be shared options.nimbleDir = expandTilde(nimbleDir).absolutePath() if propagate: @@ -438,8 +446,6 @@ proc setNimbleDir*(options: var Options) = let pkgsDir = options.getPkgsDir() if not dirExists(pkgsDir): createDir(pkgsDir) - if options.useSatSolver: - options.pkgCachePath = options.getNimbleDir() / "pkgcache" proc parseCommand*(key: string, result: var Options) = result.action = Action(typ: parseActionType(key)) diff --git a/tests/nimnimble/nim1.6.20/nim1620.nimble b/tests/nimnimble/nim1.6.20/nim1620.nimble new file mode 100644 index 00000000..34993d94 --- /dev/null +++ b/tests/nimnimble/nim1.6.20/nim1620.nimble @@ -0,0 +1,12 @@ +# Package + +version = "0.1.0" +author = "jmgomez" +description = "A new awesome nimble package" +license = "MIT" +srcDir = "src" + + +# Dependencies + +requires "nim == 1.6.20" diff --git a/tests/nimnimble/nim1.6.20/src/nim1620.nim b/tests/nimnimble/nim1.6.20/src/nim1620.nim new file mode 100644 index 00000000..b7a24803 --- /dev/null +++ b/tests/nimnimble/nim1.6.20/src/nim1620.nim @@ -0,0 +1,7 @@ +# This is just an example to get you started. A typical library package +# exports the main API in this file. Note that you cannot rename this file +# but you can remove it if you wish. + +proc add*(x, y: int): int = + ## Adds two numbers together. + return x + y diff --git a/tests/nimnimble/nim1.6.20/src/nim1620/submodule.nim b/tests/nimnimble/nim1.6.20/src/nim1620/submodule.nim new file mode 100644 index 00000000..28500469 --- /dev/null +++ b/tests/nimnimble/nim1.6.20/src/nim1620/submodule.nim @@ -0,0 +1,12 @@ +# This is just an example to get you started. Users of your library will +# import this file by writing ``import nim1620/submodule``. Feel free to rename or +# remove this file altogether. You may create additional modules alongside +# this file as required. + +type + Submodule* = object + name*: string + +proc initSubmodule*(): Submodule = + ## Initialises a new ``Submodule`` object. + Submodule(name: "Anonymous") diff --git a/tests/nimnimble/nim1.6.20/tests/test1.nim b/tests/nimnimble/nim1.6.20/tests/test1.nim new file mode 100644 index 00000000..543e3869 --- /dev/null +++ b/tests/nimnimble/nim1.6.20/tests/test1.nim @@ -0,0 +1,12 @@ +# This is just an example to get you started. You may wish to put all of your +# tests into a single file, or separate them into multiple `test1`, `test2` +# etc. files (better names are recommended, just make sure the name starts with +# the letter 't'). +# +# To run these tests, simply execute `nimble test`. + +import unittest + +import nim1620 +test "can add": + check add(5, 5) == 10 diff --git a/tests/nimnimble/nim2.0.4/nim204.nimble b/tests/nimnimble/nim2.0.4/nim204.nimble new file mode 100644 index 00000000..32bebc1c --- /dev/null +++ b/tests/nimnimble/nim2.0.4/nim204.nimble @@ -0,0 +1,12 @@ +# Package + +version = "0.1.0" +author = "jmgomez" +description = "A new awesome nimble package" +license = "MIT" +srcDir = "src" + + +# Dependencies + +requires "nim == 2.0.4" diff --git a/tests/nimnimble/nim2.0.4/src/nim204.nim b/tests/nimnimble/nim2.0.4/src/nim204.nim new file mode 100644 index 00000000..b7a24803 --- /dev/null +++ b/tests/nimnimble/nim2.0.4/src/nim204.nim @@ -0,0 +1,7 @@ +# This is just an example to get you started. A typical library package +# exports the main API in this file. Note that you cannot rename this file +# but you can remove it if you wish. + +proc add*(x, y: int): int = + ## Adds two numbers together. + return x + y diff --git a/tests/nimnimble/nim2.0.4/src/nim204/submodule.nim b/tests/nimnimble/nim2.0.4/src/nim204/submodule.nim new file mode 100644 index 00000000..6c764a17 --- /dev/null +++ b/tests/nimnimble/nim2.0.4/src/nim204/submodule.nim @@ -0,0 +1,12 @@ +# This is just an example to get you started. Users of your library will +# import this file by writing ``import nim204/submodule``. Feel free to rename or +# remove this file altogether. You may create additional modules alongside +# this file as required. + +type + Submodule* = object + name*: string + +proc initSubmodule*(): Submodule = + ## Initialises a new ``Submodule`` object. + Submodule(name: "Anonymous") diff --git a/tests/nimnimble/nim2.0.4/tests/test1.nim b/tests/nimnimble/nim2.0.4/tests/test1.nim new file mode 100644 index 00000000..c36a72c7 --- /dev/null +++ b/tests/nimnimble/nim2.0.4/tests/test1.nim @@ -0,0 +1,12 @@ +# This is just an example to get you started. You may wish to put all of your +# tests into a single file, or separate them into multiple `test1`, `test2` +# etc. files (better names are recommended, just make sure the name starts with +# the letter 't'). +# +# To run these tests, simply execute `nimble test`. + +import unittest + +import nim204 +test "can add": + check add(5, 5) == 10 diff --git a/tests/nimnimble/nimdevel/nimdevel.nimble b/tests/nimnimble/nimdevel/nimdevel.nimble new file mode 100644 index 00000000..93bf2fa8 --- /dev/null +++ b/tests/nimnimble/nimdevel/nimdevel.nimble @@ -0,0 +1,12 @@ +# Package + +version = "0.1.0" +author = "jmgomez" +description = "A new awesome nimble package" +license = "MIT" +srcDir = "src" + + +# Dependencies + +requires "nim#devel" diff --git a/tests/nimnimble/nimdevel/src/nimdevel.nim b/tests/nimnimble/nimdevel/src/nimdevel.nim new file mode 100644 index 00000000..b7a24803 --- /dev/null +++ b/tests/nimnimble/nimdevel/src/nimdevel.nim @@ -0,0 +1,7 @@ +# This is just an example to get you started. A typical library package +# exports the main API in this file. Note that you cannot rename this file +# but you can remove it if you wish. + +proc add*(x, y: int): int = + ## Adds two numbers together. + return x + y diff --git a/tests/nimnimble/nimdevel/src/nimdevel/submodule.nim b/tests/nimnimble/nimdevel/src/nimdevel/submodule.nim new file mode 100644 index 00000000..721b05c4 --- /dev/null +++ b/tests/nimnimble/nimdevel/src/nimdevel/submodule.nim @@ -0,0 +1,12 @@ +# This is just an example to get you started. Users of your library will +# import this file by writing ``import nimdevel/submodule``. Feel free to rename or +# remove this file altogether. You may create additional modules alongside +# this file as required. + +type + Submodule* = object + name*: string + +proc initSubmodule*(): Submodule = + ## Initialises a new ``Submodule`` object. + Submodule(name: "Anonymous") diff --git a/tests/nimnimble/nimdevel/tests/test1.nim b/tests/nimnimble/nimdevel/tests/test1.nim new file mode 100644 index 00000000..c006d116 --- /dev/null +++ b/tests/nimnimble/nimdevel/tests/test1.nim @@ -0,0 +1,12 @@ +# This is just an example to get you started. You may wish to put all of your +# tests into a single file, or separate them into multiple `test1`, `test2` +# etc. files (better names are recommended, just make sure the name starts with +# the letter 't'). +# +# To run these tests, simply execute `nimble test`. + +import unittest + +import nimdevel +test "can add": + check add(5, 5) == 10 diff --git a/tests/tester.nim b/tests/tester.nim index 6ca975cb..7ac166f4 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -29,6 +29,7 @@ import ttwobinaryversions import tuninstall import ttaskdeps import tsat +import tniminstall # nonim tests are very slow and (often) break the CI. # import tnonim diff --git a/tests/tniminstall.nim b/tests/tniminstall.nim new file mode 100644 index 00000000..eb89bf5c --- /dev/null +++ b/tests/tniminstall.nim @@ -0,0 +1,32 @@ + +{.used.} + +import unittest, os, strutils, sequtils, strscans +import testscommon +from nimblepkg/common import cd + +proc isNimPkgVer(folder: string, ver: string): bool = + let name = folder.split("-") + result = name.len == 3 and name[1].contains(ver) + echo "Checking ", folder, " for ", ver, " result: ", result + if ver == "devel": + #We know devel is bigger than 2.1 and it should be an odd number (notice what we test here is actually the #) + var major, minor, patch: int + if scanf(name[1], "$i.$i.$i", major, minor, patch): + return major >= 2 and minor >= 1 and minor mod 2 == 1 + else: return false + + + + +suite "Nim install": + test "Should be able to install different Nim versions": + cd "nimnimble": + for nimVerDir in ["nim1.6.20", "nim2.0.4", "nimdevel"]: + cd nimVerDir: + let nimVer = nimVerDir.replace("nim", "") + echo "Checking version ", nimVer + let (_, exitCode) = execNimble("install", "-l") + let pkgPath = getCurrentDir() / "nimbledeps" / "pkgs2" + check exitCode == QuitSuccess + check walkDir(pkgPath).toSeq.anyIt(it[1].isNimPkgVer(nimVer))