diff options
-rw-r--r-- | src/aur.nim | 2 | ||||
-rw-r--r-- | src/common.nim | 107 | ||||
-rw-r--r-- | src/feature/syncinstall.nim | 153 | ||||
-rw-r--r-- | src/package.nim | 20 |
4 files changed, 139 insertions, 143 deletions
diff --git a/src/aur.nim b/src/aur.nim index 837dea7..60df9e0 100644 --- a/src/aur.nim +++ b/src/aur.nim @@ -106,7 +106,7 @@ proc getAurPackageInfo*(pkgs: seq[string], rpcInfosOption: Option[seq[RpcPackage (@[], operror) else: let pkgInfos = parseSrcInfo("aur", srcInfo, arch, - aurUrl & base & ".git", none(string), none(string), none(string), rpcInfos) + aurUrl & base & ".git", none(string), rpcInfos) (pkgInfos, none(string)) let parsed = deduplicated.foldl(a & obtainAndParse(b, a.len), newSeq[ParseResult]()) diff --git a/src/common.nim b/src/common.nim index f45472d..c42cb82 100644 --- a/src/common.nim +++ b/src/common.nim @@ -228,7 +228,7 @@ proc ensureTmpOrError*(config: Config): Option[string] = none(string) proc bisectVersion(repoPath: string, debug: bool, firstCommit: Option[string], - compareMethod: string, relativePath: string, version: string): Option[string] = + compareMethod: string, gitSubdir: string, version: string): Option[string] = template forkExecWithoutOutput(args: varargs[string]): int = forkWait(() => (block: discard close(0) @@ -268,7 +268,7 @@ proc bisectVersion(repoPath: string, debug: bool, firstCommit: Option[string], let foundVersion = forkWaitRedirect(() => (block: dropPrivileges() execResult(pkgLibDir & "/bisect", - compareMethod, repoPath & "/" & relativePath, version))) + compareMethod, repoPath & "/" & gitSubdir, version))) .output.optFirst let checkout2Code = forkExecWithoutOutput(gitCmd, "-C", repoPath, @@ -305,7 +305,7 @@ proc bisectVersion(repoPath: string, debug: bool, firstCommit: Option[string], none(string) else: discard forkExecWithoutOutput(gitCmd, "-C", repoPath, - "bisect", "run", pkgLibDir & "/bisect", compareMethod, relativePath, version) + "bisect", "run", pkgLibDir & "/bisect", compareMethod, gitSubdir, version) let commit = forkWaitRedirect(() => (block: dropPrivileges() @@ -322,7 +322,7 @@ 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, relativePath, version) + bisectVersion(repoPath, debug, commit, compareMethod, gitSubdir, version) elif checkFirst and workFirstCommit.isSome: checkCommit(workFirstCommit.unsafeGet) else: @@ -342,73 +342,80 @@ proc obtainSrcInfo*(path: string): string = proc reloadPkgInfos*(config: Config, path: string, pkgInfos: seq[PackageInfo]): seq[PackageInfo] = let srcInfo = obtainSrcInfo(path) let res = parseSrcInfo(pkgInfos[0].repo, srcInfo, config.arch, - pkgInfos[0].gitUrl, pkgInfos[0].gitBranch, pkgInfos[0].gitCommit, pkgInfos[0].gitPath) + pkgInfos[0].gitUrl, pkgInfos[0].gitSubdir) if res.len > 0: res else: pkgInfos proc obtainBuildPkgInfosInternal(config: Config, bases: seq[LookupBaseGroup], - pacmanTargetNames: seq[string]): (seq[PackageInfo], seq[string]) = + pacmanTargetNames: seq[string]): (seq[PackageInfo], seq[string], seq[string]) = let lookupResults: seq[LookupGitResult] = bases .map(b => (b, lookupGitRepo(b.repo, b.base, b.arch))) let notFoundRepos = lookupResults.filter(r => r.git.isNone) if notFoundRepos.len > 0: let messages = notFoundRepos.map(r => tr"$#: repository not found" % [r.group.base]) - (newSeq[PackageInfo](), messages) + (newSeq[PackageInfo](), newSeq[string](), messages) else: let message = ensureTmpOrError(config) if message.isSome: - (@[], @[message.unsafeGet]) + (@[], @[], @[message.unsafeGet]) else: proc findCommitAndGetSrcInfo(base: string, version: string, - repo: string, git: GitRepo): seq[PackageInfo] = + repo: string, git: GitRepo): tuple[pkgInfos: seq[PackageInfo], path: Option[string]] = let repoPath = repoPath(config.tmpRoot, base) removeDirQuiet(repoPath) - try: - if forkWait(() => (block: - dropPrivileges() - execResult(gitCmd, "-C", config.tmpRoot, - "clone", "-q", git.url, "-b", git.branch, - "--single-branch", base))) == 0: - let commit = bisectVersion(repoPath, config.debug, none(string), - "source", git.path, version) - - if commit.isNone: - @[] - else: - discard forkWait(() => (block: - dropPrivileges() - execResult(gitCmd, "-C", repoPath, - "checkout", "-q", commit.unsafeGet))) - - let srcInfo = obtainSrcInfo(repoPath & "/" & git.path) - parseSrcInfo(repo, srcInfo, config.arch, - git.url, some(git.branch), commit, some(git.path)) - .filter(i => i.version == version) + if forkWait(() => (block: + dropPrivileges() + execResult(gitCmd, "-C", config.tmpRoot, + "clone", "-q", git.url, "-b", git.branch, + "--single-branch", base))) == 0: + let commit = bisectVersion(repoPath, config.debug, none(string), + "source", git.path, version) + + if commit.isNone: + removeDirQuiet(repoPath) + (newSeq[PackageInfo](), none(string)) else: - @[] - finally: + discard forkWait(() => (block: + dropPrivileges() + execResult(gitCmd, "-C", repoPath, + "checkout", "-q", commit.unsafeGet))) + + 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)) + else: removeDirQuiet(repoPath) + (newSeq[PackageInfo](), none(string)) - let pkgInfos = lc[x | (r <- lookupResults, x <- findCommitAndGetSrcInfo(r.group.base, - r.group.version, r.group.repo, r.git.get)), PackageInfo] + let pkgInfosWithPaths = lookupResults.map(r => findCommitAndGetSrcInfo(r.group.base, + r.group.version, r.group.repo, r.git.get)) + + let pkgInfos = lc[x | (y <- pkgInfosWithPaths, x <- y.pkgInfos), PackageInfo] + let paths = lc[x | (y <- pkgInfosWithPaths, x <- y.path), string] let pkgInfosTable = pkgInfos.map(i => (i.name, i)).toTable let foundPkgInfos = lc[x | (y <- pacmanTargetNames, x <- pkgInfosTable.opt(y)), PackageInfo] - let messages = pacmanTargetNames + let errorMessages = pacmanTargetNames .filter(n => not pkgInfosTable.hasKey(n)) .map(n => tr"$#: failed to get package info" % [n]) + if errorMessages.len > 0: + for path in paths: + removeDirQuiet(path) discard rmdir(config.tmpRoot) - (foundPkgInfos, messages) + (foundPkgInfos, paths, errorMessages) proc obtainBuildPkgInfos*[T: RpcPackageInfo](config: Config, - pacmanTargets: seq[FullPackageTarget[T]]): (seq[PackageInfo], seq[string]) = + pacmanTargets: seq[FullPackageTarget[T]]): + (seq[PackageInfo], seq[string], seq[string]) = let bases = pacmanTargets .map(proc (target: FullPackageTarget[T]): LookupBaseGroup = let info = target.foundInfos[0] @@ -419,7 +426,7 @@ proc obtainBuildPkgInfos*[T: RpcPackageInfo](config: Config, let pacmanTargetNames = pacmanTargets.map(t => t.reference.name) obtainBuildPkgInfosInternal(config, bases, pacmanTargetNames) -proc cloneRepo*(config: Config, basePackages: seq[PackageInfo]): (int, Option[string]) = +proc cloneAurRepo*(config: Config, basePackages: seq[PackageInfo]): (int, Option[string]) = let base = basePackages[0].base let repoPath = repoPath(config.tmpRoot, base) @@ -428,28 +435,12 @@ proc cloneRepo*(config: Config, basePackages: seq[PackageInfo]): (int, Option[st (1, message) elif repoPath.existsDir(): (0, none(string)) + elif basePackages[0].repo != "aur": + raise newException(SystemError, "invalid clone call") else: - let gitUrl = basePackages[0].gitUrl - let gitBranch = basePackages[0].gitBranch - let gitCommit = basePackages[0].gitCommit - let aur = basePackages[0].repo == "aur" - let branch = gitBranch.get("master") - let cloneCode = forkWait(() => (block: dropPrivileges() execResult(gitCmd, "-C", config.tmpRoot, - "clone", "-q", gitUrl, "-b", branch, "--single-branch", base))) + "clone", "-q", basePackages[0].gitUrl, "--single-branch", base))) - if cloneCode == 0: - if gitCommit.isSome: - let code = forkWait(() => (block: - dropPrivileges() - execResult(gitCmd, "-C", repoPath, - "reset", "-q", "--hard", gitCommit.unsafeGet))) - (code, none(string)) - elif aur: - (0, none(string)) - else: - (1, none(string)) - else: - (cloneCode, none(string)) + (cloneCode, none(string)) diff --git a/src/feature/syncinstall.nim b/src/feature/syncinstall.nim index c224608..94bb886 100644 --- a/src/feature/syncinstall.nim +++ b/src/feature/syncinstall.nim @@ -240,7 +240,7 @@ proc printUnsatisfied(config: Config, trp("unable to satisfy dependency '%s' required by %s\n") % [$reference, pkgInfo.name]) -proc editLoop(config: Config, base: string, repoPath: string, gitPath: Option[string], +proc editLoop(config: Config, base: string, repoPath: string, gitSubdir: Option[string], defaultYes: bool, noconfirm: bool): char = proc editFileLoop(file: string): char = let default = if defaultYes: 'y' else: 'n' @@ -267,20 +267,20 @@ proc editLoop(config: Config, base: string, repoPath: string, gitPath: Option[st 'n' else: discard forkWait(proc: int = - discard chdir(buildPath(repoPath, gitPath)) + discard chdir(buildPath(repoPath, gitSubdir)) dropPrivileges() execResult(bashCmd, "-c", """$1 "$2"""", "bash", editor, file)) editFileLoop(file) else: res - let rawFiles = if gitPath.isSome: + let rawFiles = if gitSubdir.isSome: forkWaitRedirect(() => (block: dropPrivileges() execResult(gitCmd, "-C", repoPath, "ls-tree", "-r", "--name-only", "@", - gitPath.unsafeGet & "/"))) + gitSubdir.unsafeGet & "/"))) .output - .map(s => s[gitPath.unsafeGet.len + 1 .. ^1]) + .map(s => s[gitSubdir.unsafeGet.len + 1 .. ^1]) else: forkWaitRedirect(() => (block: dropPrivileges() @@ -302,8 +302,8 @@ proc buildLoop(config: Config, pkgInfos: seq[PackageInfo], noconfirm: bool, noextract: bool): (Option[BuildResult], int, bool) = let base = pkgInfos[0].base let repoPath = repoPath(config.tmpRoot, base) - let gitPath = pkgInfos[0].gitPath - let buildPath = buildPath(repoPath, gitPath) + let gitSubdir = pkgInfos[0].gitSubdir + let buildPath = buildPath(repoPath, gitSubdir) let confFileEnv = getEnv("MAKEPKG_CONF") let confFile = if confFileEnv.len == 0: @@ -409,70 +409,64 @@ proc buildFromSources(config: Config, commonArgs: seq[Argument], pkgInfos: seq[PackageInfo], noconfirm: bool): (Option[BuildResult], int) = let base = pkgInfos[0].base let repoPath = repoPath(config.tmpRoot, base) - let gitPath = pkgInfos[0].gitPath - let (cloneCode, cloneErrorMessage) = cloneRepo(config, pkgInfos) + let gitSubdir = pkgInfos[0].gitSubdir - if cloneCode != 0: - for e in cloneErrorMessage: printError(config.color, e) - printError(config.color, tr"$#: failed to clone git repository" % [base]) - (none(BuildResult), cloneCode) - else: - proc loop(noextract: bool, showEditLoop: bool): (Option[BuildResult], int) = - let res = if showEditLoop and not noconfirm: - editLoop(config, base, repoPath, gitPath, false, noconfirm) - else: - 'n' - - if res == 'a': - (none(BuildResult), 1) + proc loop(noextract: bool, showEditLoop: bool): (Option[BuildResult], int) = + let res = if showEditLoop and not noconfirm: + editLoop(config, base, repoPath, gitSubdir, false, noconfirm) else: - let (buildResult, code, interrupted) = buildLoop(config, pkgInfos, - noconfirm, noextract) - - if interrupted: - (buildResult, 1) - elif code != 0: - proc ask(): char = - let res = printColonUserChoice(config.color, - tr"Build failed, retry?", ['y', 'e', 'n', '?'], 'n', '?', - noconfirm, 'n') - if res == '?': - printUserInputHelp(('e', tr"retry with --noextract option")) - ask() - else: - res + 'n' - let res = ask() - if res == 'e': - loop(true, true) - elif res == 'y': - loop(false, true) + if res == 'a': + (none(BuildResult), 1) + else: + let (buildResult, code, interrupted) = buildLoop(config, pkgInfos, + noconfirm, noextract) + + if interrupted: + (buildResult, 1) + elif code != 0: + proc ask(): char = + let res = printColonUserChoice(config.color, + tr"Build failed, retry?", ['y', 'e', 'n', '?'], 'n', '?', + noconfirm, 'n') + if res == '?': + printUserInputHelp(('e', tr"retry with --noextract option")) + ask() else: - (buildResult, code) + res + + let res = ask() + if res == 'e': + loop(true, true) + elif res == 'y': + loop(false, true) else: (buildResult, code) + else: + (buildResult, code) - let preBuildCode = if config.preBuildCommand.isSome: (block: - printColon(config.color, tr"Running pre-build command...") + let preBuildCode = if config.preBuildCommand.isSome: (block: + printColon(config.color, tr"Running pre-build command...") - let code = forkWait(() => (block: - discard chdir(buildPath(repoPath, gitPath)) - dropPrivileges() - execResult(bashCmd, "-c", config.preBuildCommand.unsafeGet))) + let code = forkWait(() => (block: + discard chdir(buildPath(repoPath, gitSubdir)) + dropPrivileges() + execResult(bashCmd, "-c", config.preBuildCommand.unsafeGet))) - if code != 0 and printColonUserChoice(config.color, - tr"Command failed, continue?", ['y', 'n'], 'n', 'n', - noconfirm, 'n') == 'y': - 0 - else: - code) - else: + if code != 0 and printColonUserChoice(config.color, + tr"Command failed, continue?", ['y', 'n'], 'n', 'n', + noconfirm, 'n') == 'y': 0 - - if preBuildCode != 0: - (none(BuildResult), preBuildCode) + else: + code) else: - loop(false, false) + 0 + + if preBuildCode != 0: + (none(BuildResult), preBuildCode) + else: + loop(false, false) proc installGroupFromSources(config: Config, commonArgs: seq[Argument], basePackages: seq[seq[PackageInfo]], explicits: HashSet[string], @@ -555,7 +549,13 @@ proc handleInstall(args: seq[Argument], config: Config, upgradeCount: int, noconfirm: bool, explicits: HashSet[string], installed: seq[Installed], satisfied: Table[PackageReference, SatisfyResult], unsatisfied: seq[PackageReference], keepNames: HashSet[string], build: bool, directPacmanTargets: seq[string], - additionalPacmanTargets: seq[string], basePackages: seq[seq[seq[PackageInfo]]]): int = + additionalPacmanTargets: seq[string], basePackages: seq[seq[seq[PackageInfo]]], + buildPaths: seq[string]): int = + proc clearBuildPaths() = + for path in buildPaths: + removeDirQuiet(path) + discard rmdir(config.tmpRoot) + let workDirectPacmanTargets = if build: @[] else: directPacmanTargets let (directCode, directSome) = if workDirectPacmanTargets.len > 0 or upgradeCount > 0: @@ -565,12 +565,14 @@ proc handleInstall(args: seq[Argument], config: Config, upgradeCount: int, (0, false) let directSatisfiedCode = if directCode == 0 and unsatisfied.len > 0: (block: + clearBuildPaths() printUnsatisfied(config, satisfied, unsatisfied) 1) else: directCode if directSatisfiedCode != 0: + clearBuildPaths() directSatisfiedCode else: let commonArgs = args.keepOnlyOptions(commonOptions, upgradeCommonOptions) @@ -586,6 +588,8 @@ proc handleInstall(args: seq[Argument], config: Config, upgradeCount: int, tr"Proceed with building?", ['y', 'n'], 'y', 'n', noconfirm, 'y') if input == 'y': + let buildPathsSet = buildPaths.toSet + let (update, terminate) = if config.debug: (proc (a: int, b: int) {.closure.} = discard, proc {.closure.} = discard) else: @@ -599,7 +603,11 @@ proc handleInstall(args: seq[Argument], config: Config, upgradeCount: int, let pkgInfos = flatBasePackages[index] let base = pkgInfos[0].base let repoPath = repoPath(config.tmpRoot, base) - let (cloneCode, cloneErrorMessage) = cloneRepo(config, flatBasePackages[index]) + let (cloneCode, cloneErrorMessage) = if repoPath in buildPathsSet: + (0, none(string)) + else: (block: + removeDirQuiet(repoPath) + cloneAurRepo(config, flatBasePackages[index])) if cloneCode == 0: update(index + 1, flatBasePackages.len) @@ -638,13 +646,13 @@ proc handleInstall(args: seq[Argument], config: Config, upgradeCount: int, 'n' else: (block: let defaultYes = aur and not config.viewNoDefault - editLoop(config, base, repoPath, pkgInfos[0].gitPath, defaultYes, noconfirm)) + editLoop(config, base, repoPath, pkgInfos[0].gitSubdir, defaultYes, noconfirm)) if editRes == 'a': 1 else: let resultPkgInfos = reloadPkgInfos(config, - repoPath & "/" & pkgInfos[0].gitPath.get("."), pkgInfos) + repoPath & "/" & pkgInfos[0].gitSubdir.get("."), pkgInfos) let pgpKeys = lc[x | (p <- resultPkgInfos, x <- p.pgpKeys), string].deduplicate proc keysLoop(index: int, skipKeys: bool): char = @@ -708,13 +716,14 @@ proc handleInstall(args: seq[Argument], config: Config, upgradeCount: int, else: (nil, 0) - proc removeTmp() = + proc clearPaths() = for path in paths: removeDirQuiet(path) discard rmdir(config.tmpRoot) if confirmAndCloneCode != 0: - removeTmp() + clearBuildPaths() + clearPaths() confirmAndCloneCode else: let (_, initialUnrequired, initialUnrequiredWithoutOptional) = withAlpm(config.root, @@ -733,7 +742,7 @@ proc handleInstall(args: seq[Argument], config: Config, upgradeCount: int, (0, false) if additionalCode != 0: - removeTmp() + clearPaths() additionalCode else: if basePackages.len > 0: @@ -755,7 +764,7 @@ proc handleInstall(args: seq[Argument], config: Config, upgradeCount: int, x.value.buildPkgInfo.isNone and not x.key.checkSatisfied), PackageReference] if unsatisfied.len > 0: - removeTmp() + clearPaths() printUnsatisfied(config, satisfied, unsatisfied) 1 else: @@ -771,7 +780,7 @@ proc handleInstall(args: seq[Argument], config: Config, upgradeCount: int, let (installedAs, code, index) = installNext(0, nil, 0) if code != 0 and index < basePackages.len - 1: printWarning(config.color, tr"installation aborted") - removeTmp() + clearPaths() let newKeepNames = keepNames.map(n => installedAs.opt(n).get(n)) let (_, finalUnrequired, finalUnrequiredWithoutOptional) = withAlpm(config.root, @@ -1096,11 +1105,11 @@ proc handleSyncInstall*(args: seq[Argument], config: Config): int = let checkPacmanPkgInfos = printFormat.isNone and build and neededPacmanTargets.len > 0 - let (buildPkgInfos, obtainErrorMessages) = if checkPacmanPkgInfos: (block: + let (buildPkgInfos, buildPaths, obtainErrorMessages) = if checkPacmanPkgInfos: (block: echo(tr"checking official repositories...") obtainBuildPkgInfos[PackageInfo](config, pacmanTargets)) else: - (@[], @[]) + (@[], @[], @[]) if checkPacmanPkgInfos and buildPkgInfos.len < pacmanTargets.len: # "--build" conflicts with "--sysupgrade", so it's ok to fail here @@ -1179,4 +1188,4 @@ proc handleSyncInstall*(args: seq[Argument], config: Config): int = handleInstall(pacmanArgs, config, upgradeCount, noconfirm, explicits, installed, satisfied, unsatisfied, keepNames, build, directPacmanTargets, additionalPacmanTargets, - orderedPkgInfos) + orderedPkgInfos, buildPaths) diff --git a/src/package.nim b/src/package.nim index 30ff2f8..4d0fba6 100644 --- a/src/package.nim +++ b/src/package.nim @@ -49,9 +49,7 @@ type conflicts*: seq[PackageReference] replaces*: seq[PackageReference] gitUrl*: string - gitBranch*: Option[string] - gitCommit*: Option[string] - gitPath*: Option[string] + gitSubdir*: Option[string] GitRepo* = tuple[ url: string, @@ -124,8 +122,8 @@ proc lookupGitRepo*(repo: string, base: string, arch: string): Option[GitRepo] = template repoPath*(tmpRoot: string, base: string): string = tmpRoot & "/" & base -template buildPath*(repoPath: string, gitPath: Option[string]): string = - gitPath.map(p => repoPath & "/" & p).get(repoPath) +template buildPath*(repoPath: string, gitSubdir: Option[string]): string = + gitSubdir.map(p => repoPath & "/" & p).get(repoPath) template allDepends*(pkgInfo: PackageInfo): seq[PackageReference] = pkgInfo.depends & pkgInfo.makeDepends & pkgInfo.checkDepends @@ -232,8 +230,7 @@ proc parseSrcInfoKeys(srcInfo: string): proc parseSrcInfoName(repo: string, name: string, baseIndex: int, baseCount: int, rpcInfos: seq[RpcPackageInfo], baseSeq: ref seq[SrcInfoPair], nameSeq: ref seq[SrcInfoPair], - arch: string, gitUrl: string, gitBranch: Option[string], gitCommit: Option[string], - gitPath: Option[string]): Option[PackageInfo] = + arch: string, gitUrl: string, gitSubdir: Option[string]): Option[PackageInfo] = proc collectFromPairs(pairs: seq[SrcInfoPair], keyName: string): seq[string] = lc[x.value | (x <- pairs, x.key == keyName), string] @@ -288,17 +285,16 @@ proc parseSrcInfoName(repo: string, name: string, baseIndex: int, baseCount: int lastModified: info.map( i => i.lastModified).flatten, votes: info.map(i => i.votes).get(0), popularity: info.map(i => i.popularity).get(0), - gitUrl: gitUrl, gitBranch: gitBranch, gitCommit: gitCommit, gitPath: gitPath) | + gitUrl: gitUrl, gitSubdir: gitSubdir) | (b <- base, v <- versionFull), PackageInfo].optLast -proc parseSrcInfo*(repo: string, srcInfo: string, arch: string, - gitUrl: string, gitBranch: Option[string], gitCommit: Option[string], - gitPath: Option[string], rpcInfos: seq[RpcPackageInfo] = @[]): seq[PackageInfo] = +proc parseSrcInfo*(repo: string, srcInfo: string, arch: string, gitUrl: string, + gitSubdir: Option[string], rpcInfos: seq[RpcPackageInfo] = @[]): seq[PackageInfo] = let parsed = parseSrcInfoKeys(srcInfo) toSeq(parsed.table.namedPairs).foldl(a & toSeq(parseSrcInfoName(repo, b.key, a.len, parsed.table.len, rpcInfos, parsed.baseSeq, b.value, arch, - gitUrl, gitBranch, gitCommit, gitPath).items), newSeq[PackageInfo]()) + gitUrl, gitSubdir).items), newSeq[PackageInfo]()) proc `$`*(reference: PackageReference): string = reference.constraint |