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

Add possibility to run executables from dependency packages #976

Merged
merged 5 commits into from
Jan 18, 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
1 change: 1 addition & 0 deletions changelog.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ This is a major release containing four new features:
- Support for lock files.
- Download tarballs when downloading packages from GitHub.
- A setup command.
- Added a `--package, -p` command line option.

## 0.13.0

Expand Down
7 changes: 6 additions & 1 deletion readme.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,12 @@ files.
The `run` command can be used to build and run any binary specified in your
package's `bin` list. The binary needs to be specified after any compilation flags
if there are several binaries defined. Any flags after the binary or `--`
are passed to the binary when it is run.
are passed to the binary when it is run. It is possible to run a binary from some
dependency package. To do this pass the `--package, -p` option to Nimble. For example:

```
nimble --package:foo run <compilation_flags> bar <run_flags>
```

### nimble c

Expand Down
41 changes: 32 additions & 9 deletions src/nimble.nim
Original file line number Diff line number Diff line change
Expand Up @@ -703,14 +703,18 @@ proc getDependenciesPaths(pkgInfo: PackageInfo, options: Options):
let deps = pkgInfo.processAllDependencies(options)
return deps.map(dep => dep.getRealDir())

proc build(options: Options) =
let dir = getCurrentDir()
let pkgInfo = getPkgInfo(dir, options)
proc build(pkgInfo: PackageInfo, options: Options) =
## Builds the package `pkgInfo`.
nimScriptHint(pkgInfo)
let paths = pkgInfo.getDependenciesPaths(options)
var args = options.getCompilationFlags()
buildFromDir(pkgInfo, paths, args, options)

proc build(options: Options) =
let dir = getCurrentDir()
let pkgInfo = getPkgInfo(dir, options)
pkgInfo.build(options)

proc clean(options: Options) =
let dir = getCurrentDir()
let pkgInfo = getPkgInfo(dir, options)
Expand Down Expand Up @@ -1846,21 +1850,40 @@ proc setup(options: Options) =
setupNimbleConfig(options)
setupVcsIgnoreFile()

proc getPackageForAction(pkgInfo: PackageInfo, options: Options): PackageInfo =
## Returns the `PackageInfo` for the package in `pkgInfo`'s dependencies tree
## with the name specified in `options.package`. If `options.package` is empty
## or it matches the name of the `pkgInfo` then `pkgInfo` is returned. Raises
## a `NimbleError` if the package with the provided name is not found.

result = initPackageInfo()

if options.package.len == 0 or pkgInfo.basicInfo.name == options.package:
return pkgInfo

let deps = pkgInfo.processAllDependencies(options)
for dep in deps:
if dep.basicInfo.name == options.package:
return dep.toFullInfo(options)

raise nimbleError(notFoundPkgWithNameInPkgDepTree(options.package))

proc run(options: Options) =
# Verify parameters.
var pkgInfo = getPkgInfo(getCurrentDir(), options)
pkgInfo = getPackageForAction(pkgInfo, options)

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

if binary notin pkgInfo.bin:
raise nimbleError(
"Binary '$#' is not defined in '$#' package." % [binary, pkgInfo.basicInfo.name]
)
raise nimbleError(binaryNotDefinedInPkgMsg(binary, pkgInfo.basicInfo.name))

# Build the binary.
build(options)
if pkgInfo.isLink:
# If this is not installed package then build the binary.
pkgInfo.build(options)
elif options.getCompilationFlags.len > 0:
displayWarning(ignoringCompilationFlagsMsg)

let binaryPath = pkgInfo.getOutputDir(binary)
let cmd = quoteShellCommand(binaryPath & options.action.runFlags)
Expand Down
10 changes: 10 additions & 0 deletions src/nimblepkg/displaymessages.nim
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ const
multipleDevelopFileOptionsGivenMsg* =
"Multiple develop file options are given."

ignoringCompilationFlagsMsg* =
"Ignoring compilation flags for installed package."

updatingTheLockFileMsg* = "Updating the lock file..."
generatingTheLockFileMsg* = "Generating the lock file..."
lockFileIsUpdatedMsg* = "The lock file is updated."
Expand Down Expand Up @@ -158,5 +161,12 @@ proc skipDownloadingInAlreadyExistingDirectoryMsg*(dir, name: string): string =
&"The download directory \"{dir}\" already exists.\n" &
&"Skipping the download of \"{name}\"."

proc binaryNotDefinedInPkgMsg*(binaryName, pkgName: string): string =
&"Binary '{binaryName}' is not defined in '{pkgName}' package."

proc notFoundPkgWithNameInPkgDepTree*(pkgName: string): string =
&"Not found package with name '{pkgName}' in the current package's " &
"dependency tree."

proc pkgLinkFileSavedMsg*(path: string): string =
&"Package link file \"{path}\" is saved."
12 changes: 11 additions & 1 deletion src/nimblepkg/options.nim
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ type
developLocaldeps*: bool # True if local deps + nimble develop pkg1 ...
disableSslCertCheck*: bool
enableTarballs*: bool # Enable downloading of packages as tarballs from GitHub.
package*: string
# For which package in the dependency tree the command should be executed.
# If not provided by default it applies to the current directory package.
# For now, it is used only by the run action and it is ignored by others.

