Skip to content

Commit 4e7e646

Browse files
authored
Fixes nimble hanging when there is a cycle in the requirements #Fixes #1307 (#1312)
* Fixes nimble hanging when there is a cycle in the requirements #Fixes #1307 * hashes the actual req
1 parent 6eb711b commit 4e7e646

File tree

7 files changed

+78
-23
lines changed

7 files changed

+78
-23
lines changed

src/nimblepkg/nimblesat.nim

Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -598,33 +598,37 @@ proc fillPackageTableFromPreferred*(packages: var Table[string, PackageVersions]
598598
proc getInstalledMinimalPackages*(options: Options): seq[PackageMinimalInfo] =
599599
getInstalledPkgsMin(options.getPkgsDir(), options).mapIt(it.getMinimalInfo(options))
600600

601+
proc getMinimalFromPreferred(pv: PkgTuple, getMinimalPackage: GetPackageMinimal, preferredPackages: seq[PackageMinimalInfo], options: Options): seq[PackageMinimalInfo] =
602+
for pp in preferredPackages:
603+
if pp.name == pv.name and pp.version.withinRange(pv.ver):
604+
return @[pp]
605+
getMinimalPackage(pv, options)
606+
607+
proc processRequirements(versions: var Table[string, PackageVersions], pv: PkgTuple, visited: var HashSet[PkgTuple], getMinimalPackage: GetPackageMinimal, preferredPackages: seq[PackageMinimalInfo] = newSeq[PackageMinimalInfo](), options: Options) =
608+
if pv in visited:
609+
return
610+
611+
visited.incl pv
612+
613+
if not hasVersion(versions, pv):
614+
var pkgMins = getMinimalFromPreferred(pv, getMinimalPackage, preferredPackages, options)
615+
for pkgMin in pkgMins.mitems:
616+
if pv.ver.kind == verSpecial:
617+
pkgMin.version = newVersion $pv.ver
618+
if not versions.hasKey(pv.name):
619+
versions[pv.name] = PackageVersions(pkgName: pv.name, versions: @[pkgMin])
620+
else:
621+
versions[pv.name].versions.addUnique pkgMin
622+
623+
# Process requirements
624+
for req in pkgMin.requires:
625+
processRequirements(versions, req, visited, getMinimalPackage, preferredPackages, options)
601626

602627
proc collectAllVersions*(versions: var Table[string, PackageVersions], package: PackageMinimalInfo, options: Options, getMinimalPackage: GetPackageMinimal, preferredPackages: seq[PackageMinimalInfo] = newSeq[PackageMinimalInfo]()) =
603-
proc getMinimalFromPreferred(pv: PkgTuple): seq[PackageMinimalInfo] =
604-
for pp in preferredPackages:
605-
if pp.name == pv.name and pp.version.withinRange(pv.ver):
606-
return @[pp]
607-
# echo "Getting minimal from getMinimalPackage for ", pv.name, " ", $pv.ver
608-
getMinimalPackage(pv, options)
609-
610-
proc processRequirements(versions: var Table[string, PackageVersions], pv: PkgTuple) =
611-
if not hasVersion(versions, pv):
612-
var pkgMins = getMinimalFromPreferred(pv)
613-
for pkgMin in pkgMins.mitems:
614-
if pv.ver.kind == verSpecial:
615-
pkgMin.version = newVersion $pv.ver
616-
if not versions.hasKey(pv.name):
617-
versions[pv.name] = PackageVersions(pkgName: pv.name, versions: @[pkgMin])
618-
else:
619-
versions[pv.name].versions.addUnique pkgMin
620-
621-
# Process requirements from both the package and GetMinimalPackage results
622-
for req in pkgMin.requires:
623-
# echo "Processing requirement: ", req.name, " ", $req.ver
624-
processRequirements(versions, req)
625628

629+
var visited = initHashSet[PkgTuple]()
626630
for pv in package.requires:
627-
processRequirements(versions, pv)
631+
processRequirements(versions, pv, visited, getMinimalPackage, preferredPackages, options)
628632

629633
proc topologicalSort*(solvedPkgs: seq[SolvedPackage]): seq[SolvedPackage] =
630634
var inDegree = initTable[string, int]()

src/nimblepkg/version.nim

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -465,3 +465,5 @@ when isMainModule:
465465
test "convert version to version range":
466466
check toVersionRange(newVersion("#head")).kind == verSpecial
467467
check toVersionRange(newVersion("0.2.0")).kind == verEq
468+
469+
proc hash*(pv: PkgTuple): Hash = hash($pv)
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 "https://github.com/disruptek/frosty"
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 cycletest/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 cycletest
11+
test "can add":
12+
check add(5, 5) == 10

tests/tsat.nim

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,3 +440,9 @@ suite "SAT solver":
440440
removeDir("nimbledeps")
441441
let (_, exitCode) = execNimbleYes("install", "-l")
442442
check exitCode == QuitSuccess
443+
444+
test "should be able to install packages with cycles in the requirements":
445+
cd "sattests" / "cycletest":
446+
removeDir("nimbledeps")
447+
let (_, exitCode) = execNimbleYes("install", "-l")
448+
check exitCode == QuitSuccess

0 commit comments

Comments
 (0)