Skip to content

Commit

Permalink
when in solver:sat sets the right nim version (#1267)
Browse files Browse the repository at this point in the history
* when in `solver:sat` sets the right `nim` version

* adds missing file

* a more elegant way to retrieve the nim right version

Note we may want to have the solvedPackages inside Options but a refactor would be needed for this and first we should remove the support for the `legacy` solver. Everything is build around it ( i.e. the `legacy` solver doesnt have enough information to split the download stage from the build one)

* improvement

* fixes ci

* indent

* remove unused imports

* remove comment
  • Loading branch information
jmgomez authored Oct 3, 2024
1 parent 1114068 commit 05f2014
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 48 deletions.
43 changes: 21 additions & 22 deletions src/nimble.nim
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@ proc addReverseDeps(solvedPkgs: seq[SolvedPackage], allPkgsInfo: seq[PackageInfo
reverseDep.get.isLink = true
addRevDep(options.nimbleData, solvedPkg.get.basicInfo, reverseDep.get)

var satProccesedPackages: HashSet[PackageInfo]
proc processFreeDependenciesSAT(rootPkgInfo: PackageInfo, options: Options): HashSet[PackageInfo] =
if satProccesedPackages.len > 0:
return satProccesedPackages
Expand Down Expand Up @@ -139,7 +138,7 @@ proc processFreeDependenciesSAT(rootPkgInfo: PackageInfo, options: Options): Has

result = deleteStaleDependencies(result.toSeq, rootPkgInfo, options).toHashSet
satProccesedPackages = result

if not solved:
display("Error", output, Error, priority = HighPriority)
raise nimbleError("Unsatisfiable dependencies")
Expand Down Expand Up @@ -1142,17 +1141,16 @@ proc getNimDir(options: Options): string =
var nimPkgTupl = projectPkg.requires.filterIt(it.name == "nim")
if nimPkgTupl.len > 0:
let reqNimVersion = nimPkgTupl[0].ver
let nimBinVersion = options.nimBin.getNimVersionFromBin()
if nimBinVersion.isSome and nimBinVersion.get.withinRange(reqNimVersion):
return options.nimBin.parentDir
if options.nimBin.isSome and options.nimBin.get.version.withinRange(reqNimVersion):
return options.nimBin.get.path.parentDir
var nimPkgInfo =
getInstalledPkgsMin(options.getPkgsDir(), options)
.filterIt(it.basicInfo.name == "nim" and it.withinRange(reqNimVersion))
nimPkgInfo.sort(proc (a, b: PackageInfo): int = cmp(a.basicInfo.version, b.basicInfo.version), Descending)
if nimPkgInfo.len > 0:
let nimBin = nimPkgInfo[0].getNimBin(options)
return nimBin.parentDir
options.nimBin.parentDir
return options.nimBin.get(NimBin()).path.parentDir

proc getEntryPoints(pkgInfo: PackageInfo, options: Options): seq[string] =
## Returns the entry points for a package.
Expand Down Expand Up @@ -2204,8 +2202,8 @@ proc getAlteredPath(options: Options): string =
let folder = fullInfo.getOutputDir(bin).parentDir.quoteShell
paths.add folder
paths.reverse

result = fmt "{options.nimBin.parentDir}{separator}{paths.join(separator)}{separator}{getEnv(\"PATH\")}"
let parentDir = options.nimBin.get.path.parentDir
result = fmt "{parentDir}{separator}{paths.join(separator)}{separator}{getEnv(\"PATH\")}"

proc shellenv(options: var Options) =
setVerbosity(SilentPriority)
Expand Down Expand Up @@ -2369,18 +2367,17 @@ proc doAction(options: var Options) =

proc setNimBin*(options: var Options) =
# Find nim binary and set into options
if options.nimBin.len != 0:
if options.nimBin.isSome:
let nimBin = options.nimBin.get.path
# --nim:<path> takes priority...
if options.nimBin.splitPath().head.len == 0:
if nimBin.splitPath().head.len == 0:
# Just filename, search in PATH - nim_temp shortcut
let pnim = findExe(options.nimBin)
if pnim.len != 0: options.nimBin = pnim
elif not options.nimBin.isAbsolute():
# Relative path
options.nimBin = expandTilde(options.nimBin).absolutePath()
let pnim = findExe(nimBin)
if pnim.len != 0:
options.nimBin = some makeNimBin(pnim)

if not fileExists(options.nimBin):
raise nimbleError("Unable to find `$1`" % options.nimBin)
if not fileExists(options.nimBin.get.path):
raise nimbleError("Unable to find `$1`" % options.nimBin.get.path)

# when nim is forced via command like don't try to be smart and just return
# it.
Expand All @@ -2407,13 +2404,15 @@ proc setNimBin*(options: var Options) =
break

# Search PATH to find nim to continue with
if options.nimBin.len == 0:
options.nimBin = findExe("nim")
if options.nimBin.isNone or options.useSystemNim:
options.nimBin = some makeNimBin(findExe("nim"))
if options.useSystemNim:
return

proc install(package: PkgTuple, options: Options): HashSet[PackageInfo] =
result = install(@[package], options, doPrompt = false, first = false, fromLockFile = false).deps

if options.nimBin.len == 0:
if options.nimBin.isNone:
# Search installed packages to continue with
let nimVersion = ("nim", VersionRange(kind: verAny))
let installedPkgs = getInstalledPkgsMin(options.getPkgsDir(), options)
Expand All @@ -2423,11 +2422,11 @@ proc setNimBin*(options: var Options) =
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?"):
if options.nimBin.isNone and not options.offline and options.prompt("No nim found. Download it now?"):
for pkg in install(nimVersion, options):
options.useNimFromDir(pkg.getRealDir, pkg.basicInfo.version.toVersionRange())

if options.nimBin.len == 0:
if options.nimBin.isNone:
raise nimbleError("Unable to find nim")

# try to switch to the version that is in the develop file
Expand Down
2 changes: 1 addition & 1 deletion src/nimblepkg/nimblesat.nim
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ proc findDependencyForDep(g: DepGraph; dep: string): int {.inline.} =
result = g.packageToDependency.getOrDefault(dep)

proc createRequirements(pkg: PackageMinimalInfo): Requirements =
result.deps = pkg.requires.filterIt(not it.isNim())
result.deps = pkg.requires
result.version = pkg.version
result.nimVersion = pkg.requires.getNimVersion()

Expand Down
16 changes: 3 additions & 13 deletions src/nimblepkg/nimenv.nim
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import std/[strscans, os, osproc, strutils, strformat, options]
import std/[strscans, os, strutils, strformat, options]
import version, nimblesat, cli, common, options

when defined(windows):
Expand Down Expand Up @@ -105,7 +105,7 @@ proc useNimFromDir*(options: var Options, realDir: string, v: VersionRange, tryC

let
nim = realDir / "bin" / binaryName
fileExists = fileExists(options.nimBin)
fileExists = fileExists(options.nimBin.get(NimBin()).path)

if not fileExists(nim):
if tryCompiling and options.prompt("Develop version of nim was found but it is not compiled. Compile it now?"):
Expand All @@ -114,21 +114,11 @@ proc useNimFromDir*(options: var Options, realDir: string, v: VersionRange, tryC
raise nimbleError("Trying to use nim from $1 " % realDir,
"If you are using develop mode nim make sure to compile it.")

options.nimBin = nim
options.nimBin = some makeNimBin(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 getNimVersionFromBin*(nimBin: string): Option[Version] =
let cmd = nimBin & " --version"
if nimBin.fileExists:
let info = execProcess(cmd)
var major, minor, patch: int
for line in info.splitLines:
if scanf(line, "Nim Compiler Version $i.$i.$i", major, minor, patch):
let ver = $major & "." & $minor & "." & $patch
return some newVersion(ver)
61 changes: 53 additions & 8 deletions src/nimblepkg/options.nim
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Copyright (C) Dominik Picheta. All rights reserved.
# BSD License. Look at license.txt for more info.

import json, strutils, os, parseopt, uri, tables, terminal
import json, strutils, os, parseopt, uri, tables, terminal, osproc, strscans, strformat, sets
import sequtils, sugar
import std/options as std_opt
from httpclient import Proxy, newProxy
Expand All @@ -13,6 +13,9 @@ const
defaultLockFileName* = "nimble.lock"

type
NimBin* = object
path*: string
version*: Version
DumpMode* = enum kdumpIni, kdumpJson
Options* = object
forcePrompts*: ForcePrompt
Expand Down Expand Up @@ -41,7 +44,7 @@ type
dumpMode*: DumpMode
startDir*: string # Current directory on startup - is top level pkg dir for
# some commands, useful when processing deps
nimBin*: string # Nim compiler location. Typically accessed via options.nim.
nimBin*: Option[NimBin]
localdeps*: bool # True if project local deps mode
developLocaldeps*: bool # True if local deps + nimble develop pkg1 ...
disableSslCertCheck*: bool
Expand Down Expand Up @@ -375,10 +378,10 @@ proc promptList*(options: Options, question: string, args: openarray[string]): s
return promptList(options.forcePrompts, question, args)

proc nim*(options: Options): string =
if options.nimBin.len == 0:
if options.nimBin.isNone:
raise nimbleError(
"Unable to find `nim` binary - add to $PATH or use `--nim`")
return options.nimBin
return options.nimBin.get().path

proc getNimbleDir*(options: Options): string =
return options.nimbleDir
Expand Down Expand Up @@ -459,16 +462,35 @@ proc parseCommand*(key: string, result: var Options) =
proc getNimbleFileDir*(pkgInfo: PackageInfo): string =
pkgInfo.myPath.splitFile.dir

proc getRequiredNimVersion*(pkgInfo: PackageInfo): VersionRange =
let nimPkgTupl = pkgInfo.requires.filterIt(it.name == "nim")
if nimPkgTupl.len > 0:
return nimPkgTupl[0].ver
return VersionRange(kind: verAny)

proc getNimBin*(pkgInfo: PackageInfo, options: Options): string =
if pkgInfo.basicInfo.name == "nim":
var binaryPath = "bin" / "nim"
when defined(windows):
binaryPath &= ".exe"

result = pkgInfo.getNimbleFileDir() / binaryPath
display("Info:", "compiling nim package using $1" % result, priority = HighPriority)
else:
else:
if options.useSatSolver:
#Try to first use nim from the solved packages
#TODO add the solved packages to the options (we need to remove the legacy solver first otherwise it will be messy)
for pkg in satProccesedPackages:
if pkg.basicInfo.name == "nim":
return pkg.getNimBin(options)

assert options.nimBin.isSome, "Nim binary not set"
#Check if the current nim satisfais the pacakge
let nimVer = options.nimBin.get.version
let reqNimVer = pkgInfo.getRequiredNimVersion()
if not nimVer.withinRange(reqNimVer):
display("Warning:", &"Package requires nim {reqNimVer} but {nimVer} found. Attempting to compile with the current nim version.", Warning, HighPriority)
result = options.nim
display("Info:", "compiling nim package using $1" % result, priority = HighPriority)


proc getNimBin*(options: Options): string =
return options.nim
Expand Down Expand Up @@ -530,6 +552,29 @@ proc getFlagString(kind: CmdLineKind, flag, val: string): string =
else:
return prefix & flag & ":" & val

proc getNimVersionFromBin*(nimBin: string): Option[Version] =
let cmd = nimBin & " --version"
if nimBin.fileExists:
let info = execProcess(cmd)
var major, minor, patch: int
for line in info.splitLines:
if scanf(line, "Nim Compiler Version $i.$i.$i", major, minor, patch):
let ver = $major & "." & $minor & "." & $patch
return some newVersion(ver)

proc makeNimBin*(path: string, version: Option[Version] = none(Version)): NimBin =
var path = path
if path == "nim":
path = findExe("nim")
if path == "nim":
raise nimbleError("Unable to find `nim` binary - add to $PATH or use `--nim`")
if not path.isAbsolute():
path = expandTilde(path).absolutePath()
var version = version
if version.isNone:
version = getNimVersionFromBin(path)
return NimBin(path: path, version: version.get())

proc parseFlag*(flag, val: string, result: var Options, kind = cmdLongOption) =

let f = flag.normalize().replace("-", "")
Expand All @@ -548,7 +593,7 @@ proc parseFlag*(flag, val: string, result: var Options, kind = cmdLongOption) =
of "offline": result.offline = true
of "nocolor": result.noColor = true
of "disablevalidation": result.disableValidation = true
of "nim": result.nimBin = val
of "nim": result.nimBin = some makeNimBin(val)
of "localdeps", "l": result.localdeps = true
of "nosslcheck": result.disableSslCertCheck = true
of "nolockfile": result.disableLockFile = true
Expand Down
1 change: 1 addition & 0 deletions src/nimblepkg/packageinfotypes.nim
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,4 @@ type
PackageDependenciesInfo* = tuple[deps: HashSet[PackageInfo], pkg: PackageInfo]

const noTask* = "" # Means that noTask is being ran. Use this as key for base dependencies
var satProccesedPackages*: HashSet[PackageInfo]
8 changes: 4 additions & 4 deletions tests/tsat.nim
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import unittest, os
import testscommon
# from nimblepkg/common import cd Used in the commented tests
import std/[tables, sequtils, json, jsonutils, strutils, times]
import std/[tables, sequtils, json, jsonutils, strutils, times, options]
import nimblepkg/[version, nimblesat, options, config]
from nimblepkg/common import cd

Expand Down Expand Up @@ -41,7 +41,7 @@ proc downloadAndStorePackageVersionTableFor(pkgName: string, options: Options) =

proc downloadAllPackages() {.used.} =
var options = initOptions()
options.nimBin = "nim"
options.nimBin = some makeNimBin("nim")
# options.config.packageLists["uing"] = PackageList(name: pkgName, urls: @[pkgUrl])
options.config.packageLists["official"] = PackageList(name: "Official", urls: @[
"https://raw.githubusercontent.com/nim-lang/packages/master/packages.json",
Expand Down Expand Up @@ -158,7 +158,7 @@ suite "SAT solver":
let pkgName: string = "nimlangserver"
let pv: PkgTuple = (pkgName, VersionRange(kind: verAny))
var options = initOptions()
options.nimBin = "nim"
options.nimBin = some makeNimBin("nim")
options.config.packageLists["official"] = PackageList(name: "Official", urls: @[
"https://raw.githubusercontent.com/nim-lang/packages/master/packages.json",
"https://nim-lang.org/nimble/packages.json"
Expand Down Expand Up @@ -222,7 +222,7 @@ suite "SAT solver":
"https://nim-lang.org/nimble/packages.json"
])
options.nimbleDir = getCurrentDir() / "conflictingdepres" / "nimbledeps"
options.nimBin = "nim"
options.nimBin = some makeNimBin("nim")
options.pkgCachePath = getCurrentDir() / "conflictingdepres" / "download"
let pkgs = getInstalledMinimalPackages(options)
var pkgVersionTable = initTable[string, PackageVersions]()
Expand Down

0 comments on commit 05f2014

Please sign in to comment.