ActionType* = enum
actionNil, actionRefresh, actionInit, actionDump, actionPublish,
Expand Down Expand Up @@ -195,7 +199,12 @@ Nimble Options:
-v, --version Print version information.
-y, --accept Accept all interactive prompts.
-n, --reject Reject all interactive prompts.
-l, --localdeps Run in project local dependency mode
-l, --localdeps Run in project local dependency mode.
-p, --package For which package in the dependency tree the
command should be executed. If not provided by
default it applies to the current directory
package. For now, it is used only by the run
action and it is ignored by others.
-t, --tarballs Enable downloading of packages as tarballs
when working with GitHub repositories.
--ver Query remote server for package version
Expand Down Expand Up @@ -494,6 +503,7 @@ proc parseFlag*(flag, val: string, result: var Options, kind = cmdLongOption) =
of "localdeps", "l": result.localdeps = true
of "nosslcheck": result.disableSslCertCheck = true
of "tarballs", "t": result.enableTarballs = true
of "package", "p": result.package = val
else: isGlobalFlag = false

var wasFlagHandled = true
Expand Down
4 changes: 4 additions & 0 deletions tests/runDependencyBinary/dependency/binary.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
when isMainModule:
import os
for i in 1 .. paramCount():
echo paramStr(i)
2 changes: 2 additions & 0 deletions tests/runDependencyBinary/dependency/dependency.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
proc foo* =
echo "Hello from dependency.foo"
8 changes: 8 additions & 0 deletions tests/runDependencyBinary/dependency/dependency.nimble
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
version = "0.1.0"
author = "Ivan Bobev"
description = "Test package."
license = "MIT"

bin = @["binary"]

requires "nim >= 1.5.1"
6 changes: 6 additions & 0 deletions tests/runDependencyBinary/dependent/dependent.nimble
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
version = "0.1.0"
author = "Ivan Bobev"
description = "Test package."
license = "MIT"

requires "nim >= 1.5.1", "dependency"
73 changes: 72 additions & 1 deletion tests/truncommand.nim
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@

{.used.}

import unittest, os, strutils
import unittest, os, strutils, strformat
import testscommon
import nimblepkg/displaymessages
from nimblepkg/common import cd
from nimblepkg/developfile import developFileName

suite "nimble run":
test "Invalid binary":
Expand Down Expand Up @@ -162,3 +164,72 @@ suite "nimble run":
[$DirSep, "run".changeFileExt(ExeExt)])
check output.contains("""Testing `nimble run`: @["--test"]""")
check output.contains("""Whee!""")

const
testPkgsPath = "runDependencyBinary"
dependencyPkgPath = testPkgsPath / "dependency"
dependentPkgPath = testPkgsPath / "dependent"
dependencyPkgBinary = dependencyPkgPath / "binary".addFileExt(ExeExt)
dependentPkgDevelopFile = dependentPkgPath / developFileName
packagesFilePath = "develop/packages.json"

test "Run binary from dependency in Nimble cache":
cleanDir installDir
cleanFile dependencyPkgBinary
usePackageListFile(packagesFilePath):
cd dependencyPkgPath:
let (_, exitCode) = execNimble("install")
check exitCode == QuitSuccess
cd dependentPkgPath:
let (output, exitCode) = execNimble("--package:dependency", "run",
"-d:danger", "binary", "--arg1", "--arg2")
check exitCode == QuitSuccess
var lines = output.processOutput
check lines.inLinesOrdered(ignoringCompilationFlagsMsg)
check lines.inLinesOrdered("--arg1")
check lines.inLinesOrdered("--arg2")

test "Run binary from develop mode dependency":
cleanDir installDir
cleanFiles dependencyPkgBinary, dependentPkgDevelopFile
usePackageListFile(packagesFilePath):
cd dependentPkgPath:
var (output, exitCode) = execNimble("develop", "-a:../dependency")
check exitCode == QuitSuccess
(output, exitCode) = execNimble("--package:dependency", "run",
"-d:danger", "binary", "--arg1", "--arg2")
check exitCode == QuitSuccess
var lines = output.processOutput
const binaryName = when defined(windows): "binary.exe" else: "binary"
check lines.inLinesOrdered(
&"Building dependency/{binaryName} using c backend")
check lines.inLinesOrdered("--arg1")
check lines.inLinesOrdered("--arg2")

test "Error when specified package does not exist":
cleanDir installDir
cleanFile dependencyPkgBinary
usePackageListFile(packagesFilePath):
cd dependencyPkgPath:
let (_, exitCode) = execNimble("install")
check exitCode == QuitSuccess
cd dependentPkgPath:
let (output, exitCode) = execNimble("--package:dep", "run",
"-d:danger", "binary", "--arg1", "--arg2")
check exitCode == QuitFailure
check output.contains(notFoundPkgWithNameInPkgDepTree("dep"))

test "Error when specified binary does not exist in specified package":
cleanDir installDir
cleanFile dependencyPkgBinary
usePackageListFile(packagesFilePath):
cd dependencyPkgPath:
let (_, exitCode) = execNimble("install")
check exitCode == QuitSuccess
cd dependentPkgPath:
let (output, exitCode) = execNimble("--package:dependency", "run",
"-d:danger", "bin", "--arg1", "--arg2")
check exitCode == QuitFailure
const binaryName = when defined(windows): "bin.exe" else: "bin"
check output.contains(binaryNotDefinedInPkgMsg(
binaryName, "dependency"))