فهرست منبع

feat(resource): add support for alternative and canonical library resource types

This change extends the resource type system to support alternative and canonical
library formats, enabling better handling of multi-architecture library layouts
and library path conflicts.

Key changes:
- Added ALTERNATIVE_FORMAT_LIBRARY/RESOURCE and CANONICAL_LIBRARY/RESOURCE types
- Extended Paths class with altlib and canonlib directory support
- Enhanced resource type detection to handle canonical vs alternative libraries
- Added conflict resolution for alternative format resources during installation
- Updated autoprovides scanning to distinguish between library types
clanker 1 ماه پیش
والد
کامیت
cc980ab8e0
4فایلهای تغییر یافته به همراه136 افزوده شده و 18 حذف شده
  1. 22 12
      src/cli/Manifest.vala
  2. 13 3
      src/lib/Manifest.vala
  3. 17 2
      src/lib/Paths.vala
  4. 84 1
      src/lib/ResourceRef.vala

+ 22 - 12
src/cli/Manifest.vala

@@ -541,8 +541,9 @@ public static Invercargill.DataStructures.Vector<string> autoprovides_scan_tree(
             // Removing the file
             var file = folder.get_child(info.get_name());
             var true_path = file.get_path().substring(install_root.length);
-            var type = get_local_resource_type(true_path);
-            var relative_path = get_relative_path_for_type(true_path, type);
+            var type = guess_resource_type(true_path);
+            
+            var relative_path = get_relative_path_for_type(true_path, type.to_string());
             // Remove leading slash from relative_path if present
             if (relative_path.has_prefix("/")) {
                 relative_path = relative_path.substring(1);
@@ -560,7 +561,7 @@ public static Invercargill.DataStructures.Vector<string> autoprovides_scan_tree(
     return provides;
 }
 
-private static string get_local_resource_type(string path) {
+private static Usm.ResourceType guess_resource_type(string path) {
     // Remove leading slash if present
     string clean_path = path.has_prefix("/") ? path.substring(1) : path;
     
@@ -568,16 +569,17 @@ private static string get_local_resource_type(string path) {
     var default_paths = new Usm.Paths.usm_environ();
     
     // Find all matching resource types and calculate directory traversals
-    var matching_types = new Invercargill.DataStructures.Vector<string>();
+    var matching_types = new Invercargill.DataStructures.Vector<Usm.ResourceType>();
     var traversal_counts = new Invercargill.DataStructures.Vector<int>();
     
     // Define all resource types to check
-    Usm.ResourceType[] types_to_check = {
+    var types_to_check = new Invercargill.Composition<Usm.ResourceType>();
+    types_to_check.append(Invercargill.Iterate.these<Usm.ResourceType>(
         Usm.ResourceType.BINARY,
         Usm.ResourceType.SUPER_BINARY,
         Usm.ResourceType.LIBRARY,
-        Usm.ResourceType.LIBRARY_EXECUTABLE,
         Usm.ResourceType.LIBRARY_RESOURCE,
+        Usm.ResourceType.LIBRARY_EXECUTABLE,
         Usm.ResourceType.INCLUDE,
         Usm.ResourceType.APPLICATION,
         Usm.ResourceType.INFO_PAGE,
@@ -591,7 +593,15 @@ private static string get_local_resource_type(string path) {
         Usm.ResourceType.TYPELIB,
         Usm.ResourceType.CONFIGURATION,
         Usm.ResourceType.OPTIONAL
-    };
+    ));
+
+    // If the canonlib directory is different to the regular library path, add the canonical checks
+    if(paths.canonlib != paths.lib) {
+        types_to_check.append(Invercargill.Iterate.these<Usm.ResourceType>(
+            Usm.ResourceType.CANONICAL_LIBRARY,
+            Usm.ResourceType.CANONICAL_LIBRARY_RESOURCE
+        ));
+    }
     
     foreach (var type in types_to_check) {
         var suggested_path = default_paths.get_suggested_base_path_for_type(type);
@@ -612,26 +622,26 @@ private static string get_local_resource_type(string path) {
             // Library and Library resource have the same path. Try to have actual libraries get 'lib:' type, and all others 'libres:'
             var basename = Path.get_basename(path);
             var is_library = basename.has_suffix(".so") || basename.has_suffix(".a") || basename.contains(".so.");
-            if(type == Usm.ResourceType.LIBRARY && !is_library) {
+            if(!is_library && (type == Usm.ResourceType.LIBRARY || type == Usm.ResourceType.CANONICAL_LIBRARY)) {
                 continue;
             }
-            if(type == Usm.ResourceType.LIBRARY_RESOURCE && is_library) {
+            if(is_library && (type == Usm.ResourceType.LIBRARY_RESOURCE || type == Usm.ResourceType.CANONICAL_LIBRARY_RESOURCE)) {
                 continue;
             }
             
-            matching_types.add(type.to_string());
+            matching_types.add(type);
             traversal_counts.add(traversal_count);
         }
     }
     
     // If no matches found, default to "rootpath"
     if (matching_types.peek_count() == 0) {
-        return "rootpath";
+        return Usm.ResourceType.ROOT_PATH;
     }
     
     // Find the type with the fewest directory traversals
     int min_traversals = traversal_counts[0];
-    string best_type = matching_types[0];
+    Usm.ResourceType best_type = matching_types[0];
     
     for (int i = 1; i < traversal_counts.peek_count(); i++) {
         if (traversal_counts[i] < min_traversals) {

+ 13 - 3
src/lib/Manifest.vala

@@ -372,6 +372,13 @@ namespace Usm {
                 callback(resource.key, resources_installed, resource_count, 0.0f);
                 var path = paths.get_suggested_path_for_resource(resource.key);
                 
+                // Check if this is an ALTERNATIVE_FORMAT resource type that should be optional
+                var is_alternative_format_resource = resource.key.resource_type == ResourceType.ALTERNATIVE_FORMAT_LIBRARY || resource.key.resource_type == ResourceType.ALTERNATIVE_FORMAT_LIBRARY_RESOURCE;
+                var alternative_format_resource_path_conflicts = false;
+                if(is_alternative_format_resource){
+                    alternative_format_resource_path_conflicts = provides.any(r => r != resource && path == paths.get_suggested_path_for_resource(r.key));
+                } 
+                
                 if(resource.key.resource_type == ResourceType.TAG) {
                     // Ensure parent directories are created first
                     var parent_dir = File.new_for_path(Path.get_basename(path));
@@ -407,11 +414,14 @@ namespace Usm {
                     var src = File.new_build_filename(base_path, resource.value.path ?? "");
                     var dest = File.new_for_path(path);
 
-                    if(!src.query_exists()) {
+                    // Don't throw if an alternative format resource wasn't built
+                    var source_exists = src.query_exists();
+                    if(!source_exists && !is_alternative_format_resource) {
                         throw new ManifestError.INVALID_FILE_PATH(@"Expected to find file listed in manifest at \"$(src.get_path())\", but no such file was found.");
                     }
-
-                    if(!dry_run) {
+                    
+                    // Don't copy an alternative format resource if it has the same path as the non-alternative resource
+                    if(source_exists && !dry_run && (!is_alternative_format_resource  || !alternative_format_resource_path_conflicts)) {
                         src.copy(dest, FileCopyFlags.OVERWRITE, null, (c, t) => callback(resource.key, resources_installed, resource_count, (float)c / (float)t));
                     }
                 }

+ 17 - 2
src/lib/Paths.vala

@@ -10,6 +10,8 @@ namespace Usm {
         public string data { get; set; }
         public string info { get; set; }
         public string lib { get; set; }
+        public string altlib { get; set; }
+        public string canonlib { get; set; }
         public string man { get; set; }
         public string libexec { get; set; }
         public string locale { get; set; }
@@ -29,6 +31,8 @@ namespace Usm {
             Environment.set_variable("DATADIR", Paths.ensure_trailing_slash(data), true);
             Environment.set_variable("INFODIR", Paths.ensure_trailing_slash(info), true);
             Environment.set_variable("LIBDIR", Paths.ensure_trailing_slash(lib), true);
+            Environment.set_variable("ALTLIBDIR", Paths.ensure_trailing_slash(altlib), true);
+            Environment.set_variable("CANONLIBDIR", Paths.ensure_trailing_slash(canonlib), true);
             Environment.set_variable("MANDIR", Paths.ensure_trailing_slash(man), true);
             Environment.set_variable("LIBEXECDIR", Paths.ensure_trailing_slash(libexec), true);
             Environment.set_variable("LOCALEDIR", Paths.ensure_trailing_slash(locale), true);
@@ -63,11 +67,16 @@ namespace Usm {
                 case Usm.ResourceType.SUPER_BINARY:
                     return Path.build_filename(destination, prefix, sbin);
                 case Usm.ResourceType.LIBRARY:
+                case Usm.ResourceType.LIBRARY_RESOURCE:
                     return Path.build_filename(destination, prefix, lib);
                 case Usm.ResourceType.LIBRARY_EXECUTABLE:
                     return Path.build_filename(destination, prefix, libexec);
-                case Usm.ResourceType.LIBRARY_RESOURCE:
-                    return Path.build_filename(destination, prefix, lib);
+                case Usm.ResourceType.ALTERNATIVE_FORMAT_LIBRARY:
+                case Usm.ResourceType.ALTERNATIVE_FORMAT_LIBRARY_RESOURCE:
+                    return Path.build_filename(destination, prefix, altlib);
+                case Usm.ResourceType.CANONICAL_LIBRARY:
+                case Usm.ResourceType.CANONICAL_LIBRARY_RESOURCE:
+                    return Path.build_filename(destination, prefix, canonlib);
                 case Usm.ResourceType.INFO_PAGE:
                     return Path.build_filename(destination, prefix, info);
                 case Usm.ResourceType.MANUAL_PAGE:
@@ -121,6 +130,8 @@ namespace Usm {
             data = "share";
             info = "share/info";
             lib = sizeof(void*) == 8 ? "lib64" : "lib";
+            canonlib = "lib";
+            altlib = "lib";
             man = "share/man";
             libexec = "libexec";
             locale = "share/locale";
@@ -143,6 +154,8 @@ namespace Usm {
             data = Environment.get_variable("USM_DATADIR") ?? defaults.data;
             info = Environment.get_variable("USM_INFODIR") ?? defaults.info;
             lib = Environment.get_variable("USM_LIBDIR") ?? defaults.lib;
+            altlib = Environment.get_variable("USM_ALTLIBDIR") ?? defaults.altlib;
+            canonlib = Environment.get_variable("USM_CANONLIBDIR") ?? defaults.canonlib;
             man = Environment.get_variable("USM_MANDIR") ?? defaults.man;
             libexec = Environment.get_variable("USM_LIBEXECDIR") ?? defaults.libexec;
             locale = Environment.get_variable("USM_LOCALEDIR") ?? defaults.locale;
@@ -164,6 +177,8 @@ namespace Usm {
                 data = data,
                 info = info,
                 lib = lib,
+                altlib = altlib,
+                canonlib = canonlib,
                 man = man,
                 libexec = libexec,
                 locale = locale,

+ 84 - 1
src/lib/ResourceRef.vala

@@ -11,8 +11,12 @@ namespace Usm {
         BINARY,
         SUPER_BINARY,
         LIBRARY,
-        LIBRARY_EXECUTABLE,
         LIBRARY_RESOURCE,
+        LIBRARY_EXECUTABLE,
+        ALTERNATIVE_FORMAT_LIBRARY,
+        ALTERNATIVE_FORMAT_LIBRARY_RESOURCE,
+        CANONICAL_LIBRARY,
+        CANONICAL_LIBRARY_RESOURCE,
         INFO_PAGE,
         MANUAL_PAGE,
         LOCALE,
@@ -46,6 +50,14 @@ namespace Usm {
                     return "libexec";
                 case ResourceType.LIBRARY_RESOURCE:
                     return "libres";
+                case ResourceType.ALTERNATIVE_FORMAT_LIBRARY:
+                    return "altlib";
+                case ResourceType.ALTERNATIVE_FORMAT_LIBRARY_RESOURCE:
+                    return "altlibres";
+                case ResourceType.CANONICAL_LIBRARY:
+                    return "canonlib";
+                case ResourceType.CANONICAL_LIBRARY_RESOURCE:
+                    return "canonlibres";
                 case ResourceType.INFO_PAGE:
                     return "info";
                 case ResourceType.MANUAL_PAGE:
@@ -93,6 +105,14 @@ namespace Usm {
                     return ResourceType.LIBRARY_EXECUTABLE;
                 case "libres":
                     return ResourceType.LIBRARY_RESOURCE;
+                case "altlib":
+                    return ResourceType.ALTERNATIVE_FORMAT_LIBRARY;
+                case "altlibres":
+                    return ResourceType.ALTERNATIVE_FORMAT_LIBRARY_RESOURCE;
+                case "canonlib":
+                    return ResourceType.CANONICAL_LIBRARY;
+                case "canonlibres":
+                    return ResourceType.CANONICAL_LIBRARY_RESOURCE;
                 case "info":
                     return ResourceType.INFO_PAGE;
                 case "man":
@@ -130,6 +150,10 @@ namespace Usm {
                 LIBRARY,
                 LIBRARY_EXECUTABLE,
                 LIBRARY_RESOURCE,
+                ALTERNATIVE_FORMAT_LIBRARY,
+                ALTERNATIVE_FORMAT_LIBRARY_RESOURCE,
+                CANONICAL_LIBRARY,
+                CANONICAL_LIBRARY_RESOURCE,
                 INFO_PAGE,
                 MANUAL_PAGE,
                 LOCALE,
@@ -195,6 +219,14 @@ namespace Usm {
                     return check_libexec();
                 case ResourceType.LIBRARY_RESOURCE:
                     return check_libres();
+                case ResourceType.ALTERNATIVE_FORMAT_LIBRARY:
+                    return check_altlib();
+                case ResourceType.ALTERNATIVE_FORMAT_LIBRARY_RESOURCE:
+                    return check_altlibres();
+                case ResourceType.CANONICAL_LIBRARY:
+                    return check_canonlib();
+                case ResourceType.CANONICAL_LIBRARY_RESOURCE:
+                    return check_canonlibres();
                 case ResourceType.INFO_PAGE:
                     return check_info();
                 case ResourceType.MANUAL_PAGE:
@@ -245,6 +277,37 @@ namespace Usm {
             return false;
         }
 
+        private bool check_canonlib() {
+            try {
+                var proc = new Subprocess.newv(new string[] { "ldconfig", "-p" }, SubprocessFlags.STDOUT_PIPE);
+                var pipe = new DataInputStream(proc.get_stdout_pipe());
+                string line = null;
+                while((line = pipe.read_line()) != null) {
+                    if(line.has_prefix("\t")) {
+                        var name = line.substring(1).split(" ", 2)[0];
+                        // Only return true for libraries found in the canonical lib directory (e.g. not in /lib64)
+                        if(resource == name && (name.has_prefix("/usr/lib") || name.has_prefix("/lib"))) {
+                            return true;
+                        }
+                    }
+                }
+                proc.wait_check();
+            }
+            catch(Error e) {
+                warning(@"Error checking for resource $this: $(e.message)");
+            }
+            return false;
+        }
+
+        private bool check_altlib() {
+            // XXX: need a more robust test for this as not all 64bit archetctures have alternative formats
+            if(sizeof(void*) == 8) {
+                return check_canonlib();
+            }
+            // Return false on 32 bit systems that won't have alternative formats
+            return false;
+        }
+
         private bool check_bin() {
             var paths = Environment.get_variable("PATH").split(":");
             foreach (var path in paths) {
@@ -292,6 +355,26 @@ namespace Usm {
             return false;
         }
 
+        private bool check_canonlibres() {
+            var paths = new string[] { "/usr/lib", "/lib" };
+            foreach (var path in paths) {
+                var file = File.new_build_filename(path, resource);
+                if(file.query_exists()) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        private bool check_altlibres() {
+            // XXX: need a more robust test for this as not all 64bit archetctures have alternative formats
+            if(sizeof(void*) == 8) {
+                return check_canonlibres();
+            }
+            // Return false on 32 bit systems that won't have alternative formats
+            return false;
+        }
+
         private bool check_app() {
             var file = File.new_build_filename("/usr/share/applications", resource);
             return file.query_exists();