diff options
Diffstat (limited to 'src/common.nim')
-rw-r--r-- | src/common.nim | 216 |
1 files changed, 149 insertions, 67 deletions
diff --git a/src/common.nim b/src/common.nim index b66237a..351dd73 100644 --- a/src/common.nim +++ b/src/common.nim @@ -1,6 +1,6 @@ import future, options, os, osproc, posix, sequtils, sets, strutils, tables, - args, config, lists, package, pacman, utils, + args, config, format, lists, package, pacman, utils, "wrapper/alpm" type @@ -18,6 +18,7 @@ type PackageTarget* = object of RootObj reference*: PackageReference repo*: Option[string] + destination*: Option[string] SyncPackageTarget* = object of PackageTarget foundInfos*: seq[SyncFoundInfo] @@ -51,15 +52,25 @@ proc checkAndRefresh*(color: bool, args: seq[Argument]): tuple[code: int, args: else: (0, args) -proc packageTargets*(args: seq[Argument]): seq[PackageTarget] = +proc packageTargets*(args: seq[Argument], parseDestination: bool): seq[PackageTarget] = args.targets.map(target => (block: - let splitTarget = target.split('/', 2) - let (repo, nameConstraint) = if splitTarget.len == 2: - (some(splitTarget[0]), splitTarget[1]) + let (noDestinationTarget, destination) = if parseDestination: (block: + let split = target.split("::", 2) + if split.len == 2: + (split[0], some(split[1])) + else: + (target, none(string))) + else: + (target, none(string)) + + let splitRepoTarget = noDestinationTarget.split('/', 2) + let (repo, nameConstraint) = if splitRepoTarget.len == 2: + (some(splitRepoTarget[0]), splitRepoTarget[1]) else: - (none(string), target) + (none(string), noDestinationTarget) + let reference = parsePackageReference(nameConstraint, false) - PackageTarget(reference: reference, repo: repo))) + PackageTarget(reference: reference, repo: repo, destination: destination))) proc isAurTargetSync*(target: SyncPackageTarget): bool = target.foundInfos.len == 0 and (target.repo.isNone or target.repo == some("aur")) @@ -67,6 +78,29 @@ proc isAurTargetSync*(target: SyncPackageTarget): bool = proc isAurTargetFull*[T: RpcPackageInfo](target: FullPackageTarget[T]): bool = target.foundInfos.len > 0 and target.foundInfos[0].repo == "aur" +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 + syncTargets.filter(t => not (upToDateNeededTable.opt(t.reference.name) + .map(r => t.reference.isProvidedBy(r)).get(false)) and t.foundInfos.len == 0 and + not (t.isAurTargetSync and pkgInfoReferencesTable.opt(t.reference.name) + .map(r => t.reference.isProvidedBy(r)).get(false))) + +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.reference]) + else: + printError(config.color, trp("database not found: %s\n") % [target.repo.unsafeGet]) + proc findSyncTargets*(handle: ptr AlpmHandle, dbs: seq[ptr AlpmDatabase], targets: seq[PackageTarget], allowGroups: bool, checkProvides: bool): (seq[SyncPackageTarget], seq[string]) = @@ -125,7 +159,7 @@ proc findSyncTargets*(handle: ptr AlpmHandle, dbs: seq[ptr AlpmDatabase], return @[] let syncTargets = targets.map(t => SyncPackageTarget(reference: t.reference, - repo: t.repo, foundInfos: findSync(t))) + repo: t.repo, destination: t.destination, foundInfos: findSync(t))) let checkAurNames = syncTargets.filter(isAurTargetSync).map(t => t.reference.name) (syncTargets, checkAurNames) @@ -146,10 +180,10 @@ proc mapAurTargets*[T: RpcPackageInfo](targets: seq[SyncPackageTarget], if res.isSome: let (syncInfo, pkgInfo) = res.get FullPackageTarget[T](reference: target.reference, repo: target.repo, - foundInfos: @[syncInfo], pkgInfo: some(pkgInfo)) + destination: target.destination, foundInfos: @[syncInfo], pkgInfo: some(pkgInfo)) else: FullPackageTarget[T](reference: target.reference, repo: target.repo, - foundInfos: target.foundInfos, pkgInfo: none(T))) + destination: target.destination, foundInfos: target.foundInfos, pkgInfo: none(T))) proc queryUnrequired*(handle: ptr AlpmHandle, withOptional: bool, withoutOptional: bool, assumeExplicit: HashSet[string]): (HashSet[string], HashSet[string], HashSet[string]) = @@ -213,22 +247,46 @@ proc queryUnrequired*(handle: ptr AlpmHandle, withOptional: bool, withoutOptiona proc `$`*[T: PackageTarget](target: T): string = target.repo.map(proc (r: string): string = r & "/" & $target.reference).get($target.reference) -proc ensureTmpOrError*(config: Config): Option[string] = +template tmpRoot(config: Config, dropPrivileges: bool): string = + if dropPrivileges: config.tmpRootInitial else: config.tmpRootCurrent + +proc ensureTmpOrError*(config: Config, dropPrivileges: bool): Option[string] = let tmpRootExists = try: - let user = initialUser.get(currentUser) - discard config.tmpRoot.existsOrCreateDir() - discard chown(config.tmpRoot, (Uid) user.uid, (Gid) user.gid) + discard config.tmpRoot(dropPrivileges).existsOrCreateDir() + if dropPrivileges: + let user = initialUser.get(currentUser) + discard chown(config.tmpRoot(dropPrivileges), (Uid) user.uid, (Gid) user.gid) true except: false if not tmpRootExists: - some(tr"failed to create tmp directory '$#'" % [config.tmpRoot]) + some(tr"failed to create tmp directory '$#'" % [config.tmpRoot(dropPrivileges)]) else: none(string) +proc getGitFiles*(repoPath: string, gitSubdir: Option[string], + dropPrivileges: bool): seq[string] = + if gitSubdir.isSome: + forkWaitRedirect(() => (block: + if not dropPrivileges or dropPrivileges(): + execResult(gitCmd, "-C", repoPath, "ls-tree", "-r", "--name-only", "@", + gitSubdir.unsafeGet & "/") + else: + quit(1))) + .output + .map(s => s[gitSubdir.unsafeGet.len + 1 .. ^1]) + else: + forkWaitRedirect(() => (block: + if not dropPrivileges or dropPrivileges(): + execResult(gitCmd, "-C", repoPath, "ls-tree", "-r", "--name-only", "@") + else: + quit(1))) + .output + proc bisectVersion(repoPath: string, debug: bool, firstCommit: Option[string], - compareMethod: string, gitSubdir: string, version: string): Option[string] = + compareMethod: string, gitSubdir: string, version: string, + dropPrivileges: bool): Option[string] = template forkExecWithoutOutput(args: varargs[string]): int = forkWait(() => (block: discard close(0) @@ -236,7 +294,7 @@ proc bisectVersion(repoPath: string, debug: bool, firstCommit: Option[string], discard close(1) discard close(2) - if dropPrivileges(): + if not dropPrivileges or dropPrivileges(): execResult(args) else: quit(1))) @@ -245,7 +303,7 @@ proc bisectVersion(repoPath: string, debug: bool, firstCommit: Option[string], (firstCommit, false) else: (forkWaitRedirect(() => (block: - if dropPrivileges(): + if not dropPrivileges or dropPrivileges(): execResult(gitCmd, "-C", repoPath, "rev-list", "--max-parents=0", "@") else: @@ -253,7 +311,7 @@ proc bisectVersion(repoPath: string, debug: bool, firstCommit: Option[string], .output.optLast, true) let (realLastThreeCommits, _) = forkWaitRedirect(() => (block: - if dropPrivileges(): + if not dropPrivileges or dropPrivileges(): execResult(gitCmd, "-C", repoPath, "rev-list", "--max-count=3", "@") else: @@ -273,7 +331,7 @@ proc bisectVersion(repoPath: string, debug: bool, firstCommit: Option[string], none(string) else: let foundVersion = forkWaitRedirect(() => (block: - if dropPrivileges(): + if not dropPrivileges or dropPrivileges(): execResult(pkgLibDir & "/bisect", compareMethod, repoPath & "/" & gitSubdir, version) else: @@ -317,7 +375,7 @@ proc bisectVersion(repoPath: string, debug: bool, firstCommit: Option[string], "bisect", "run", pkgLibDir & "/bisect", compareMethod, gitSubdir, version) let commit = forkWaitRedirect(() => (block: - if dropPrivileges(): + if not dropPrivileges or dropPrivileges(): execResult(gitCmd, "-C", repoPath, "rev-list", "--max-count=1", "refs/bisect/bad") else: @@ -333,7 +391,8 @@ proc bisectVersion(repoPath: string, debug: bool, firstCommit: Option[string], checkedCommit else: # non-incremental git history (e.g. downgrade without epoch change), bisect again - bisectVersion(repoPath, debug, commit, compareMethod, gitSubdir, version) + bisectVersion(repoPath, debug, commit, compareMethod, gitSubdir, + version, dropPrivileges) elif checkFirst and workFirstCommit.isSome: checkCommit(workFirstCommit.unsafeGet) else: @@ -360,8 +419,52 @@ proc reloadPkgInfos*(config: Config, path: string, pkgInfos: seq[PackageInfo]): else: pkgInfos +proc clonePackageRepoInternal(config: Config, base: string, version: string, + git: GitRepo, dropPrivileges: bool): Option[string] = + let tmpRoot = config.tmpRoot(dropPrivileges) + let repoPath = repoPath(tmpRoot, base) + removeDirQuiet(repoPath) + + if forkWait(() => (block: + if not dropPrivileges or dropPrivileges(): + execResult(gitCmd, "-C", tmpRoot, + "clone", "-q", git.url, "-b", git.branch, + "--single-branch", base) + else: + quit(1))) == 0: + let commit = bisectVersion(repoPath, config.debug, none(string), + "source", git.path, version, dropPrivileges) + + if commit.isNone: + removeDirQuiet(repoPath) + none(string) + else: + discard forkWait(() => (block: + if not dropPrivileges or dropPrivileges(): + execResult(gitCmd, "-C", repoPath, + "checkout", "-q", commit.unsafeGet) + else: + quit(1))) + + some(repoPath) + else: + removeDirQuiet(repoPath) + none(string) + +proc clonePackageRepo*(config: Config, base: string, version: string, + git: GitRepo, dropPrivileges: bool): Option[string] = + let message = ensureTmpOrError(config, dropPrivileges) + if message.isSome: + message + else: + let repoPath = clonePackageRepoInternal(config, base, version, git, dropPrivileges) + if repoPath.isNone: + some(tr"$#: failed to clone git repository" % [base]) + else: + none(string) + proc obtainBuildPkgInfosInternal(config: Config, bases: seq[LookupBaseGroup], - pacmanTargetNames: seq[string], progressCallback: (int, int) -> void): + pacmanTargetNames: seq[string], progressCallback: (int, int) -> void, dropPrivileges: bool): (seq[PackageInfo], seq[string], seq[string]) = let lookupResults: seq[LookupGitResult] = bases .map(b => (b, lookupGitRepo(b.repo, b.base, b.arch))) @@ -371,43 +474,21 @@ proc obtainBuildPkgInfosInternal(config: Config, bases: seq[LookupBaseGroup], let messages = notFoundRepos.map(r => tr"$#: repository not found" % [r.group.base]) (newSeq[PackageInfo](), newSeq[string](), messages) else: - let message = ensureTmpOrError(config) + let message = ensureTmpOrError(config, dropPrivileges) if message.isSome: (@[], @[], @[message.unsafeGet]) else: proc findCommitAndGetSrcInfo(base: string, version: string, repo: string, git: GitRepo): tuple[pkgInfos: seq[PackageInfo], path: Option[string]] = - let repoPath = repoPath(config.tmpRoot, base) - removeDirQuiet(repoPath) - - if forkWait(() => (block: - if dropPrivileges(): - execResult(gitCmd, "-C", config.tmpRoot, - "clone", "-q", git.url, "-b", git.branch, - "--single-branch", base) - else: - quit(1))) == 0: - let commit = bisectVersion(repoPath, config.debug, none(string), - "source", git.path, version) - - if commit.isNone: - removeDirQuiet(repoPath) - (newSeq[PackageInfo](), none(string)) - else: - discard forkWait(() => (block: - if dropPrivileges(): - execResult(gitCmd, "-C", repoPath, - "checkout", "-q", commit.unsafeGet) - else: - quit(1))) - - let srcInfo = obtainSrcInfo(repoPath & "/" & git.path) - let pkgInfos = parseSrcInfo(repo, srcInfo, config.arch, - git.url, some(git.path)) - .filter(i => i.version == version) - (pkgInfos, some(repoPath)) + let repoPath = clonePackageRepoInternal(config, base, version, git, dropPrivileges) + + if repoPath.isSome: + let srcInfo = obtainSrcInfo(repoPath.unsafeGet & "/" & git.path) + let pkgInfos = parseSrcInfo(repo, srcInfo, config.arch, + git.url, some(git.path)) + .filter(i => i.version == version) + (pkgInfos, repoPath) else: - removeDirQuiet(repoPath) (newSeq[PackageInfo](), none(string)) progressCallback(0, lookupResults.len) @@ -434,12 +515,12 @@ proc obtainBuildPkgInfosInternal(config: Config, bases: seq[LookupBaseGroup], if errorMessages.len > 0: for path in paths: removeDirQuiet(path) - discard rmdir(config.tmpRoot) + discard rmdir(config.tmpRoot(dropPrivileges)) (foundPkgInfos, paths, errorMessages) proc obtainBuildPkgInfos*[T: RpcPackageInfo](config: Config, - pacmanTargets: seq[FullPackageTarget[T]], progressCallback: (int, int) -> void): - (seq[PackageInfo], seq[string], seq[string]) = + pacmanTargets: seq[FullPackageTarget[T]], progressCallback: (int, int) -> void, + dropPrivileges: bool): (seq[PackageInfo], seq[string], seq[string]) = let bases = pacmanTargets .map(proc (target: FullPackageTarget[T]): LookupBaseGroup = let info = target.foundInfos[0] @@ -448,20 +529,21 @@ proc obtainBuildPkgInfos*[T: RpcPackageInfo](config: Config, .deduplicate let pacmanTargetNames = pacmanTargets.map(t => t.reference.name) - obtainBuildPkgInfosInternal(config, bases, pacmanTargetNames, progressCallback) + obtainBuildPkgInfosInternal(config, bases, pacmanTargetNames, progressCallback, dropPrivileges) -proc cloneAurRepo*(config: Config, base: string, gitUrl: string): (int, Option[string]) = - let repoPath = repoPath(config.tmpRoot, base) +proc cloneAurRepo*(config: Config, base: string, gitUrl: string, + dropPrivileges: bool): (int, Option[string]) = + let repoPath = repoPath(config.tmpRoot(dropPrivileges), base) - let message = ensureTmpOrError(config) + let message = ensureTmpOrError(config, dropPrivileges) if message.isSome: (1, message) elif repoPath.existsDir(): (0, none(string)) else: let cloneCode = forkWait(() => (block: - if dropPrivileges(): - execResult(gitCmd, "-C", config.tmpRoot, + if not dropPrivileges or dropPrivileges(): + execResult(gitCmd, "-C", config.tmpRoot(dropPrivileges), "clone", "-q", gitUrl, "--single-branch", base) else: quit(1))) @@ -472,7 +554,7 @@ proc cloneAurRepo*(config: Config, base: string, gitUrl: string): (int, Option[s (0, none(string)) proc cloneAurReposWithPackageInfos*(config: Config, rpcInfos: seq[RpcPackageInfo], - keepRepos: bool, progressCallback: (int, int) -> void): + keepRepos: bool, progressCallback: (int, int) -> void, dropPrivileges: bool): (seq[PackageInfo], seq[PackageInfo], seq[string], seq[string]) = let bases: seq[tuple[base: string, gitUrl: string]] = rpcInfos .map(i => (i.base, i.gitUrl)).deduplicate @@ -484,11 +566,11 @@ proc cloneAurReposWithPackageInfos*(config: Config, rpcInfos: seq[RpcPackageInfo if index >= bases.len: (toSeq(pkgInfos.items), toSeq(paths.items), toSeq(errors.items)) else: - let repoPath = repoPath(config.tmpRoot, bases[index].base) + let repoPath = repoPath(config.tmpRoot(dropPrivileges), bases[index].base) removeDirQuiet(repoPath) let (cloneCode, cloneErrorMessage) = cloneAurRepo(config, - bases[index].base, bases[index].gitUrl) + bases[index].base, bases[index].gitUrl, dropPrivileges) progressCallback(index + 1, bases.len) @@ -516,5 +598,5 @@ proc cloneAurReposWithPackageInfos*(config: Config, rpcInfos: seq[RpcPackageInfo let names = rpcInfos.map(i => i.name).toSet let additionalPkgInfos = fullPkgInfos.filter(i => not (i.name in names)) - discard rmdir(config.tmpRoot) + discard rmdir(config.tmpRoot(dropPrivileges)) (resultPkgInfos, additionalPkgInfos, paths, errors) |