Skip to content

Commit fa09e48

Browse files
authored
Improves nim installation by using csources (same as atlas) (#1233)
* draft: improves nim installation by using csources (same as atlas) Notice when SAT is enabled, csources is stored in the cache. Missing: -- Proper reporting -- Handle special versions (assume csources_2?). We could have special cases for #version-x - Refactor to another file (nimble.nim is crazy big already) * progress * refactor: extract file nimenv * Fixes an issue where the packageCache wasnt being shared in local mode * [Green]Should be able to install different Nim versions * fix warnings * missing display * fix typo * Remove nimble from nim compilation Fixes #1175
1 parent 701136c commit fa09e48

File tree

18 files changed

+308
-55
lines changed

18 files changed

+308
-55
lines changed

src/nimble.nim

Lines changed: 16 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import nimblepkg/packageinfotypes, nimblepkg/packageinfo, nimblepkg/version,
2121
nimblepkg/nimscriptwrapper, nimblepkg/developfile, nimblepkg/paths,
2222
nimblepkg/nimbledatafile, nimblepkg/packagemetadatafile,
2323
nimblepkg/displaymessages, nimblepkg/sha1hashes, nimblepkg/syncfile,
24-
nimblepkg/deps, nimblepkg/nimblesat, nimblepkg/forge_aliases
24+
nimblepkg/deps, nimblepkg/nimblesat, nimblepkg/forge_aliases, nimblepkg/nimenv
2525

2626
const
2727
nimblePathsFileName* = "nimble.paths"
@@ -754,35 +754,6 @@ proc processLockedDependencies(pkgInfo: PackageInfo, options: Options):
754754

755755
return res.toHashSet
756756

757-
proc compileNim(realDir: string) =
758-
let command = when defined(windows): "build_all.bat" else: "./build_all.sh"
759-
cd realDir:
760-
display("Info:", "compiling nim in $1" % realDir, priority = HighPriority)
761-
tryDoCmdEx(command)
762-
763-
proc useNimFromDir(options: var Options, realDir: string, tryCompiling = false) =
764-
const binaryName = when defined(windows): "nim.exe" else: "nim"
765-
766-
let
767-
nim = realDir / "bin" / binaryName
768-
fileExists = fileExists(options.nimBin)
769-
770-
if not fileExists(nim):
771-
if tryCompiling and options.prompt("Develop version of nim was found but it is not compiled. Compile it now?"):
772-
compileNim(realDir)
773-
else:
774-
raise nimbleError("Trying to use nim from $1 " % realDir,
775-
"If you are using develop mode nim make sure to compile it.")
776-
777-
options.nimBin = nim
778-
let separator = when defined(windows): ";" else: ":"
779-
780-
putEnv("PATH", realDir / "bin" & separator & getEnv("PATH"))
781-
if fileExists:
782-
display("Info:", "switching to $1 for compilation" % options.nim, priority = HighPriority)
783-
else:
784-
display("Info:", "using $1 for compilation" % options.nim, priority = HighPriority)
785-
786757
proc install(packages: seq[PkgTuple], options: Options,
787758
doPrompt, first, fromLockFile: bool,
788759
preferredPackages: seq[PackageInfo] = @[]): PackageDependenciesInfo =
@@ -817,6 +788,9 @@ proc install(packages: seq[PkgTuple], options: Options,
817788
var downloadPath = ""
818789
if options.useSatSolver and subdir == "": #Ignore the cache if subdir is set
819790
downloadPath = getCacheDownloadDir(url, pv.ver, options)
791+
# if pv.name.isNim:
792+
# downloadPath = "/Volumes/Store/Projects/nim/nimble/temptest/nimtest"
793+
820794

821795
let (downloadDir, downloadVersion, vcsRevision) =
822796
if not isAlias:
@@ -831,8 +805,8 @@ proc install(packages: seq[PkgTuple], options: Options,
831805
try:
832806
var opt = options
833807
if pv.name.isNim:
834-
compileNim(downloadDir)
835-
opt.useNimFromDir(downloadDir, true)
808+
compileNim(opt, downloadDir, pv.ver)
809+
opt.useNimFromDir(downloadDir, pv.ver, true)
836810
result = installFromDir(downloadDir, pv.ver, opt, url,
837811
first, fromLockFile, vcsRevision,
838812
preferredPackages = preferredPackages)
@@ -2403,16 +2377,17 @@ proc setNimBin*(options: var Options) =
24032377
if lockFile.fileExists and not options.disableLockFile and not options.useSystemNim:
24042378
for name, dep in lockFile.getLockedDependencies.lockedDepsFor(options):
24052379
if name.isNim:
2380+
let v = dep.version.toVersionRange()
24062381
if isInstalled(name, dep, options):
2407-
options.useNimFromDir(getDependencyDir(name, dep, options))
2382+
options.useNimFromDir(getDependencyDir(name, dep, options), v)
24082383
elif not options.offline:
24092384
let depsOnly = options.depsOnly
24102385
options.depsOnly = false
24112386
let downloadResult = downloadDependency(name, dep, options, false)
2412-
compileNim(downloadResult.downloadDir)
2413-
options.useNimFromDir(downloadResult.downloadDir)
2387+
compileNim(options, downloadResult.downloadDir, v)
2388+
options.useNimFromDir(downloadResult.downloadDir, v)
24142389
let pkgInfo = installDependency(initTable[string, LockFileDep](), downloadResult, options, @[])
2415-
options.useNimFromDir(pkgInfo.getRealDir)
2390+
options.useNimFromDir(pkgInfo.getRealDir, v)
24162391
options.depsOnly = depsOnly
24172392
break
24182393
@@ -2429,13 +2404,13 @@ proc setNimBin*(options: var Options) =
24292404
let installedPkgs = getInstalledPkgsMin(options.getPkgsDir(), options)
24302405
var pkg = initPackageInfo()
24312406
if findPkg(installedPkgs, nimVersion, pkg):
2432-
options.useNimFromDir(pkg.getRealDir)
2407+
options.useNimFromDir(pkg.getRealDir, pkg.basicInfo.version.toVersionRange())
24332408
else:
24342409
# It still no nim found then download and install one to allow parsing of
24352410
# other packages.
24362411
if options.nimBin.len == 0 and not options.offline and options.prompt("No nim found. Download it now?"):
24372412
for pkg in install(nimVersion, options):
2438-
options.useNimFromDir(pkg.getRealDir)
2413+
options.useNimFromDir(pkg.getRealDir, pkg.basicInfo.version.toVersionRange())
24392414
24402415
if options.nimBin.len == 0:
24412416
raise nimbleError("Unable to find nim")
@@ -2446,7 +2421,7 @@ proc setNimBin*(options: var Options) =
24462421
pkgInfo = getPkgInfo(getCurrentDir(), options)
24472422
for pkg in pkgInfo.processDevelopDependencies(options):
24482423
if pkg.name.isNim:
2449-
options.useNimFromDir(pkg.getRealDir, true)
2424+
options.useNimFromDir(pkg.getRealDir, pkg.basicInfo.version.toVersionRange(), true)
24502425
return
24512426
options.pkgInfoCache.clear()
24522427
except NimbleError:
@@ -2464,11 +2439,11 @@ proc setNimBin*(options: var Options) =
24642439
let installedPkgs = getInstalledPkgsMin(options.getPkgsDir(), options)
24652440
var pkg = initPackageInfo()
24662441
if findPkg(installedPkgs, require, pkg):
2467-
options.useNimFromDir(pkg.getRealDir)
2442+
options.useNimFromDir(pkg.getRealDir, require.ver)
24682443
else:
24692444
if not options.offline and options.prompt("No nim version matching $1. Download it now?" % $require.ver):
24702445
for pkg in install(require, options):
2471-
options.useNimFromDir(pkg.getRealDir)
2446+
options.useNimFromDir(pkg.getRealDir, require.ver)
24722447
else:
24732448
let msg = "Unsatisfied dependency: " & require.name & " (" & $require.ver & ")"
24742449
raise nimbleError(msg)

src/nimblepkg/nimblesat.nim

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -105,22 +105,22 @@ proc hasVersion*(packagesVersions: Table[string, PackageVersions], name: string,
105105
return true
106106
false
107107

108-
proc getNimVersion*(pvs: seq[PkgTuple]): Version =
109-
proc getVersion(ver: VersionRange): Version =
110-
case ver.kind:
111-
of verLater, verEarlier, verEqLater, verEqEarlier, verEq:
112-
ver.ver
113-
of verSpecial:
114-
ver.spe
115-
of verIntersect, verTilde, verCaret:
116-
getVersion(ver.verILeft)
117-
of verAny:
118-
newVersion "0.0.0"
108+
proc getNimVersion*(ver: VersionRange): Version =
109+
case ver.kind:
110+
of verLater, verEarlier, verEqLater, verEqEarlier, verEq:
111+
ver.ver
112+
of verSpecial:
113+
ver.spe
114+
of verIntersect, verTilde, verCaret:
115+
getNimVersion(ver.verILeft)
116+
of verAny:
117+
newVersion "0.0.0"
119118

119+
proc getNimVersion*(pvs: seq[PkgTuple]): Version =
120120
result = newVersion("0.0.0")
121121
for pv in pvs:
122122
if pv.name == "nim":
123-
result = getVersion(pv.ver)
123+
result = getNimVersion(pv.ver)
124124

125125
proc findDependencyForDep(g: DepGraph; dep: string): int {.inline.} =
126126
assert g.packageToDependency.hasKey(dep), dep & " not found"

src/nimblepkg/nimenv.nim

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
import std/[strscans, os, strutils, strformat]
2+
import version, nimblesat, cli, common, options
3+
4+
when defined(windows):
5+
const
6+
BatchFile = """
7+
@echo off
8+
set PATH="$1";%PATH%
9+
"""
10+
else:
11+
const
12+
ShellFile = "export PATH=$1:$$PATH\n"
13+
14+
const ActivationFile =
15+
when defined(windows): "activate.bat" else: "activate.sh"
16+
17+
proc infoAboutActivation(nimDest, nimVersion: string) =
18+
when defined(windows):
19+
display("Info", nimDest & "installed; activate with 'nim-" & nimVersion & "activate.bat'")
20+
else:
21+
display("Info", nimDest & "installed; activate with 'source nim-" & nimVersion & "activate.sh'")
22+
23+
proc compileNim*(options: Options, nimDest: string, v: VersionRange) =
24+
let keepCsources = options.useSatSolver #SAT Solver has a cache instead of a temp dir for downloads
25+
template exec(command: string) =
26+
let cmd = command # eval once
27+
if os.execShellCmd(cmd) != 0:
28+
display("Error", "Failed to execute: $1" % cmd, Error, HighPriority)
29+
return
30+
let nimVersion = v.getNimVersion()
31+
let workspace = nimDest.parentDir()
32+
if dirExists(workspace / nimDest):
33+
if not fileExists(nimDest / ActivationFile):
34+
display("Info", &"Directory {nimDest} already exists; remove or rename and try again")
35+
else:
36+
infoAboutActivation nimDest, $nimVersion
37+
return
38+
39+
var major, minor, patch: int
40+
if not nimVersion.isSpecial:
41+
if not scanf($nimVersion, "$i.$i.$i", major, minor, patch):
42+
display("Error", "cannot parse version requirement", Error)
43+
return
44+
let csourcesVersion =
45+
#TODO We could test special against the special versionn-x branch to get the right csources
46+
if nimVersion.isSpecial or (major == 1 and minor >= 9) or major >= 2:
47+
# already uses csources_v2
48+
"csources_v2"
49+
elif major == 0:
50+
"csources" # has some chance of working
51+
else:
52+
"csources_v1"
53+
cd workspace:
54+
echo "Entering CSOURCES", csourcesVersion, " exists ", dirExists(csourcesVersion)
55+
if not dirExists(csourcesVersion):
56+
exec "git clone https://github.com/nim-lang/" & csourcesVersion
57+
58+
cd workspace / csourcesVersion:
59+
when defined(windows):
60+
exec "build.bat"
61+
else:
62+
let makeExe = findExe("make")
63+
if makeExe.len == 0:
64+
exec "sh build.sh"
65+
else:
66+
exec "make"
67+
let nimExe0 = ".." / csourcesVersion / "bin" / "nim".addFileExt(ExeExt)
68+
cd nimDest:
69+
let nimExe = "bin" / "nim".addFileExt(ExeExt)
70+
copyFileWithPermissions nimExe0, nimExe
71+
exec nimExe & " c --noNimblePath --skipUserCfg --skipParentCfg --hints:off koch"
72+
let kochExe = when defined(windows): "koch.exe" else: "./koch"
73+
exec kochExe & " boot -d:release --skipUserCfg --skipParentCfg --hints:off"
74+
exec kochExe & " tools --skipUserCfg --skipParentCfg --hints:off"
75+
# unless --keep is used delete the csources because it takes up about 2GB and
76+
# is not necessary afterwards:
77+
if not keepCsources:
78+
removeDir workspace / csourcesVersion / "c_code"
79+
let pathEntry = workspace / nimDest / "bin"
80+
#remove nimble so it doesnt interfer with the current one:
81+
removeFile "bin" / "nimble".addFileExt(ExeExt)
82+
when defined(windows):
83+
writeFile "activate.bat", BatchFile % pathEntry.replace('/', '\\')
84+
else:
85+
writeFile "activate.sh", ShellFile % pathEntry
86+
infoAboutActivation nimDest, $nimVersion
87+
88+
89+
proc useNimFromDir*(options: var Options, realDir: string, v: VersionRange, tryCompiling = false) =
90+
const binaryName = when defined(windows): "nim.exe" else: "nim"
91+
92+
let
93+
nim = realDir / "bin" / binaryName
94+
fileExists = fileExists(options.nimBin)
95+
96+
if not fileExists(nim):
97+
if tryCompiling and options.prompt("Develop version of nim was found but it is not compiled. Compile it now?"):
98+
compileNim(options, realDir, v)
99+
else:
100+
raise nimbleError("Trying to use nim from $1 " % realDir,
101+
"If you are using develop mode nim make sure to compile it.")
102+
103+
options.nimBin = nim
104+
let separator = when defined(windows): ";" else: ":"
105+
106+
putEnv("PATH", realDir / "bin" & separator & getEnv("PATH"))
107+
if fileExists:
108+
display("Info:", "switching to $1 for compilation" % options.nim, priority = HighPriority)
109+
else:
110+
display("Info:", "using $1 for compilation" % options.nim, priority = HighPriority)

src/nimblepkg/options.nim

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,11 @@ proc getPkgsLinksDir*(options: Options): string =
390390
proc getBinDir*(options: Options): string =
391391
options.getNimbleDir() / nimbleBinariesDirName
392392

393+
proc setPackageCache(options: var Options, baseDir: string) =
394+
if options.useSatSolver:
395+
options.pkgCachePath = baseDir / "pkgcache"
396+
display("Info:", "Package cache path " & options.pkgCachePath, priority = HighPriority)
397+
393398
proc setNimbleDir*(options: var Options) =
394399
var
395400
nimbleDir = options.config.nimbleDir
@@ -407,13 +412,15 @@ proc setNimbleDir*(options: var Options) =
407412
# --nimbleDir:<dir> takes priority...
408413
nimbleDir = options.nimbleDir
409414
propagate = true
415+
setPackageCache(options, nimbleDir)
410416
else:
411417
# ...followed by the environment variable.
412418
let env = getEnv("NIMBLE_DIR")
413419
if env.len != 0:
414420
display("Info:", "Using the environment variable: NIMBLE_DIR='" &
415421
env & "'", Success, priority = HighPriority)
416422
nimbleDir = env
423+
setPackageCache(options, nimbleDir)
417424
else:
418425
# ...followed by project local deps mode
419426
if dirExists(nimbledeps) or (options.localdeps and not options.developLocaldeps):
@@ -422,6 +429,7 @@ proc setNimbleDir*(options: var Options) =
422429
nimbleDir = nimbledeps
423430
options.localdeps = true
424431
propagate = true
432+
setPackageCache(options, options.config.nimbleDir) #We want to use the nimbleDir from the config so it can be shared
425433

426434
options.nimbleDir = expandTilde(nimbleDir).absolutePath()
427435
if propagate:
@@ -438,8 +446,6 @@ proc setNimbleDir*(options: var Options) =
438446
let pkgsDir = options.getPkgsDir()
439447
if not dirExists(pkgsDir):
440448
createDir(pkgsDir)
441-
if options.useSatSolver:
442-
options.pkgCachePath = options.getNimbleDir() / "pkgcache"
443449

444450
proc parseCommand*(key: string, result: var Options) =
445451
result.action = Action(typ: parseActionType(key))
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Package
2+
3+
version = "0.1.0"
4+
author = "jmgomez"
5+
description = "A new awesome nimble package"
6+
license = "MIT"
7+
srcDir = "src"
8+
9+
10+
# Dependencies
11+
12+
requires "nim == 1.6.20"
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# This is just an example to get you started. A typical library package
2+
# exports the main API in this file. Note that you cannot rename this file
3+
# but you can remove it if you wish.
4+
5+
proc add*(x, y: int): int =
6+
## Adds two numbers together.
7+
return x + y
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# This is just an example to get you started. Users of your library will
2+
# import this file by writing ``import nim1620/submodule``. Feel free to rename or
3+
# remove this file altogether. You may create additional modules alongside
4+
# this file as required.
5+
6+
type
7+
Submodule* = object
8+
name*: string
9+
10+
proc initSubmodule*(): Submodule =
11+
## Initialises a new ``Submodule`` object.
12+
Submodule(name: "Anonymous")
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# This is just an example to get you started. You may wish to put all of your
2+
# tests into a single file, or separate them into multiple `test1`, `test2`
3+
# etc. files (better names are recommended, just make sure the name starts with
4+
# the letter 't').
5+
#
6+
# To run these tests, simply execute `nimble test`.
7+
8+
import unittest
9+
10+
import nim1620
11+
test "can add":
12+
check add(5, 5) == 10
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Package
2+
3+
version = "0.1.0"
4+
author = "jmgomez"
5+
description = "A new awesome nimble package"
6+
license = "MIT"
7+
srcDir = "src"
8+
9+
10+
# Dependencies
11+
12+
requires "nim == 2.0.4"
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# This is just an example to get you started. A typical library package
2+
# exports the main API in this file. Note that you cannot rename this file
3+
# but you can remove it if you wish.
4+
5+
proc add*(x, y: int): int =
6+
## Adds two numbers together.
7+
return x + y

0 commit comments

Comments
 (0)