Procházet zdrojové kódy

feat: maintain compile_commands.json for the Vala language server - initial build on new, copy from builddir on every dev build, ignore entries scaffolded

clanker před 1 týdnem
rodič
revize
c38e43628a

+ 73 - 0
tools/spry/CompileCommands.vala

@@ -0,0 +1,73 @@
+using GLib;
+
+namespace Spry.Cli {
+
+    /**
+     * Maintains a `compile_commands.json` in the application root for the
+     * Vala language server: meson emits the database as a build artifact in
+     * `builddir/`, and it is copied out to the root whenever a build
+     * happens (the initial build on `spry new`, and every `spry dev`
+     * build/rebuild). The copied file is generated state — gitignored and
+     * excluded from packaging.
+     */
+    public class CompileCommands : Object {
+
+        /**
+         * Runs the initial meson setup + build of a freshly scaffolded
+         * application (so the compile database exists) and copies the
+         * database to the project root. Failures are reported but do not
+         * fail scaffolding itself.
+         */
+        public static void build_initial(string app_dir, string? libdir) {
+            var launcher = new SubprocessLauncher(SubprocessFlags.NONE);
+            Tools.apply_env(launcher, libdir);
+            stdout.printf("[spry] Running initial build (for compile_commands.json)…\n");
+            if (!run_step(launcher, app_dir, { "meson", "setup", ".", "builddir" })
+                    || !run_step(launcher, app_dir, { "ninja", "-C", "builddir" })) {
+                return;
+            }
+            copy_from_builddir(app_dir);
+        }
+
+        private static bool run_step(SubprocessLauncher launcher, string app_dir, string[] argv) {
+            try {
+                var previous = Environment.get_current_dir();
+                Environment.set_current_dir(app_dir);
+                var process = launcher.spawnv(argv);
+                Environment.set_current_dir(previous);
+                if (!process.wait_check()) {
+                    stderr.printf("[spry] Initial build failed — compile_commands.json not generated\n");
+                    return false;
+                }
+            }
+            catch (Error e) {
+                stderr.printf("[spry] Initial build could not run: %s\n", e.message);
+                return false;
+            }
+            return true;
+        }
+
+        /**
+         * Copies `builddir/compile_commands.json` to the project root when
+         * it exists; a no-op otherwise (e.g. the build failed or produced
+         * none).
+         */
+        public static void copy_from_builddir(string app_dir) {
+            try {
+                var source = File.new_for_path(Path.build_filename(app_dir, "builddir", "compile_commands.json"));
+                if (!source.query_exists()) {
+                    return;
+                }
+                var destination = File.new_for_path(Path.build_filename(app_dir, "compile_commands.json"));
+                if (!destination.query_exists()
+                        || source.query_info("time::modified", FileQueryInfoFlags.NONE).get_modification_date_time()
+                            .difference(destination.query_info("time::modified", FileQueryInfoFlags.NONE).get_modification_date_time()) > 0) {
+                    source.copy(destination, FileCopyFlags.OVERWRITE);
+                    stdout.printf("[spry] compile_commands.json copied to the project root\n");
+                }
+            }
+            catch (Error e) {
+            }
+        }
+    }
+}

+ 2 - 0
tools/spry/Dev.vala

@@ -74,6 +74,7 @@ namespace Spry.Cli {
             if (!dev.build()) {
             if (!dev.build()) {
                 return 1;
                 return 1;
             }
             }
+            CompileCommands.copy_from_builddir(dev.app_dir);
             if (no_run) {
             if (no_run) {
                 return 0;
                 return 0;
             }
             }
@@ -174,6 +175,7 @@ namespace Spry.Cli {
                 stderr.printf("[spry] Build could not run: %s\n", e.message);
                 stderr.printf("[spry] Build could not run: %s\n", e.message);
                 return;
                 return;
             }
             }
+            CompileCommands.copy_from_builddir(app_dir);
             restart_child();
             restart_child();
         }
         }
 
 

+ 1 - 1
tools/spry/meson.build

@@ -34,7 +34,7 @@ spry_templates = custom_target('spry-templates',
 )
 )
 
 
 executable('spry',
 executable('spry',
-    ['spry.vala', 'Generator.vala', 'Keys.vala', 'Deploy.vala', 'Dev.vala', spry_templates],
+    ['spry.vala', 'Generator.vala', 'Keys.vala', 'Deploy.vala', 'Dev.vala', 'CompileCommands.vala', spry_templates],
     dependencies: [glib_dep, gobject_dep, gio_dep, json_glib_dep],
     dependencies: [glib_dep, gobject_dep, gio_dep, json_glib_dep],
     install: true
     install: true
 )
 )

+ 1 - 0
tools/spry/spry.vala

@@ -213,6 +213,7 @@ namespace Spry.Cli {
                 Generator.write_file(config_path, "{\n  \"statum\": {\n  }\n}\n");
                 Generator.write_file(config_path, "{\n  \"statum\": {\n  }\n}\n");
             }
             }
 
 
+            CompileCommands.build_initial(app_dir, libdir);
             stdout.printf("Created %s\n", app_dir);
             stdout.printf("Created %s\n", app_dir);
             stdout.printf("Next:\n  cd %s\n  spry dev\n", name);
             stdout.printf("Next:\n  cd %s\n  spry dev\n", name);
             return 0;
             return 0;

+ 3 - 0
tools/spry/templates/gitignore

@@ -1,3 +1,6 @@
 builddir/
 builddir/
 *.sqlite*
 *.sqlite*
 web-config.json
 web-config.json
+
+# Generated by meson; copied from builddir by spry for the Vala language server
+compile_commands.json

+ 3 - 0
tools/spry/templates/usmignore

@@ -10,3 +10,6 @@ web-config.json
 
 
 # Local agent session state (directory-only)
 # Local agent session state (directory-only)
 .kilo/
 .kilo/
+
+# Generated build artifact (Vala language server)
+compile_commands.json