Skip to content

Commit 8323bfa

Browse files
committed
Add possibility to run executables from dependency packages
Nimble's run command is extended to be able to run executables not only from the current package but also from some of its dependencies. The package from which we want to run an executable is specified with a newly added to Nimble `--package` command-line option. There are two cases: - For installed in the Nimble cache packages the build step is skipped and the installed package binary is being run. - For develop mode packages first the package's binary is being built with provided compilation flags and the package is being run.
1 parent 96df458 commit 8323bfa

File tree

8 files changed

+140
-10
lines changed

8 files changed

+140
-10
lines changed

src/nimble.nim

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -703,14 +703,18 @@ proc getDependenciesPaths(pkgInfo: PackageInfo, options: Options):
703703
let deps = pkgInfo.processAllDependencies(options)
704704
return deps.map(dep => dep.getRealDir())
705705

706-
proc build(options: Options) =
707-
let dir = getCurrentDir()
708-
let pkgInfo = getPkgInfo(dir, options)
706+
proc build(pkgInfo: PackageInfo, options: Options) =
707+
## Builds the package `pkgInfo`.
709708
nimScriptHint(pkgInfo)
710709
let paths = pkgInfo.getDependenciesPaths(options)
711710
var args = options.getCompilationFlags()
712711
buildFromDir(pkgInfo, paths, args, options)
713712

713+
proc build(options: Options) =
714+
let dir = getCurrentDir()
715+
let pkgInfo = getPkgInfo(dir, options)
716+
pkgInfo.build(options)
717+
714718
proc clean(options: Options) =
715719
let dir = getCurrentDir()
716720
let pkgInfo = getPkgInfo(dir, options)
@@ -1829,21 +1833,40 @@ proc setup(options: Options) =
18291833
setupNimbleConfig(options)
18301834
setupVcsIgnoreFile()
18311835

1836+
proc getPackageForAction(pkgInfo: PackageInfo, options: Options): PackageInfo =
1837+
## Returns the `PackageInfo` for the package in `pkgInfo`'s dependencies tree
1838+
## with the name specified in `options.package`. If `options.package` is empty
1839+
## or it matches the name of the `pkgInfo` then `pkgInfo` is returned. Raises
1840+
## a `NimbleError` if the package with the provided name is not found.
1841+
1842+
result = initPackageInfo()
1843+
1844+
if options.package.len == 0 or pkgInfo.basicInfo.name == options.package:
1845+
return pkgInfo
1846+
1847+
let deps = pkgInfo.processAllDependencies(options)
1848+
for dep in deps:
1849+
if dep.basicInfo.name == options.package:
1850+
return dep.toFullInfo(options)
1851+
1852+
raise nimbleError(notFoundPkgWithNameInPkgDepTree(options.package))
1853+
18321854
proc run(options: Options) =
1833-
# Verify parameters.
18341855
var pkgInfo = getPkgInfo(getCurrentDir(), options)
1856+
pkgInfo = getPackageForAction(pkgInfo, options)
18351857

18361858
let binary = options.getCompilationBinary(pkgInfo).get("")
18371859
if binary.len == 0:
18381860
raise nimbleError("Please specify a binary to run")
18391861

18401862
if binary notin pkgInfo.bin:
1841-
raise nimbleError(
1842-
"Binary '$#' is not defined in '$#' package." % [binary, pkgInfo.basicInfo.name]
1843-
)
1863+
raise nimbleError(binaryNotDefinedInPkgMsg(binary, pkgInfo.basicInfo.name))
18441864

1845-
# Build the binary.
1846-
build(options)
1865+
if pkgInfo.isLink:
1866+
# If this is not installed package then build the binary.
1867+
pkgInfo.build(options)
1868+
elif options.getCompilationFlags.len > 0:
1869+
displayWarning(ignoringCompilationFlagsMsg)
18471870

18481871
let binaryPath = pkgInfo.getOutputDir(binary)
18491872
let cmd = quoteShellCommand(binaryPath & options.action.runFlags)

src/nimblepkg/displaymessages.nim

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ const
3434
multipleDevelopFileOptionsGivenMsg* =
3535
"Multiple develop file options are given."
3636

37+
ignoringCompilationFlagsMsg* =
38+
"Ignoring compilation flags for installed package."
39+
3740
updatingTheLockFileMsg* = "Updating the lock file..."
3841
generatingTheLockFileMsg* = "Generating the lock file..."
3942
lockFileIsUpdatedMsg* = "The lock file is updated."
@@ -157,3 +160,10 @@ proc pkgAlreadyExistsInTheCacheMsg*(pkgInfo: PackageInfo): string =
157160
proc skipDownloadingInAlreadyExistingDirectoryMsg*(dir, name: string): string =
158161
&"The download directory \"{dir}\" already exists.\n" &
159162
&"Skipping the download of \"{name}\"."
163+
164+
proc binaryNotDefinedInPkgMsg*(binaryName, pkgName: string): string =
165+
&"Binary '{binaryName}' is not defined in '{pkgName}' package."
166+
167+
proc notFoundPkgWithNameInPkgDepTree*(pkgName: string): string =
168+
&"Not found package with name '{pkgName}' in the current package's " &
169+
"dependency tree."

src/nimblepkg/options.nim

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ type
4343
developLocaldeps*: bool # True if local deps + nimble develop pkg1 ...
4444
disableSslCertCheck*: bool
4545
enableTarballs*: bool # Enable downloading of packages as tarballs from GitHub.
46+
package*: string
47+
# For which package in the dependency tree the command should be executed.
48+
# If not provided by default it applies to the current directory package.
49+
# For now, it is used only by the run action and it is ignored by others.
4650

