mirror of https://github.com/encounter/objdiff.git
Export function to decomp.me scratch (beta)
This commit is contained in:
parent
e88a58ba39
commit
c2fcf2797b
|
@ -2537,6 +2537,16 @@ version = "0.3.17"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
|
||||
|
||||
[[package]]
|
||||
name = "mime_guess"
|
||||
version = "2.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef"
|
||||
dependencies = [
|
||||
"mime",
|
||||
"unicase",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mime_guess2"
|
||||
version = "2.0.5"
|
||||
|
@ -3403,6 +3413,7 @@ dependencies = [
|
|||
"js-sys",
|
||||
"log",
|
||||
"mime",
|
||||
"mime_guess",
|
||||
"native-tls",
|
||||
"once_cell",
|
||||
"percent-encoding",
|
||||
|
|
|
@ -64,12 +64,12 @@ twox-hash = "1.6.3"
|
|||
|
||||
# For Linux static binaries, use rustls
|
||||
[target.'cfg(target_os = "linux")'.dependencies]
|
||||
reqwest = { version = "0.11.23", default-features = false, features = ["blocking", "json", "rustls"] }
|
||||
reqwest = { version = "0.11.23", default-features = false, features = ["blocking", "json", "multipart", "rustls"] }
|
||||
self_update = { version = "0.39.0", default-features = false, features = ["rustls"] }
|
||||
|
||||
# For all other platforms, use native TLS
|
||||
[target.'cfg(not(target_os = "linux"))'.dependencies]
|
||||
reqwest = "0.11.23"
|
||||
reqwest = { version = "0.11.23", default-features = false, features = ["blocking", "json", "multipart", "default-tls"] }
|
||||
self_update = "0.39.0"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
|
|
|
@ -16,7 +16,7 @@ use time::UtcOffset;
|
|||
|
||||
use crate::{
|
||||
app_config::{deserialize_config, AppConfigVersion},
|
||||
config::{build_globset, load_project_config, ProjectObject, ProjectObjectNode},
|
||||
config::{build_globset, load_project_config, ProjectObject, ProjectObjectNode, ScratchConfig},
|
||||
diff::DiffAlg,
|
||||
jobs::{
|
||||
objdiff::{start_build, ObjDiffConfig},
|
||||
|
@ -60,6 +60,7 @@ pub struct ObjectConfig {
|
|||
pub base_path: Option<PathBuf>,
|
||||
pub reverse_fn_order: Option<bool>,
|
||||
pub complete: Option<bool>,
|
||||
pub scratch: Option<ScratchConfig>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Eq, PartialEq)]
|
||||
|
@ -128,6 +129,8 @@ pub struct AppConfig {
|
|||
#[serde(skip)]
|
||||
pub queue_reload: bool,
|
||||
#[serde(skip)]
|
||||
pub queue_scratch: bool,
|
||||
#[serde(skip)]
|
||||
pub project_config_info: Option<ProjectConfigInfo>,
|
||||
}
|
||||
|
||||
|
@ -157,6 +160,7 @@ impl Default for AppConfig {
|
|||
obj_change: false,
|
||||
queue_build: false,
|
||||
queue_reload: false,
|
||||
queue_scratch: false,
|
||||
project_config_info: None,
|
||||
}
|
||||
}
|
||||
|
@ -314,7 +318,7 @@ impl App {
|
|||
|
||||
let ViewState { jobs, diff_state, config_state, .. } = &mut self.view_state;
|
||||
config_state.post_update(ctx, jobs, &self.config);
|
||||
diff_state.post_update(&self.config);
|
||||
diff_state.post_update(ctx, jobs, &self.config);
|
||||
|
||||
let Ok(mut config) = self.config.write() else {
|
||||
return;
|
||||
|
|
|
@ -60,6 +60,7 @@ impl ObjectConfigV0 {
|
|||
base_path: Some(self.base_path),
|
||||
reverse_fn_order: self.reverse_fn_order,
|
||||
complete: None,
|
||||
scratch: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,6 +50,22 @@ pub struct ProjectObject {
|
|||
pub reverse_fn_order: Option<bool>,
|
||||
#[serde(default)]
|
||||
pub complete: Option<bool>,
|
||||
#[serde(default)]
|
||||
pub scratch: Option<ScratchConfig>,
|
||||
}
|
||||
|
||||
#[derive(Default, Clone, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
|
||||
pub struct ScratchConfig {
|
||||
#[serde(default)]
|
||||
pub platform: Option<String>,
|
||||
#[serde(default)]
|
||||
pub compiler: Option<String>,
|
||||
#[serde(default)]
|
||||
pub c_flags: Option<String>,
|
||||
#[serde(default)]
|
||||
pub ctx_path: Option<PathBuf>,
|
||||
#[serde(default)]
|
||||
pub build_ctx: bool,
|
||||
}
|
||||
|
||||
impl ProjectObject {
|
||||
|
@ -66,7 +82,7 @@ impl ProjectObject {
|
|||
|
||||
#[derive(Clone)]
|
||||
pub enum ProjectObjectNode {
|
||||
File(String, ProjectObject),
|
||||
File(String, Box<ProjectObject>),
|
||||
Dir(String, Vec<ProjectObjectNode>),
|
||||
}
|
||||
|
||||
|
@ -114,7 +130,7 @@ fn build_nodes(
|
|||
}
|
||||
}
|
||||
}
|
||||
let mut object = object.clone();
|
||||
let mut object = Box::new(object.clone());
|
||||
if let (Some(target_obj_dir), Some(path), None) =
|
||||
(target_obj_dir, &object.path, &object.target_path)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,135 @@
|
|||
use std::{fs, path::PathBuf, sync::mpsc::Receiver};
|
||||
|
||||
use anyhow::{anyhow, bail, Context, Result};
|
||||
use const_format::formatcp;
|
||||
|
||||
use crate::{
|
||||
app::AppConfig,
|
||||
jobs::{
|
||||
objdiff::{run_make, BuildConfig, BuildStatus},
|
||||
start_job, update_status, Job, JobContext, JobResult, JobState,
|
||||
},
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CreateScratchConfig {
|
||||
pub build_config: BuildConfig,
|
||||
pub context_path: Option<PathBuf>,
|
||||
pub build_context: bool,
|
||||
|
||||
// Scratch fields
|
||||
pub compiler: String,
|
||||
pub platform: String,
|
||||
pub compiler_flags: String,
|
||||
pub function_name: String,
|
||||
pub target_obj: PathBuf,
|
||||
}
|
||||
|
||||
impl CreateScratchConfig {
|
||||
pub(crate) fn from_config(config: &AppConfig, function_name: String) -> Result<Self> {
|
||||
let Some(selected_obj) = &config.selected_obj else {
|
||||
bail!("No object selected");
|
||||
};
|
||||
let Some(target_path) = &selected_obj.target_path else {
|
||||
bail!("No target path for {}", selected_obj.name);
|
||||
};
|
||||
let Some(scratch_config) = &selected_obj.scratch else {
|
||||
bail!("No scratch configuration for {}", selected_obj.name);
|
||||
};
|
||||
Ok(Self {
|
||||
build_config: BuildConfig::from_config(config),
|
||||
context_path: scratch_config.ctx_path.clone(),
|
||||
build_context: scratch_config.build_ctx,
|
||||
compiler: scratch_config.compiler.clone().unwrap_or_default(),
|
||||
platform: scratch_config.platform.clone().unwrap_or_default(),
|
||||
compiler_flags: scratch_config.c_flags.clone().unwrap_or_default(),
|
||||
function_name,
|
||||
target_obj: target_path.to_path_buf(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn is_available(config: &AppConfig) -> bool {
|
||||
let Some(selected_obj) = &config.selected_obj else {
|
||||
return false;
|
||||
};
|
||||
selected_obj.target_path.is_some() && selected_obj.scratch.is_some()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone)]
|
||||
pub struct CreateScratchResult {
|
||||
pub scratch_url: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, serde::Deserialize)]
|
||||
struct CreateScratchResponse {
|
||||
pub slug: String,
|
||||
pub claim_token: String,
|
||||
}
|
||||
|
||||
const API_HOST: &str = "http://127.0.0.1:8000";
|
||||
const WEB_HOST: &str = "http://localhost:8080";
|
||||
|
||||
fn run_create_scratch(
|
||||
status: &JobContext,
|
||||
cancel: Receiver<()>,
|
||||
config: CreateScratchConfig,
|
||||
) -> Result<Box<CreateScratchResult>> {
|
||||
let project_dir =
|
||||
config.build_config.project_dir.as_ref().ok_or_else(|| anyhow!("Missing project dir"))?;
|
||||
|
||||
let mut context = None;
|
||||
if let Some(context_path) = &config.context_path {
|
||||
if config.build_context {
|
||||
update_status(status, "Building context".to_string(), 0, 2, &cancel)?;
|
||||
match run_make(&config.build_config, context_path) {
|
||||
BuildStatus { success: true, .. } => {}
|
||||
BuildStatus { success: false, stdout, stderr, .. } => {
|
||||
bail!("Failed to build context:\n{stdout}\n{stderr}")
|
||||
}
|
||||
}
|
||||
}
|
||||
let context_path = project_dir.join(context_path);
|
||||
context = Some(
|
||||
fs::read_to_string(&context_path)
|
||||
.map_err(|e| anyhow!("Failed to read {}: {}", context_path.display(), e))?,
|
||||
);
|
||||
}
|
||||
|
||||
update_status(status, "Creating scratch".to_string(), 1, 2, &cancel)?;
|
||||
let diff_flags = [format!("--disassemble={}", config.function_name)];
|
||||
let diff_flags = serde_json::to_string(&diff_flags).unwrap();
|
||||
let obj_path = project_dir.join(&config.target_obj);
|
||||
let file = reqwest::blocking::multipart::Part::file(&obj_path)
|
||||
.with_context(|| format!("Failed to open {}", obj_path.display()))?;
|
||||
let form = reqwest::blocking::multipart::Form::new()
|
||||
.text("compiler", config.compiler.clone())
|
||||
.text("platform", config.platform.clone())
|
||||
.text("compiler_flags", config.compiler_flags.clone())
|
||||
.text("diff_label", config.function_name.clone())
|
||||
.text("diff_flags", diff_flags)
|
||||
.text("context", context.unwrap_or_default())
|
||||
.text("source_code", "// Move related code from Context tab to here")
|
||||
.part("target_obj", file);
|
||||
let client = reqwest::blocking::Client::new();
|
||||
let response = client
|
||||
.post(formatcp!("{API_HOST}/api/scratch"))
|
||||
.multipart(form)
|
||||
.send()
|
||||
.map_err(|e| anyhow!("Failed to send request: {}", e))?;
|
||||
if !response.status().is_success() {
|
||||
return Err(anyhow!("Failed to create scratch: {}", response.text()?));
|
||||
}
|
||||
let body: CreateScratchResponse = response.json().context("Failed to parse response")?;
|
||||
let scratch_url = format!("{WEB_HOST}/scratch/{}/claim?token={}", body.slug, body.claim_token);
|
||||
|
||||
update_status(status, "Complete".to_string(), 2, 2, &cancel)?;
|
||||
Ok(Box::from(CreateScratchResult { scratch_url }))
|
||||
}
|
||||
|
||||
pub fn start_create_scratch(ctx: &egui::Context, config: CreateScratchConfig) -> JobState {
|
||||
start_job(ctx, "Create scratch", Job::CreateScratch, move |context, cancel| {
|
||||
run_create_scratch(&context, cancel, config)
|
||||
.map(|result| JobResult::CreateScratch(Some(result)))
|
||||
})
|
||||
}
|
|
@ -9,9 +9,13 @@ use std::{
|
|||
|
||||
use anyhow::Result;
|
||||
|
||||
use crate::jobs::{check_update::CheckUpdateResult, objdiff::ObjDiffResult, update::UpdateResult};
|
||||
use crate::jobs::{
|
||||
check_update::CheckUpdateResult, create_scratch::CreateScratchResult, objdiff::ObjDiffResult,
|
||||
update::UpdateResult,
|
||||
};
|
||||
|
||||
pub mod check_update;
|
||||
pub mod create_scratch;
|
||||
pub mod objdiff;
|
||||
pub mod update;
|
||||
|
||||
|
@ -20,6 +24,7 @@ pub enum Job {
|
|||
ObjDiff,
|
||||
CheckUpdate,
|
||||
Update,
|
||||
CreateScratch,
|
||||
}
|
||||
pub static JOB_ID: AtomicUsize = AtomicUsize::new(0);
|
||||
|
||||
|
@ -119,6 +124,7 @@ pub enum JobResult {
|
|||
ObjDiff(Option<Box<ObjDiffResult>>),
|
||||
CheckUpdate(Option<Box<CheckUpdateResult>>),
|
||||
Update(Box<UpdateResult>),
|
||||
CreateScratch(Option<Box<CreateScratchResult>>),
|
||||
}
|
||||
|
||||
fn should_cancel(rx: &Receiver<()>) -> bool {
|
||||
|
|
|
@ -33,13 +33,28 @@ impl Default for BuildStatus {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct BuildConfig {
|
||||
pub project_dir: Option<PathBuf>,
|
||||
pub custom_make: Option<String>,
|
||||
pub selected_wsl_distro: Option<String>,
|
||||
}
|
||||
|
||||
impl BuildConfig {
|
||||
pub(crate) fn from_config(config: &AppConfig) -> Self {
|
||||
Self {
|
||||
project_dir: config.project_dir.clone(),
|
||||
custom_make: config.custom_make.clone(),
|
||||
selected_wsl_distro: config.selected_wsl_distro.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ObjDiffConfig {
|
||||
pub build_config: BuildConfig,
|
||||
pub build_base: bool,
|
||||
pub build_target: bool,
|
||||
pub custom_make: Option<String>,
|
||||
pub project_dir: Option<PathBuf>,
|
||||
pub selected_obj: Option<ObjectConfig>,
|
||||
pub selected_wsl_distro: Option<String>,
|
||||
pub code_alg: DiffAlg,
|
||||
pub data_alg: DiffAlg,
|
||||
pub relax_reloc_diffs: bool,
|
||||
|
@ -47,13 +62,11 @@ pub struct ObjDiffConfig {
|
|||
|
||||
impl ObjDiffConfig {
|
||||
pub(crate) fn from_config(config: &AppConfig) -> Self {
|
||||
ObjDiffConfig {
|
||||
Self {
|
||||
build_config: BuildConfig::from_config(config),
|
||||
build_base: config.build_base,
|
||||
build_target: config.build_target,
|
||||
custom_make: config.custom_make.clone(),
|
||||
project_dir: config.project_dir.clone(),
|
||||
selected_obj: config.selected_obj.clone(),
|
||||
selected_wsl_distro: config.selected_wsl_distro.clone(),
|
||||
code_alg: config.code_alg,
|
||||
data_alg: config.data_alg,
|
||||
relax_reloc_diffs: config.relax_reloc_diffs,
|
||||
|
@ -69,7 +82,14 @@ pub struct ObjDiffResult {
|
|||
pub time: OffsetDateTime,
|
||||
}
|
||||
|
||||
fn run_make(cwd: &Path, arg: &Path, config: &ObjDiffConfig) -> BuildStatus {
|
||||
pub(crate) fn run_make(config: &BuildConfig, arg: &Path) -> BuildStatus {
|
||||
let Some(cwd) = &config.project_dir else {
|
||||
return BuildStatus {
|
||||
success: false,
|
||||
stderr: "Missing project dir".to_string(),
|
||||
..Default::default()
|
||||
};
|
||||
};
|
||||
match (|| -> Result<BuildStatus> {
|
||||
let make = config.custom_make.as_deref().unwrap_or("make");
|
||||
#[cfg(not(windows))]
|
||||
|
@ -130,8 +150,11 @@ fn run_build(
|
|||
config: ObjDiffConfig,
|
||||
) -> Result<Box<ObjDiffResult>> {
|
||||
let obj_config = config.selected_obj.as_ref().ok_or_else(|| Error::msg("Missing obj path"))?;
|
||||
let project_dir =
|
||||
config.project_dir.as_ref().ok_or_else(|| Error::msg("Missing project dir"))?;
|
||||
let project_dir = config
|
||||
.build_config
|
||||
.project_dir
|
||||
.as_ref()
|
||||
.ok_or_else(|| Error::msg("Missing project dir"))?;
|
||||
let target_path_rel = if let Some(target_path) = &obj_config.target_path {
|
||||
Some(target_path.strip_prefix(project_dir).map_err(|_| {
|
||||
anyhow!(
|
||||
|
@ -171,7 +194,7 @@ fn run_build(
|
|||
total,
|
||||
&cancel,
|
||||
)?;
|
||||
run_make(project_dir, target_path_rel, &config)
|
||||
run_make(&config.build_config, target_path_rel)
|
||||
}
|
||||
_ => BuildStatus::default(),
|
||||
};
|
||||
|
@ -185,7 +208,7 @@ fn run_build(
|
|||
total,
|
||||
&cancel,
|
||||
)?;
|
||||
run_make(project_dir, base_path_rel, &config)
|
||||
run_make(&config.build_config, base_path_rel)
|
||||
}
|
||||
_ => BuildStatus::default(),
|
||||
};
|
||||
|
|
|
@ -93,6 +93,7 @@ impl ConfigViewState {
|
|||
base_path: Some(path),
|
||||
reverse_fn_order: None,
|
||||
complete: None,
|
||||
scratch: None,
|
||||
});
|
||||
} else if let Ok(obj_path) = path.strip_prefix(target_dir) {
|
||||
let base_path = base_dir.join(obj_path);
|
||||
|
@ -102,6 +103,7 @@ impl ConfigViewState {
|
|||
base_path: Some(base_path),
|
||||
reverse_fn_order: None,
|
||||
complete: None,
|
||||
scratch: None,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -393,6 +395,7 @@ fn display_object(
|
|||
base_path: object.base_path.clone(),
|
||||
reverse_fn_order: object.reverse_fn_order,
|
||||
complete: object.complete,
|
||||
scratch: object.scratch.clone(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -192,7 +192,7 @@ pub fn data_diff_ui(ui: &mut egui::Ui, state: &mut DiffViewState, appearance: &A
|
|||
|ui| {
|
||||
ui.set_width(column_width);
|
||||
|
||||
if ui.button("Back").clicked() {
|
||||
if ui.button("⏴ Back").clicked() {
|
||||
state.current_view = View::SymbolDiff;
|
||||
}
|
||||
|
||||
|
|
|
@ -586,9 +586,23 @@ pub fn function_diff_ui(ui: &mut egui::Ui, state: &mut DiffViewState, appearance
|
|||
|ui| {
|
||||
ui.set_width(column_width);
|
||||
|
||||
if ui.button("Back").clicked() {
|
||||
state.current_view = View::SymbolDiff;
|
||||
}
|
||||
ui.horizontal(|ui| {
|
||||
if ui.button("⏴ Back").clicked() {
|
||||
state.current_view = View::SymbolDiff;
|
||||
}
|
||||
ui.separator();
|
||||
if ui
|
||||
.add_enabled(
|
||||
!state.scratch_running && state.scratch_available,
|
||||
egui::Button::new("📲 decomp.me"),
|
||||
)
|
||||
.on_hover_text_at_pointer("Create a new scratch on decomp.me (beta)")
|
||||
.on_disabled_hover_text("Scratch configuration missing")
|
||||
.clicked()
|
||||
{
|
||||
state.queue_scratch = true;
|
||||
}
|
||||
});
|
||||
|
||||
let demangled = demangle(&selected_symbol.symbol_name, &Default::default());
|
||||
let name = demangled.as_deref().unwrap_or(&selected_symbol.symbol_name);
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
use std::mem::take;
|
||||
|
||||
use egui::{
|
||||
text::LayoutJob, Align, CollapsingHeader, Color32, Id, Layout, ScrollArea, SelectableLabel,
|
||||
TextEdit, Ui, Vec2, Widget,
|
||||
text::LayoutJob, Align, CollapsingHeader, Color32, Id, Layout, OpenUrl, ScrollArea,
|
||||
SelectableLabel, TextEdit, Ui, Vec2, Widget,
|
||||
};
|
||||
use egui_extras::{Size, StripBuilder};
|
||||
|
||||
use crate::{
|
||||
app::AppConfigRef,
|
||||
jobs::{
|
||||
create_scratch::{start_create_scratch, CreateScratchConfig, CreateScratchResult},
|
||||
objdiff::{BuildStatus, ObjDiffResult},
|
||||
Job, JobQueue, JobResult,
|
||||
},
|
||||
|
@ -33,12 +34,16 @@ pub enum View {
|
|||
#[derive(Default)]
|
||||
pub struct DiffViewState {
|
||||
pub build: Option<Box<ObjDiffResult>>,
|
||||
pub scratch: Option<Box<CreateScratchResult>>,
|
||||
pub current_view: View,
|
||||
pub symbol_state: SymbolViewState,
|
||||
pub function_state: FunctionViewState,
|
||||
pub search: String,
|
||||
pub queue_build: bool,
|
||||
pub build_running: bool,
|
||||
pub scratch_available: bool,
|
||||
pub queue_scratch: bool,
|
||||
pub scratch_running: bool,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
|
@ -52,15 +57,19 @@ pub struct SymbolViewState {
|
|||
|
||||
impl DiffViewState {
|
||||
pub fn pre_update(&mut self, jobs: &mut JobQueue, config: &AppConfigRef) {
|
||||
jobs.results.retain_mut(|result| {
|
||||
if let JobResult::ObjDiff(result) = result {
|
||||
jobs.results.retain_mut(|result| match result {
|
||||
JobResult::ObjDiff(result) => {
|
||||
self.build = take(result);
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
JobResult::CreateScratch(result) => {
|
||||
self.scratch = take(result);
|
||||
false
|
||||
}
|
||||
_ => true,
|
||||
});
|
||||
self.build_running = jobs.is_running(Job::ObjDiff);
|
||||
self.scratch_running = jobs.is_running(Job::CreateScratch);
|
||||
|
||||
self.symbol_state.disable_reverse_fn_order = false;
|
||||
if let Ok(config) = config.read() {
|
||||
|
@ -70,16 +79,41 @@ impl DiffViewState {
|
|||
self.symbol_state.disable_reverse_fn_order = true;
|
||||
}
|
||||
}
|
||||
self.scratch_available = CreateScratchConfig::is_available(&config);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn post_update(&mut self, config: &AppConfigRef) {
|
||||
pub fn post_update(&mut self, ctx: &egui::Context, jobs: &mut JobQueue, config: &AppConfigRef) {
|
||||
if let Some(result) = take(&mut self.scratch) {
|
||||
ctx.output_mut(|o| o.open_url = Some(OpenUrl::new_tab(result.scratch_url)));
|
||||
}
|
||||
|
||||
if self.queue_build {
|
||||
self.queue_build = false;
|
||||
if let Ok(mut config) = config.write() {
|
||||
config.queue_build = true;
|
||||
}
|
||||
}
|
||||
|
||||
if self.queue_scratch {
|
||||
self.queue_scratch = false;
|
||||
if let Some(function_name) =
|
||||
self.symbol_state.selected_symbol.as_ref().map(|sym| sym.symbol_name.clone())
|
||||
{
|
||||
if let Ok(config) = config.read() {
|
||||
match CreateScratchConfig::from_config(&config, function_name) {
|
||||
Ok(config) => {
|
||||
jobs.push_once(Job::CreateScratch, || {
|
||||
start_create_scratch(ctx, config)
|
||||
});
|
||||
}
|
||||
Err(err) => {
|
||||
log::error!("Failed to create scratch config: {err}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue