From 19b5d3072fc1ebb15fa7d35a0576b4ee6c577f6b Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Wed, 26 Jun 2013 22:45:13 +0100 Subject: [PATCH] Implemented a whitelist mode. --- babel.nim | 116 +++++++++++++++++++++++++++++++++--------------- license.txt | 2 +- packageinfo.nim | 12 +++++ readme.markdown | 7 ++- tools.nim | 7 ++- 5 files changed, 104 insertions(+), 40 deletions(-) diff --git a/babel.nim b/babel.nim index 150fa69..8eb488c 100644 --- a/babel.nim +++ b/babel.nim @@ -107,6 +107,10 @@ proc copyFileD(fro, to: string) = echo(fro, " -> ", to) copyFile(fro, to) +proc copyDirD(fro, to: string) = + echo(fro, " -> ", to) + copyDir(fro, to) + proc doCmd(cmd: string) = let exitCode = execCmd(cmd) if exitCode != QuitSuccess: @@ -122,42 +126,81 @@ template cd(dir: string, body: stmt) = body setCurrentDir(lastDir) +proc checkInstallFile(pkgInfo: TPackageInfo, + origDir, file: string): bool = + ## Checks whether ``file`` should be installed. + ## ``True`` means file should be skipped. + + for ignoreFile in pkgInfo.skipFiles: + if ignoreFile.endswith("babel"): + raise newException(EBabel, ignoreFile & " must be installed.") + if samePaths(file, origDir / ignoreFile): + result = true + break + + for ignoreExt in pkgInfo.skipExt: + if file.splitFile.ext == ('.' & ignoreExt): + result = true + break + + if file.splitFile().name[0] == '.': result = true + +proc checkInstallDir(pkgInfo: TPackageInfo, + origDir, dir: string): bool = + ## Determines whether ``dir`` should be installed. + ## ``True`` means dir should be skipped. + for ignoreDir in pkgInfo.skipDirs: + if samePaths(dir, origDir / ignoreDir): + result = true + break + + let thisDir = splitPath(dir).tail + assert thisDir != "" + if thisDir[0] == '.': result = true + if thisDir == "nimcache": result = true + +proc copyWithExt(origDir, currentDir, dest: string, pkgInfo: TPackageInfo) = + for kind, path in walkDir(currentDir): + if kind == pcDir: + copyWithExt(origDir, path, dest, pkgInfo) + else: + for iExt in pkgInfo.installExt: + if path.splitFile.ext == ('.' & iExt): + createDir(changeRoot(origDir, dest, path).splitFile.dir) + copyFileD(path, changeRoot(origDir, dest, path)) + proc copyFilesRec(origDir, currentDir, dest: string, pkgInfo: TPackageInfo) = ## Copies all the required files, skips files specified in the .babel file ## (TPackageInfo). - for kind, file in walkDir(currentDir): - if kind == pcDir: - var skip = false - for ignoreDir in pkgInfo.skipDirs: - if samePaths(file, origDir / ignoreDir): - skip = true - break - let thisDir = splitPath(file).tail - assert thisDir != "" - if thisDir[0] == '.': skip = true - if thisDir == "nimcache": skip = true - - if skip: continue - # Create the dir. - createDir(changeRoot(origDir, dest, file)) - - copyFilesRec(origDir, file, dest, pkgInfo) - else: - var skip = false - if file.splitFile().name[0] == '.': skip = true - for ignoreFile in pkgInfo.skipFiles: - if ignoreFile.endswith("babel"): - raise newException(EBabel, ignoreFile & " must be installed.") - if samePaths(file, origDir / ignoreFile): - skip = true - break - - for ignoreExt in pkgInfo.skipExt: - if file.splitFile.ext == ('.' & ignoreExt): - skip = true - break - - if not skip: + let whitelistMode = + pkgInfo.installDirs.len != 0 or + pkgInfo.installFiles.len != 0 or + pkgInfo.installExt.len != 0 + if whitelistMode: + for file in pkgInfo.installFiles: + createDir(dest / file.splitFile.dir) + copyFileD(origDir / file, dest / file) + + for dir in pkgInfo.installDirs: + # TODO: Allow skipping files inside dirs? + copyDirD(origDir / dir, dest / dir) + + copyWithExt(origDir, currentDir, dest, pkgInfo) + else: + for kind, file in walkDir(currentDir): + if kind == pcDir: + let skip = pkgInfo.checkInstallDir(origDir, file) + + if skip: continue + # Create the dir. + createDir(changeRoot(origDir, dest, file)) + + copyFilesRec(origDir, file, dest, pkgInfo) + else: + let skip = pkgInfo.checkInstallFile(origDir, file) + + if skip: continue + copyFileD(file, changeRoot(origDir, dest, file)) proc install(packages: seq[String], verRange: PVersionRange): string {.discardable.} @@ -220,12 +263,13 @@ proc installFromDir(dir: string, latest: bool): string = buildFromDir(dir, paths) createDir(binDir) # Copy all binaries and files that are not skipped - var nPkgInfo = pkgInfo - nPkgInfo.skipExt.add("nim") # Implicitly skip .nim files - copyFilesRec(dir, dir, pkgDestDir, nPkgInfo) + copyFilesRec(dir, dir, pkgDestDir, pkgInfo) # Set file permissions to +x for all binaries built, # and symlink them on *nix OS' to $babelDir/bin/ for bin in pkgInfo.bin: + if not existsFile(pkgDestDir / bin): + copyFileD(dir / bin, pkgDestDir / bin) + let currentPerms = getFilePermissions(pkgDestDir / bin) setFilePermissions(pkgDestDir / bin, currentPerms + {fpUserExec}) when defined(unix): diff --git a/license.txt b/license.txt index 115cca2..7767636 100644 --- a/license.txt +++ b/license.txt @@ -1,4 +1,4 @@ -Copyright (c) 2012, Dominik Picheta +Copyright (c) 2013, Dominik Picheta All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/packageinfo.nim b/packageinfo.nim index fcdd90c..30f4ca3 100644 --- a/packageinfo.nim +++ b/packageinfo.nim @@ -13,6 +13,9 @@ type skipDirs*: seq[string] skipFiles*: seq[string] skipExt*: seq[string] + installDirs*: seq[string] + installFiles*: seq[string] + installExt*: seq[string] requires*: seq[tuple[name: string, ver: PVersionRange]] bin*: seq[string] @@ -36,6 +39,9 @@ proc initPackageInfo(): TPackageInfo = result.skipDirs = @[] result.skipFiles = @[] result.skipExt = @[] + result.installDirs = @[] + result.installFiles = @[] + result.installExt = @[] result.requires = @[] result.bin = @[] @@ -93,6 +99,12 @@ proc readPackageInfo*(path: string): TPackageInfo = result.skipFiles.add(ev.value.split(',')) of "skipext": result.skipExt.add(ev.value.split(',')) + of "installdirs": + result.installDirs.add(ev.value.split(',')) + of "installfiles": + result.installFiles.add(ev.value.split(',')) + of "installext": + result.installExt.add(ev.value.split(',')) of "bin": for i in ev.value.split(','): result.bin.add(i.addFileExt(ExeExt)) diff --git a/readme.markdown b/readme.markdown index 2801033..16e6d66 100644 --- a/readme.markdown +++ b/readme.markdown @@ -53,7 +53,10 @@ structure may be enforced in the future. All files and folders in the directory of where the .babel file resides will be copied as-is, you can however skip some directories or files by setting -the 'SkipDirs' or 'SkipFiles' options in your .babel file. +the ``SkipDirs``, ``SkipFiles`` or ``SkipExt`` options in your .babel file. +Directories and files can also be specified on a *whitelist* basis, if you +specify either of ``InstallDirs``, ``InstallFiles`` or ``InstallExt`` then +babel will **only** install the files specified. #### Example library .babel file @@ -90,6 +93,8 @@ file, copy it into ``$babelDir/pkgs/pkgname-ver/`` and subsequently create a symlink to the binary in ``$babelDir/bin/``. On Windows a stub .bat file is created instead. +Other files will be copied in the same way as they are for library packages. + Dependencies are automatically installed before building. ## Dependencies diff --git a/tools.nim b/tools.nim index 2bb7f14..13eb1e3 100644 --- a/tools.nim +++ b/tools.nim @@ -14,8 +14,11 @@ proc getNimrodVersion*: TVersion = proc samePaths*(p1, p2: string): bool = ## Normalizes path (by adding a trailing slash) and compares. - let cp1 = if not p1.endsWith("/"): p1 & "/" else: p1 - let cp2 = if not p2.endsWith("/"): p2 & "/" else: p2 + var cp1 = if not p1.endsWith("/"): p1 & "/" else: p1 + var cp2 = if not p2.endsWith("/"): p2 & "/" else: p2 + cp1 = cp1.replace('/', DirSep).replace('\\', DirSep) + cp2 = cp2.replace('/', DirSep).replace('\\', DirSep) + return cmpPaths(cp1, cp2) == 0 proc changeRoot*(origRoot, newRoot, path: string): string =