# # # Maintenance program for Nim # (c) Copyright 2017 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # # See doc/koch.txt for documentation. # when defined(gcc) and defined(windows): when defined(x86): {.link: "icons/koch.res".} else: {.link: "icons/koch_icon.o".} when defined(amd64) and defined(windows) and defined(vcc): {.link: "icons/koch-amd64-windows-vcc.res" .} when defined(i386) and defined(windows) and defined(vcc): {.link: "icons/koch-i386-windows-vcc.res" .} import os, strutils, parseopt, osproc, streams const VersionAsString = system.NimVersion const HelpText = """ +-----------------------------------------------------------------+ | Maintenance program for Nim | | Version $1| | (c) 2017 Andreas Rumpf | +-----------------------------------------------------------------+ Build time: $2, $3 Usage: koch [options] command [options for command] Options: --help, -h shows this help and quits Possible Commands: boot [options] bootstraps with given command line options distrohelper [bindir] helper for distro packagers tools builds Nim related tools nimble builds the Nimble tool Boot options: -d:release produce a release version of the compiler -d:useLinenoise use the linenoise library for interactive mode (not needed on Windows) -d:avoidTimeMachine only for Mac OS X, excludes nimcache dir from backups Commands for core developers: web [options] generates the website and the full documentation website [options] generates only the website csource -d:release builds the C sources for installation pdf builds the PDF documentation zip builds the installation zip package xz builds the installation tar.xz package testinstall test tar.xz package; Unix only! tests [options] run the testsuite temp options creates a temporary compiler for testing winrelease creates a Windows release pushcsource push generated C sources to its repo Web options: --googleAnalytics:UA-... add the given google analytics code to the docs. To build the official docs, use UA-48159761-1 """ const gaCode = " --googleAnalytics:UA-48159761-1" proc exe(f: string): string = result = addFileExt(f, ExeExt) when defined(windows): result = result.replace('/','\\') template withDir(dir, body) = let old = getCurrentDir() try: setCurrentDir(dir) body finally: setCurrentdir(old) proc findNim(): string = var nim = "nim".exe result = "bin" / nim if existsFile(result): return for dir in split(getEnv("PATH"), PathSep): if existsFile(dir / nim): return dir / nim # assume there is a symlink to the exe or something: return nim proc exec(cmd: string, errorcode: int = QuitFailure, additionalPath = "") = let prevPath = getEnv("PATH") if additionalPath.len > 0: var absolute = additionalPATH if not absolute.isAbsolute: absolute = getCurrentDir() / absolute echo("Adding to $PATH: ", absolute) putEnv("PATH", (if prevPath.len > 0: prevPath & PathSep else: "") & absolute) echo(cmd) if execShellCmd(cmd) != 0: quit("FAILURE", errorcode) putEnv("PATH", prevPath) proc nimexec(cmd: string) = exec findNim() & " " & cmd proc execCleanPath(cmd: string, additionalPath = ""; errorcode: int = QuitFailure) = # simulate a poor man's virtual environment let prevPath = getEnv("PATH") when defined(windows): let CleanPath = r"$1\system32;$1;$1\System32\Wbem" % getEnv"SYSTEMROOT" else: const CleanPath = r"/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin" putEnv("PATH", CleanPath & PathSep & additionalPath) echo(cmd) if execShellCmd(cmd) != 0: quit("FAILURE", errorcode) putEnv("PATH", prevPath) proc testUnixInstall() = let oldCurrentDir = getCurrentDir() try: let destDir = getTempDir() copyFile("build/nim-$1.tar.xz" % VersionAsString, destDir / "nim-$1.tar.xz" % VersionAsString) setCurrentDir(destDir) execCleanPath("tar -xJf nim-$1.tar.xz" % VersionAsString) setCurrentDir("nim-$1" % VersionAsString) execCleanPath("sh build.sh") # first test: try if './bin/nim --version' outputs something sane: let output = execProcess("./bin/nim --version").splitLines if output.len > 0 and output[0].contains(VersionAsString): echo "Version check: success" execCleanPath("./bin/nim c koch.nim") execCleanPath("./koch boot -d:release", destDir / "bin") # check the docs build: execCleanPath("./koch web", destDir / "bin") # check nimble builds: execCleanPath("./koch tools") # check the tests work: execCleanPath("./koch tests", destDir / "bin") else: echo "Version check: failure" finally: setCurrentDir oldCurrentDir proc tryExec(cmd: string): bool = echo(cmd) result = execShellCmd(cmd) == 0 proc safeRemove(filename: string) = if existsFile(filename): removeFile(filename) proc overwriteFile(source, dest: string) = safeRemove(dest) moveFile(source, dest) proc copyExe(source, dest: string) = safeRemove(dest) copyFile(dest=dest, source=source) inclFilePermissions(dest, {fpUserExec}) const compileNimInst = "tools/niminst/niminst" proc csource(args: string) = nimexec(("cc $1 -r $3 --var:version=$2 --var:mingw=none csource " & "--main:compiler/nim.nim compiler/installer.ini $1") % [args, VersionAsString, compileNimInst]) proc bundleNimbleSrc() = ## bunldeNimbleSrc() bundles a specific Nimble commit with the tarball. We ## always bundle the latest official release. if not dirExists("dist/nimble/.git"): exec("git clone https://github.com/nim-lang/nimble.git dist/nimble") withDir("dist/nimble"): exec("git checkout -f stable") exec("git pull") proc bundleNimbleExe() = bundleNimbleSrc() # now compile Nimble and copy it to $nim/bin for the installer.ini # to pick it up: nimexec("c -d:release dist/nimble/src/nimble.nim") copyExe("dist/nimble/src/nimble".exe, "bin/nimble".exe) proc buildNimble(latest: bool) = # old installations created nim/nimblepkg/*.nim files. We remove these # here so that it cannot cause problems (nimble bug #306): if dirExists("bin/nimblepkg"): removeDir("bin/nimblepkg") # if koch is used for a tar.xz, build the dist/nimble we shipped # with the tarball: var installDir = "dist/nimble" if not latest and dirExists(installDir) and not dirExists("dist/nimble/.git"): discard "don't do the git dance" else: if not dirExists("dist/nimble/.git"): if dirExists(installDir): var id = 0 while dirExists("dist/nimble" & $id): inc id installDir = "dist/nimble" & $id exec("git clone https://github.com/nim-lang/nimble.git " & installDir) withDir(installDir): if latest: exec("git checkout -f master") else: exec("git checkout -f stable") exec("git pull") nimexec("c --noNimblePath -p:compiler -d:release " & installDir / "src/nimble.nim") copyExe(installDir / "src/nimble".exe, "bin/nimble".exe) proc bundleNimsuggest(buildExe: bool) = if buildExe: nimexec("c --noNimblePath -d:release -p:compiler nimsuggest/nimsuggest.nim") copyExe("nimsuggest/nimsuggest".exe, "bin/nimsuggest".exe) removeFile("nimsuggest/nimsuggest".exe) proc buildVccTool() = nimexec("c -o:bin/vccexe.exe tools/vccenv/vccexe") proc bundleWinTools() = nimexec("c tools/finish.nim") copyExe("tools/finish".exe, "finish".exe) removeFile("tools/finish".exe) buildVccTool() nimexec("c -o:bin/nimgrab.exe -d:ssl tools/nimgrab.nim") nimexec("c -o:bin/nimgrep.exe tools/nimgrep.nim") when false: # not yet a tool worth including nimexec(r"c --cc:vcc --app:gui -o:bin\downloader.exe -d:ssl --noNimblePath " & r"--path:..\ui tools\downloader.nim") proc zip(args: string) = bundleNimbleExe() bundleNimsuggest(true) bundleWinTools() nimexec("cc -r $2 --var:version=$1 --var:mingw=none --main:compiler/nim.nim scripts compiler/installer.ini" % [VersionAsString, compileNimInst]) exec("$# --var:version=$# --var:mingw=none --main:compiler/nim.nim zip compiler/installer.ini" % ["tools/niminst/niminst".exe, VersionAsString]) proc xz(args: string) = bundleNimbleSrc() bundleNimsuggest(false) nimexec("cc -r $2 --var:version=$1 --var:mingw=none --main:compiler/nim.nim scripts compiler/installer.ini" % [VersionAsString, compileNimInst]) exec("$# --var:version=$# --var:mingw=none --main:compiler/nim.nim xz compiler/installer.ini" % ["tools" / "niminst" / "niminst".exe, VersionAsString]) proc buildTool(toolname, args: string) = nimexec("cc $# $#" % [args, toolname]) copyFile(dest="bin"/ splitFile(toolname).name.exe, source=toolname.exe) proc buildTools(latest: bool) = let nimsugExe = "bin/nimsuggest".exe nimexec "c --noNimblePath -p:compiler -d:release -o:" & nimsugExe & " nimsuggest/nimsuggest.nim" let nimgrepExe = "bin/nimgrep".exe nimexec "c -d:release -o:" & nimgrepExe & " tools/nimgrep.nim" when defined(windows): buildVccTool() #nimexec "c -o:" & ("bin/nimresolve".exe) & " tools/nimresolve.nim" buildNimble(latest) proc nsis(args: string) = bundleNimbleExe() bundleNimsuggest(true) bundleWinTools() # make sure we have generated the niminst executables: buildTool("tools/niminst/niminst", args) #buildTool("tools/nimgrep", args) # produce 'nim_debug.exe': #exec "nim c compiler" / "nim.nim" #copyExe("