Fix bisect script run and level validators
This commit is contained in:
@@ -20,8 +20,8 @@ android {
|
|||||||
applicationId = "solutions.tretter.githugandroid"
|
applicationId = "solutions.tretter.githugandroid"
|
||||||
minSdk = 26
|
minSdk = 26
|
||||||
targetSdk = 35
|
targetSdk = 35
|
||||||
versionCode = 182
|
versionCode = 183
|
||||||
versionName = "0.1.181"
|
versionName = "0.1.182"
|
||||||
|
|
||||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||||
vectorDrawables.useSupportLibrary = true
|
vectorDrawables.useSupportLibrary = true
|
||||||
|
|||||||
@@ -24,6 +24,27 @@ internal fun directoryCompletionCandidates(repo: RepoState): List<String> {
|
|||||||
.distinct()
|
.distinct()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal fun contextualCompletionCandidates(
|
||||||
|
candidates: List<String>,
|
||||||
|
commandBeforeToken: String,
|
||||||
|
token: String,
|
||||||
|
directoriesOnly: Boolean,
|
||||||
|
): List<String> {
|
||||||
|
val matches = candidates.sorted().filter { it.startsWith(token) }
|
||||||
|
if (directoriesOnly) return matches
|
||||||
|
|
||||||
|
val commandTokens = GitSandboxEngine.tokenizeCommand(commandBeforeToken.trim())
|
||||||
|
if (commandTokens == listOf("git", "bisect", "run")) {
|
||||||
|
val scriptMatches = matches.filter { candidate ->
|
||||||
|
val normalized = candidate.removePrefix("./")
|
||||||
|
normalized.endsWith(".sh") && '/' !in normalized && !normalized.startsWith(".")
|
||||||
|
}
|
||||||
|
if (scriptMatches.isNotEmpty()) return scriptMatches
|
||||||
|
}
|
||||||
|
|
||||||
|
return matches
|
||||||
|
}
|
||||||
|
|
||||||
private fun RepoState.currentDirPrefix(): String {
|
private fun RepoState.currentDirPrefix(): String {
|
||||||
return if (currentDir == ".") "" else currentDir.trimEnd('/') + "/"
|
return if (currentDir == ".") "" else currentDir.trimEnd('/') + "/"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -369,7 +369,12 @@ fun GitHugApp() {
|
|||||||
if (token.isBlank() && !isCdCompletion) return
|
if (token.isBlank() && !isCdCompletion) return
|
||||||
|
|
||||||
val candidates = runtime.completionCandidates(currentLevel, repo, directoriesOnly = isCdCompletion)
|
val candidates = runtime.completionCandidates(currentLevel, repo, directoriesOnly = isCdCompletion)
|
||||||
val matches = candidates.sorted().filter { it.startsWith(token) }
|
val matches = contextualCompletionCandidates(
|
||||||
|
candidates = candidates,
|
||||||
|
commandBeforeToken = beforeCursor.substring(0, tokenStart),
|
||||||
|
token = token,
|
||||||
|
directoriesOnly = isCdCompletion,
|
||||||
|
)
|
||||||
if (matches.isEmpty()) return
|
if (matches.isEmpty()) return
|
||||||
|
|
||||||
val replacement = if (matches.size == 1) matches.first() else commonPrefix(matches)
|
val replacement = if (matches.size == 1) matches.first() else commonPrefix(matches)
|
||||||
|
|||||||
@@ -144,7 +144,12 @@ class GitRepositoryRuntime private constructor(
|
|||||||
|
|
||||||
val result = when (expandedTokens.first()) {
|
val result = when (expandedTokens.first()) {
|
||||||
"git" -> {
|
"git" -> {
|
||||||
val gitResult = runGit(nativeGit, workingDir, expandedTokens.drop(1), invocation.environment)
|
val gitResult = runGit(
|
||||||
|
nativeGit,
|
||||||
|
workingDir,
|
||||||
|
normalizeGitArgumentsForAndroid(expandedTokens.drop(1)),
|
||||||
|
invocation.environment,
|
||||||
|
)
|
||||||
AppLog.d(
|
AppLog.d(
|
||||||
"GitRuntime",
|
"GitRuntime",
|
||||||
"Git command result level=${level.id} exit=${gitResult.exitCode} output=${gitResult.outputLines}",
|
"Git command result level=${level.id} exit=${gitResult.exitCode} output=${gitResult.outputLines}",
|
||||||
@@ -167,6 +172,19 @@ class GitRepositoryRuntime private constructor(
|
|||||||
return refreshedRepo to result.second
|
return refreshedRepo to result.second
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun normalizeGitArgumentsForAndroid(arguments: List<String>): List<String> {
|
||||||
|
if (
|
||||||
|
arguments.size >= 3 &&
|
||||||
|
arguments[0] == "bisect" &&
|
||||||
|
arguments[1] == "run" &&
|
||||||
|
arguments[2].startsWith("./") &&
|
||||||
|
arguments[2].endsWith(".sh")
|
||||||
|
) {
|
||||||
|
return arguments.take(2) + listOf("sh", arguments[2]) + arguments.drop(3)
|
||||||
|
}
|
||||||
|
return arguments
|
||||||
|
}
|
||||||
|
|
||||||
fun completionCandidates(level: Level, currentRepo: RepoState, directoriesOnly: Boolean): List<String> {
|
fun completionCandidates(level: Level, currentRepo: RepoState, directoriesOnly: Boolean): List<String> {
|
||||||
requireNativeGit()
|
requireNativeGit()
|
||||||
val sandbox = sandboxDir(level)
|
val sandbox = sandboxDir(level)
|
||||||
|
|||||||
@@ -504,6 +504,37 @@ class GitSandboxEngineTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun nativeBisectRunScriptShortcutRunsThroughShell() {
|
||||||
|
val git = testGitBinary()
|
||||||
|
assumeTrue(git.exists() && git.canExecute())
|
||||||
|
val root = Files.createTempDirectory("githug-bisect-run-script").toFile()
|
||||||
|
try {
|
||||||
|
val runtime = GitRepositoryRuntime(root, git)
|
||||||
|
val level = bisectLevel()
|
||||||
|
var repo = runtime.prepareLevel(level)
|
||||||
|
|
||||||
|
listOf(
|
||||||
|
"git bisect start",
|
||||||
|
"git bisect bad HEAD",
|
||||||
|
"git bisect good known-good",
|
||||||
|
).forEach { command ->
|
||||||
|
val (nextRepo, _) = runtime.execute(level, repo, command)
|
||||||
|
repo = nextRepo
|
||||||
|
}
|
||||||
|
|
||||||
|
val (_, output) = runtime.execute(level, repo, "git bisect run ./test-balance.sh")
|
||||||
|
val text = output.joinToString("\n")
|
||||||
|
|
||||||
|
assertFalse(text, text.contains("Permission denied", ignoreCase = true))
|
||||||
|
assertFalse(text, text.contains("can't execute", ignoreCase = true))
|
||||||
|
assertFalse(text, text.contains("bogus exit code", ignoreCase = true))
|
||||||
|
assertTrue(text, text.contains("first bad commit", ignoreCase = true))
|
||||||
|
} finally {
|
||||||
|
root.deleteRecursively()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun testGitBinary(): File {
|
private fun testGitBinary(): File {
|
||||||
System.getenv("GITHUG_TEST_GIT_BINARY")
|
System.getenv("GITHUG_TEST_GIT_BINARY")
|
||||||
?.takeIf { it.isNotBlank() }
|
?.takeIf { it.isNotBlank() }
|
||||||
|
|||||||
Reference in New Issue
Block a user