Skip to content

Commit

Permalink
Implemented context-oriented build
Browse files Browse the repository at this point in the history
  • Loading branch information
Andrey Zak committed Jul 14, 2017
1 parent 2dad6b8 commit 4d49925
Show file tree
Hide file tree
Showing 14 changed files with 220 additions and 59 deletions.
29 changes: 29 additions & 0 deletions contexts.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import tables

type TaskContext* = ref object
caption*: string
timing*: int64
info*: seq[string]
warn*: seq[string]
err*: seq[string]
skipped*: bool

type GlobalContext* = ref object
stop*:bool
timing*: int64
tasks*: OrderedTable[string, TaskContext]
completed*: OrderedTable[string, TaskContext]

var
context = GlobalContext()

context.tasks = initOrderedTable[string, TaskContext]()

proc globalContext*(): GlobalContext =
return context

proc getOrAddContext*(name: string): var TaskContext =
if not context.tasks.contains(name):
let newContext = TaskContext(caption: name, info: @[], err: @[], skipped: true)
context.tasks.add(name, newContext)
return context.tasks[name]
2 changes: 1 addition & 1 deletion nimb.nim
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ let currDir = getCurrentDir()
putEnv("nimbfilePath", currDir)

let nimbfilePath = currDir / buildFile
echo "Nimbfile path: " & nimbfilePath
echo "nimbfile path: " & nimbfilePath

if not existsFile(nimbfilePath):
quit("error: nimb file not found", 1)
Expand Down
18 changes: 11 additions & 7 deletions tasks/assemblyInfo.nim
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
template assemblyinfoOf*(body: untyped) =
proc `assemblyinfoOf Task`*() =
when not declaredInScope(outputPath):
var outputPath {.inject.}: string
var asmversion {.inject.}: Version
var copyright {.inject.}: string
import ../contexts
import version

template assemblyinfoOf*(context: TaskContext; body: untyped) =
when not declaredInScope(outputPath):
var outputPath {.inject.}: string
var asmversion {.inject.}: Version
var copyright {.inject.}: string
proc `assemblyinfoOf Task`*() =
proc `assemblyinfoOf Body`() = body
`assemblyinfoOf Body`()
context.info.add("detected assembly version $1" % [$asmversion])
var buffer = ""
buffer.add("using System.Reflection;\n\c")
buffer.add("using System.Runtime.InteropServices;\n\c")
buffer.add("[assembly: AssemblyVersion(\"$1\")]\n\c" % [asmversion.short()])
buffer.add("[assembly: AssemblyFileVersion(\"$1\")]\n\c" % [asmversion.short()])
buffer.add("[assembly: AssemblyInformationalVersionAttribute(\"$1\")]\n\c" % [asmversion.shortWithDirty()])
buffer.add("[assembly: AssemblyCopyrightAttribute(\"$1\")]\n\c" % [copyright])
writeFile(outputPath / "SolutionVersion.cs", buffer)
writeFile(outputPath / "SolutionVersion.cs", buffer)
context.info.add("file SolutionVersion.cs put in $1" % [outputPath])
12 changes: 12 additions & 0 deletions tasks/cleanbuildfolder.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import ../contexts
import strutils

template cleanBuildFolder*(context: TaskContext; body: untyped) =
when not declaredInScope(buildFolder):
var buildFolder {.inject.}: string
proc `cleanBuildFolder Task`*() =
proc `cleanBuildFolder Body`() = body
`cleanBuildFolder Body`()
removeDir(buildFolder, context.warn)
makeDir(buildFolder, context.err)
context.info.add("cleaned folder $1" % [buildFolder])
34 changes: 34 additions & 0 deletions tasks/dotnet.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import ../contexts
import ../tools/runner

template dotnetbuild*(context: TaskContext; body: untyped) =
when not declaredInScope(slnFile):
var slnFile {.inject.}: string
proc `dotnetbuild Task`*() =
proc `dotnetbuild Body`() = body
`dotnetbuild Body`()
var output = runAbs("dotnet restore " & slnFile.toAbsolutePath, context.err)
context.info.add(output)
output = runAbs("dotnet build " & slnFile.toAbsolutePath, context.err)
context.info.add(output)

template dotnettest*(context: TaskContext; body: untyped) =
when not declaredInScope(testsProject):
var testsProject {.inject.}: string
proc `dotnettest Task`*() =
proc `dotnettest Body`() = body
`dotnettest Body`()
var output = runAbs("dotnet test " & testsProject, context.err)
context.info.add(output)

