Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[POC] Implement 'nimble depsTree' #1012

Merged
merged 2 commits into from
Sep 1, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 28 additions & 1 deletion src/nimble.nim
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ import nimblepkg/packageinfotypes, nimblepkg/packageinfo, nimblepkg/version,
nimblepkg/checksums, nimblepkg/topologicalsort, nimblepkg/lockfile,
nimblepkg/nimscriptwrapper, nimblepkg/developfile, nimblepkg/paths,
nimblepkg/nimbledatafile, nimblepkg/packagemetadatafile,
nimblepkg/displaymessages, nimblepkg/sha1hashes, nimblepkg/syncfile
nimblepkg/displaymessages, nimblepkg/sha1hashes, nimblepkg/syncfile,
nimblepkg/deps

const
nimblePathsFileName* = "nimble.paths"
Expand Down Expand Up @@ -1630,6 +1631,30 @@ proc lock(options: Options) =
updateSyncFile(pkgInfo, options)
displayLockOperationFinish(doesLockFileExist)


proc depsTree(options: Options) =
## Prints the dependency tree

let pkgInfo = getPkgInfo(getCurrentDir(), options)

var errors = validateDevModeDepsWorkingCopiesBeforeLock(pkgInfo, options)

let dependencies = pkgInfo.processFreeDependencies(options).map(
pkg => pkg.toFullInfo(options)).toSeq
pkgInfo.validateDevelopDependenciesVersionRanges(dependencies, options)
var dependencyGraph = buildDependencyGraph(dependencies, options)

# delete errors for dependencies that aren't part of the graph
for name, error in common.dup errors:
if not dependencyGraph.contains name:
errors.del name

if options.action.format == "json":
echo (%depsRecursive(pkgInfo, dependencies, errors)).pretty
else:
echo pkgInfo.basicInfo.name
printDepsHumanReadable(pkgInfo, dependencies, 1, errors)

proc syncWorkingCopy(name: string, path: Path, dependentPkg: PackageInfo,
options: Options) =
## Syncs a working copy of a develop mode dependency of package `dependentPkg`
Expand Down Expand Up @@ -1969,6 +1994,8 @@ proc doAction(options: var Options) =
check(options)
of actionLock:
lock(options)
of actionDeps:
depsTree(options)
of actionSync:
sync(options)
of actionSetup:
Expand Down
51 changes: 51 additions & 0 deletions src/nimblepkg/deps.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import packageinfotypes, developfile, packageinfo, version, tables, strformat, strutils

type
DependencyNode = ref object of RootObj
name*: string
version*: string
resolvedTo*: string
error*: string
dependencies*: seq[DependencyNode]

proc depsRecursive*(pkgInfo: PackageInfo,
dependencies: seq[PackageInfo],
errors: ValidationErrors): seq[DependencyNode] =
result = @[]
for (name, ver) in pkgInfo.requires:
var depPkgInfo = initPackageInfo()
let
found = dependencies.findPkg((name, ver), depPkgInfo)
packageName = if found: depPkgInfo.basicInfo.name else: name

let node = DependencyNode(name: packageName)

result.add node
node.version = if ver.kind == verAny: "@any" else: $ver
node.resolvedTo = if found: $depPkgInfo.basicInfo.version else: ""
node.error = if errors.contains(packageName):
getValidationErrorMessage(packageName, errors.getOrDefault packageName)
else: ""

if found:
node.dependencies = depsRecursive(depPkgInfo, dependencies, errors)

proc printDepsHumanReadable*(pkgInfo: PackageInfo,
dependencies: seq[PackageInfo],
level: int,
errors: ValidationErrors) =
for (name, ver) in pkgInfo.requires:
var depPkgInfo = initPackageInfo()
let
found = dependencies.findPkg((name, ver), depPkgInfo)
packageName = if found: depPkgInfo.basicInfo.name else: name

echo " ".repeat(level * 2),
packageName,
if ver.kind == verAny: "@any" else: " " & $ver,
if found: fmt "(resolved {depPkgInfo.basicInfo.version})" else: "",
if errors.contains(packageName):
" - error: " & getValidationErrorMessage(packageName, errors.getOrDefault packageName)
else:
""
if found: printDepsHumanReadable(depPkgInfo, dependencies, level + 1, errors)
15 changes: 14 additions & 1 deletion src/nimblepkg/options.nim
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ type
actionInstall, actionSearch, actionList, actionBuild, actionPath,
actionUninstall, actionCompile, actionDoc, actionCustom, actionTasks,
actionDevelop, actionCheck, actionLock, actionRun, actionSync, actionSetup,
actionClean
actionClean, actionDeps

DevelopActionType* = enum
datAdd, datRemoveByPath, datRemoveByName, datInclude, datExclude
Expand Down Expand Up @@ -101,6 +101,8 @@ type
arguments*: seq[string]
custCompileFlags*: seq[string]
custRunFlags*: seq[string]
of actionDeps:
format*: string

const
help* = """
Expand Down Expand Up @@ -189,6 +191,9 @@ Commands:
the name of an installed package.
[--ini, --json] Selects the output format (the default is --ini).
lock Generates or updates a package lock file.
deps Outputs dependency tree
[--format type] Specify the output format. Json is the only supported
format
sync Synchronizes develop mode dependencies with
the content of the lock file.
[-l, --list-only] Only lists the packages which are not synced
Expand Down Expand Up @@ -283,6 +288,8 @@ proc parseActionType*(action: string): ActionType =
result = actionCheck
of "lock":
result = actionLock
of "deps":
result = actionDeps
of "sync":
result = actionSync
of "setup":
Expand Down Expand Up @@ -603,6 +610,12 @@ proc parseFlag*(flag, val: string, result: var Options, kind = cmdLongOption) =
result.action.listOnly = true
else:
wasFlagHandled = false
of actionDeps:
case f
of "format":
result.action.format = val
else:
wasFlagHandled = false
else:
wasFlagHandled = false

Expand Down
6 changes: 6 additions & 0 deletions tests/deps/deps.nimble
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
version = "0.1.0"
author = "Ivan Yonchovski"
description = "Nim package manager."
license = "BSD"

requires "timezones == 0.5.4"
1 change: 1 addition & 0 deletions tests/deps/src/def.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
echo "def727"
43 changes: 43 additions & 0 deletions tests/tdeps.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Copyright (C) Dominik Picheta. All rights reserved.
# BSD License. Look at license.txt for more info.

{.used.}

import unittest, os, osproc, strutils, strformat
import testscommon
from nimblepkg/common import cd

suite "nimble deps":
test "nimble deps":
cd "deps":
let (output, exitCode) = execCmdEx(nimblePath & " --silent deps -y")
check exitCode == QuitSuccess
check output.contains("""
deps
timezones 0.5.4(resolved 0.5.4)
nim >= 0.19.9
""")

test "nimble deps(json)":
cd "issue727":
let (output, exitCode) = execCmdEx(nimblePath & " --format:json deps -y")
check exitCode == QuitSuccess
check output.contains("""
[
{
"name": "timezones",
"version": "@any",
"resolvedTo": "0.5.4",
"error": "",
"dependencies": [
{
"name": "nim",
"version": ">= 0.19.9",
"resolvedTo": "",
"error": "",
"dependencies": []
}
]
}
]
""")