CachedPackage.vala 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. using Invercargill;
  2. namespace Usm {
  3. public class CachedPackage {
  4. public string state_path { get; private set; }
  5. public string package_path { get; private set; }
  6. public string package_name { get; private set; }
  7. /**
  8. * The package's manifest when already known without reading the
  9. * cached .usmc — set from a repository listing entry so a plan
  10. * can be described, confirmed and strategised before the package
  11. * is downloaded. Null (the default) reads {@link package_path}
  12. * as usual; execution itself always works from the extracted
  13. * sources' own MANIFEST.usm.
  14. */
  15. public Manifest? known_manifest { get; set; }
  16. public CachedPackage(string path) {
  17. this.state_path = path;
  18. this.package_path = Path.build_filename(path, "package.usmc");
  19. this.package_name = Path.get_basename(path);
  20. }
  21. public Manifest get_manifest() throws Error {
  22. if(known_manifest != null) {
  23. return known_manifest;
  24. }
  25. return new Manifest.from_package(package_path);
  26. }
  27. public OriginInformation get_origin_information() throws Error {
  28. return new OriginInformation.from_file(Path.build_filename(state_path, "origin-info"));
  29. }
  30. public bool has_build_directory() {
  31. return File.new_for_path(build_directory_path()).query_exists();
  32. }
  33. public bool has_build_archive() {
  34. return File.new_for_path(build_archive_path()).query_exists();
  35. }
  36. public string create_build_directory() throws Error {
  37. var path = build_directory_path();
  38. var manifest = get_manifest();
  39. var file = File.new_for_path(path);
  40. if(manifest.flags.has(ManifestFlag.BUILD_IN_SOURCE_TREE)) {
  41. file.make_symbolic_link(source_directory_path());
  42. }
  43. else {
  44. File.new_for_path(path).make_directory();
  45. }
  46. return path;
  47. }
  48. public string get_build_directory() throws Error {
  49. var path = build_directory_path();
  50. if(File.new_for_path(path).query_exists()) {
  51. return path;
  52. }
  53. var archive_path = build_archive_path();
  54. if(!File.new_for_path(archive_path).query_exists()) {
  55. throw new StateError.NO_BUILD_ARTIFACT(@"The package \"$package_name\" has no build artifact");
  56. }
  57. Util.unarchive(archive_path, path);
  58. return path;
  59. }
  60. public string get_build_archive() throws Error {
  61. var path = build_archive_path();
  62. if(File.new_for_path(path).query_exists()) {
  63. return path;
  64. }
  65. var dir_path = build_directory_path();
  66. if(!File.new_for_path(dir_path).query_exists()) {
  67. throw new StateError.NO_BUILD_ARTIFACT(@"The package \"$package_name\" has no build artifact");
  68. }
  69. Util.archive(dir_path, path);
  70. return path;
  71. }
  72. public void archive_build(Usm.ProgressDelegate? progress = null) throws Error {
  73. // An archive with no build directory is already the
  74. // authoritative artifact: extracting it just to repack the
  75. // same bytes is pure churn
  76. if(!has_build_directory() && has_build_archive()) {
  77. return;
  78. }
  79. var build_dir = get_build_directory();
  80. // Delete existing archive, if it exists
  81. var archive_file = File.new_for_path(build_archive_path());
  82. if(archive_file.query_exists()) {
  83. archive_file.delete();
  84. }
  85. Util.archive_with_progress(build_dir, archive_file.get_path(), progress);
  86. clean_build_directory();
  87. }
  88. public void unarchive_build() throws Error {
  89. clean_build_directory();
  90. get_build_directory();
  91. }
  92. public void clean_build_directory() throws Error {
  93. var path = build_directory_path();
  94. if(File.new_for_path(path).query_exists()) {
  95. Util.delete_tree(path);
  96. }
  97. }
  98. /**
  99. * Removes the build directory AND the build.tar.xz archive,
  100. * forcing the next build to compile from scratch.
  101. */
  102. public void clean_build_cache() throws Error {
  103. clean_build_directory();
  104. var archive = build_archive_path();
  105. var archive_file = File.new_for_path(archive);
  106. if(archive_file.query_exists()) {
  107. archive_file.delete();
  108. }
  109. }
  110. /**
  111. * Extracts the cached .usmc into the package directory,
  112. * forwarding extraction progress (see
  113. * {@link Util.unarchive_with_progress}) to {@link progress}
  114. * when supplied. A directory that already exists is returned
  115. * as-is without extracting.
  116. */
  117. public string get_source_directory(Usm.ProgressDelegate? progress = null) throws Error {
  118. var path = source_directory_path();
  119. if(File.new_for_path(path).query_exists()) {
  120. return path;
  121. }
  122. Util.unarchive_with_progress(package_path, path, progress);
  123. return path;
  124. }
  125. public void clean_source() throws Error {
  126. var path = source_directory_path();
  127. if(File.new_for_path(path).query_exists()) {
  128. Util.delete_tree(path);
  129. }
  130. }
  131. public string create_install_directory() throws Error {
  132. var path = install_directory_path();
  133. File.new_for_path(path).make_directory();
  134. return path;
  135. }
  136. public void clean_install() throws Error {
  137. var path = install_directory_path();
  138. if(File.new_for_path(path).query_exists()) {
  139. Util.delete_tree(path);
  140. }
  141. }
  142. public void update_origin_information(OriginInformation info) throws Error {
  143. var properties = OriginInformation.get_mapper().map_from(info);
  144. var json = new InvercargillJson.JsonElement.from_properties(properties);
  145. json.write_to_file(Path.build_filename(state_path, "origin-info"));
  146. }
  147. private string build_directory_path() {
  148. return Path.build_filename(state_path, "build");
  149. }
  150. private string build_archive_path() {
  151. return Path.build_filename(state_path, "build.tar.xz");
  152. }
  153. private string source_directory_path() {
  154. return Path.build_filename(state_path, "package");
  155. }
  156. private string install_directory_path() {
  157. return Path.build_filename(state_path, "install");
  158. }
  159. }
  160. public class CachedPackageManifest {
  161. public CachedPackage package { get; private set; }
  162. public Manifest manifest { get; private set; }
  163. public CachedPackageManifest(CachedPackage package) throws Error {
  164. this.package = package;
  165. this.manifest = package.get_manifest();
  166. }
  167. }
  168. }