From 99d35b78c5f4a0e49f3baafc463142994fe051b8 Mon Sep 17 00:00:00 2001 From: Sonny Piers Date: Wed, 14 Feb 2024 17:10:31 +0100 Subject: [PATCH] Asynchronize file copies (#882) --- src/Library/Library.js | 2 +- src/PanelCode.js | 11 ++++++++++- src/application.js | 9 +++------ src/init.js | 2 ++ src/langs/rust/Compiler.js | 6 +++--- src/langs/rust/rust.js | 40 +++++++++++++++++++++++++++++++++++++- src/sessions.js | 16 ++++++++++----- src/util.js | 14 ++++++++----- src/window.js | 2 +- 9 files changed, 79 insertions(+), 23 deletions(-) diff --git a/src/Library/Library.js b/src/Library/Library.js index 5f2f0c29e..7267f36e4 100644 --- a/src/Library/Library.js +++ b/src/Library/Library.js @@ -80,7 +80,7 @@ export function getDemo(name) { async function openDemo({ application, demo_name, language }) { const demo = getDemo(demo_name); - const session = createSessionFromDemo(demo); + const session = await createSessionFromDemo(demo); if (language) { session.settings.set_int("code-language", language.index); diff --git a/src/PanelCode.js b/src/PanelCode.js index 5bf0a619c..e101ff253 100644 --- a/src/PanelCode.js +++ b/src/PanelCode.js @@ -2,8 +2,13 @@ import Gio from "gi://Gio"; import GObject from "gi://GObject"; import { settings as global_settings, makeDropdownFlat } from "./util.js"; +import { setupRustProject } from "./langs/rust/rust.js"; -export default function PanelCode({ builder, previewer, settings }) { +export default function PanelCode({ + builder, + previewer, + session: { settings, file }, +}) { const panel_code = builder.get_object("panel_code"); const button_code = builder.get_object("button_code"); const stack_code = builder.get_object("stack_code"); @@ -47,6 +52,10 @@ export default function PanelCode({ builder, previewer, settings }) { panel.language = dropdown_code_lang.selected_item?.string; stack_code.visible_child_name = panel.language; previewer.useInternal().catch(console.error); + + if (panel.language.toLowerCase() === "rust") { + setupRustProject(file).catch(console.error); + } } switchLanguage(); diff --git a/src/application.js b/src/application.js index a05f1f8d5..eed32b76b 100644 --- a/src/application.js +++ b/src/application.js @@ -75,14 +75,11 @@ function setColorScheme() { setColorScheme(); settings.connect("changed::color-scheme", setColorScheme); -// We are not using async otherwise the app segfaults -// does not like opening a window in a promise -// TODO: make a reproducer and file a GJS bug function restoreSessions() { const sessions = getSessions(); if (sessions.length < 1) { - bootstrap(); + bootstrap().catch(console.error); } else { sessions.forEach((session) => { const { load } = Window({ @@ -94,7 +91,7 @@ function restoreSessions() { } } -function bootstrap() { +async function bootstrap() { const first_run = settings.get_boolean("first-run"); if (!first_run) { application.activate_action("library", null); @@ -102,7 +99,7 @@ function bootstrap() { } const demo = getDemo("Welcome"); - const session = createSessionFromDemo(demo); + const session = await createSessionFromDemo(demo); const { load, window } = Window({ application, session, diff --git a/src/init.js b/src/init.js index b6ca0cb7e..25ccf56c2 100644 --- a/src/init.js +++ b/src/init.js @@ -96,3 +96,5 @@ Gio._promisify( "next_files_async", "next_files_finish", ); + +Gio._promisify(Gio.File.prototype, "copy_async", "copy_finish"); diff --git a/src/langs/rust/Compiler.js b/src/langs/rust/Compiler.js index 4e7c129b1..1daf8ca27 100644 --- a/src/langs/rust/Compiler.js +++ b/src/langs/rust/Compiler.js @@ -1,8 +1,8 @@ import Gio from "gi://Gio"; import GLib from "gi://GLib"; import dbus_previewer from "../../Previewer/DBusPreviewer.js"; -import { copyDirectory, decode, encode } from "../../util.js"; -import { rust_template_dir } from "./rust.js"; +import { decode, encode } from "../../util.js"; +import { installRustLibraries } from "./rust.js"; export default function Compiler({ session }) { const { file } = session; @@ -16,7 +16,7 @@ export default function Compiler({ session }) { let savedRustcVersion; async function compile() { - copyDirectory(rust_template_dir, file); + await installRustLibraries(file); rustcVersion ||= await getRustcVersion(); savedRustcVersion ||= await getSavedRustcVersion({ rustcVersionFile }); diff --git a/src/langs/rust/rust.js b/src/langs/rust/rust.js index 20746eca6..29bd494cb 100644 --- a/src/langs/rust/rust.js +++ b/src/langs/rust/rust.js @@ -1,4 +1,5 @@ import Gio from "gi://Gio"; +import GLib from "gi://GLib"; import { createLSPClient } from "../../common.js"; import { getLanguage } from "../../util.js"; @@ -32,6 +33,43 @@ export function setup({ document }) { return lspc; } -export const rust_template_dir = Gio.File.new_for_path( +const rust_template_dir = Gio.File.new_for_path( pkg.pkgdatadir, ).resolve_relative_path("langs/rust/template"); + +export async function setupRustProject(destination) { + return Promise.all([ + copy("Cargo.toml", rust_template_dir, destination, Gio.FileCopyFlags.NONE), + copy("Cargo.lock", rust_template_dir, destination, Gio.FileCopyFlags.NONE), + ]); +} + +export async function installRustLibraries(destination) { + return Promise.all([ + copy("lib.rs", rust_template_dir, destination, Gio.FileCopyFlags.OVERWRITE), + copy( + "workbench.rs", + rust_template_dir, + destination, + Gio.FileCopyFlags.OVERWRITE, + ), + ]); +} + +async function copy(filename, source_dir, dest_dir, flags) { + const file = source_dir.get_child(filename); + try { + await file.copy_async( + dest_dir.get_child(file.get_basename()), + flags, + GLib.PRIORITY_DEFAULT, + null, + null, + null, + ); + } catch (err) { + if (!err.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.EXISTS)) { + throw err; + } + } +} diff --git a/src/sessions.js b/src/sessions.js index e6576ca45..d0c6bc378 100644 --- a/src/sessions.js +++ b/src/sessions.js @@ -13,7 +13,6 @@ import { copyDirectory, } from "./util.js"; import { languages } from "./common.js"; -import { rust_template_dir } from "./langs/rust/rust.js"; export const sessions_dir = data_dir.get_child("sessions"); @@ -57,16 +56,16 @@ function createSession() { return session; } -export function createSessionFromDemo(demo) { +export async function createSessionFromDemo(demo) { const { name, panels } = demo; const session = createSession(); const demo_dir = demos_dir.get_child(name); const { file, settings } = session; - copyDirectory(demo_dir, file); - copyDirectory(rust_template_dir, file); + await copyDirectory(demo_dir, file); + settings.delay(); settings.set_string("name", name); settings.set_boolean("show-code", panels.includes("code")); settings.set_boolean("show-style", panels.includes("style")); @@ -76,6 +75,7 @@ export function createSessionFromDemo(demo) { "code-language", global_settings.get_int("recent-code-language"), ); + settings.apply(); return session; } @@ -84,7 +84,13 @@ export async function deleteSession(session) { // There is no method to recursively delete a folder so we trash instead // https://github.com/flatpak/xdg-desktop-portal/issues/630 :/ // portal.trash_file(file.get_path(), null).catch(console.error); - session.file.trash(null); + try { + session.file.trash(null); + } catch (err) { + if (!err.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.EXISTS)) { + throw err; + } + } } export async function saveSessionAsProject(session, destination) { diff --git a/src/util.js b/src/util.js index ca7705cc0..3be4b8f2a 100644 --- a/src/util.js +++ b/src/util.js @@ -104,19 +104,23 @@ export const demos_dir = Gio.File.new_for_path( ).resolve_relative_path("demos"); // There is no copy directory function -export function copyDirectory(source, destination) { - for (const file_info of source.enumerate_children( - "", +export async function copyDirectory(source, destination) { + const enumerator = await source.enumerate_children_async( + "standard::name", Gio.FileQueryInfoFlags.NOFOLLOW_SYMLINKS, + GLib.PRIORITY_DEFAULT, null, - )) { + ); + + for await (const file_info of enumerator) { if (file_info.get_file_type() === Gio.FileType.DIRECTORY) continue; const child = source.get_child(file_info.get_name()); try { - child.copy( + await child.copy_async( destination.get_child(child.get_basename()), Gio.FileCopyFlags.NONE, + GLib.PRIORITY_DEFAULT, null, null, ); diff --git a/src/window.js b/src/window.js index bb66c7e0f..7577bc20f 100644 --- a/src/window.js +++ b/src/window.js @@ -154,7 +154,7 @@ export default function Window({ application, session }) { const panel_code = PanelCode({ builder, previewer, - settings, + session, }); previewer.setPanelCode(panel_code);