mirror of
https://github.com/stablyai/orca.git
synced 2026-11-03 18:47:40 +00:00
fix(wsl): don't start a stopped distro to read a repo's default base ref (#35778)
* fix(wsl): don't start a stopped distro to read a repo's default base ref Opening a repo's Settings pane ran git for-each-ref and git remote through the repo's WSL distro, which started it after the user had stopped it (E9). Background reads now return the existing unknown result while the distro is stopped; an explicit refresh can pass wakeWslDistro. The runtime RPC that serves the same read to paired clients is gated the same way. * fix(wsl): re-read a refused default base ref once its distro runs A refused read now names the distro and defers a preflight:wslDistroRunning broadcast; Settings and Source Control re-ask on it, so base comparison returns without a repo switch. Drops the unused wakeWslDistro option.
This commit is contained in:
@@ -18,14 +18,18 @@ function broadcastWslDistroRunning(distro: string): void {
|
||||
}
|
||||
}
|
||||
|
||||
/** Tells renderers once `distro` runs, so they re-ask a background read it refused (E9). */
|
||||
export function broadcastWhenWslDistroRunning(distro: string, key: string): void {
|
||||
deferUntilWslDistroRunning(distro, key, () => broadcastWslDistroRunning(distro))
|
||||
}
|
||||
|
||||
/** A refused background check is deferred, not done: renderers re-ask once the distro runs (E9). */
|
||||
export async function deferRefusedPreflight<T>(run: () => Promise<T>): Promise<T> {
|
||||
try {
|
||||
return await run()
|
||||
} catch (error) {
|
||||
if (error instanceof WslDistroStoppedError || error instanceof WslDistroUnverifiableError) {
|
||||
const { distro } = error
|
||||
deferUntilWslDistroRunning(distro, RETRY_KEY, () => broadcastWslDistroRunning(distro))
|
||||
broadcastWhenWslDistroRunning(error.distro, RETRY_KEY)
|
||||
}
|
||||
throw error
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import type * as GitRunner from '../git/runner'
|
||||
import type * as RepoModule from '../git/repo'
|
||||
import type * as WslUncAccessGate from '../wsl/wsl-unc-access-gate'
|
||||
|
||||
const { reposMocks, moduleMocks } = await vi.hoisted(async () => {
|
||||
const moduleMocks = await import('./repos-remote-test-harness')
|
||||
@@ -21,6 +22,11 @@ vi.mock('./registered-worktree-roots-cache', () =>
|
||||
vi.mock('../worktree-root-preparation', () =>
|
||||
moduleMocks.worktreeRootPreparationModuleMock(reposMocks)
|
||||
)
|
||||
// The stopped-distro gate has its own tests; here it must not hide the routing under test.
|
||||
vi.mock('../wsl/wsl-unc-access-gate', async (importOriginal) => ({
|
||||
...(await importOriginal<typeof WslUncAccessGate>()),
|
||||
blockedWslDistroForPath: vi.fn(async () => null)
|
||||
}))
|
||||
|
||||
import { registerRepoHandlers } from './repos'
|
||||
import { WSL_HOSTS_INTERNAL_GATE_ENV } from '../../shared/wsl-host-internal-gate'
|
||||
|
||||
@@ -0,0 +1,181 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import type * as DistroGateModule from '../../wsl-background-distro-gate'
|
||||
import type { Repo } from '../../../shared/repo-types'
|
||||
|
||||
const mocks = vi.hoisted(() => {
|
||||
const state: {
|
||||
distroState: 'running' | 'stopped' | 'unverifiable'
|
||||
gitOptions: { wslDistro?: string }
|
||||
} = { distroState: 'stopped', gitOptions: {} }
|
||||
return {
|
||||
state,
|
||||
handlers: new Map<string, (event: unknown, args: unknown) => Promise<unknown>>(),
|
||||
send: vi.fn(),
|
||||
getBaseRefDefault: vi.fn(async (_path: string, _options?: unknown) => 'origin/main'),
|
||||
getRemoteCount: vi.fn(async (_path: string, _options?: unknown) => 1)
|
||||
}
|
||||
})
|
||||
|
||||
vi.mock('electron', () => ({
|
||||
BrowserWindow: {
|
||||
getAllWindows: () => [{ isDestroyed: () => false, webContents: { send: mocks.send } }]
|
||||
},
|
||||
ipcMain: {
|
||||
handle: (channel: string, handler: (event: unknown, args: unknown) => Promise<unknown>) =>
|
||||
mocks.handlers.set(channel, handler)
|
||||
}
|
||||
}))
|
||||
vi.mock('../../git/repo', () => ({
|
||||
getBaseRefDefault: mocks.getBaseRefDefault,
|
||||
getRemoteCount: mocks.getRemoteCount,
|
||||
searchBaseRefDetails: vi.fn(async () => [])
|
||||
}))
|
||||
vi.mock('../../project-runtime-git-options', () => ({
|
||||
getProjectRuntimeReadGitOptions: () => mocks.state.gitOptions
|
||||
}))
|
||||
vi.mock('../../wsl-background-distro-gate', async (importOriginal) => ({
|
||||
...(await importOriginal<typeof DistroGateModule>()),
|
||||
readWslDistroRunningState: vi.fn(async () => mocks.state.distroState)
|
||||
}))
|
||||
|
||||
import { registerBaseRefQueryHandlers } from './base-ref-query-handlers'
|
||||
import {
|
||||
_resetWslBackgroundDistroGateForTests,
|
||||
noteWslDistrosRunning
|
||||
} from '../../wsl-background-distro-gate'
|
||||
import { RuntimeRepositoryRefQueries } from '../../runtime/runtime-repository-ref-queries'
|
||||
|
||||
const WSL_REPO = '\\\\wsl.localhost\\Ubuntu\\home\\me\\repo'
|
||||
const UNKNOWN = { defaultBaseRef: null, remoteCount: 0 }
|
||||
const REFUSED = { ...UNKNOWN, refusedWslDistro: 'Ubuntu' }
|
||||
const originalPlatform = Object.getOwnPropertyDescriptor(process, 'platform')
|
||||
|
||||
function makeRepo(overrides: Partial<Repo> = {}): Repo {
|
||||
return {
|
||||
id: 'repo-1',
|
||||
path: WSL_REPO,
|
||||
displayName: 'repo',
|
||||
badgeColor: '#000',
|
||||
addedAt: 1,
|
||||
kind: 'git',
|
||||
...overrides
|
||||
}
|
||||
}
|
||||
|
||||
function registerWith(repo: Repo): (args: Record<string, unknown>) => Promise<unknown> {
|
||||
const store = { getRepo: () => repo, getRepos: () => [repo] }
|
||||
registerBaseRefQueryHandlers(
|
||||
// oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: the handler reads only getRepo/getRepos, both provided.
|
||||
store as unknown as Parameters<typeof registerBaseRefQueryHandlers>[0]
|
||||
)
|
||||
const handler = mocks.handlers.get('repos:getBaseRefDefault')
|
||||
if (!handler) {
|
||||
throw new Error('repos:getBaseRefDefault was not registered')
|
||||
}
|
||||
return (args) => handler(null, { repoId: repo.id, ...args })
|
||||
}
|
||||
|
||||
describe('repos:getBaseRefDefault for a stopped WSL distro (E9)', () => {
|
||||
beforeEach(() => {
|
||||
Object.defineProperty(process, 'platform', { configurable: true, value: 'win32' })
|
||||
mocks.handlers.clear()
|
||||
mocks.send.mockClear()
|
||||
_resetWslBackgroundDistroGateForTests()
|
||||
mocks.state.distroState = 'stopped'
|
||||
mocks.state.gitOptions = {}
|
||||
mocks.getBaseRefDefault.mockClear()
|
||||
mocks.getRemoteCount.mockClear()
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
if (originalPlatform) {
|
||||
Object.defineProperty(process, 'platform', originalPlatform)
|
||||
}
|
||||
})
|
||||
|
||||
it('returns unknown without running Git when the Settings pane opens', async () => {
|
||||
const getDefault = registerWith(makeRepo())
|
||||
|
||||
await expect(getDefault({})).resolves.toEqual(REFUSED)
|
||||
expect(mocks.getBaseRefDefault).not.toHaveBeenCalled()
|
||||
expect(mocks.getRemoteCount).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('tells renderers to re-ask once the refusing distro runs', async () => {
|
||||
const getDefault = registerWith(makeRepo())
|
||||
await getDefault({})
|
||||
expect(mocks.send).not.toHaveBeenCalled()
|
||||
|
||||
noteWslDistrosRunning(['Ubuntu'])
|
||||
|
||||
expect(mocks.send).toHaveBeenCalledWith('preflight:wslDistroRunning', 'Ubuntu')
|
||||
})
|
||||
|
||||
it('refuses a host path whose Git runs through wsl.exe in a stopped distro', async () => {
|
||||
mocks.state.gitOptions = { wslDistro: 'Ubuntu' }
|
||||
const getDefault = registerWith(makeRepo({ path: 'C:\\src\\repo' }))
|
||||
|
||||
await expect(getDefault({})).resolves.toEqual(REFUSED)
|
||||
expect(mocks.getBaseRefDefault).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('treats unverifiable like stopped', async () => {
|
||||
mocks.state.distroState = 'unverifiable'
|
||||
const getDefault = registerWith(makeRepo())
|
||||
|
||||
await expect(getDefault({})).resolves.toEqual(REFUSED)
|
||||
expect(mocks.getBaseRefDefault).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('runs Git when the distro is running', async () => {
|
||||
mocks.state.distroState = 'running'
|
||||
const getDefault = registerWith(makeRepo())
|
||||
|
||||
await expect(getDefault({})).resolves.toEqual({ defaultBaseRef: 'origin/main', remoteCount: 1 })
|
||||
})
|
||||
|
||||
it('leaves Windows-host repos ungated', async () => {
|
||||
const getDefault = registerWith(makeRepo({ path: 'C:\\src\\repo' }))
|
||||
|
||||
await expect(getDefault({})).resolves.toEqual({ defaultBaseRef: 'origin/main', remoteCount: 1 })
|
||||
})
|
||||
|
||||
it('leaves folder and SSH repos on their existing unknown result', async () => {
|
||||
const folder = registerWith(makeRepo({ kind: 'folder' }))
|
||||
await expect(folder({})).resolves.toEqual(UNKNOWN)
|
||||
const ssh = registerWith(makeRepo({ path: '/home/me/repo', connectionId: 'ssh-1' }))
|
||||
await expect(ssh({})).resolves.toEqual(UNKNOWN)
|
||||
expect(mocks.getBaseRefDefault).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
describe('runtime repo.baseRefDefault for a stopped WSL distro (E9)', () => {
|
||||
beforeEach(() => {
|
||||
Object.defineProperty(process, 'platform', { configurable: true, value: 'win32' })
|
||||
mocks.state.distroState = 'stopped'
|
||||
mocks.getBaseRefDefault.mockClear()
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
if (originalPlatform) {
|
||||
Object.defineProperty(process, 'platform', originalPlatform)
|
||||
}
|
||||
})
|
||||
|
||||
it("returns unknown without touching the stopped distro's UNC path", async () => {
|
||||
const queries = new RuntimeRepositoryRefQueries({ resolveRepo: async () => makeRepo() })
|
||||
|
||||
await expect(queries.getDefault('id:repo-1')).resolves.toEqual(UNKNOWN)
|
||||
expect(mocks.getBaseRefDefault).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('reads the default once the distro runs', async () => {
|
||||
mocks.state.distroState = 'running'
|
||||
const queries = new RuntimeRepositoryRefQueries({ resolveRepo: async () => makeRepo() })
|
||||
|
||||
await expect(queries.getDefault('id:repo-1')).resolves.toEqual({
|
||||
defaultBaseRef: 'origin/main',
|
||||
remoteCount: 1
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -14,6 +14,8 @@ import {
|
||||
} from '../../../shared/execution-host'
|
||||
import { getBaseRefDefault, getRemoteCount, searchBaseRefDetails } from '../../git/repo'
|
||||
import { getProjectRuntimeReadGitOptions } from '../../project-runtime-git-options'
|
||||
import { blockedWslDistroForPath } from '../../wsl/wsl-unc-access-gate'
|
||||
import { broadcastWhenWslDistroRunning } from '../preflight-wsl-refusal-retry'
|
||||
|
||||
export function registerBaseRefQueryHandlers(store: Store): void {
|
||||
ipcMain.handle(
|
||||
@@ -33,6 +35,12 @@ export function registerBaseRefQueryHandlers(store: Store): void {
|
||||
}
|
||||
// Where the project's runtime runs Git; a runtime needing repair reads with host Git.
|
||||
const git = getProjectRuntimeReadGitOptions(store, repo)
|
||||
// Opening Settings must not start a stopped distro (E9); the renderer re-asks once it runs.
|
||||
const blocked = await blockedWslDistroForPath(repo.path, git.wslDistro)
|
||||
if (blocked) {
|
||||
broadcastWhenWslDistroRunning(blocked.distro, `base-ref-default:${repo.id}`)
|
||||
return { defaultBaseRef: null, remoteCount: 0, refusedWslDistro: blocked.distro }
|
||||
}
|
||||
const [defaultBaseRef, remoteCount] = await Promise.all([
|
||||
getBaseRefDefault(repo.path, git),
|
||||
getRemoteCount(repo.path, git)
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
} from '../../shared/repo-search-limits'
|
||||
import { getBaseRefDefault, getRemoteCount, searchBaseRefDetails } from '../git/repo'
|
||||
import { getRepoRoutingConnectionId } from '../../shared/execution-host'
|
||||
import { blockedWslDistroForPath } from '../wsl/wsl-unc-access-gate'
|
||||
|
||||
type RuntimeRepositoryRefQueryDependencies = {
|
||||
resolveRepo: (selector: string) => Promise<Repo>
|
||||
@@ -53,6 +54,10 @@ export class RuntimeRepositoryRefQueries {
|
||||
if (getRepoRoutingConnectionId(repo)) {
|
||||
return { defaultBaseRef: null, remoteCount: 0 }
|
||||
}
|
||||
// A client's Settings pane must not start this host's stopped distro over `\\wsl.localhost` (E9).
|
||||
if (await blockedWslDistroForPath(repo.path)) {
|
||||
return { defaultBaseRef: null, remoteCount: 0 }
|
||||
}
|
||||
const [defaultBaseRef, remoteCount] = await Promise.all([
|
||||
getBaseRefDefault(repo.path),
|
||||
getRemoteCount(repo.path)
|
||||
|
||||
+7
-16
@@ -1,5 +1,5 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import { getRuntimeRepoBaseRefDefault } from '@/runtime/runtime-repo-client'
|
||||
import { watchRuntimeRepoBaseRefDefault } from '@/runtime/runtime-repo-client'
|
||||
import type { ExecutionHostId } from '../../../../../../shared/execution-host'
|
||||
|
||||
export function useSourceControlBaseRefDefault({
|
||||
@@ -23,24 +23,15 @@ export function useSourceControlBaseRefDefault({
|
||||
}
|
||||
// Drop the previous repo’s default while loading to prevent transient invalid-base comparisons.
|
||||
setDefaultBaseRef(null)
|
||||
let stale = false
|
||||
// Resolve on the repo owner, which may differ from the focused host.
|
||||
void getRuntimeRepoBaseRefDefault(activeRepoExecutionHostId, activeRepoId)
|
||||
.then((result) => {
|
||||
if (!stale) {
|
||||
setDefaultBaseRef(result.defaultBaseRef)
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
return watchRuntimeRepoBaseRefDefault(activeRepoExecutionHostId, activeRepoId, {
|
||||
onResult: (result) => setDefaultBaseRef(result.defaultBaseRef),
|
||||
onError: (err) => {
|
||||
console.error('[SourceControl] getBaseRefDefault failed', err)
|
||||
// Keep failures unknown so comparison/review fetches cannot use a fabricated ref.
|
||||
if (!stale) {
|
||||
setDefaultBaseRef(null)
|
||||
}
|
||||
})
|
||||
return () => {
|
||||
stale = true
|
||||
}
|
||||
setDefaultBaseRef(null)
|
||||
}
|
||||
})
|
||||
}, [
|
||||
// Only owner changes reset the base; metadata churn must not restart eligibility’s timeout.
|
||||
activeRepoConnectionId,
|
||||
|
||||
@@ -4,8 +4,8 @@ import { Input } from '../ui/input'
|
||||
import { useAppStore } from '@/store'
|
||||
import { findRepoForHost } from '@/store/slices/repo-host-identity'
|
||||
import {
|
||||
getRuntimeRepoBaseRefDefault,
|
||||
searchRuntimeRepoBaseRefs
|
||||
searchRuntimeRepoBaseRefs,
|
||||
watchRuntimeRepoBaseRefDefault
|
||||
} from '@/runtime/runtime-repo-client'
|
||||
import { isRuntimeRepoRefSearchQueryWithinLimit } from '@/runtime/runtime-repo-search-bounds'
|
||||
import { translate } from '@/i18n/i18n'
|
||||
@@ -61,37 +61,25 @@ export function BaseRefPicker({
|
||||
}, [baseRefResults.length])
|
||||
|
||||
useEffect(() => {
|
||||
let stale = false
|
||||
|
||||
const loadDefaultBaseRef = async (): Promise<void> => {
|
||||
try {
|
||||
if (!ownerHostId) {
|
||||
return
|
||||
}
|
||||
const result = await getRuntimeRepoBaseRefDefault(ownerHostId, repoId)
|
||||
if (!stale) {
|
||||
setDefaultBaseRef(result.defaultBaseRef)
|
||||
setRemoteCount(result.remoteCount)
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('[BaseRefPicker] getBaseRefDefault failed', err)
|
||||
if (!stale) {
|
||||
setDefaultBaseRef(null)
|
||||
setRemoteCount(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setBaseRefQuery('')
|
||||
setBaseRefResults([])
|
||||
// Drop the previous repo’s default before loading so its Following label cannot describe the new repo.
|
||||
setDefaultBaseRef(null)
|
||||
setRemoteCount(0)
|
||||
void loadDefaultBaseRef()
|
||||
|
||||
return () => {
|
||||
stale = true
|
||||
if (!ownerHostId) {
|
||||
return
|
||||
}
|
||||
return watchRuntimeRepoBaseRefDefault(ownerHostId, repoId, {
|
||||
onResult: (result) => {
|
||||
setDefaultBaseRef(result.defaultBaseRef)
|
||||
setRemoteCount(result.remoteCount)
|
||||
},
|
||||
onError: (err) => {
|
||||
console.error('[BaseRefPicker] getBaseRefDefault failed', err)
|
||||
setDefaultBaseRef(null)
|
||||
setRemoteCount(0)
|
||||
}
|
||||
})
|
||||
}, [ownerHostId, repoId])
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
// @vitest-environment happy-dom
|
||||
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { watchRuntimeRepoBaseRefDefault } from './runtime-repo-client'
|
||||
|
||||
const getBaseRefDefault = vi.fn()
|
||||
const distroRunningListeners = new Set<(distro: string) => void>()
|
||||
|
||||
function emitDistroRunning(distro: string): void {
|
||||
for (const listener of distroRunningListeners) {
|
||||
listener(distro)
|
||||
}
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
getBaseRefDefault.mockReset()
|
||||
distroRunningListeners.clear()
|
||||
vi.stubGlobal('window', {
|
||||
api: {
|
||||
repos: { getBaseRefDefault },
|
||||
preflight: {
|
||||
onWslDistroRunning: (listener: (distro: string) => void) => {
|
||||
distroRunningListeners.add(listener)
|
||||
return () => distroRunningListeners.delete(listener)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
vi.unstubAllGlobals()
|
||||
})
|
||||
|
||||
const REFUSED = { defaultBaseRef: null, remoteCount: 0, refusedWslDistro: 'Ubuntu' }
|
||||
const LOADED = { defaultBaseRef: 'origin/main', remoteCount: 1 }
|
||||
|
||||
describe('watchRuntimeRepoBaseRefDefault after a stopped-distro refusal (E9)', () => {
|
||||
it('loads again once the refusing distro runs', async () => {
|
||||
getBaseRefDefault.mockResolvedValueOnce(REFUSED).mockResolvedValueOnce(LOADED)
|
||||
const onResult = vi.fn()
|
||||
watchRuntimeRepoBaseRefDefault('local', 'repo-1', { onResult, onError: vi.fn() })
|
||||
await vi.waitFor(() => expect(onResult).toHaveBeenCalledWith(REFUSED))
|
||||
|
||||
emitDistroRunning('ubuntu')
|
||||
|
||||
await vi.waitFor(() => expect(onResult).toHaveBeenLastCalledWith(LOADED))
|
||||
expect(getBaseRefDefault).toHaveBeenCalledTimes(2)
|
||||
expect(distroRunningListeners.size).toBe(0)
|
||||
})
|
||||
|
||||
it('ignores other distros', async () => {
|
||||
getBaseRefDefault.mockResolvedValue(REFUSED)
|
||||
const onResult = vi.fn()
|
||||
watchRuntimeRepoBaseRefDefault('local', 'repo-1', { onResult, onError: vi.fn() })
|
||||
await vi.waitFor(() => expect(distroRunningListeners.size).toBe(1))
|
||||
|
||||
emitDistroRunning('Debian')
|
||||
|
||||
expect(getBaseRefDefault).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it('stops listening when cancelled', async () => {
|
||||
getBaseRefDefault.mockResolvedValue(REFUSED)
|
||||
const cancel = watchRuntimeRepoBaseRefDefault('local', 'repo-1', {
|
||||
onResult: vi.fn(),
|
||||
onError: vi.fn()
|
||||
})
|
||||
await vi.waitFor(() => expect(distroRunningListeners.size).toBe(1))
|
||||
|
||||
cancel()
|
||||
emitDistroRunning('Ubuntu')
|
||||
|
||||
expect(distroRunningListeners.size).toBe(0)
|
||||
expect(getBaseRefDefault).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it('does not listen after a result that was not refused', async () => {
|
||||
getBaseRefDefault.mockResolvedValue(LOADED)
|
||||
const onResult = vi.fn()
|
||||
watchRuntimeRepoBaseRefDefault('local', 'repo-1', { onResult, onError: vi.fn() })
|
||||
await vi.waitFor(() => expect(onResult).toHaveBeenCalledWith(LOADED))
|
||||
|
||||
expect(distroRunningListeners.size).toBe(0)
|
||||
})
|
||||
})
|
||||
@@ -18,6 +18,7 @@ function repoHostTarget(hostId: ExecutionHostId): RuntimeClientTarget {
|
||||
export type RuntimeRepoBaseRefDefault = {
|
||||
defaultBaseRef: string | null
|
||||
remoteCount: number
|
||||
refusedWslDistro?: string
|
||||
}
|
||||
|
||||
export async function getRuntimeRepoBaseRefDefault(
|
||||
@@ -36,6 +37,53 @@ export async function getRuntimeRepoBaseRefDefault(
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the repo's default base ref and, when a stopped WSL distro refused it (E9), loads it again
|
||||
* once main reports that distro running. Returns a cancel.
|
||||
*/
|
||||
export function watchRuntimeRepoBaseRefDefault(
|
||||
hostId: ExecutionHostId,
|
||||
repoId: string,
|
||||
handlers: {
|
||||
onResult: (result: RuntimeRepoBaseRefDefault) => void
|
||||
onError: (error: unknown) => void
|
||||
}
|
||||
): () => void {
|
||||
let cancelled = false
|
||||
let stopRetry: (() => void) | null = null
|
||||
const load = (): void => {
|
||||
getRuntimeRepoBaseRefDefault(hostId, repoId).then(
|
||||
(result) => {
|
||||
if (cancelled) {
|
||||
return
|
||||
}
|
||||
handlers.onResult(result)
|
||||
const refused = result.refusedWslDistro?.toLowerCase()
|
||||
const onDistroRunning = window.api.preflight?.onWslDistroRunning
|
||||
if (refused && typeof onDistroRunning === 'function') {
|
||||
stopRetry = onDistroRunning((distro) => {
|
||||
if (distro.toLowerCase() === refused) {
|
||||
stopRetry?.()
|
||||
stopRetry = null
|
||||
load()
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
(error: unknown) => {
|
||||
if (!cancelled) {
|
||||
handlers.onError(error)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
load()
|
||||
return () => {
|
||||
cancelled = true
|
||||
stopRetry?.()
|
||||
}
|
||||
}
|
||||
|
||||
export async function searchRuntimeRepoBaseRefs(
|
||||
hostId: ExecutionHostId,
|
||||
repoId: string,
|
||||
|
||||
@@ -104,6 +104,8 @@ export type Repo = {
|
||||
export type BaseRefDefaultResult = {
|
||||
defaultBaseRef: string | null
|
||||
remoteCount: number
|
||||
/** This stopped (or unverifiable) WSL distro refused the read (E9); re-ask once it runs. */
|
||||
refusedWslDistro?: string
|
||||
}
|
||||
|
||||
export type BaseRefSearchResult = {
|
||||
|
||||
Reference in New Issue
Block a user