Skip current APKs during project updates

This commit is contained in:
iris committed 2026-09-10 00:58:08 -04:00
1 parent 605f353f4b
commit 4d00fe1b60
2 files changed
+35 -5

No files matched your search

+9
View File
@@ -1400,6 +1400,15 @@ mutable at runtime from the phone.
in *what* counts as stale, only in building past that answer once any in *what* counts as stale, only in building past that answer once any
one component tripped it. Regression test: one component tripped it. Regression test:
`a_pull_touching_one_component_does_not_rebuild_its_sibling`. `a_pull_touching_one_component_does_not_rebuild_its_sibling`.
- **A project-wide Update installs only the APKs that are waiting on this
phone.** Skipping a current APK's build was only half of the rule above:
after the pull, `startProjectUpdate` re-read the correctly current
component and then downloaded and offered every APK in the project to the
installer anyway. This showed up on a server-only change as an APK update
despite the card already knowing the installed copy was current.
`needsInstall` is deliberately the one predicate used both to make the
card's Update button pressable and to select the APKs that press installs;
the reason a project needs attention may belong to a sibling component.
- **Two words for one measurement is a bug even when both are true.** - **Two words for one measurement is a bug even when both are true.**
`MismatchedPairNote` said a sibling still on its old build was "older `MismatchedPairNote` said a sibling still on its old build was "older
than this build," while `freshnessNote` already has a word for that than this build," while `freshnessNote` already has a word for that
@@ -1127,7 +1127,7 @@ private fun AppListScreen(
/** /**
* Update is the whole way from the remote to this phone: pull, build what that brought in, and * Update is the whole way from the remote to this phone: pull, build what that brought in, and
* install every APK it produced. * install each APK whose built copy is newer than what is on this phone.
* *
* Written as the two halves in order rather than as a route of its own, because each half is * Written as the two halves in order rather than as a route of its own, because each half is
* already a thing this app does and reports: the pull-and-build reports in the project's row * already a thing this app does and reports: the pull-and-build reports in the project's row
@@ -1170,7 +1170,12 @@ private fun AppListScreen(
// fired together means the second replaces the first on // fired together means the second replaces the first on
// screen, and a component silently not installed is worse than // screen, and a component silently not installed is worse than
// one that says it is waiting. // one that says it is waiting.
for (component in fresh.components.filter { it.apk != null }) { val installed = installedTimes[fresh.key].orEmpty()
val variants = chosenVariants[fresh.key].orEmpty()
for (component in
fresh.components.filter {
needsInstall(it, installed[it.name], variants[it.name])
}) {
// Not the one whose build just failed: its row already // Not the one whose build just failed: its row already
// says so, and asking for it again would run the same // says so, and asking for it again would run the same
// failing command a second time to say it twice. // failing command a second time to say it twice.
@@ -4318,11 +4323,27 @@ private fun hasWorkWaiting(
entry.newCommits || entry.newCommits ||
entry.components.any { component -> entry.components.any { component ->
component.isStale || component.isStale ||
component.apk?.let { needsInstall(
!isUpToDate(it, installedTimes[component.name], chosenVariants[component.name]) component,
} == true installedTimes[component.name],
chosenVariants[component.name],
)
} }
/**
* Whether this component has an APK that would change what is installed on this phone.
*
* Shared by the card's Update button and the project-wide Update loop: once a pull has left an APK
* current, the button's reason for being enabled may belong to a sibling server, and that must not
* make this APK an install candidate anyway.
*/
private fun needsInstall(
component: ProjectComponent,
installedLastUpdateTimeMillis: Long?,
chosenVariantPath: String?,
): Boolean =
component.apk?.let { !isUpToDate(it, installedLastUpdateTimeMillis, chosenVariantPath) } == true
private fun isUpToDate( private fun isUpToDate(
apk: ComponentApk, apk: ComponentApk,
installedLastUpdateTimeMillis: Long?, installedLastUpdateTimeMillis: Long?,