From a1a5e345daaeae0fae1da58e3683041d48e2583a Mon Sep 17 00:00:00 2001 From: kitsunyan Date: Mon, 23 Apr 2018 01:47:55 +0300 Subject: Add support for version constraints for targets --- src/common.nim | 68 +++++++++++++++++++++---------------- src/feature/syncinfo.nim | 6 ++-- src/feature/syncinstall.nim | 81 +++++++++++++++++++++++---------------------- src/package.nim | 44 ++++++++++++------------ 4 files changed, 105 insertions(+), 94 deletions(-) (limited to 'src') diff --git a/src/common.nim b/src/common.nim index d1c4daa..9288d64 100644 --- a/src/common.nim +++ b/src/common.nim @@ -16,7 +16,7 @@ type ] PackageTarget* = object of RootObj - name*: string + reference*: PackageReference repo*: Option[string] SyncPackageTarget* = object of PackageTarget @@ -52,12 +52,14 @@ proc checkAndRefresh*(color: bool, args: seq[Argument]): tuple[code: int, args: (0, args) proc packageTargets*(args: seq[Argument]): seq[PackageTarget] = - args.targets.map(proc (target: string): PackageTarget = + args.targets.map(target => (block: let splitTarget = target.split('/', 2) - if splitTarget.len == 2: - PackageTarget(name: splitTarget[1], repo: some(splitTarget[0])) - else: - PackageTarget(name: target, repo: none(string))) + let (repo, nameConstraint) = if splitTarget.len == 2: + (some(splitTarget[0]), splitTarget[1]) + else: + (none(string), target) + let reference = parsePackageReference(nameConstraint, false) + PackageTarget(reference: reference, repo: repo))) proc isAurTargetSync*(target: SyncPackageTarget): bool = target.foundInfo.isNone and (target.repo.isNone or target.repo == some("aur")) @@ -70,10 +72,10 @@ proc findSyncTargets*(handle: ptr AlpmHandle, dbs: seq[ptr AlpmDatabase], (seq[SyncPackageTarget], seq[string]) = let dbTable = dbs.map(d => ($d.name, d)).toTable - proc checkProvided(name: string, db: ptr AlpmDatabase): bool = + proc checkProvided(reference: PackageReference, db: ptr AlpmDatabase): bool = for pkg in db.packages: for provides in pkg.provides: - if $provides.name == name: + if reference.isProvidedBy(provides.toPackageReference): return true return false @@ -83,12 +85,12 @@ proc findSyncTargets*(handle: ptr AlpmHandle, dbs: seq[ptr AlpmDatabase], if dbTable.hasKey(repo): let db = dbTable[repo] - let pkg = db[target.name] + let pkg = db[target.reference.name] - if pkg != nil: - let base = if pkg.base == nil: target.name else: $pkg.base + if pkg != nil and target.reference.isProvidedBy(pkg.toPackageReference): + let base = if pkg.base == nil: target.reference.name else: $pkg.base return some((repo, some((base, $pkg.version, some($pkg.arch))))) - elif checkProvides and target.name.checkProvided(db): + elif checkProvides and target.reference.checkProvided(db): return some((repo, none(SyncFoundPackageInfo))) else: return none(SyncFoundInfo) @@ -97,9 +99,9 @@ proc findSyncTargets*(handle: ptr AlpmHandle, dbs: seq[ptr AlpmDatabase], else: let directResult = dbs .map(db => (block: - let pkg = db[target.name] - if pkg != nil: - let base = if pkg.base == nil: target.name else: $pkg.base + let pkg = db[target.reference.name] + if pkg != nil and target.reference.isProvidedBy(pkg.toPackageReference): + let base = if pkg.base == nil: target.reference.name else: $pkg.base some(($db.name, some((base, $pkg.version, some($pkg.arch))))) else: none(SyncFoundInfo))) @@ -110,37 +112,45 @@ proc findSyncTargets*(handle: ptr AlpmHandle, dbs: seq[ptr AlpmDatabase], if directResult.isSome: return directResult else: - if allowGroups: - let groupRepo = lc[d | (d <- dbs, g <- d.groups, $g.name == target.name), - ptr AlpmDatabase].optFirst + if allowGroups and target.reference.constraint.isNone: + let groupRepo = lc[d | (d <- dbs, g <- d.groups, + $g.name == target.reference.name), ptr AlpmDatabase].optFirst if groupRepo.isSome: return groupRepo.map(d => ($d.name, none(SyncFoundPackageInfo))) if checkProvides: for db in dbs: - if target.name.checkProvided(db): + if target.reference.checkProvided(db): return some(($db.name, none(SyncFoundPackageInfo))) return none(SyncFoundInfo) else: return none(SyncFoundInfo) - let syncTargets = targets.map(t => SyncPackageTarget(name: t.name, + let syncTargets = targets.map(t => SyncPackageTarget(reference: t.reference, repo: t.repo, foundInfo: findSync(t))) - let checkAur = syncTargets.filter(isAurTargetSync).map(t => t.name) - (syncTargets, checkAur) + let checkAurNames = syncTargets.filter(isAurTargetSync).map(t => t.reference.name) + (syncTargets, checkAurNames) proc mapAurTargets*[T: RpcPackageInfo](targets: seq[SyncPackageTarget], pkgInfos: seq[T]): seq[FullPackageTarget[T]] = let aurTable = pkgInfos.map(i => (i.name, i)).toTable targets.map(proc (target: SyncPackageTarget): FullPackageTarget[T] = - if target.foundInfo.isNone and aurTable.hasKey(target.name): - let pkgInfo = aurTable[target.name] - let syncInfo = ("aur", some((pkgInfo.base, pkgInfo.version, none(string)))) - FullPackageTarget[T](name: target.name, repo: target.repo, + let res = if target.foundInfo.isNone and aurTable.hasKey(target.reference.name): (block: + let pkgInfo = aurTable[target.reference.name] + if target.reference.isProvidedBy(pkgInfo.toPackageReference): + some((("aur", some((pkgInfo.base, pkgInfo.version, none(string)))), pkgInfo)) + else: + none((SyncFoundInfo, T))) + else: + none((SyncFoundInfo, T)) + + if res.isSome: + let (syncInfo, pkgInfo) = res.get + FullPackageTarget[T](reference: target.reference, repo: target.repo, foundInfo: some(syncInfo), pkgInfo: some(pkgInfo)) else: - FullPackageTarget[T](name: target.name, repo: target.repo, + FullPackageTarget[T](reference: target.reference, repo: target.repo, foundInfo: target.foundInfo, pkgInfo: none(T))) proc queryUnrequired*(handle: ptr AlpmHandle, withOptional: bool, withoutOptional: bool, @@ -203,7 +213,7 @@ proc queryUnrequired*(handle: ptr AlpmHandle, withOptional: bool, withoutOptiona (installed, withOptionalSet, withoutOptionalSet) proc formatArgument*(target: PackageTarget): string = - target.repo.map(r => r & "/" & target.name).get(target.name) + target.repo.map(r => r & "/" & $target.reference).get($target.reference) proc ensureTmpOrError*(config: Config): Option[string] = let tmpRootExists = try: @@ -408,7 +418,7 @@ proc obtainBuildPkgInfos*[T: RpcPackageInfo](config: Config, (pkg.base, pkg.version, pkg.arch.get, info.repo)) .deduplicate - let pacmanTargetNames = pacmanTargets.map(t => t.name) + let pacmanTargetNames = pacmanTargets.map(t => t.reference.name) obtainBuildPkgInfosInternal(config, bases, pacmanTargetNames) proc cloneRepo*(config: Config, basePackages: seq[PackageInfo]): (int, Option[string]) = diff --git a/src/feature/syncinfo.nim b/src/feature/syncinfo.nim index 5ff6b38..d00dcc0 100644 --- a/src/feature/syncinfo.nim +++ b/src/feature/syncinfo.nim @@ -100,13 +100,13 @@ proc handleSyncInfo*(args: seq[Argument], config: Config): int = let (_, callArgs) = checkAndRefresh(config.color, args) let targets = args.packageTargets - let (syncTargets, checkAur) = withAlpm(config.root, config.db, + let (syncTargets, checkAurNames) = withAlpm(config.root, config.db, config.dbs, config.arch, handle, dbs, errors): for e in errors: printError(config.color, e) findSyncTargets(handle, dbs, targets, false, false) - let (pkgInfos, aerrors) = getAurPackageInfo(checkAur, none(seq[RpcPackageInfo]), - config.arch, proc (a: int, b: int) = discard) + let (pkgInfos, aerrors) = getAurPackageInfo(checkAurNames, + none(seq[RpcPackageInfo]), config.arch, proc (a: int, b: int) = discard) for e in aerrors: printError(config.color, e) let fullTargets = mapAurTargets[PackageInfo](syncTargets, pkgInfos) diff --git a/src/feature/syncinstall.nim b/src/feature/syncinstall.nim index ecb9f18..163bf34 100644 --- a/src/feature/syncinstall.nim +++ b/src/feature/syncinstall.nim @@ -206,26 +206,26 @@ proc findDependencies(config: Config, handle: ptr AlpmHandle, let unsatisfied = lc[x | (i <- pkgInfos, x <- i.allDepends), PackageReference].deduplicate findDependencies(config, handle, dbs, satisfied, unsatisfied, @[], printMode, noaur) -proc filterNotFoundSyncTargets[T: RpcPackageInfo](syncTargets: seq[SyncPackageTarget], - pkgInfos: seq[T], upToDateNeededNames: HashSet[string]): - (Table[string, T], seq[SyncPackageTarget]) = - let rpcInfoTable = pkgInfos.map(d => (d.name, d)).toTable - - proc notFoundOrFoundInAur(target: SyncPackageTarget): bool = - not (target.name in upToDateNeededNames) and target.foundInfo.isNone and - not (target.isAurTargetSync and rpcInfoTable.hasKey(target.name)) - +proc filterNotFoundSyncTargetsInternal(syncTargets: seq[SyncPackageTarget], + pkgInfoReferencesTable: Table[string, PackageReference], + upToDateNeededTable: Table[string, PackageReference]): seq[SyncPackageTarget] = # collect packages which were found neither in sync DB nor in AUR - let notFoundTargets = syncTargets.filter(notFoundOrFoundInAur) + syncTargets.filter(t => not (upToDateNeededTable.opt(t.reference.name) + .map(r => t.reference.isProvidedBy(r)).get(false)) and t.foundInfo.isNone and + not (t.isAurTargetSync and pkgInfoReferencesTable.opt(t.reference.name) + .map(r => t.reference.isProvidedBy(r)).get(false))) - (rpcInfoTable, notFoundTargets) +proc filterNotFoundSyncTargets[T: RpcPackageInfo](syncTargets: seq[SyncPackageTarget], + pkgInfos: seq[T], upToDateNeededTable: Table[string, PackageReference]): seq[SyncPackageTarget] = + let pkgInfoReferencesTable = pkgInfos.map(i => (i.name, i.toPackageReference)).toTable + filterNotFoundSyncTargetsInternal(syncTargets, pkgInfoReferencesTable, upToDateNeededTable) proc printSyncNotFound(config: Config, notFoundTargets: seq[SyncPackageTarget]) = let dbs = config.dbs.toSet for target in notFoundTargets: if target.repo.isNone or target.repo == some("aur") or target.repo.unsafeGet in dbs: - printError(config.color, trp("target not found: %s\n") % [target.name]) + printError(config.color, trp("target not found: %s\n") % [$target.reference]) else: printError(config.color, trp("database not found: %s\n") % [target.repo.unsafeGet]) @@ -854,14 +854,14 @@ proc handlePrint(args: seq[Argument], config: Config, printFormat: string, upgra code proc filterIgnoresAndConflicts(config: Config, pkgInfos: seq[PackageInfo], - targetsSet: HashSet[string], installed: Table[string, Installed], + targetNamesSet: HashSet[string], installed: Table[string, Installed], print: bool, noconfirm: bool): (seq[PackageInfo], seq[PackageInfo]) = let acceptedPkgInfos = pkgInfos.filter(pkgInfo => (block: let instGroups = lc[x | (i <- installed.opt(pkgInfo.name), x <- i.groups), string] if config.ignored(pkgInfo.name, (instGroups & pkgInfo.groups).deduplicate): - if pkgInfo.name in targetsSet: + if pkgInfo.name in targetNamesSet: if not print: let input = printColonUserChoice(config.color, trp"%s is in IgnorePkg/IgnoreGroup. Install anyway?" % [pkgInfo.name], @@ -902,11 +902,11 @@ proc checkNeeded(installed: Table[string, Installed], (true, 0) proc obtainAurPackageInfos(config: Config, rpcInfos: seq[RpcPackageInfo], - targets: seq[FullPackageTarget[RpcPackageInfo]], + rpcAurTargets: seq[FullPackageTarget[RpcPackageInfo]], installed: Table[string, Installed], print: bool, needed: bool, upgradeCount: int): (seq[PackageInfo], seq[Installed], seq[LocalIsNewer], seq[string]) = let targetRpcInfoPairs: seq[tuple[rpcInfo: RpcPackageInfo, upgradeable: bool]] = - targets.map(t => t.pkgInfo.get).map(i => (i, installed + rpcAurTargets.map(t => t.pkgInfo.get).map(i => (i, installed .checkNeeded(i.name, i.version, true).needed)) let upToDateNeeded: seq[Installed] = if needed: @@ -920,9 +920,9 @@ proc obtainAurPackageInfos(config: Config, rpcInfos: seq[RpcPackageInfo], else: @[] - let targetsSet = targets.map(t => t.name).toSet - let installedUpgradeRpcInfos = rpcInfos.filter(i => upgradeCount > 0 and - not (i.name in targetsSet)) + let installedUpgradeRpcInfos = rpcInfos.filter(i => upgradeCount > 0 and (block: + let reference = i.toPackageReference + rpcAurTargets.filter(t => t.reference.isProvidedBy(reference)).len == 0)) let upgradeStructs: seq[tuple[rpcInfo: RpcPackageInfo, needed: bool, localIsNewer: Option[LocalIsNewer]]] = installedUpgradeRpcInfos @@ -977,11 +977,11 @@ proc handleSyncInstall*(args: seq[Argument], config: Config): int = let targets = args.packageTargets - let (syncTargets, checkAur, installed, foreignUpgrade) = withAlpm(config.root, config.db, + let (syncTargets, checkAurNames, installed, foreignUpgrade) = withAlpm(config.root, config.db, config.dbs, config.arch, handle, dbs, errors): for e in errors: printError(config.color, e) - let (syncTargets, checkAur) = findSyncTargets(handle, dbs, targets, + let (syncTargets, checkAurNames) = findSyncTargets(handle, dbs, targets, not build, not build) let installed = lc[($p.name, $p.version, p.groupsSeq, p.reason == AlpmReason.explicit) | @@ -1006,32 +1006,33 @@ proc handleSyncInstall*(args: seq[Argument], config: Config): int = else: initSet[string]() - (syncTargets, checkAur, installed, foreignUpgrade) + (syncTargets, checkAurNames, installed, foreignUpgrade) - let checkAurFull = if noaur: + let checkAurNamesFull = if noaur: @[] elif upgradeCount > 0: installed .filter(i => i.name in foreignUpgrade and (config.checkIgnored or not config.ignored(i.name, i.groups))) - .map(i => i.name) & checkAur + .map(i => i.name) & checkAurNames else: - checkAur + checkAurNames withAur(): - if checkAurFull.len > 0 and printFormat.isNone: + if checkAurNamesFull.len > 0 and printFormat.isNone: printColon(config.color, tr"Checking AUR database...") - let (rpcInfos, rerrors) = getRpcPackageInfo(checkAurFull) + let (rpcInfos, rerrors) = getRpcPackageInfo(checkAurNamesFull) for e in rerrors: printError(config.color, e) - let (rpcInfoTable, rpcNotFoundTargets) = filterNotFoundSyncTargets(syncTargets, - rpcInfos, initSet[string]()) + let rpcNotFoundTargets = filterNotFoundSyncTargets(syncTargets, + rpcInfos, initTable[string, PackageReference]()) if rpcNotFoundTargets.len > 0: printSyncNotFound(config, rpcNotFoundTargets) 1 else: if upgradeCount > 0 and not noaur and printFormat.isNone and config.printAurNotFound: + let rpcInfoTable = rpcInfos.map(i => (i.name, i)).toTable for inst in installed: if inst.name in foreignUpgrade and not config.ignored(inst.name, inst.groups) and not rpcInfoTable.hasKey(inst.name): @@ -1044,16 +1045,17 @@ proc handleSyncInstall*(args: seq[Argument], config: Config): int = rpcInfos, rpcAurTargets, installedTable, printFormat.isSome, needed, upgradeCount) for e in aperrors: printError(config.color, e) - let upToDateNeededNames = upToDateNeeded.map(i => i.name).toSet - let (_, notFoundTargets) = filterNotFoundSyncTargets(syncTargets, - aurPkgInfos, upToDateNeededNames) + let upToDateNeededTable = upToDateNeeded.map(i => (i.name, + (i.name, none(string), some((ConstraintOperation.eq, i.version))))).toTable + let notFoundTargets = filterNotFoundSyncTargets(syncTargets, + aurPkgInfos, upToDateNeededTable) if notFoundTargets.len > 0: printSyncNotFound(config, notFoundTargets) 1 else: - let fullTargets = mapAurTargets(syncTargets - .filter(t => not (t.name in upToDateNeededNames)), aurPkgInfos) + let fullTargets = mapAurTargets(syncTargets.filter(t => not (upToDateNeededTable + .opt(t.reference.name).map(r => t.reference.isProvidedBy(r)).get(false))), aurPkgInfos) let pacmanTargets = fullTargets.filter(t => not isAurTargetFull(t)) let aurTargets = fullTargets.filter(isAurTargetFull) @@ -1070,11 +1072,11 @@ proc handleSyncInstall*(args: seq[Argument], config: Config): int = let neededPacmanTargets = if printFormat.isNone and build and needed: pacmanTargets.filter(target => (block: let version = target.foundInfo.get.pkg.get.version - if installedTable.checkNeeded(target.name, version, true).needed: + if installedTable.checkNeeded(target.reference.name, version, true).needed: true else: printWarning(config.color, tra("%s-%s is up to date -- skipping\n") % - [target.name, version]) + [target.reference.name, version]) false)) else: pacmanTargets @@ -1094,9 +1096,9 @@ proc handleSyncInstall*(args: seq[Argument], config: Config): int = 1 else: let pkgInfos = buildPkgInfos & aurPkgInfos - let targetsSet = (pacmanTargets & aurTargets).map(t => t.name).toSet + let targetNamesSet = (pacmanTargets & aurTargets).map(t => t.reference.name).toSet let (finalPkgInfos, acceptedPkgInfos) = filterIgnoresAndConflicts(config, pkgInfos, - targetsSet, installedTable, printFormat.isSome, noconfirm) + targetNamesSet, installedTable, printFormat.isSome, noconfirm) if finalPkgInfos.len > 0 and printFormat.isNone: echo(trp("resolving dependencies...\n")) @@ -1109,7 +1111,7 @@ proc handleSyncInstall*(args: seq[Argument], config: Config): int = for pkgInfo in pkgInfos: if not (pkgInfo.name in acceptedSet): - if not (pkgInfo.name in targetsSet) and upgradeCount > 0 and + if not (pkgInfo.name in targetNamesSet) and upgradeCount > 0 and installedTable.hasKey(pkgInfo.name): let installedVersion = installedTable[pkgInfo.name].version let newVersion = pkgInfo.version @@ -1152,7 +1154,6 @@ proc handleSyncInstall*(args: seq[Argument], config: Config): int = .filter(i => i.explicit).map(i => i.name).toSet let foreignDepsNamesSet = foreignInstalled .filter(i => not i.explicit).map(i => i.name).toSet - let targetNamesSet = targets.map(t => t.name).toSet let keepNames = foreignExplicitsNamesSet + foreignDepsNamesSet + targetNamesSet let explicits = if args.check((none(string), "asexplicit")): diff --git a/src/package.nim b/src/package.nim index f0a4ee1..30ff2f8 100644 --- a/src/package.nim +++ b/src/package.nim @@ -177,9 +177,29 @@ proc toPackageReference*(dependency: ptr AlpmDependency): PackageReference = template toPackageReference*(pkg: ptr AlpmPackage): PackageReference = ($pkg.name, none(string), some((ConstraintOperation.eq, $pkg.version))) -template toPackageReference*(pkg: PackageInfo): PackageReference = +template toPackageReference*(pkg: RpcPackageInfo): PackageReference = (pkg.name, none(string), some((ConstraintOperation.eq, pkg.version))) +proc parsePackageReference*(name: string, withDescription: bool): PackageReference = + var matches: array[3, string] + + let descIndex = name.find(": ") + let (description, workName) = if withDescription and descIndex >= 0: + (some(name[descIndex + 2 .. ^1]), name[0 .. descIndex - 1]) + else: + (none(string), name) + + if workName.match(re"([^><=]*)\ *(=|>=|<=|>|<)\ *([^ ]*)", matches): + let constraints = toSeq(enumerate[ConstraintOperation]()) + let index = constraints.map(s => $s).find(matches[1]) + + if index >= 0: + (matches[0], description, some((constraints[index], matches[2]))) + else: + (matches[0], description, none(VersionConstraint)) + else: + (workName, description, none(VersionConstraint)) + proc parseSrcInfoKeys(srcInfo: string): tuple[baseSeq: ref seq[SrcInfoPair], table: OrderedTable[string, ref seq[SrcInfoPair]]] = var table = initOrderedTable[string, ref seq[SrcInfoPair]]() @@ -224,29 +244,9 @@ proc parseSrcInfoName(repo: string, name: string, baseIndex: int, baseCount: int else: res - proc splitConstraint(name: string): PackageReference = - var matches: array[3, string] - - let descIndex = name.find(": ") - let (description, workName) = if descIndex >= 0: - (some(name[descIndex + 2 .. ^1]), name[0 .. descIndex - 1]) - else: - (none(string), name) - - if workName.match(re"([^><=]*)\ *(=|>=|<=|>|<)\ *([^ ]*)", matches): - let constraints = toSeq(enumerate[ConstraintOperation]()) - let index = constraints.map(s => $s).find(matches[1]) - - if index >= 0: - (matches[0], description, some((constraints[index], matches[2]))) - else: - (matches[0], description, none(VersionConstraint)) - else: - (workName, description, none(VersionConstraint)) - proc collectArch(keyName: string): seq[PackageReference] = (collect(keyName) & collect(keyName & "_" & arch)) - .map(splitConstraint) + .map(n => parsePackageReference(n, true)) .filter(c => c.name.len > 0) proc filterReferences(references: seq[PackageReference], -- cgit v1.2.3-70-g09d2