From fa85cd48e8f6a097727f22d868ab4743f5263239 Mon Sep 17 00:00:00 2001 From: Avinash Kumar Deepak <152387616+avinxshKD@users.noreply.github.com> Date: Wed, 28 Jan 2026 06:13:24 +0530 Subject: [PATCH] fix(cli): support sketches with custom main file names (#1329) * fix(cli): support sketches with custom main file names Previously, the CLI only accepted sketches where the main .pde file matched the sketch folder name (e.g., sketch/sketch.pde). This caused issues when users renamed their main file in the IDE, which stores the custom filename in sketch.properties. Now the CLI checks sketch.properties for a 'main' property before falling back to the default naming convention, matching the IDE's behavior implemented in Sketch.findMain(). Fixes #1219 * test: add CLI test for custom main file support Added testSketchWithCustomMainFile() to CLITest.kt as requested by maintainer. This test provides a placeholder for manual testing of sketches with custom main files specified in sketch.properties. Follows the same pattern as existing CLI tests (testLSP, testLegacyCLI) and is intended to be run manually in IntelliJ IDEA. * test: convert to automated CLI test with temp directory Converted testSketchWithCustomMainFile() from manual to automated test. Now creates a temporary sketch folder with custom main file and sketch.properties, then tests the CLI build command. Follows the pattern from SchemaTest.kt using Files.createTempDirectory() and automatic cleanup. --- app/test/processing/app/CLITest.kt | 31 +++++++ java/src/processing/mode/java/Commander.java | 20 ++++- .../processing/mode/java/CommanderTest.java | 89 +++++++++++++++++++ 3 files changed, 139 insertions(+), 1 deletion(-) create mode 100644 java/test/processing/mode/java/CommanderTest.java diff --git a/app/test/processing/app/CLITest.kt b/app/test/processing/app/CLITest.kt index 2bd8cc81e..6ae04e46c 100644 --- a/app/test/processing/app/CLITest.kt +++ b/app/test/processing/app/CLITest.kt @@ -1,6 +1,7 @@ package processing.app import java.io.File +import java.nio.file.Files import kotlin.test.Test /* @@ -25,6 +26,36 @@ class CLITest { runCLIWithArguments("cli --help") } + @Test + fun testSketchWithCustomMainFile(){ + val tempDir = Files.createTempDirectory("cli_custom_main_test") + try { + val sketchFolder = tempDir.resolve("TestSketch").toFile() + sketchFolder.mkdirs() + + // Create custom main file (not matching folder name) + val customMain = File(sketchFolder, "custom_main.pde") + customMain.writeText(""" + void setup() { + println("Custom main file test"); + } + + void draw() { + exit(); + } + """.trimIndent()) + + // Create sketch.properties with custom main + val propsFile = File(sketchFolder, "sketch.properties") + propsFile.writeText("main=custom_main.pde") + + // Test with CLI + runCLIWithArguments("cli --sketch=${sketchFolder.absolutePath} --build") + } finally { + tempDir.toFile().deleteRecursively() + } + } + /* This function runs the CLI with the given arguments. */ diff --git a/java/src/processing/mode/java/Commander.java b/java/src/processing/mode/java/Commander.java index b13c1a5f1..d9618578f 100644 --- a/java/src/processing/mode/java/Commander.java +++ b/java/src/processing/mode/java/Commander.java @@ -32,6 +32,7 @@ import processing.app.Base; import processing.app.Platform; import processing.app.Preferences; import processing.app.RunnerListener; +import processing.app.Settings; import processing.app.Sketch; import processing.utils.SketchException; import processing.app.Util; @@ -145,7 +146,24 @@ public class Commander implements RunnerListener { if (!sketchFolder.exists()) { complainAndQuit(sketchFolder + " does not exist.", false); } - File pdeFile = new File(sketchFolder, sketchFolder.getName() + ".pde"); + + // Check for main file in sketch.properties first, then fall back to default + File pdeFile = null; + try { + Settings props = new Settings(new File(sketchFolder, "sketch.properties")); + String mainFileName = props.get("main"); + if (mainFileName != null) { + pdeFile = new File(sketchFolder, mainFileName); + } + } catch (IOException e) { + // sketch.properties doesn't exist or couldn't be read, will use default + } + + // Fall back to default naming convention if no custom main file specified + if (pdeFile == null || !pdeFile.exists()) { + pdeFile = new File(sketchFolder, sketchFolder.getName() + ".pde"); + } + if (!pdeFile.exists()) { complainAndQuit("Not a valid sketch folder. " + pdeFile + " does not exist.", true); } diff --git a/java/test/processing/mode/java/CommanderTest.java b/java/test/processing/mode/java/CommanderTest.java new file mode 100644 index 000000000..263f8c93b --- /dev/null +++ b/java/test/processing/mode/java/CommanderTest.java @@ -0,0 +1,89 @@ +package processing.mode.java; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import processing.app.Settings; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.file.Files; + +import static org.junit.Assert.*; + + +public class CommanderTest { + + private File tempSketchFolder; + + @Before + public void setUp() throws IOException { + tempSketchFolder = Files.createTempDirectory("sketch_test").toFile(); + } + + @After + public void tearDown() { + if (tempSketchFolder != null && tempSketchFolder.exists()) { + deleteDirectory(tempSketchFolder); + } + } + + @Test + public void testSketchWithDefaultMainFile() throws IOException { + String sketchName = tempSketchFolder.getName(); + File mainFile = new File(tempSketchFolder, sketchName + ".pde"); + + try (FileWriter writer = new FileWriter(mainFile)) { + writer.write("void setup() {}\nvoid draw() {}"); + } + + assertTrue("Default main file should exist", mainFile.exists()); + } + + @Test + public void testSketchWithCustomMainFile() throws IOException { + File customMainFile = new File(tempSketchFolder, "custom_main.pde"); + try (FileWriter writer = new FileWriter(customMainFile)) { + writer.write("void setup() {}\nvoid draw() {}"); + } + + File propsFile = new File(tempSketchFolder, "sketch.properties"); + Settings props = new Settings(propsFile); + props.set("main", "custom_main.pde"); + props.save(); + + assertTrue("Custom main file should exist", customMainFile.exists()); + assertTrue("sketch.properties should exist", propsFile.exists()); + + Settings readProps = new Settings(propsFile); + assertEquals("custom_main.pde", readProps.get("main")); + } + + @Test + public void testSketchPropertiesMainProperty() throws IOException { + File propsFile = new File(tempSketchFolder, "sketch.properties"); + Settings props = new Settings(propsFile); + props.set("main", "my_sketch.pde"); + props.save(); + + Settings readProps = new Settings(propsFile); + String mainFile = readProps.get("main"); + + assertEquals("Main property should match", "my_sketch.pde", mainFile); + } + + private void deleteDirectory(File directory) { + File[] files = directory.listFiles(); + if (files != null) { + for (File file : files) { + if (file.isDirectory()) { + deleteDirectory(file); + } else { + file.delete(); + } + } + } + directory.delete(); + } +}