diff options
-rw-r--r-- | src/config.nim | 45 | ||||
-rw-r--r-- | src/main.nim | 13 | ||||
-rw-r--r-- | src/pacman.nim | 57 |
3 files changed, 71 insertions, 44 deletions
diff --git a/src/config.nim b/src/config.nim index 2aa9974..be27291 100644 --- a/src/config.nim +++ b/src/config.nim @@ -20,14 +20,16 @@ type progressBar*: bool verbosePkgList*: bool pgpKeyserver*: Option[string] + defaultRoot*: bool ignorePkgs*: HashSet[string] ignoreGroups*: HashSet[string] PacmanConfig* = object of CommonConfig - rootOption*: Option[string] - dbOption*: Option[string] - cacheOption*: Option[string] - gpgOption*: Option[string] + sysrootOption*: Option[string] + rootRelOption*: Option[string] + dbRelOption*: Option[string] + cacheRelOption*: Option[string] + gpgRelOption*: Option[string] colorMode*: ColorMode Config* = object of CommonConfig @@ -95,36 +97,42 @@ proc readConfigFile*(configFile: string): proc ignored*(config: Config, name: string, groups: openArray[string]): bool = name in config.ignorePkgs or (config.ignoreGroups * groups.toSet).len > 0 -proc isRootDefault*(config: Config): bool = - config.root == "/" - proc get*(colorMode: ColorMode): bool = case colorMode: of ColorMode.colorNever: false of ColorMode.colorAlways: true of ColorMode.colorAuto: isatty(1) == 1 -proc root*(config: PacmanConfig): string = - config.rootOption.get("/") +proc pacmanRootRel*(config: PacmanConfig): string = + config.rootRelOption.get("/") -proc db*(config: PacmanConfig): string = - if config.dbOption.isSome: - config.dbOption.unsafeGet +proc pacmanDbRel*(config: PacmanConfig): string = + if config.dbRelOption.isSome: + config.dbRelOption.unsafeGet else: - let root = config.root + let root = config.pacmanRootRel let workRoot = if root == "/": "" else: root workRoot & localStateDir & "/lib/pacman/" -proc cache*(config: PacmanConfig): string = - config.cacheOption.get(localStateDir & "/cache/pacman/pkg") +proc pacmanCacheRel*(config: PacmanConfig): string = + config.cacheRelOption.get(localStateDir & "/cache/pacman/pkg") + +proc simplifyConfigPath(path: string): string = + if path.find("//") >= 0: + simplifyConfigPath(path.replace("//", "/")) + else: + path + +proc extendRel*(pathRel: string, sysroot: Option[string]): string = + sysroot.map(s => (s & "/" & pathRel).simplifyConfigPath).get(pathRel) proc obtainConfig*(config: PacmanConfig): Config = let (configTable, _) = readConfigFile(sysConfDir & "/pakku.conf") let options = configTable.opt("options").map(t => t[]).get(initTable[string, string]()) - let root = config.root - let db = config.db - let cache = config.cache + let root = config.pacmanRootRel.extendRel(config.sysrootOption) + let db = config.pacmanDbRel.extendRel(config.sysrootOption) + let cache = config.pacmanCacheRel.extendRel(config.sysrootOption) let color = config.colorMode.get proc handleDirPattern(dirPattern: string, user: User): string = @@ -160,6 +168,7 @@ proc obtainConfig*(config: PacmanConfig): Config = tmpRootInitial: tmpRootInitial, tmpRootCurrent: tmpRootCurrent, color: color, dbs: config.dbs, arch: config.arch, debug: config.debug, progressBar: config.progressBar, verbosePkgList: config.verbosePkgList, pgpKeyserver: config.pgpKeyserver, + defaultRoot: config.defaultRoot and config.sysrootOption.isNone, ignorePkgs: config.ignorePkgs, ignoreGroups: config.ignoreGroups, aurComments: aurComments, checkIgnored: checkIgnored, printAurNotFound: printAurNotFound, sudoExec: sudoExec, viewNoDefault: viewNoDefault, preserveBuilt: preserveBuilt, diff --git a/src/main.nim b/src/main.nim index 7171716..54fbb08 100644 --- a/src/main.nim +++ b/src/main.nim @@ -9,6 +9,10 @@ import "feature/syncsource", "feature/localquery" +proc execSudo*(args: seq[Argument]): int = + execResult(sudoPrefix & getAppFilename() & + lc[x | (y <- args, x <- y.collectArg), string]) + proc passValidation(args: seq[Argument], config: Config, nonRootArgs: openArray[OptionPair], rootArgs: openArray[OptionPair], opts: varargs[seq[CommandOption]]): int = @@ -90,11 +94,9 @@ proc handleSync(args: seq[Argument], config: Config): int = let printMode = args.check(%%%"print") or args.check(%%%"print-format") if currentUser.uid != 0 and config.sudoExec and not printMode: - let collectedArgs = sudoPrefix & getAppFilename() & - lc[x | (y <- args, x <- y.collectArg), string] - execResult(collectedArgs) + execSudo(args) else: - let isNonDefaultRoot = not config.isRootDefault + let isNonDefaultRoot = not config.defaultRoot let isRootNoDrop = currentUser.uid == 0 and not canDropPrivileges() let build = args.check(%%%"build") @@ -225,6 +227,9 @@ let init = withErrorHandler(none(bool), parsedArgs.check((some("V"), "version")): let code = handleVersion() raise haltError(code) + elif parsedArgs.check(%%%"sysroot") and currentUser.uid != 0: + let code = execSudo(parsedArgs) + raise haltError(code) else: let pacmanConfig = obtainPacmanConfig(parsedArgs) let config = obtainConfig(pacmanConfig) diff --git a/src/pacman.nim b/src/pacman.nim index af8902b..067906d 100644 --- a/src/pacman.nim +++ b/src/pacman.nim @@ -84,6 +84,7 @@ const ^o("logfile"), o("noconfirm"), o("confirm"), + ^o("sysroot"), ^o("ask") ] @@ -278,9 +279,9 @@ proc pacmanRun*(root: bool, color: bool, args: varargs[Argument]): int = let argsSeq = @args forkWait(() => pacmanExec(root, color, argsSeq)) -proc pacmanValidateAndThrow(args: varargs[Argument]): void = +proc pacmanValidateAndThrow(args: varargs[tuple[arg: Argument, pass: bool]]): void = let argsSeq = @args - let collectedArgs = lc[x | (y <- argsSeq, x <- y.collectArg), string] + let collectedArgs = lc[x | (y <- argsSeq, y.pass, x <- y.arg.collectArg), string] let code = forkWait(() => pacmanExecInternal(false, "-T" & collectedArgs)) if code != 0: raise haltError(code) @@ -291,10 +292,10 @@ proc getMachineName: Option[string] = if length > 0: some(utsname.machine.toString(some(length))) else: none(string) proc createConfigFromTable(table: Table[string, string], dbs: seq[string]): PacmanConfig = - let root = table.opt("RootDir") - let db = table.opt("DBPath") - let cache = table.opt("CacheDir") - let gpg = table.opt("GPGDir") + let rootRel = table.opt("RootDir") + let dbRel = table.opt("DBPath") + let cacheRel = table.opt("CacheDir") + let gpgRel = table.opt("GPGDir") let color = if table.hasKey("Color"): ColorMode.colorAuto else: ColorMode.colorNever let verbosePkgList = table.hasKey("VerbosePkgLists") let arch = table.opt("Architecture").get("auto") @@ -306,33 +307,38 @@ proc createConfigFromTable(table: Table[string, string], dbs: seq[string]): Pacm raise commandError(tr"can not get the architecture", colorNeeded = some(color.get)) - PacmanConfig(rootOption: root, dbOption: db, cacheOption: cache, gpgOption: gpg, + PacmanConfig(sysrootOption: none(string), rootRelOption: rootRel, + dbRelOption: dbRel, cacheRelOption: cacheRel, gpgRelOption: gpgRel, dbs: dbs, arch: archFinal, colorMode: color, debug: false, progressBar: true, - verbosePkgList: verbosePkgList, pgpKeyserver: none(string), + verbosePkgList: verbosePkgList, pgpKeyserver: none(string), defaultRoot: true, ignorePkgs: ignorePkgs, ignoreGroups: ignoreGroups) proc obtainPacmanConfig*(args: seq[Argument]): PacmanConfig = proc getAll(pair: OptionPair): seq[string] = args.filter(arg => arg.matchOption(pair)).map(arg => arg.value.get) - let configFile = getAll(%%%"config").optLast.get(sysConfDir & "/pacman.conf") - let (configTable, wasError) = readConfigFile(configFile) + let sysroot = args.filter(a => a.matchOption(%%%"sysroot")).optFirst.map(a => a.value).flatten + + let configFileRel = getAll(%%%"config").optLast.get(sysConfDir & "/pacman.conf") + let (configTable, wasError) = readConfigFile(configFileRel.extendRel(sysroot)) let options = configTable.opt("options").map(t => t[]).get(initTable[string, string]()) let dbs = toSeq(configTable.keys).filter(k => k != "options") let defaultConfig = createConfigFromTable(options, dbs) if wasError: - pacmanValidateAndThrow(("config", some(configFile), ArgumentType.long)) + pacmanValidateAndThrow((("sysroot", sysroot, ArgumentType.long), sysroot.isSome), + (("config", some(configFileRel), ArgumentType.long), true)) + raise haltError(1) proc getColor(color: string): ColorMode = let colors = toSeq(enumerate[ColorMode]()) colors.filter(c => $c == color).optLast.get(ColorMode.colorNever) - let root = getAll(%%%"root").optLast.orElse(defaultConfig.rootOption) - let db = getAll(%%%"dbpath").optLast.orElse(defaultConfig.dbOption) - let cache = getAll(%%%"cachedir").optLast.orElse(defaultConfig.cacheOption) - let gpg = getAll(%%%"gpgdir").optLast.orElse(defaultConfig.gpgOption) + let rootRel = getAll(%%%"root").optLast.orElse(defaultConfig.rootRelOption) + let dbRel = getAll(%%%"dbpath").optLast.orElse(defaultConfig.dbRelOption) + let cacheRel = getAll(%%%"cachedir").optLast.orElse(defaultConfig.cacheRelOption) + let gpgRel = getAll(%%%"gpgdir").optLast.orElse(defaultConfig.gpgRelOption) let arch = getAll(%%%"arch").optLast.get(defaultConfig.arch) let colorStr = getAll(%%%"color").optLast.get($defaultConfig.colorMode) let color = getColor(colorStr) @@ -362,7 +368,7 @@ proc obtainPacmanConfig*(args: seq[Argument]): PacmanConfig = else: var pgpKeyserver = none(string) var file: File - if file.open(gpg.get(sysConfDir & "/pacman.d/gnupg") & "/gpg.conf"): + if file.open(gpgRel.get(sysConfDir & "/pacman.d/gnupg").extendRel(sysroot) & "/gpg.conf"): try: while true: let line = file.readLine() @@ -374,19 +380,26 @@ proc obtainPacmanConfig*(args: seq[Argument]): PacmanConfig = file.close() pgpKeyserver) - let config = PacmanConfig(rootOption: root, dbOption: db, cacheOption: cache, gpgOption: gpg, + let defaultRootRel = defaultConfig.rootRelOption.get("/") + let argsRootRel = rootRel.get("/") + let defaultRoot = defaultRootRel == argsRootRel + + let config = PacmanConfig(sysrootOption: sysroot, rootRelOption: rootRel, + dbRelOption: dbRel, cacheRelOption: cacheRel, gpgRelOption: gpgRel, dbs: defaultConfig.dbs, arch: arch, colorMode: color, debug: debug, progressBar: progressBar, verbosePkgList: defaultConfig.verbosePkgList, - pgpKeyserver: pgpKeyserver, ignorePkgs: ignorePkgs + defaultConfig.ignorePkgs, + pgpKeyserver: pgpKeyserver, defaultRoot: defaultRoot, + ignorePkgs: ignorePkgs + defaultConfig.ignorePkgs, ignoreGroups: ignoreGroups + defaultConfig.ignoreGroups) if config.dbs.find("aur") >= 0: raise commandError(tr"repo '$#' is reserved by this program" % ["aur"], colorNeeded = some(color.get)) - pacmanValidateAndThrow(("root", some(config.root), ArgumentType.long), - ("dbpath", some(config.db), ArgumentType.long), - ("arch", some(config.arch), ArgumentType.long), - ("color", some(colorStr), ArgumentType.long)) + pacmanValidateAndThrow((("sysroot", sysroot, ArgumentType.long), sysroot.isSome), + (("root", some(config.pacmanRootRel), ArgumentType.long), not defaultRoot), + (("dbpath", some(config.pacmanDbRel), ArgumentType.long), true), + (("arch", some(config.arch), ArgumentType.long), true), + (("color", some(colorStr), ArgumentType.long), true)) config |