Billy Barrow před 6 měsíci
rodič
revize
c8675fd0c9

+ 7 - 7
MANIFEST.usm

@@ -4,13 +4,13 @@
   "summary": "Universal Source Manifest",
   "licences": [ {"name": "GPLv3", "category": "libre", "text": "src/LICENSE"} ],
   "provides": {
-    "bin:usm": "cli/usm",
-    "lib:libusm.so": "lib/libusm.so",
-    "inc:usm.h": "lib/usm.h",
-    "vapi:usm.vapi": "lib/usm.vapi",
-    "typelib:usm-1.0.typelib": "lib/usm-1.0.typelib",
-    "gir:usm-1.0.gir": "lib/usm-1.0.gir",
-    "pc:usm.pc": "meson-private/usm.pc"
+    "bin:usm": "build:cli/usm",
+    "lib:libusm.so": "build:lib/libusm.so",
+    "inc:usm.h": "build:lib/usm.h",
+    "vapi:usm.vapi": "build:lib/usm.vapi",
+    "typelib:usm-1.0.typelib": "build:lib/usm-1.0.typelib",
+    "gir:usm-1.0.gir": "build:lib/usm-1.0.gir",
+    "pc:usm.pc": "build:meson-private/usm.pc"
   },
   "depends": {
     "runtime": [

+ 3 - 1
src/lib/Exectuables.vala

@@ -6,6 +6,7 @@ namespace Usm {
         public string? install { get; set; }
         public string? remove { get; set; }
         public string? rebuild { get; set; }
+        public string? post_install { get; set; }
         public string? acquire { get; set; }
 
         public static PropertyMapper<Executables> get_mapper() {
@@ -13,7 +14,8 @@ namespace Usm {
                 cfg.map<string>("build", o => o.build, (o, v) => o.build = v);
                 cfg.map<string?>("rebuild", o => o.rebuild, (o, v) => o.rebuild = v, false);
                 cfg.map<string?>("acquire", o => o.acquire, (o, v) => o.acquire = v, false);
-                cfg.map<string?>("install", o => o.install, (o, v) => o.remove = v, false);
+                cfg.map<string?>("install", o => o.install, (o, v) => o.install = v, false);
+                cfg.map<string?>("post_install", o => o.post_install, (o, v) => o.post_install = v, false);
                 cfg.map<string?>("remove", o => o.remove, (o, v) => o.remove = v, false);
                 cfg.set_constructor(() => new Executables());
             });

+ 49 - 2
src/lib/File.vala

@@ -4,6 +4,7 @@ namespace Usm {
 
     public class ManifestFile {
 
+        public ManifestFilePathBase path_base { get; set; }
         public string path { get; set; }
         public ManifestFileType file_type { get; set; }
         public string? destination { get; set; }
@@ -13,6 +14,7 @@ namespace Usm {
         public static PropertyMapper<ManifestFile> get_mapper() {
             return PropertyMapper.build_for<ManifestFile>(cfg => {
                 cfg.map<string>("path", o => o.path, (o, v) => o.path = v);
+                cfg.map<string>("pathBase", o => o.path_base.to_string(), (o, v) => o.path_base = ManifestFilePathBase.from_string(v));
                 cfg.map<string>("type", o => o.file_type.to_string(), (o, v) => o.file_type = ManifestFileType.from_string(v));
                 cfg.map<string>("dest", o => o.destination, (o, v) => o.destination = v, false);
                 cfg.map_many<string>("keepOn", o => o.keep_on.select<string>(i => i.to_string()), (o, v) => o.keep_on = v.convert<RemoveType>(i => RemoveType.from_string(i)).to_vector(), false);
@@ -21,9 +23,17 @@ namespace Usm {
             });
         }
 
-        public ManifestFile.from_string(string str) {
-            path = str;
+        public ManifestFile.from_string(string str) throws ManifestError {
+            var parts = str.split(":", 2);
+            path_base = ManifestFilePathBase.from_string(parts[0]);
             file_type = ManifestFileType.REGULAR;
+            if(path_base == ManifestFilePathBase.AS_EXPECTED) {
+                return;
+            }
+            if(parts.length != 2) {
+                throw new ManifestError.INVALID_FILE_PATH("No file path provided");
+            }
+            path = parts[1];
         }
         
     }
@@ -60,4 +70,41 @@ namespace Usm {
         }
     }
 
+    public enum ManifestFilePathBase {
+        SOURCE,
+        BUILD,
+        INSTALL,
+        AS_EXPECTED;
+
+        public string to_string() {
+            switch(this) {
+                case ManifestFilePathBase.SOURCE:
+                    return "source";
+                case ManifestFilePathBase.BUILD:
+                    return "build";
+                case ManifestFilePathBase.INSTALL:
+                    return "install";
+                case ManifestFilePathBase.AS_EXPECTED:
+                    return "as-expected";
+                default:
+                    assert_not_reached();
+            }
+        }
+
+        public static ManifestFilePathBase from_string(string str) throws ManifestError {
+            switch(str) {
+                case "source":
+                    return ManifestFilePathBase.SOURCE;
+                case "build":
+                    return ManifestFilePathBase.BUILD;
+                case "install":
+                    return ManifestFilePathBase.INSTALL;
+                case "as-expected":
+                    return ManifestFilePathBase.AS_EXPECTED;
+                default:
+                    throw new ManifestError.INVALID_PATH_BASE(@"Unknown path base \"$str\".");
+            }
+        }
+    }
+
 }

+ 52 - 7
src/lib/Manifest.vala

@@ -10,7 +10,9 @@ namespace Usm {
         INVALID_FILE_TYPE,
         INVALID_REMOVE_TYPE,
         INVALID_INSTALL_TYPE,
-        INVALID_PACKAGE
+        INVALID_PACKAGE,
+        INVALID_PATH_BASE,
+        INVALID_FILE_PATH,
     }
 
     public class Manifest {
@@ -139,11 +141,20 @@ namespace Usm {
             return proc;
         }
 
-        public Subprocess? run_install(string build_path, InstallType type, SubprocessFlags flags) throws Error {
+        public Subprocess? run_install(string build_path, string install_path, InstallType type, SubprocessFlags flags) throws Error {
             if(executables.install == null) {
                 return null;
             }
             var path = Path.build_filename(Environment.get_current_dir(), executables.install);
+            var proc = new Subprocess.newv(new string[] { path, build_path, install_path, type.to_string() }, flags);
+            return proc;
+        }
+
+        public Subprocess? run_post_install(string build_path, InstallType type, SubprocessFlags flags) throws Error {
+            if(executables.install == null) {
+                return null;
+            }
+            var path = Path.build_filename(Environment.get_current_dir(), executables.post_install);
             var proc = new Subprocess.newv(new string[] { path, build_path, type.to_string() }, flags);
             return proc;
         }
@@ -158,7 +169,7 @@ namespace Usm {
         }
 
         public delegate void ResourceProgressCallback(ResourceRef resource, int current_resource, int total_resources, float resource_frac);
-        public void install_resources(string build_path, Paths paths, ResourceProgressCallback callback) throws Error {
+        public void install_resources(string source_path, string build_path, string? install_path, Paths paths, ResourceProgressCallback callback, bool dry_run = false) throws Error {
             // Install each resource speficied by the manifest
             var resource_count = provides.count();
             var resources_installed = 0;
@@ -172,23 +183,57 @@ namespace Usm {
                 if(resource.key.resource_type == ResourceType.TAG) {
                     // Ensure parent directories are created first
                     var parent_dir = File.new_for_path(Path.get_basename(path));
-                    if(!parent_dir.query_exists()) {
+                    if(!parent_dir.query_exists() && !dry_run) {
                         parent_dir.make_directory_with_parents();
                     }
                 }
 
                 if(resource.value.file_type == Usm.ManifestFileType.REGULAR) {
+                    var base_path = "";
+                    switch (resource.value.path_base) {
+                        case ManifestFilePathBase.BUILD:
+                            base_path = build_path;
+                            break;
+                        case ManifestFilePathBase.SOURCE:
+                            base_path = source_path;
+                            break;
+                        case ManifestFilePathBase.INSTALL:
+                            if(install_path == null) {
+                                throw new ManifestError.INVALID_FILE_PATH("Install path was not provided");
+                            }
+                            base_path = install_path;
+                            break;
+                        case ManifestFilePathBase.AS_EXPECTED:
+                            if(install_path == null) {
+                                throw new ManifestError.INVALID_FILE_PATH("Install path was not provided");
+                            }
+                            base_path = Path.build_filename(install_path, paths.get_suggested_path(resource.key));
+                            break;
+                        default:
+                            assert_not_reached();                            
+                    }
                     var src = File.new_build_filename(build_path, resource.value.path);
                     var dest = File.new_for_path(path);
-                    src.copy(dest, FileCopyFlags.OVERWRITE, null, (c, t) => callback(resource.key, resources_installed, resource_count, (float)c / (float)t));
+
+                    if(!src.query_exists()) {
+                        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) {
+                        src.copy(dest, FileCopyFlags.OVERWRITE, null, (c, t) => callback(resource.key, resources_installed, resource_count, (float)c / (float)t));
+                    }
                 }
                 else if(resource.value.file_type == Usm.ManifestFileType.DIRECTORY) {
                     var dest = File.new_for_path(path);
-                    dest.make_directory();
+                    if(!dry_run) {
+                        dest.make_directory();
+                    }
                 }
                 else if(resource.value.file_type == Usm.ManifestFileType.SYMBOLIC_LINK) {
                     var dest = File.new_for_path(path);
-                    dest.make_symbolic_link(resource.value.path);
+                    if(!dry_run){
+                        dest.make_symbolic_link(resource.value.path);
+                    }
                 }
                 else {
                     throw new TransactionError.INSTALL_ERROR(@"Could not understand resource key \"$(resource.key)\"");

+ 18 - 0
src/lib/State/CachedPackage.vala

@@ -109,6 +109,20 @@ namespace Usm {
             }
         }
 
+        public string create_install_directory() throws Error {
+            var path = install_directory_path();
+            File.new_for_path(path).make_directory();
+            return path;
+        }
+
+        public void clean_install() throws Error {
+            var path = install_directory_path();
+            if(File.new_for_path(path).query_exists()) {
+                Util.delete_tree(path);
+            }
+        }
+
+
         public void update_origin_information(OriginInformation info) throws Error {
             var properties = OriginInformation.get_mapper().map_from(info);
             var json = new InvercargillJson.JsonElement.from_properties(properties);
@@ -127,6 +141,10 @@ namespace Usm {
             return Path.build_filename(state_path, "package");
         }
 
+        private string install_directory_path() {
+            return Path.build_filename(state_path, "install");
+        }
+
     }
 
     public class CachedPackageManifest {

+ 16 - 7
src/lib/Transaction.vala

@@ -213,7 +213,6 @@ namespace Usm {
         private void remove_package(CachedPackage package) throws Error {
             // Get source and build directories
             var source_dir = package.get_source_directory();
-            var build_dir = package.get_build_directory();
 
             // "cd" into the source directory and read the manifest
             Environment.set_current_dir(source_dir);
@@ -238,13 +237,21 @@ namespace Usm {
             var manifest = new Usm.Manifest.from_file("MANIFEST.usm");
             report_progress(TransactionTask.INSTALLING, 0.0f);
 
+            string? install_dir = null;
+            // Run install process if present
+            if(manifest.executables.install != null) {
+                install_dir = package.create_install_directory();
+                var install_proc = manifest.run_install(build_dir, install_dir, InstallType.FRESH, SubprocessFlags.STDOUT_SILENCE);
+                install_proc.wait_check();
+            }
+
             // Install the package's resources
-            manifest.install_resources(build_dir, paths, (r, cr, tr, f) => report_progress(TransactionTask.INSTALLING, ((float)cr + (float)f) / (float)tr));
+            manifest.install_resources(source_dir, build_dir, install_dir, paths, (r, cr, tr, f) => report_progress(TransactionTask.INSTALLING, ((float)cr + (float)f) / (float)tr));
 
-            // Run install process if present
-            var build_proc = manifest.run_install(build_dir, InstallType.FRESH, SubprocessFlags.STDOUT_SILENCE);
-            if(build_proc != null)
-                build_proc.wait_check();
+            // Run post install process if present
+            var post_install_proc = manifest.run_post_install(build_dir, InstallType.FRESH, SubprocessFlags.STDOUT_SILENCE);
+            if(post_install_proc != null)
+            post_install_proc.wait_check();
 
             // Update the system state, and cleanup
             state.mark_installed(package);
@@ -252,8 +259,10 @@ namespace Usm {
 
         private void cleanup_package(CachedPackage package) throws Error {
             package.archive_build();
-            report_progress(TransactionTask.CLEANING_UP, 0.5f);
+            report_progress(TransactionTask.CLEANING_UP, 0.33334f);
             package.clean_source();
+            report_progress(TransactionTask.CLEANING_UP, 0.66667f);
+            package.clean_install();
             report_progress(TransactionTask.CLEANING_UP, 1.0f);
         }
     }