From 013cb10961329d454bd5ebf2b94104ab753f40a1 Mon Sep 17 00:00:00 2001 From: Jonathan Tran Date: Fri, 10 Jan 2025 22:33:05 -0500 Subject: [PATCH] Fix so that all artifact commands are returned regardless of caching (#5005) * Fix so that all artifact commands are returned regardless of caching * Add some more docs and fix up old ones --- src/wasm-lib/kcl/src/execution/mod.rs | 18 ++++-- src/wasm-lib/tests/executor/cache.rs | 54 +++++++++++++++++- ...add_line_preserves_artifact_commands_0.png | Bin 0 -> 29207 bytes ...add_line_preserves_artifact_commands_1.png | Bin 0 -> 47712 bytes 4 files changed, 63 insertions(+), 9 deletions(-) create mode 100644 src/wasm-lib/tests/executor/outputs/cache_add_line_preserves_artifact_commands_0.png create mode 100644 src/wasm-lib/tests/executor/outputs/cache_add_line_preserves_artifact_commands_1.png diff --git a/src/wasm-lib/kcl/src/execution/mod.rs b/src/wasm-lib/kcl/src/execution/mod.rs index b66a356419..7036b4b169 100644 --- a/src/wasm-lib/kcl/src/execution/mod.rs +++ b/src/wasm-lib/kcl/src/execution/mod.rs @@ -2013,10 +2013,13 @@ impl ExecutorContext { // AND if we aren't in wasm it doesn't really matter. Ok(()) } - // Given an old ast, old program memory and new ast, find the parts of the code that need to be - // re-executed. - // This function should never error, because in the case of any internal error, we should just pop - // the cache. + /// Given an old ast, old program memory and new ast, find the parts of the code that need to be + /// re-executed. + /// This function should never error, because in the case of any internal error, we should just pop + /// the cache. + /// + /// Returns `None` when there are no changes to the program, i.e. it is + /// fully cached. pub async fn get_changed_program(&self, info: CacheInformation) -> Option { let Some(old) = info.old else { // We have no old info, we need to re-execute the whole thing. @@ -2137,7 +2140,7 @@ impl ExecutorContext { } } std::cmp::Ordering::Equal => { - // currently unreachable, but lets pretend like the code + // currently unreachable, but let's pretend like the code // above can do something meaningful here for when we get // to diffing and yanking chunks of the program apart. @@ -2236,7 +2239,10 @@ impl ExecutorContext { ) })?; // Move the artifact commands to simplify cache management. - exec_state.global.artifact_commands = self.engine.take_artifact_commands(); + exec_state + .global + .artifact_commands + .extend(self.engine.take_artifact_commands()); let session_data = self.engine.get_session_data(); Ok(session_data) } diff --git a/src/wasm-lib/tests/executor/cache.rs b/src/wasm-lib/tests/executor/cache.rs index 579a19aed2..4247e83988 100644 --- a/src/wasm-lib/tests/executor/cache.rs +++ b/src/wasm-lib/tests/executor/cache.rs @@ -1,14 +1,18 @@ //! Cache testing framework. use anyhow::Result; -use kcl_lib::ExecError; +use kcl_lib::{ExecError, ExecState}; +#[derive(Debug)] struct Variation<'a> { code: &'a str, settings: &'a kcl_lib::ExecutorSettings, } -async fn cache_test(test_name: &str, variations: Vec>) -> Result> { +async fn cache_test( + test_name: &str, + variations: Vec>, +) -> Result> { let first = variations .first() .ok_or_else(|| anyhow::anyhow!("No variations provided for test '{}'", test_name))?; @@ -42,7 +46,7 @@ async fn cache_test(test_name: &str, variations: Vec>) -> Result startProfileAt([5.5229, 5.25217], %) + |> line([10.50433, -1.19122], %) + |> line([8.01362, -5.48731], %) + |> line([-1.02877, -6.76825], %) + |> line([-11.53311, 2.81559], %) + |> close(%) +"#; + // Use a new statement; don't extend the prior pipeline. This allows us to + // detect a prefix. + let code_with_extrude = code.to_owned() + + r#" +extrude(4, sketch001) +"#; + + let result = cache_test( + "add_line_preserves_artifact_commands", + vec![ + Variation { + code, + settings: &Default::default(), + }, + Variation { + code: code_with_extrude.as_str(), + settings: &Default::default(), + }, + ], + ) + .await + .unwrap(); + + let first = result.first().unwrap(); + let second = result.last().unwrap(); + + assert!( + first.2.global.artifact_commands.len() < second.2.global.artifact_commands.len(), + "Second should have all the artifact commands of the first, plus more. first={:?}, second={:?}", + first.2.global.artifact_commands.len(), + second.2.global.artifact_commands.len() + ); +} diff --git a/src/wasm-lib/tests/executor/outputs/cache_add_line_preserves_artifact_commands_0.png b/src/wasm-lib/tests/executor/outputs/cache_add_line_preserves_artifact_commands_0.png new file mode 100644 index 0000000000000000000000000000000000000000..d896c35507405d877ce62a2178d6d6df34afaa39 GIT binary patch literal 29207 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 WRk+|Y{0ARROBXL+RQ1FQ8~z6_60d&% literal 0 HcmV?d00001 diff --git a/src/wasm-lib/tests/executor/outputs/cache_add_line_preserves_artifact_commands_1.png b/src/wasm-lib/tests/executor/outputs/cache_add_line_preserves_artifact_commands_1.png new file mode 100644 index 0000000000000000000000000000000000000000..8f97850b798bec922f5db9d51d6a9e2d86f5d570 GIT binary patch literal 47712 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 literal 0 HcmV?d00001