4751
ActionType* = enum
4852
actionNil, actionRefresh, actionInit, actionDump, actionPublish,
@@ -189,7 +193,12 @@ Nimble Options:
189193
-v, --version Print version information.
190194
-y, --accept Accept all interactive prompts.
191195
-n, --reject Reject all interactive prompts.
192-
-l, --localdeps Run in project local dependency mode
196+
-l, --localdeps Run in project local dependency mode.
197+
-p, --package For which package in the dependency tree the
198+
command should be executed. If not provided by
199+
default it applies to the current directory
200+
package. For now, it is used only by the run
201+
action and it is ignored by others.
193202
-t, --tarballs Enable downloading of packages as tarballs
194203
when working with GitHub repositories.
195204
--ver Query remote server for package version
@@ -485,6 +494,7 @@ proc parseFlag*(flag, val: string, result: var Options, kind = cmdLongOption) =
485494
of "localdeps", "l": result.localdeps = true
486495
of "nosslcheck": result.disableSslCertCheck = true
487496
of "tarballs", "t": result.enableTarballs = true
497+
of "package", "p": result.package = val
488498
else: isGlobalFlag = false
489499

490500
var wasFlagHandled = true
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
when isMainModule:
2+
import os
3+
for i in 1 .. paramCount():
4+
echo paramStr(i)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
proc foo* =
2+
echo "Hello from dependency.foo"
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
version = "0.1.0"
2+
author = "Ivan Bobev"
3+
description = "Test package."
4+
license = "MIT"
5+
6+
bin = @["binary"]
7+
8+
requires "nim >= 1.7.1"
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
version = "0.1.0"
2+
author = "Ivan Bobev"
3+
description = "Test package."
4+
license = "MIT"
5+
6+
requires "nim >= 1.7.1", "dependency"

tests/truncommand.nim

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55

66
import unittest, os, strutils
77
import testscommon
8+
import nimblepkg/displaymessages
89
from nimblepkg/common import cd
10+
from nimblepkg/developfile import developFileName
911

1012
suite "nimble run":
1113
test "Invalid binary":
@@ -162,3 +164,68 @@ suite "nimble run":
162164
[$DirSep, "run".changeFileExt(ExeExt)])
163165
check output.contains("""Testing `nimble run`: @["--test"]""")
164166
check output.contains("""Whee!""")
167+
168+
const
169+
testPkgsPath = "runDependencyBinary"
170+
dependencyPkgPath = testPkgsPath / "dependency"
171+
dependentPkgPath = testPkgsPath / "dependent"
172+
dependencyPkgBinary = dependencyPkgPath / "binary".addFileExt(ExeExt)
173+
dependentPkgDevelopFile = dependentPkgPath / developFileName
174+
packagesFilePath = "develop/packages.json"
175+
176+
test "Run binary from dependency in Nimble cache":
177+
cleanDir installDir
178+
cleanFile dependencyPkgBinary
179+
usePackageListFile(packagesFilePath):
180+
cd dependencyPkgPath:
181+
let (_, exitCode) = execNimble("install")
182+
check exitCode == QuitSuccess
183+
cd dependentPkgPath:
184+
let (output, exitCode) = execNimble("--package:dependency", "run",
185+
"-d:danger", "binary", "--arg1", "--arg2")
186+
check exitCode == QuitSuccess
187+
var lines = output.processOutput
188+
check lines.inLinesOrdered(ignoringCompilationFlagsMsg)
189+
check lines.inLinesOrdered("--arg1")
190+
check lines.inLinesOrdered("--arg2")
191+
192+
test "Run binary from develop mode dependency":
193+
cleanDir installDir
194+
cleanFiles dependencyPkgBinary, dependentPkgDevelopFile
195+
usePackageListFile(packagesFilePath):
196+
cd dependentPkgPath:
197+
var (output, exitCode) = execNimble("develop", "-a:../dependency")
198+
check exitCode == QuitSuccess
199+
(output, exitCode) = execNimble("--package:dependency", "run",
200+
"-d:danger", "binary", "--arg1", "--arg2")
201+
check exitCode == QuitSuccess
202+
var lines = output.processOutput
203+
check lines.inLinesOrdered("Building dependency/binary using c backend")
204+
check lines.inLinesOrdered("--arg1")
205+
check lines.inLinesOrdered("--arg2")
206+
207+
test "Error when specified package does not exist":
208+
cleanDir installDir
209+
cleanFile dependencyPkgBinary
210+
usePackageListFile(packagesFilePath):
211+
cd dependencyPkgPath:
212+
let (_, exitCode) = execNimble("install")
213+
check exitCode == QuitSuccess
214+
cd dependentPkgPath:
215+
let (output, exitCode) = execNimble("--package:dep", "run",
216+
"-d:danger", "binary", "--arg1", "--arg2")
217+
check exitCode == QuitFailure
218+
check output.contains(notFoundPkgWithNameInPkgDepTree("dep"))
219+
220+
test "Error when specified binary does not exist in specified package":
221+
cleanDir installDir
222+
cleanFile dependencyPkgBinary
223+
usePackageListFile(packagesFilePath):
224+
cd dependencyPkgPath:
225+
let (_, exitCode) = execNimble("install")
226+
check exitCode == QuitSuccess
227+
cd dependentPkgPath:
228+
let (output, exitCode) = execNimble("--package:dependency", "run",
229+
"-d:danger", "bin", "--arg1", "--arg2")
230+
check exitCode == QuitFailure
231+
check output.contains(binaryNotDefinedInPkgMsg("bin", "dependency"))

0 commit comments

Comments
 (0)