Skip to content

Commit 9fd2746

Browse files
committed
Clearer error boundary, clean up some naming
1 parent fd76a99 commit 9fd2746

File tree

5 files changed

+36
-20
lines changed

5 files changed

+36
-20
lines changed

interface.d.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,10 @@ export interface IElectronAPI {
6565
sep: typeof path.sep
6666
copy: typeof fs.cp
6767
// No such thing as fs.mv, but our function will use fs.cp as a fallback
68-
move: (source: string | URL, destination: string | URL) => Promise<void>
68+
move: (
69+
source: string | URL,
70+
destination: string | URL
71+
) => Promise<void | Error>
6972
rename: (prev: string, next: string) => ReturnType<typeof fs.rename>
7073
packageJson: {
7174
name: string
@@ -97,7 +100,7 @@ export interface IElectronAPI {
97100
callback: (value: { version: string; releaseNotes: string }) => void
98101
) => Electron.IpcRenderer
99102
onUpdateError: (callback: (value: { error: Error }) => void) => Electron
100-
getArchivePath: () => Promise<string>
103+
getPathUserData: () => Promise<string>
101104
appRestart: () => void
102105
appCheckForUpdates: () => Promise<unknown>
103106
getArgvParsed: () => any

src/lib/paths.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -324,13 +324,17 @@ export function getFilePathRelativeToProject(
324324
return absoluteFilePath.slice(projectIndexInPath + sliceOffset) ?? ''
325325
}
326326

327+
/** Gets our "archive" directory for deletion/restoration, within the electron userData path */
327328
async function getArchiveBasePath() {
328-
return window.electron ? window.electron.getArchivePath() : `/${ARCHIVE_DIR}`
329+
return `${window.electron ? await window.electron.getPathUserData() : '/'}'${ARCHIVE_DIR}`
329330
}
330331

332+
/**
333+
* Our archive simply mirrors the absolute location on disk for the item
334+
* being archived, joining it with the archive base path.
335+
*/
331336
export async function toArchivePath(absolutePath: string) {
332337
const basePath = await getArchiveBasePath()
333-
console.log('basePath', basePath)
334338
return window.electron
335339
? window.electron.join(basePath, absolutePath)
336340
: webSafeJoin([basePath, absolutePath])

src/machines/systemIO/systemIOMachineDesktop.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {
2020
parentPathRelativeToProject,
2121
} from '@src/lib/paths'
2222
import type { Project } from '@src/lib/project'
23+
import { isErr } from '@src/lib/trap'
2324
import type { AppMachineContext } from '@src/lib/types'
2425
import type { ModuleType } from '@src/lib/wasm_lib_wrapper'
2526
import { systemIOMachine } from '@src/machines/systemIO/systemIOMachine'
@@ -762,8 +763,23 @@ export const systemIOMachineDesktop = systemIOMachine.provide({
762763
}
763764
}) => {
764765
if (window.electron) {
765-
console.log('moving', input)
766-
await window.electron.move(input.src, input.target)
766+
const result = await window.electron.move(input.src, input.target)
767+
if (
768+
isErr(result) &&
769+
// Where did the error code go? It's available in preload.ts
770+
result.message.includes('ENOTEMPTY') &&
771+
window.electron
772+
) {
773+
// TODO: this force deletion behavior assumes this move is only
774+
// really used in our archive/restore workflow. We should make
775+
// dedicated archive/restore code paths for that if we need cases
776+
// where we want to check with the user before going through with forcing.
777+
await window.electron.rm(input.target, {
778+
recursive: true,
779+
force: true,
780+
})
781+
await window.electron.move(input.src, input.target)
782+
}
767783
return {
768784
message: input.successMessage || 'Moved successfully',
769785
requestedAbsolutePath: '',

src/main.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ import {
2929
} from '@src/commandLineArgs'
3030
import { initialiseWasmNode } from '@src/lang/wasmUtilsNode'
3131
import {
32-
ARCHIVE_DIR,
3332
OAUTH2_DEVICE_CLIENT_ID,
3433
ZOO_STUDIO_PROTOCOL,
3534
} from '@src/lib/constants'
@@ -524,9 +523,7 @@ ipcMain.handle('disable-menu', (event, data) => {
524523
disableMenu(menuId)
525524
})
526525

527-
ipcMain.handle('get-archive-path', () =>
528-
path.join(app.getPath('userData'), ARCHIVE_DIR)
529-
)
526+
ipcMain.handle('get-path-userdata', () => app.getPath('userData'))
530527

531528
app.on('ready', () => {
532529
// Disable auto updater on non-versioned builds

src/preload.ts

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ async function move(source: string | URL, destination: string | URL) {
129129
.rename(source, destination)
130130
.catch(async (e) => {
131131
if (e.code === 'ENOENT') {
132+
// We need to make the directories in the destination
132133
const dirToMake =
133134
type === 'dir'
134135
? destination
@@ -143,6 +144,7 @@ async function move(source: string | URL, destination: string | URL) {
143144
.catch((e) => {
144145
console.error(e)
145146
if (e.code === 'EXDEV') {
147+
// Rename somehow isn't allowed, but copy+delete might be 🤞
146148
return Promise.all([
147149
fs.cp(source, destination, {
148150
recursive: true,
@@ -151,15 +153,9 @@ async function move(source: string | URL, destination: string | URL) {
151153
recursive: true,
152154
}),
153155
])
154-
} else if (e.code === 'ENOTEMPTY') {
155-
return Promise.all([
156-
fs.rm(destination, { recursive: true, force: true }),
157-
fs.rename(source, destination),
158-
])
159156
}
160157
return e
161158
})
162-
.catch((e) => e)
163159
}
164160

165161
// Electron has behavior where it doesn't clone the prototype chain over.
@@ -266,9 +262,9 @@ const disableMenu = async (menuId: string): Promise<any> => {
266262
})
267263
}
268264

269-
// Get the user data folder according to Electron, plus our designated archive folder
270-
const getArchivePath = async (): Promise<string> =>
271-
ipcRenderer.invoke('get-archive-path')
265+
// Get the user data folder according to Electron
266+
const getPathUserData = async (): Promise<string> =>
267+
ipcRenderer.invoke('get-path-userdata')
272268

273269
/**
274270
* Gotcha: Even if the callback function is the same function in JS memory
@@ -366,5 +362,5 @@ contextBridge.exposeInMainWorld('electron', {
366362
canReadWriteDirectory,
367363
copy,
368364
move,
369-
getArchivePath,
365+
getPathUserData,
370366
})

0 commit comments

Comments
 (0)