Class: Autoproj::Ops::Snapshot
- Inherits:
-
Object
- Object
- Autoproj::Ops::Snapshot
- Defined in:
- lib/autoproj/ops/snapshot.rb
Constant Summary collapse
- DEFAULT_VERSIONS_FILE_BASENAME =
"50-versions.yml"
Instance Attribute Summary collapse
-
#manifest ⇒ Object
readonly
Returns the value of attribute manifest.
Class Method Summary collapse
-
.create_commit(pkg, path, message, parent_id = nil, real_author: true) {|io| ... } ⇒ String
Create a git commit in which a file contains provided content.
- .import_state_log_ref ⇒ Object
-
.merge_packets(overrides, state) ⇒ Object
Update version control information with new choices.
- .snapshot(packages, target_dir) ⇒ Object
- .update_log_available?(manifest) ⇒ Boolean
Instance Method Summary collapse
- #current_import_state ⇒ Object
- #error_or_warn(package, error) ⇒ Object
- #import_state_log_file ⇒ Object
-
#import_state_log_package ⇒ Autobuild::Package
Returns a package that is used to store this installs import history.
-
#initialize(manifest, keep_going: false) ⇒ Snapshot
constructor
A new instance of Snapshot.
-
#keep_going? ⇒ Boolean
Control what happens if a package fails to be snapshotted.
- #save_import_state(name, versions) ⇒ Object
- #save_versions(versions, versions_file, replace: false) ⇒ Object
- #snapshot_package_sets(target_dir = nil, only_local: true) ⇒ Object
- #snapshot_packages(packages, target_dir = nil, only_local: true, fingerprint: false) ⇒ Object
- #sort_versions(versions) ⇒ Object
-
#tags(package) ⇒ Object
Returns the list of existing version tags.
- #update_package_import_state(name, packages) ⇒ Object
Constructor Details
#initialize(manifest, keep_going: false) ⇒ Snapshot
Returns a new instance of Snapshot.
81 82 83 84 |
# File 'lib/autoproj/ops/snapshot.rb', line 81 def initialize(manifest, keep_going: false) @manifest = manifest @keep_going = keep_going end |
Instance Attribute Details
#manifest ⇒ Object (readonly)
Returns the value of attribute manifest.
68 69 70 |
# File 'lib/autoproj/ops/snapshot.rb', line 68 def manifest @manifest end |
Class Method Details
.create_commit(pkg, path, message, parent_id = nil, real_author: true) {|io| ... } ⇒ String
Create a git commit in which a file contains provided content
The target git repository’s current index and history is left unmodified. The only modification is the creation of a new dangling commit.
It creates a temporary file and gives it to the block so that the file gets filled with the new content
254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 |
# File 'lib/autoproj/ops/snapshot.rb', line 254 def self.create_commit(pkg, path, , parent_id = nil, real_author: true) importer = pkg.importer object_id = Tempfile.open "autoproj-versions" do |io| yield(io) io.flush importer.( pkg, "hash-object", "-w", "--path", path, io.path ).first end cacheinfo = ["100644", object_id, path] cacheinfo = cacheinfo.join(",") if Autobuild::Git.at_least_version(2, 1) parent_id ||= importer.rev_parse(pkg, "HEAD") env = Hash.new unless env["GIT_AUTHOR_NAME"] = "autoproj" env["GIT_AUTHOR_EMAIL"] = "autoproj" env["GIT_COMMITTER_NAME"] = "autoproj" env["GIT_COMMITTER_EMAIL"] = "autoproj" end # Create the tree using a temporary index in order to not mess with # the user's index state. read-tree initializes the new index and # then we add the overrides file with update-index / write-tree our_index = File.join(importer.git_dir(pkg, false), "index.autoproj") FileUtils.rm_f our_index begin ENV["GIT_INDEX_FILE"] = our_index importer.(pkg, "read-tree", parent_id) # And add the new file importer.( pkg, "update-index", "--add", "--cacheinfo", *cacheinfo ) tree_id = importer.(pkg, "write-tree").first ensure ENV.delete("GIT_INDEX_FILE") FileUtils.rm_f our_index end importer.( pkg, "commit-tree", tree_id, "-p", parent_id, env: env, input_streams: [] ).first end |
.import_state_log_ref ⇒ Object
187 188 189 |
# File 'lib/autoproj/ops/snapshot.rb', line 187 def self.import_state_log_ref "refs/autoproj" end |
.merge_packets(overrides, state) ⇒ Object
Update version control information with new choices
The two parameters are formatted as expected in the version_control and overrides fields in source.yml / overrides.yml, that is (in YAML)
- package_name:
version: '10'
control: '20'
info: '30'
The two parameters are expected to only use full package names, and not regular expressions
21 22 23 24 25 26 27 28 |
# File 'lib/autoproj/ops/snapshot.rb', line 21 def self.merge_packets(overrides, state) overriden = overrides.map { |entry| entry.keys.first }.to_set filtered_state = state.find_all do |pkg| name, = pkg.first !overriden.include?(name) end filtered_state + overrides end |
.snapshot(packages, target_dir) ⇒ Object
64 65 66 |
# File 'lib/autoproj/ops/snapshot.rb', line 64 def self.snapshot(packages, target_dir) # todo end |
.update_log_available?(manifest) ⇒ Boolean
30 31 32 33 34 35 |
# File 'lib/autoproj/ops/snapshot.rb', line 30 def self.update_log_available?(manifest) new(manifest).import_state_log_package true rescue ArgumentError false end |
Instance Method Details
#current_import_state ⇒ Object
197 198 199 200 201 202 203 204 205 206 |
# File 'lib/autoproj/ops/snapshot.rb', line 197 def current_import_state main = import_state_log_package # Try to resolve the log ref, and extract the version file from it begin yaml = main.importer.show(main, self.class.import_state_log_ref, import_state_log_file) YAML.load(yaml) || Array.new rescue Autobuild::PackageException Array.new end end |
#error_or_warn(package, error) ⇒ Object
107 108 109 110 111 112 113 114 115 116 117 118 |
# File 'lib/autoproj/ops/snapshot.rb', line 107 def error_or_warn(package, error) if error.kind_of?(Interrupt) raise elsif keep_going? error = error. unless error.respond_to?(:to_str) Autoproj.warn error elsif error.respond_to?(:to_str) raise Autobuild::PackageException.new(package, "snapshot"), error else raise end end |
#import_state_log_file ⇒ Object
193 194 195 |
# File 'lib/autoproj/ops/snapshot.rb', line 193 def import_state_log_file File.join(Workspace::OVERRIDES_DIR, DEFAULT_VERSIONS_FILE_BASENAME) end |
#import_state_log_package ⇒ Autobuild::Package
Returns a package that is used to store this installs import history
Its importer is guaranteed to be a git importer
172 173 174 175 176 177 178 179 180 181 182 183 184 185 |
# File 'lib/autoproj/ops/snapshot.rb', line 172 def import_state_log_package pkg = manifest.main_package_set.create_autobuild_package unless pkg.importer if Autobuild::Git.can_handle?(pkg.srcdir) pkg.importer = Autobuild.git(pkg.srcdir) end end unless pkg.importer.kind_of?(Autobuild::Git) raise ArgumentError, "cannot use autoproj auto-import feature if the main configuration is not managed under git" end pkg end |
#keep_going? ⇒ Boolean
Control what happens if a package fails to be snapshotted
If true, the failure to snapshot a package should lead to a warning. Otherwise (the default), it leads to an error.
77 78 79 |
# File 'lib/autoproj/ops/snapshot.rb', line 77 def keep_going? !!@keep_going end |
#save_import_state(name, versions) ⇒ Object
223 224 225 226 227 228 229 230 231 232 233 234 235 236 |
# File 'lib/autoproj/ops/snapshot.rb', line 223 def save_import_state(name, versions) versions = sort_versions(versions) main = import_state_log_package git_dir = main.importer.git_dir(main, false) # Ensure that our ref is being logged FileUtils.touch File.join(git_dir, "logs", *self.class.import_state_log_ref.split("/")) # Create the commit with the versions info commit_id = Snapshot.create_commit(main, import_state_log_file, name, real_author: false) do |io| YAML.dump(versions, io) end # And save it in our reflog main.importer.(main, "update-ref", "-m", name, self.class.import_state_log_ref, commit_id) end |
#save_versions(versions, versions_file, replace: false) ⇒ Object
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
# File 'lib/autoproj/ops/snapshot.rb', line 43 def save_versions(versions, versions_file, replace: false) existing_versions = Array.new if !replace && File.exist?(versions_file) existing_versions = YAML.load(File.read(versions_file)) || Array.new end # create direcotry for versions file first FileUtils.mkdir_p(File.dirname(versions_file)) # augment the versions file with the updated versions versions = Snapshot.merge_packets(versions, existing_versions) versions = sort_versions(versions) # write the yaml file File.open(versions_file, "w") do |io| io.write YAML.dump(versions) end end |
#snapshot_package_sets(target_dir = nil, only_local: true) ⇒ Object
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
# File 'lib/autoproj/ops/snapshot.rb', line 86 def snapshot_package_sets(target_dir = nil, only_local: true) result = Array.new manifest.each_package_set do |pkg_set| next if pkg_set.local? vcs_info = begin pkg_set.snapshot(target_dir, only_local: only_local) rescue Exception => e error_or_warn(pkg_set, e) next end if vcs_info result << Hash["pkg_set:#{pkg_set.repository_id}", vcs_info] else error_or_warn(pkg_set, "cannot snapshot package set #{pkg_set.name}: importer snapshot failed") end end result end |
#snapshot_packages(packages, target_dir = nil, only_local: true, fingerprint: false) ⇒ Object
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
# File 'lib/autoproj/ops/snapshot.rb', line 120 def snapshot_packages(packages, target_dir = nil, only_local: true, fingerprint: false) result = Array.new fingerprint_memo = Hash.new packages.each do |package_name| package = manifest.find_package_definition(package_name) unless package raise ArgumentError, "#{package_name} is not a known package" end importer = package.autobuild.importer if !importer error_or_warn(package, "cannot snapshot #{package_name} as it has no importer") next elsif !importer.respond_to?(:snapshot) error_or_warn(package, "cannot snapshot #{package_name} as the #{importer.class} importer does not support it") next end vcs_info = begin importer.snapshot(package.autobuild, target_dir, only_local: only_local) rescue Exception => e error_or_warn(package, e) next end if fingerprint vcs_info["fingerprint"] = package.autobuild.fingerprint(memo: fingerprint_memo) end if vcs_info result << Hash[package_name, vcs_info] else error_or_warn(package, "cannot snapshot #{package_name}: importer snapshot failed") end end result end |
#sort_versions(versions) ⇒ Object
37 38 39 40 41 |
# File 'lib/autoproj/ops/snapshot.rb', line 37 def sort_versions(versions) pkg_sets, pkgs = versions.partition { |vcs| vcs.keys.first =~ /^pkg_set:/ } pkg_sets.sort_by { |vcs| vcs.keys.first } + pkgs.sort_by { |vcs| vcs.keys.first } end |
#tags(package) ⇒ Object
Returns the list of existing version tags
159 160 161 162 163 164 |
# File 'lib/autoproj/ops/snapshot.rb', line 159 def (package) importer = package.importer = importer.(package, "tag") .find_all do |tag_name| end end |
#update_package_import_state(name, packages) ⇒ Object
208 209 210 211 212 213 214 215 216 217 218 219 220 221 |
# File 'lib/autoproj/ops/snapshot.rb', line 208 def update_package_import_state(name, packages) current_versions = current_import_state if current_versions.empty? # Do a full snapshot this time only Autoproj. " building initial autoproj import log, this may take a while" packages = manifest.all_selected_source_packages .find_all { |pkg| File.directory?(pkg.autobuild.srcdir) } .map(&:name) end versions = snapshot_package_sets versions += snapshot_packages(packages) versions = Snapshot.merge_packets(versions, current_versions) save_import_state(name, versions) end |