aboutsummaryrefslogtreecommitdiff
path: root/src/feature/localquery.nim
diff options
context:
space:
mode:
Diffstat (limited to 'src/feature/localquery.nim')
-rw-r--r--src/feature/localquery.nim81
1 files changed, 81 insertions, 0 deletions
diff --git a/src/feature/localquery.nim b/src/feature/localquery.nim
new file mode 100644
index 0000000..b07ec98
--- /dev/null
+++ b/src/feature/localquery.nim
@@ -0,0 +1,81 @@
+import
+ algorithm, future, options, sequtils, sets, strutils, tables,
+ "../args", "../common", "../config", "../format", "../package", "../pacman", "../utils",
+ "../wrapper/alpm"
+
+proc handleQueryOrphans*(args: seq[Argument], config: Config): int =
+ type Package = tuple[name: string, explicit: bool]
+
+ let (installed, alternatives) = withAlpm(config.root, config.db,
+ newSeq[string](), config.arch, handle, dbs, errors):
+ for e in errors: printError(config.color, e)
+
+ var installed = initTable[Package, HashSet[PackageReference]]()
+ var alternatives = initTable[string, HashSet[PackageReference]]()
+
+ for pkg in handle.local.packages:
+ proc fixProvides(reference: PackageReference): PackageReference =
+ if reference.constraint.isNone:
+ (reference.name, reference.description,
+ some((ConstraintOperation.eq, $pkg.version)))
+ else:
+ reference
+
+ let depends = toSeq(pkg.depends.items)
+ .map(toPackageReference).toSet
+ let optional = toSeq(pkg.optional.items)
+ .map(toPackageReference).toSet
+ let provides = toSeq(pkg.provides.items)
+ .map(toPackageReference).map(fixProvides).toSet
+
+ installed.add(($pkg.name, pkg.reason == AlpmReason.explicit),
+ depends + optional)
+ if provides.len > 0:
+ alternatives.add($pkg.name, provides)
+
+ (installed, alternatives)
+
+ let providedBy = lc[(y, x.key) | (x <- alternatives.namedPairs, y <- x.value),
+ tuple[reference: PackageReference, name: string]]
+
+ let installedSeq = lc[x | (x <- installed.pairs),
+ tuple[package: Package, dependencies: HashSet[PackageReference]]]
+ let explicit = installedSeq
+ .filter(t => t.package.explicit)
+ .map(t => t.package.name)
+ .toSet
+
+ proc findRequired(results: HashSet[string], check: HashSet[string]): HashSet[string] =
+ let full = results + check
+
+ let direct = lc[x | (y <- installedSeq, y.package.name in check,
+ x <- y.dependencies), PackageReference]
+
+ let indirect = lc[x.name | (y <- direct, x <- providedBy,
+ y.isProvidedBy(x.reference)), string].toSet
+
+ let checkNext = (direct.map(p => p.name).toSet + indirect) - full
+ if checkNext.len > 0: findRequired(full, checkNext) else: full
+
+ let required = findRequired(initSet[string](), explicit)
+ let orphans = installedSeq.map(t => t.package.name).toSet - required
+
+ let targets = args.targets.map(t => (if t[0 .. 5] == "local/": t[6 .. ^1] else: t))
+
+ # Provide similar output for not installed packages
+ let unknownTargets = targets.toSet - toSeq(installed.keys).map(p => p.name).toSet
+ let results = if targets.len > 0:
+ targets.filter(t => t in orphans or t in unknownTargets)
+ else:
+ toSeq(orphans.items).sorted(cmp)
+
+ if results.len > 0:
+ let newArgs = args.filter(arg => not arg.isTarget and
+ not arg.matchOption((some("t"), "unrequired")) and
+ not arg.matchOption((some("d"), "deps"))) &
+ results.map(r => (r, none(string), ArgumentType.target))
+ pacmanExec(false, config.color, newArgs)
+ elif targets.len == 0:
+ 0
+ else:
+ 1