template dotnetgcfix*(context: TaskContext; body: untyped) =
# specify server gc manually in *.config file
when not declaredInScope(targetConfig):
var targetConfig {.inject.}: string
proc `dotnetgcfix Task`*() =
proc `dotnetgcfix Body`() = body
`dotnetgcfix Body`()
var config = targetConfig.readFile()
config = config.replace(" <runtime>", " <runtime>\r\n <gcServer enabled=\"true\" />")
targetConfig.writeFile(config)
context.info.add("dotnet gc fix was written to $1" % [targetConfig])
39 changes: 18 additions & 21 deletions tasks/filetools.nim
Original file line number Diff line number Diff line change
@@ -1,33 +1,30 @@
import strutils

proc removeDir*(dir: string) =
echo "test"
proc removeDirSafe(dir: string) =
echo "removed $1" % [dir]
let dirs = listDirs(dir)
proc removeDir*(dir: string; errors: var seq[string]) =
let dirs = listDirs(dir)

for dir in dirs:
try:
removeDirSafe(dir)
rmDir(dir)
except: continue
for dir in dirs:
try:
removeDir(dir, errors)
rmDir(dir)
except:
errors.add("can't remove $1" % [dir])
continue

let files = listFiles(dir)
let files = listFiles(dir)

for file in files:
try:
rmFile(file)
except: continue
for file in files:
try:
rmFile(file)
except:
errors.add("can't remove $1" % [file])
continue

removeDirSafe(dir)

proc makeDir*(dir: string) =
proc makeDir*(dir: string; errors: var seq[string]) =
if existsDir(dir):
echo "dir $1 already exists" % [dir]
return

try:
mkDir dir
echo "created dir $1" % [dir]
except:
echo "can't create $1 dir" % [dir]
errors.add("can't create $1 dir" % [dir])
35 changes: 33 additions & 2 deletions tasks/nimbscript.nim
Original file line number Diff line number Diff line change
@@ -1,2 +1,33 @@
template call*(name: untyped) =
`name Task`()
import system
import strutils
import tables
import ../contexts
import ../tools/time
import ../tools/prettyreport

template getContext(name: untyped): TaskContext =
let taskName = astToStr(name)
getOrAddContext(taskName)

template call*(name: untyped) =
if not globalContext().stop:
var taskContext = getContext(name)
let before = getTicks()
`name Task`()
let delta = getTicks() - before
taskContext.timing = delta
taskContext.skipped = false
if taskContext.err.len > 0:
globalContext().stop = true

template nimbTask*(name: untyped; body: untyped): untyped =
var taskContext = getContext(name)
`name`(taskContext, body)

template nimbExecute*(actions: untyped): untyped =
task build, "":
let before = getTicks()
actions
let delta = getTicks() - before
globalContext().timing = delta
prettyReport(globalContext())
30 changes: 17 additions & 13 deletions tasks/nuget.nim
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import strutils
import ospaths
import runner
import ../tools/runner
import buildtools
import ../contexts

template nugetpack*(body: untyped) =
proc logInfo*(self: TaskContext, msg: string): untyped =
self.info.add(msg)

template nugetpack*(context: TaskContext; body: untyped) =
proc `nugetpack Task`*() =
when not declaredInScope(packageId):
var nugetExecutable {.inject.}: string
Expand Down Expand Up @@ -33,8 +37,8 @@ template nugetpack*(body: untyped) =
var filesXml = "\n"
for item in items(files):
filesXml.add(spaces(12) & "<file $1 target=''/>\n" % [item.fillWithQuotes()])

makeDir(outputDir)
makeDir(outputDir, context.err)

