aboutsummaryrefslogtreecommitdiff
path: root/src/main.nim
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.nim')
-rw-r--r--src/main.nim260
1 files changed, 260 insertions, 0 deletions
diff --git a/src/main.nim b/src/main.nim
new file mode 100644
index 0000000..9e98c30
--- /dev/null
+++ b/src/main.nim
@@ -0,0 +1,260 @@
+import
+ future, options, os, posix, re, sequtils, strutils,
+ args, config, format, pacman, utils
+
+import
+ "feature/syncinfo",
+ "feature/syncsearch",
+ "feature/syncinstall",
+ "feature/localquery"
+
+proc passValidation(args: seq[Argument], config: Config,
+ nonRootArgs: openArray[OptionPair], rootArgs: openArray[OptionPair],
+ opts: varargs[seq[CommandOption]]): int =
+ let checkArgs = args.filterOptions(true, false, true, opts)
+
+ if checkArgs.len == 0:
+ let needRoot = (nonRootArgs.len == 0 and args.check(rootArgs)) or
+ (nonRootArgs.len > 0 and (not args.check(nonRootArgs) or args.check(rootArgs)))
+ return pacmanExec(needRoot, config.color, args.filterExtensions(true, true))
+ else:
+ let extensions = args.filterExtensions(false, false)
+ if extensions.len == 0:
+ return pacmanExec(false, config.color, args)
+ else:
+ let arg = extensions[0]
+ if arg.isShort:
+ raise commandError(trp("invalid option '-%c'\n").strip
+ .replace("%c", "$#") % arg.key)
+ else:
+ raise commandError(trp("invalid option '--%s'\n").strip
+ .replace("%s", "$#") % arg.key)
+
+proc handleDatabase(args: seq[Argument], config: Config): int =
+ let nonRootArgs = [
+ (some("k"), "check")
+ ]
+
+ passValidation(args, config, nonRootArgs, [],
+ commonOptions, databaseOptions)
+
+proc handleFiles(args: seq[Argument], config: Config): int =
+ let rootArgs = [
+ (some("y"), "refresh")
+ ]
+
+ passValidation(args, config, [], rootArgs,
+ commonOptions, filesOptions)
+
+proc handleQuery(args: seq[Argument], config: Config): int =
+ let queryArgs = args.removeMatchOptions(commonOptions)
+
+ if queryArgs.checkOpGroup(OpGroup.localQuery) and
+ not queryArgs.check((some("e"), "explicit")) and
+ queryArgs.check((some("d"), "deps")) and
+ queryArgs.count((some("t"), "unrequired")) >= 3:
+ handleQueryOrphans(args, config)
+ else:
+ passValidation(args, config, [], [],
+ commonOptions, queryOptions)
+
+proc handleRemove(args: seq[Argument], config: Config): int =
+ let nonRootArgs = [
+ (some("p"), "print"),
+ (none(string), "print-format")
+ ]
+
+ passValidation(args, config, nonRootArgs, [],
+ commonOptions, transactionOptions, removeOptions)
+
+proc handleSync(args: seq[Argument], config: Config): int =
+ let syncArgs = args.removeMatchOptions(commonOptions, transactionOptions, upgradeOptions)
+ let conflict = args.checkConflicts(syncConflictingOptions)
+
+ if conflict.isSome:
+ let (left, right) = conflict.unsafeGet
+ printError(config.color, trp("invalid option: '%s' and '%s' may not be used together\n") %
+ ["--" & left, "--" & right])
+ 1
+ elif syncArgs.check((some("i"), "info")) and
+ syncArgs.checkOpGroup(OpGroup.syncQuery):
+ handleSyncInfo(args, config)
+ elif syncArgs.check((some("s"), "search")) and
+ syncArgs.checkOpGroup(OpGroup.syncSearch):
+ handleSyncSearch(args, config)
+ elif syncArgs.checkOpGroup(OpGroup.syncInstall) and
+ (args.check((some("u"), "sysupgrade")) or args.targets.len > 0):
+ let isNonDefaultRoot = not config.isRootDefault
+ let isDowngrade = args.count((some("u"), "sysupgrade")) >= 2
+ let isSkipDeps = args.check((some("d"), "nodeps"))
+ let isRoot = getuid() == 0
+
+ let build = args.check((none(string), "build"))
+ let noaur = args.check((none(string), "noaur"))
+
+ let noBuild = isNonDefaultRoot or isDowngrade or isSkipDeps or isRoot
+
+ if build and noBuild:
+ if isNonDefaultRoot:
+ printError(config.color, tr"non-default root path is specified" & " -- " &
+ tr"building is not allowed")
+ elif isDowngrade:
+ printError(config.color, tr"downgrades are enabled" & " -- " &
+ tr"building is not allowed")
+ elif isSkipDeps:
+ printError(config.color, tr"dependency check is skipped" & " -- " &
+ tr"building is not allowed")
+ elif isRoot:
+ printError(config.color, tr"running as root" & " -- " &
+ tr"building is not allowed")
+ 1
+ else:
+ let noaurAdd = noBuild and not noaur
+
+ if noaurAdd:
+ if isNonDefaultRoot:
+ printWarning(config.color, tr"non-default root path is specified" & " -- " &
+ tr"'$#' is assumed" % ["--noaur"])
+ elif isDowngrade:
+ printWarning(config.color, tr"downgrades are enabled" & " -- " &
+ tr"'$#' is assumed" % ["--noaur"])
+ elif isSkipDeps:
+ printWarning(config.color, tr"dependency check is skipped" & " -- " &
+ tr"'$#' is assumed" % ["--noaur"])
+ elif isRoot:
+ printWarning(config.color, tr"running as root" & " -- " &
+ tr"'$#' is assumed" % ["--noaur"])
+
+ if noaurAdd:
+ handleSyncInstall(args & ("noaur", none(string), ArgumentType.long), config)
+ else:
+ handleSyncInstall(args, config)
+ else:
+ let nonRootArgs = [
+ (some("p"), "print"),
+ (none(string), "print-format"),
+ (some("g"), "groups"),
+ (some("i"), "info"),
+ (some("l"), "list"),
+ (some("s"), "search")
+ ]
+
+ let rootArgs = [
+ (some("y"), "refresh"),
+ ]
+
+ passValidation(args, config, nonRootArgs, rootArgs,
+ commonOptions, transactionOptions, upgradeOptions, syncOptions)
+
+proc handleDeptest(args: seq[Argument], config: Config): int =
+ passValidation(args, config, [], [], commonOptions)
+
+proc handleUpgrade(args: seq[Argument], config: Config): int =
+ let nonRootArgs = [
+ (some("p"), "print"),
+ (none(string), "print-format")
+ ]
+
+ passValidation(args, config, nonRootArgs, [],
+ commonOptions, transactionOptions, upgradeOptions)
+
+proc handleHelp(operation: OperationType) =
+ proc printHelp(command: string, text: string) =
+ echo(' '.repeat(6), "--", command, ' '.repeat(15 - command.len), text)
+
+ let operationArgs = operations
+ .filter(o => o.otype == operation)
+ .map(o => @["-" & o.pair.short.get])
+ .optFirst.get(@[]) & @["-h"]
+
+ let lines = runProgram(pacmanCmd & operationArgs)
+
+ for line in lines:
+ echo(line.replace(re"\bpacman\b", "pakku"))
+
+ if lines.len > 0:
+ case operation:
+ of OperationType.sync:
+ printHelp("build", tr"build targets from source")
+ printHelp("noaur", tr"disable all AUR operations")
+ else:
+ discard
+
+const
+ version = $getenv("PROG_VERSION")
+ copyright = $getenv("PROG_COPYRIGHT")
+
+proc handleVersion(): int =
+ echo()
+ echo(' '.repeat(23), "Pakku v", version)
+ echo(' '.repeat(23), "Copyright (C) ", copyright)
+ pacmanExec(false, false, ("V", none(string), ArgumentType.short))
+
+proc signal(sign: cint, handler: pointer): pointer
+ {.importc, header: "<signal.h>".}
+
+discard setlocale(LC_ALL, "")
+discard signal(SIGINT, cast[pointer](SIG_DFL))
+
+template withErrorHandler(propColor: Option[bool], T: typedesc, body: untyped):
+ tuple[success: Option[T], code: int] =
+ try:
+ (some(body), 0)
+ except HaltError:
+ let e = (ref HaltError) getCurrentException()
+ (none(T), e.code)
+ except CommandError:
+ let e = (ref CommandError) getCurrentException()
+ if e.error:
+ printError(e.color.orElse(propColor).get(false), e.msg)
+ else:
+ stderr.writeLine(e.msg)
+ (none(T), 1)
+
+let init = withErrorHandler(none(bool),
+ tuple[parsedArgs: seq[Argument], config: Config]):
+ let parsedArgs = splitArgs(commandLineParams(), optionsWithParameter)
+ let pacmanConfig = obtainPacmanConfig(parsedArgs)
+ let config = obtainConfig(pacmanConfig)
+ (parsedArgs, config)
+
+proc run(parsedArgs: seq[Argument], config: Config):
+ tuple[success: Option[int], code: int] =
+ withErrorHandler(some(config.color), int):
+ let operation = getOperation(parsedArgs)
+ if operation != OperationType.invalid and
+ parsedArgs.check((some("h"), "help")):
+ handleHelp(operation)
+ 0
+ elif operation != OperationType.invalid and
+ parsedArgs.check((some("V"), "version")):
+ handleVersion()
+ else:
+ case operation:
+ of OperationType.database:
+ handleDatabase(parsedArgs, config)
+ of OperationType.files:
+ handleFiles(parsedArgs, config)
+ of OperationType.query:
+ handleQuery(parsedArgs, config)
+ of OperationType.remove:
+ handleRemove(parsedArgs, config)
+ of OperationType.sync:
+ handleSync(parsedArgs, config)
+ of OperationType.deptest:
+ handleDeptest(parsedArgs, config)
+ of OperationType.upgrade:
+ handleUpgrade(parsedArgs, config)
+ else:
+ pacmanExec(false, config.color,
+ parsedArgs.filterExtensions(true, true))
+
+let runResult = if init.success.isSome:
+ run(init.success.unsafeGet.parsedArgs, init.success.unsafeGet.config)
+ else:
+ (none(int), init.code)
+
+programResult = if runResult.success.isSome:
+ runResult.success.unsafeGet
+ else:
+ runResult.code