Skip to content
33 changes: 25 additions & 8 deletions src/nimble.nim
Original file line number Diff line number Diff line change
Expand Up @@ -157,14 +157,23 @@ proc buildFromDir(pkgInfo: PackageInfo, paths: HashSet[string],
## Builds a package as specified by ``pkgInfo``.
# Handle pre-`build` hook.
let
realDir = pkgInfo.getRealDir()
pkgDir = pkgInfo.myPath.parentDir()
realDir =
if options.example:
pkgInfo.getRealExamplesDir()
else:
pkgInfo.getRealDir()
bin =
if options.example:
pkgInfo.getExampleBin()
else:
pkgInfo.bin

cd pkgDir: # Make sure `execHook` executes the correct .nimble file.
if not execHook(options, actionBuild, true):
raise nimbleError("Pre-hook prevented further execution.")

if pkgInfo.bin.len == 0:
if bin.len == 0:
raise nimbleError(
"Nothing to build. Did you specify a module to build using the" &
" `bin` key in your .nimble file?")
Expand All @@ -181,6 +190,8 @@ proc buildFromDir(pkgInfo: PackageInfo, paths: HashSet[string],
if options.verbosity == SilentPriority:
# Hide Nim warnings
args.add("--warnings:off")
if options.example:
args.add("--path:" & pkgInfo.srcDir.quoteShell)

let binToBuild =
# Only build binaries specified by user if any, but only if top-level package,
Expand All @@ -189,13 +200,13 @@ proc buildFromDir(pkgInfo: PackageInfo, paths: HashSet[string],
options.getCompilationBinary(pkgInfo).get("")
else: ""

for bin, src in pkgInfo.bin:
for bin, src in bin:
# Check if this is the only binary that we want to build.
if binToBuild.len != 0 and binToBuild != bin:
if bin.extractFilename().changeFileExt("") != binToBuild:
continue

let outputDir = pkgInfo.getOutputDir("")
let outputDir = pkgInfo.getOutputDir("", options.example)
if dirExists(outputDir):
if fileExists(outputDir / bin):
if not pkgInfo.needsRebuild(outputDir / bin, realDir, options):
Expand All @@ -206,7 +217,7 @@ proc buildFromDir(pkgInfo: PackageInfo, paths: HashSet[string],
else:
createDir(outputDir)

let outputOpt = "-o:" & pkgInfo.getOutputDir(bin).quoteShell
let outputOpt = "-o:" & pkgInfo.getOutputDir(bin, options.example).quoteShell
display("Building", "$1/$2 using $3 backend" %
[pkginfo.basicInfo.name, bin, pkgInfo.backend], priority = HighPriority)

Expand Down Expand Up @@ -724,7 +735,11 @@ proc clean(options: Options) =

proc execBackend(pkgInfo: PackageInfo, options: Options) =
let
bin = options.getCompilationBinary(pkgInfo).get("")
bin =
if options.example:
pkgInfo.getRealExamplesDir() / options.getCompilationBinary(pkgInfo).get("")
else:
options.getCompilationBinary(pkgInfo).get("")
binDotNim = bin.addFileExt("nim")

if bin == "":
Expand All @@ -750,6 +765,8 @@ proc execBackend(pkgInfo: PackageInfo, options: Options) =
if options.verbosity == SilentPriority:
# Hide Nim warnings
args.add("--warnings:off")
if options.example:
args.add("--path:" & pkgInfo.srcDir.quoteShell)

for option in options.getCompilationFlags():
args.add(option.quoteShell)
Expand Down Expand Up @@ -1918,7 +1935,7 @@ proc run(options: Options) =
if binary.len == 0:
raise nimbleError("Please specify a binary to run")

if binary notin pkgInfo.bin:
if not options.example and binary notin pkgInfo.bin:
raise nimbleError(binaryNotDefinedInPkgMsg(binary, pkgInfo.basicInfo.name))

if pkgInfo.isLink:
Expand All @@ -1927,7 +1944,7 @@ proc run(options: Options) =
elif options.getCompilationFlags.len > 0:
displayWarning(ignoringCompilationFlagsMsg)

let binaryPath = pkgInfo.getOutputDir(binary)
let binaryPath = pkgInfo.getOutputDir(binary, options.example)
let cmd = quoteShellCommand(binaryPath & options.action.runFlags)
displayDebug("Executing", cmd)

Expand Down
43 changes: 42 additions & 1 deletion src/nimblepkg/init.nim
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import os, strutils
import os, strutils, std/options

import ./cli, ./tools

Expand All @@ -20,6 +20,36 @@ proc writeExampleIfNonExistent(file: string, content: string) =
display("Info:", "File " & file & " already exists, did not write " &
"example code", priority = HighPriority)

proc exampleCode(info: PkgInitInfo): Option[string] =
case info.pkgType
of "library":
result = some("""
# You may create as many example files as you want. Example file names should
# be valid Nim module names.
#
# To run this example, simply execute `nimble run --example example1`.

import $1

echo "One plus one equals ", $$add(1, 1)

""" % info.pkgName)

of "hybrid":
result = some("""
# You may create as many example files as you want. Example file names should
# be valid Nim module names.
#
# To run this example, simply execute `nimble run --example example1`.

import $1pkg/submodule

echo getWelcomeMessage()

""" % info.pkgName)
else:
discard

proc createPkgStructure*(info: PkgInitInfo, pkgRoot: string) =
# Create source directory
createDirD(pkgRoot / info.pkgSrcDir)
Expand Down Expand Up @@ -154,6 +184,17 @@ test "correct welcome":
else:
assert false, "Invalid package type specified."

# Create examples directory and dummy example
let pkgExamplesDir = "examples"
let pkgExampleCode = exampleCode(info)
if pkgExampleCode.isSome():
let pkgExampleCode = pkgExampleCode.get("")
let pkgExamplesPath = pkgRoot / pkgExamplesDir

createDirD(pkgExamplesPath)
nimbleFileOptions.add("# examplesDir = $1 # Uncomment to change the name of the examples directory\n" % pkgExamplesDir.escape())
writeExampleIfNonExistent(pkgExamplesPath / "example1".addFileExt(".nim"), pkgExampleCode)

# Write the nimble file
let nimbleFile = pkgRoot / info.pkgName.changeFileExt("nimble")
writeFile(nimbleFile, """# Package
Expand Down
2 changes: 2 additions & 0 deletions src/nimblepkg/nimscriptapi.nim
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ var
srcDir*: string ## The package's source directory.
binDir*: string ## The package's binary directory.
backend*: string ## The package's backend.
examplesDir*: string ## The package's examples directory.

skipDirs*, skipFiles*, skipExt*, installDirs*, installFiles*,
installExt*, bin*: seq[string] = @[] ## Nimble metadata.
Expand Down Expand Up @@ -126,6 +127,7 @@ proc printPkgInfo(): string =
printIfLen srcDir
printIfLen binDir
printIfLen backend
printIfLen examplesDir

printSeqIfLen skipDirs
printSeqIfLen skipFiles
Expand Down
4 changes: 4 additions & 0 deletions src/nimblepkg/options.nim
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ type
showVersion*: bool
offline*: bool
noColor*: bool
example*: bool
disableValidation*: bool
continueTestsOnFailure*: bool
## Whether packages' repos should always be downloaded with their history.
Expand All @@ -56,6 +57,7 @@ type
actionUninstall, actionCompile, actionDoc, actionCustom, actionTasks,
actionDevelop, actionCheck, actionLock, actionRun, actionSync, actionSetup,
actionClean, actionDeps


DevelopActionType* = enum
datAdd, datRemoveByPath, datRemoveByName, datInclude, datExclude
Expand Down Expand Up @@ -223,6 +225,7 @@ Nimble Options:
--silent Hide all Nimble and Nim output
--verbose Show all non-debug output.
--debug Show all output including debug messages.
--example Build/run an example instead of a package.
--offline Don't use network.
--noColor Don't colorise output.
--noSSLCheck Don't check SSL certificates.
Expand Down Expand Up @@ -517,6 +520,7 @@ proc parseFlag*(flag, val: string, result: var Options, kind = cmdLongOption) =
of "tarballs", "t": result.enableTarballs = true
of "package", "p": result.package = val
of "lock-file": result.lockFileName = val
of "example": result.example = true
else: isGlobalFlag = false

var wasFlagHandled = true
Expand Down
37 changes: 33 additions & 4 deletions src/nimblepkg/packageinfo.nim
Original file line number Diff line number Diff line change
Expand Up @@ -367,15 +367,30 @@ proc getRealDir*(pkgInfo: PackageInfo): string =
else:
result = pkgInfo.getNimbleFileDir()

proc getOutputDir*(pkgInfo: PackageInfo, bin: string): string =
proc getOutputDir*(pkgInfo: PackageInfo, bin: string, example = false): string =
## Returns a binary output dir for the package.
if pkgInfo.binDir != "":
result = pkgInfo.getNimbleFileDir() / pkgInfo.binDir / bin
if example and pkgInfo.examplesDir != "":
if pkgInfo.binDir != "":
result = pkgInfo.getNimbleFileDir() / pkgInfo.binDir / pkgInfo.examplesDir / bin
else:
result = pkgInfo.mypath.splitFile.dir / pkgInfo.examplesDir / bin
else:
result = pkgInfo.mypath.splitFile.dir / bin
if pkgInfo.binDir != "":
result = pkgInfo.getNimbleFileDir() / pkgInfo.binDir / bin
else:
result = pkgInfo.mypath.splitFile.dir / bin
if bin.len != 0 and dirExists(result):
result &= ".out"

proc getRealExamplesDir*(pkgInfo: PackageInfo): string =
## Returns the directory containing the example source files.
## If no example directory was specified in the package info, "examples"
## is returned.
if pkgInfo.examplesDir != "" and (not pkgInfo.isInstalled or pkgInfo.isLink):
result = pkgInfo.getNimbleFileDir() / pkgInfo.examplesDir
elif not pkgInfo.isInstalled or pkgInfo.isLink:
result = "examples"

proc echoPackage*(pkg: Package) =
echo(pkg.name & ":")
if pkg.alias.len > 0:
Expand Down Expand Up @@ -530,6 +545,20 @@ proc hash*(x: PackageInfo): Hash =
proc getNameAndVersion*(pkgInfo: PackageInfo): string =
&"{pkgInfo.basicInfo.name}@{pkgInfo.basicInfo.version}"

proc getExampleBin*(pkgInfo: PackageInfo): Table[string,string] =
let examplesDir = pkgInfo.getRealExamplesDir()
if examplesDir == "":
raise nimbleError("Cannot find example files", hint="Was 'examplesDir' defined in '$1' ?" % pkgInfo.myPath)

if not examplesDir.dirExists():
raise nimbleError("Examples directory not found: $1" % examplesDir)

for kind, path in walkDir(examplesDir):
if kind in {pcFile, pcLinkToFile}:
let (_, name, ext) = path.splitFile()
if ext == ".nim":
result[name] = name

when isMainModule:
import unittest

Expand Down
1 change: 1 addition & 0 deletions src/nimblepkg/packageinfotypes.nim
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ type
bin*: Table[string, string]
binDir*: string
srcDir*: string
examplesDir*: string
backend*: string
foreignDeps*: seq[string]
basicInfo*: PackageBasicInfo
Expand Down
1 change: 1 addition & 0 deletions src/nimblepkg/packageparser.nim
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ proc readPackageInfoFromNimble(path: string; result: var PackageInfo) =
of "license": result.license = ev.value
of "srcdir": result.srcDir = ev.value
of "bindir": result.binDir = ev.value
of "examplesdir": result.examplesDir = ev.value
of "skipdirs":
result.skipDirs.add(ev.value.multiSplit)
of "skipfiles":
Expand Down