let xmlTemplate = """
<?xml version='1.0'?>
Expand Down Expand Up @@ -63,11 +67,12 @@ template nugetpack*(body: untyped) =

nuspecDir = nuspecDir / fullPackageId & ".nuspec"

echo "creating .nuspec for $1 in $2..." % [part, nuspecDir]
context.logInfo("creating .nuspec for $1 in $2..." % [part, nuspecDir])

writeFile(nuspecDir, xml)
echo "created .nuspec for $1 packing..." % [part]
context.logInfo("created .nuspec for $1 packing..." % [part])
let nugetCmd = nugetExecutable & " pack \\\"$1\\\" -OutputDirectory \\\"$2\\\"" % [nuspecDir, outputDir.toAbsolutePath]
echo run nugetCmd
context.logInfo(run(nugetCmd, context.err))

proc add*(param: string): string=
result = "src=$1" % [param]
Expand All @@ -78,7 +83,7 @@ proc add*(str: string, param: string): string=
proc exclude*(str: string, param: string): string=
result = str & " exclude=$1" % [param]

template nugetpush*(body: untyped) =
template nugetpush*(context: TaskContext; body: untyped) =
proc `nugetpush Task`*() =
when not declaredInScope(packageId):
var nugetExecutable {.inject.}: string
Expand All @@ -96,13 +101,12 @@ template nugetpush*(body: untyped) =
if ext != ".nupkg":
continue
if name.contains("dirty"):
echo "nuget $1 is dirty, nugetpush ignored" % [name]
context.logInfo("nuget $1 is dirty, nugetpush ignored" % [name])
continue
let nugetCmd = nugetExecutable & " push \\\"$1\\\" -ApiKey $2 -Source $3" % [file, repoKey, repoUrl]
echo run nugetCmd
echo "completed."
context.logInfo(run(nugetCmd, context.err))

template nugetrestore*(body: untyped) =
template nugetrestore*(context: TaskContext; body: untyped) =
proc `nugetrestore Task`*() =
when not declaredInScope(packageId):
var nugetExecutable {.inject.}: string
Expand All @@ -112,4 +116,4 @@ template nugetrestore*(body: untyped) =
`nugetpack Body`()

let nugetCmd = nugetExecutable & " restore " & dir.toAbsolutePath
echo run nugetCmd
context.logInfo(run(nugetCmd, context.err))
7 changes: 4 additions & 3 deletions tasks/nunit.nim
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import runner
import buildtools
import ../tools/runner
import ../contexts

template nunitrun*(body: untyped) =
template nunitrun*(context: TaskContext; body: untyped) =
proc `nunitrun Task`*() =
when not declaredInScope(outputPath):
var assembliesDir {.inject.}: string
Expand Down Expand Up @@ -57,4 +58,4 @@ template nunitrun*(body: untyped) =

let nunitCmd = "$1 $2 /framework=net-4.5 /result=$3\\NUnit_report.xml /noheader -x86" % [nunitRunnerExe, assembliesList, assembliesDir]

echo run nunitCmd
echo run(nunitCmd, context.err)
7 changes: 3 additions & 4 deletions tasks/version.nim
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import strutils
import runner
import ../tools/runner

type
Version* = object
Expand All @@ -25,8 +25,8 @@ proc short* (version: Version): string =
# parsing output. It looks like: v1.0-0-g69d5874d6aa1cbfd2ef5d5205162b872cccb0471-dirty
proc getVersion*(): Version =
let scriptPath = getEnv("nimbfilePath")
let output = runAbs("git -C $1 describe --abbrev=64 --first-parent --long --dirty --always" % scriptPath)
echo "git output: " & output
var errors: seq[string] = @[]
let output = runAbs("git -C $1 describe --abbrev=64 --first-parent --long --dirty --always" % scriptPath, errors)

let splitMajor = output.split('.')

Expand All @@ -44,5 +44,4 @@ proc getVersion*(): Version =
let splitMinor = output.split('-')
result = Version(major: "0", minor: "0", patch: "0", hash: hash)
result.isDirty = splitMinor.len() > 3
echo "detected version: $1" % [$result]

37 changes: 37 additions & 0 deletions tools/prettyreport.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import ../contexts
import strutils
import tables
import time

proc prettyReport*(context: GlobalContext) =
echo "nimb report"

for task in context.tasks.values:
if task.skipped:
continue

echo task.caption.indent(1, "\t")
for line in task.info:
echo line.indent(2, "\t")

if task.warn.len > 0:
echo "warnings: $1".indent(2, "\t") % [$task.warn.len]
for line in task.warn:
echo line.indent(3, "\t")

if task.err.len > 0:
echo "errors: $1".indent(2, "\t") % [$task.err.len]
for line in task.err:
echo line.indent(3, "\t")

echo "executed tasks:"
for task in context.tasks.values:
if task.skipped:
continue
let taskTiming = float(task.timing) * 0.001
let taskTimingStr = "$1 ms" % [$taskTiming]
let line = "$1 $2" % [task.caption, taskTimingStr]
echo line.indent(1, "\t")

let globalTiming = float(context.timing) * 0.001
echo "nimb done in $1 ms" % [$globalTiming]
Loading

0 comments on commit 4d49925

Please sign in to comment.