Browse Source

feat(cli): add genconfig command for configuration generation

Add a new 'usm genconfig' command that outputs a default configuration
file. Integrate this into the installer to automatically generate
/etc/usm/usm.config during installation, while preserving any existing
configuration to avoid overwriting user customizations.
Billy Barrow 1 ngày trước cách đây
mục cha
commit
48e86a02db

+ 25 - 0
installer/build_config.sh

@@ -188,6 +188,8 @@ build_component() {
 install_shim() {
 install_shim() {
     local target_dir="$1"
     local target_dir="$1"
     local shim_path="/usr/bin/usm"
     local shim_path="/usr/bin/usm"
+    local config_dir="/etc/usm"
+    local config_path="$config_dir/usm.config"
     local sudo=""
     local sudo=""
     
     
     if ! is_root; then
     if ! is_root; then
@@ -210,6 +212,29 @@ exec \"${target_dir}/bin/usm\" \"\$@\"
     fi
     fi
     
     
     log_info "Shim installed to $shim_path"
     log_info "Shim installed to $shim_path"
+    
+    # Generate USM configuration file only if it doesn't already exist
+    if [[ -f "$config_path" ]]; then
+        log_info "Configuration file already exists at $config_path, skipping generation"
+    else
+        log_step "Generating USM configuration..."
+        
+        # Create config directory if it doesn't exist
+        if [[ -n "$sudo" ]]; then
+            $sudo mkdir -p "$config_dir"
+        else
+            mkdir -p "$config_dir"
+        fi
+        
+        # Generate config using usm genconfig
+        if [[ -n "$sudo" ]]; then
+            usm genconfig | $sudo tee "$config_path" >/dev/null
+        else
+            usm genconfig > "$config_path"
+        fi
+        
+        log_info "Configuration generated at $config_path"
+    fi
 }
 }
 
 
 # Build all components in order
 # Build all components in order

+ 4 - 1
src/cli/Cli.vala

@@ -65,6 +65,9 @@ public static int main(string[] args) {
         if(command == "scaffold") {
         if(command == "scaffold") {
             return scaffold_main(args);
             return scaffold_main(args);
         }
         }
+        if(command == "genconfig") {
+            return genconfig_main();
+        }
     }
     }
     catch(Error e) {
     catch(Error e) {
         printerr(@"Unhandled error: $(e.message)\n");
         printerr(@"Unhandled error: $(e.message)\n");
@@ -76,7 +79,7 @@ public static int main(string[] args) {
 }
 }
 
 
 private void usage() {
 private void usage() {
-    printerr("USAGE:\n\tusm manifest\n\tusm info\n\tusm repository\n\tusm install\n\tusm scaffold\n");
+    printerr("USAGE:\n\tusm manifest\n\tusm info\n\tusm repository\n\tusm install\n\tusm scaffold\n\tusm genconfig\n");
 }
 }
 
 
 
 

+ 108 - 0
src/cli/GenConfig.vala

@@ -0,0 +1,108 @@
+using Invercargill.Mapping;
+using InvercargillJson;
+
+public int genconfig_main() {
+    // Create a configuration with is_managed = false and autodiscovered paths
+    var config = new Usm.Configuration();
+    config.is_managed = false;
+    config.managed_config = null;
+    
+    // Start with defaults and autodetect system-specific paths
+    var paths = new Usm.Paths.defaults();
+    
+    // Autodetect the correct lib directory for this system
+    // Uses ldconfig to find the system's primary library directory
+    // canonlib remains "lib" as it's for architecture-independent libraries
+    paths.lib = detect_lib_dir();
+    
+    config.paths = paths;
+
+    // Map to properties and create JSON
+    var properties = Usm.Configuration.get_mapper().map_from(config);
+    var json_element = new JsonElement.from_properties(properties);
+    
+    // Output pretty-printed JSON to stdout
+    print("%s\n", json_element.stringify(true));
+    
+    return 0;
+}
+
+private string detect_lib_dir() {
+    try {
+        // Use ldconfig -p to get the library cache and find the primary lib directory
+        // The first entry's path tells us where the system stores its libraries
+        var proc = new Subprocess.newv(
+            new string[] { "ldconfig", "-p" },
+            SubprocessFlags.STDOUT_PIPE
+        );
+        
+        var stdout_pipe = proc.get_stdout_pipe();
+        var data_input = new DataInputStream(stdout_pipe);
+        
+        // Skip the header line (e.g., "3426 libs found in cache `/etc/ld.so.cache'")
+        var header = data_input.read_line();
+        if (header == null) {
+            // Drain remaining output before wait
+            while (data_input.read_line() != null) {}
+            proc.wait();
+            return "lib";
+        }
+        
+        // Read the first library entry to get the path
+        var first_entry = data_input.read_line();
+        
+        // Drain remaining output to avoid deadlock
+        while (data_input.read_line() != null) {}
+        
+        proc.wait();
+        
+        if (first_entry == null) {
+            return "lib";
+        }
+        
+        // Parse the entry: "	libname.so (arch) => /lib64/libname.so"
+        // We want to extract the directory from the path after "=> "
+        var arrow_pos = first_entry.index_of("=> ");
+        if (arrow_pos == -1) {
+            return "lib";
+        }
+        
+        var full_path = first_entry.substring(arrow_pos + 3).strip();
+        // full_path is now "/lib64/lib3mf.so.2"
+        
+        // Find the directory part (everything before the last "/")
+        var last_slash = full_path.last_index_of("/");
+        if (last_slash <= 0) {
+            return "lib";
+        }
+        
+        // Extract directory path (e.g., "/lib64" from "/lib64/lib3mf.so.2")
+        var dir_path = full_path.substring(0, last_slash);
+        // dir_path is now "/lib64"
+        
+        // Get the directory name (e.g., "lib64" from "/lib64")
+        var prev_slash = dir_path.last_index_of("/");
+        var lib_dir = prev_slash >= 0 ? dir_path.substring(prev_slash + 1) : dir_path;
+        
+        // Verify it's actually a lib directory
+        if (!lib_dir.has_prefix("lib")) {
+            return "lib";
+        }
+        
+        return lib_dir;
+    }
+    catch (Error e) {
+        // Fallback to checking for directory existence if ldconfig fails
+        return detect_lib_dir_fallback();
+    }
+}
+
+private string detect_lib_dir_fallback() {
+    var usr_lib64 = File.new_for_path("/usr/lib64");
+    if (usr_lib64.query_exists()) {
+        return "lib64";
+    }
+    
+    // Default fallback
+    return "lib";
+}

+ 1 - 0
src/cli/meson.build

@@ -4,6 +4,7 @@ sources += files('Manifest.vala')
 sources += files('Repository.vala')
 sources += files('Repository.vala')
 sources += files('Install.vala')
 sources += files('Install.vala')
 sources += files('Scaffold.vala')
 sources += files('Scaffold.vala')
+sources += files('GenConfig.vala')
 
 
  deps = dependencies
  deps = dependencies
  deps += usm_dep
  deps += usm_dep