|
|
@@ -31,7 +31,7 @@ public static int manifest_main(string[] args) {
|
|
|
build_path = args[i];
|
|
|
}
|
|
|
}
|
|
|
- } else if(verb != "remove" && verb != "acquire" && verb != "install" && verb != "package" && verb != "test") {
|
|
|
+ } else if(verb != "remove" && verb != "acquire" && verb != "install" && verb != "package" && verb != "test" && verb != "validate") {
|
|
|
if(args.length < 3) {
|
|
|
manifest_usage();
|
|
|
return 255;
|
|
|
@@ -54,7 +54,7 @@ public static int manifest_main(string[] args) {
|
|
|
}
|
|
|
|
|
|
// Automatically create a temporary directory for these commands if one was not provided.
|
|
|
- if(verb == "install" || verb == "autoprovides" || verb == "test") {
|
|
|
+ if(verb == "install" || verb == "autoprovides" || verb == "test" || verb == "validate") {
|
|
|
if(build_path == null) {
|
|
|
var dir = File.new_build_filename("/tmp", Uuid.string_random());
|
|
|
try {
|
|
|
@@ -69,7 +69,7 @@ public static int manifest_main(string[] args) {
|
|
|
}
|
|
|
|
|
|
// Automatically create the specified directory for these commands if it doesn't exist
|
|
|
- if(verb == "install" || verb == "autoprovides" || verb == "test" || verb == "build") {
|
|
|
+ if(verb == "install" || verb == "autoprovides" || verb == "test" || verb == "build" || verb == "validate") {
|
|
|
var build_dir = File.new_for_path(build_path);
|
|
|
if(!build_dir.query_exists()) {
|
|
|
printerr(@"Creating build directory: $build_path\n");
|
|
|
@@ -111,12 +111,16 @@ public static int manifest_main(string[] args) {
|
|
|
return test();
|
|
|
}
|
|
|
|
|
|
+ if(verb == "validate") {
|
|
|
+ return validate();
|
|
|
+ }
|
|
|
+
|
|
|
manifest_usage();
|
|
|
return 255;
|
|
|
}
|
|
|
|
|
|
private void manifest_usage() {
|
|
|
- printerr("USAGE:\n\tusm manifest build <build path>\n\tusm manifest install <build path>\n\tusm manifest remove\nusm manifest acquire\nusm manifest autoprovides [--replace] [--debug] [build path]\nusm manifest test [build path]\n");
|
|
|
+ printerr("USAGE:\n\tusm manifest build <build path>\n\tusm manifest install <build path>\n\tusm manifest remove\nusm manifest acquire\nusm manifest autoprovides [--replace] [--debug] [build path]\nusm manifest test [build path]\nusm manifest validate [build path]\n");
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -786,5 +790,214 @@ private int test() {
|
|
|
return 251;
|
|
|
}
|
|
|
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+private int validate() {
|
|
|
+ if(build_path == null) {
|
|
|
+ var dir = File.new_build_filename("/tmp", Uuid.string_random());
|
|
|
+ try {
|
|
|
+ dir.make_directory();
|
|
|
+ }
|
|
|
+ catch(Error e) {
|
|
|
+ printerr(@"Could not create temporary build directory, try specifying one instead: $(e.message)\n");
|
|
|
+ return 255;
|
|
|
+ }
|
|
|
+ build_path = dir.get_path();
|
|
|
+ } else {
|
|
|
+ // Create build directory if it doesn't exist
|
|
|
+ var build_dir = File.new_for_path(build_path);
|
|
|
+ if(!build_dir.query_exists()) {
|
|
|
+ printerr(@"Creating build directory: $build_path\n");
|
|
|
+ try {
|
|
|
+ build_dir.make_directory_with_parents();
|
|
|
+ }
|
|
|
+ catch(Error e) {
|
|
|
+ printerr(@"Could not create build directory: $(e.message)\n");
|
|
|
+ return 255;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ var missing_management_deps = manifest.dependencies.manage.where(d => !resfinder.has_resource(d));
|
|
|
+ var missing_build_deps = manifest.dependencies.build.where(d => !resfinder.has_resource(d));
|
|
|
+ var missing_runtime_deps = manifest.dependencies.runtime.where(d => !destresfinder.has_resource(d));
|
|
|
+
|
|
|
+ var sane = true;
|
|
|
+ if(missing_management_deps.any()) {
|
|
|
+ sane = false;
|
|
|
+ foreach (var item in missing_management_deps) {
|
|
|
+ printerr(@"Missing management dependency \"$item\".\n");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if(missing_build_deps.any()) {
|
|
|
+ sane = false;
|
|
|
+ foreach (var item in missing_build_deps) {
|
|
|
+ printerr(@"Missing build dependency \"$item\".\n");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if(missing_runtime_deps.any()) {
|
|
|
+ sane = false;
|
|
|
+ foreach (var item in missing_runtime_deps) {
|
|
|
+ printerr(@"Missing runtime dependency \"$item\".\n");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if(!sane) {
|
|
|
+ printerr("Could not validate manifest, missing dependencies\n");
|
|
|
+ return 252;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Check for license
|
|
|
+ if(manifest.licences == null || manifest.licences.count() == 0) {
|
|
|
+ printerr("Warning: No licence has been provided in the manifest.\n");
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ // Run build
|
|
|
+ var build_proc = manifest.run_build(build_path, paths, SubprocessFlags.STDOUT_SILENCE, frac => printerr(@"Building '$(manifest.name)': $((int)(frac*100))%\r"));
|
|
|
+ build_proc.wait_check();
|
|
|
+ printerr("\n");
|
|
|
+ }
|
|
|
+ catch(Error e) {
|
|
|
+ printerr(@"\nError running build exec: $(e.message)\n");
|
|
|
+ return 251;
|
|
|
+ }
|
|
|
+
|
|
|
+ var install_dir = File.new_build_filename("/tmp", Uuid.string_random());
|
|
|
+ if(manifest.executables.install != null) {
|
|
|
+ try {
|
|
|
+ install_dir.make_directory();
|
|
|
+ }
|
|
|
+ catch(Error e) {
|
|
|
+ printerr(@"Could not create temporary install directory: $(e.message)\n");
|
|
|
+ return 250;
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ manifest.run_install(build_path, install_dir.get_path(), paths, Usm.InstallType.FRESH, SubprocessFlags.STDOUT_SILENCE).wait_check();
|
|
|
+ }
|
|
|
+ catch(Error e) {
|
|
|
+ printerr(@"Error running install exec: $(e.message)\n");
|
|
|
+ return 249;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ printerr("Warning: No install script specified, cannot validate installation.\n");
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Validate each expected resource exists in its expected location
|
|
|
+ var missing_resources = new Invercargill.DataStructures.Vector<Usm.ResourceRef>();
|
|
|
+ foreach (var expected in manifest.provides) {
|
|
|
+ bool found = false;
|
|
|
+ string expected_path = "";
|
|
|
+
|
|
|
+ try {
|
|
|
+ switch(expected.value.path_base) {
|
|
|
+ case Usm.ManifestFilePathBase.AS_EXPECTED:
|
|
|
+ // For as-expected, check in install directory at suggested path
|
|
|
+ var install_paths = paths.clone();
|
|
|
+ install_paths.destination = install_dir.get_path();
|
|
|
+ expected_path = install_paths.get_suggested_path_for_resource(expected.key);
|
|
|
+ var file = File.new_for_path(expected_path);
|
|
|
+ found = file.query_exists();
|
|
|
+ break;
|
|
|
+
|
|
|
+ case Usm.ManifestFilePathBase.BUILD:
|
|
|
+ // For build:, check in build directory at specified path
|
|
|
+ expected_path = Path.build_filename(build_path, expected.value.path ?? "");
|
|
|
+ var file = File.new_for_path(expected_path);
|
|
|
+ found = file.query_exists();
|
|
|
+ break;
|
|
|
+
|
|
|
+ case Usm.ManifestFilePathBase.SOURCE:
|
|
|
+ // For source:, check in source directory at specified path
|
|
|
+ expected_path = Path.build_filename(Environment.get_current_dir(), expected.value.path ?? "");
|
|
|
+ var file = File.new_for_path(expected_path);
|
|
|
+ found = file.query_exists();
|
|
|
+ break;
|
|
|
+
|
|
|
+ case Usm.ManifestFilePathBase.INSTALL:
|
|
|
+ // For install:, check in install directory at specified path
|
|
|
+ expected_path = Path.build_filename(install_dir.get_path(), expected.value.path ?? "");
|
|
|
+ var file = File.new_for_path(expected_path);
|
|
|
+ found = file.query_exists();
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ assert_not_reached();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch(Error e) {
|
|
|
+ printerr(@"Error validating resource $(expected.key.to_string()): $(e.message)\n");
|
|
|
+ found = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(!found) {
|
|
|
+ missing_resources.add(expected.key);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if(missing_resources.any()) {
|
|
|
+ printerr("Error: Expected resources not found:\n");
|
|
|
+ foreach (var resource in missing_resources) {
|
|
|
+ var expected_resource = manifest.provides[resource];
|
|
|
+ string location_desc = "";
|
|
|
+ switch(expected_resource.path_base) {
|
|
|
+ case Usm.ManifestFilePathBase.AS_EXPECTED:
|
|
|
+ location_desc = "at expected install location";
|
|
|
+ break;
|
|
|
+ case Usm.ManifestFilePathBase.BUILD:
|
|
|
+ location_desc = @"in build directory at \"$(expected_resource.path ?? "")\"";
|
|
|
+ break;
|
|
|
+ case Usm.ManifestFilePathBase.SOURCE:
|
|
|
+ location_desc = @"in source directory at \"$(expected_resource.path ?? "")\"";
|
|
|
+ break;
|
|
|
+ case Usm.ManifestFilePathBase.INSTALL:
|
|
|
+ location_desc = @"in install directory at \"$(expected_resource.path ?? "")\"";
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ location_desc = "at unknown location";
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ printerr(@" - $(resource.to_string()) ($location_desc)\n");
|
|
|
+ }
|
|
|
+ return 248;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Scan for unexpected resources in the install directory
|
|
|
+ try {
|
|
|
+ var installed_resources = autoprovides_scan_tree(install_dir.get_path(), install_dir.get_path());
|
|
|
+ var expected_resources = manifest.provides;
|
|
|
+
|
|
|
+ // Check for unexpected resources
|
|
|
+ var unexpected_resources = new Invercargill.DataStructures.Vector<Usm.ResourceRef>();
|
|
|
+ foreach (var installed in installed_resources) {
|
|
|
+ bool found = false;
|
|
|
+ foreach (var expected in expected_resources) {
|
|
|
+ if(installed.key.to_string() == expected.key.to_string()) {
|
|
|
+ found = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if(!found) {
|
|
|
+ unexpected_resources.add(installed.key);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if(unexpected_resources.any()) {
|
|
|
+ printerr("Warning: Unexpected resources found in install directory:\n");
|
|
|
+ foreach (var resource in unexpected_resources) {
|
|
|
+ printerr(@" - $(resource.to_string())\n");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch(Error e) {
|
|
|
+ printerr(@"Error validating installation result: $(e.message)\n");
|
|
|
+ return 247;
|
|
|
+ }
|
|
|
+
|
|
|
+ printerr("Manifest validation completed successfully.\n");
|
|
|
return 0;
|
|
|
}
|