Class: Snapsync::Snapshot
- Inherits:
-
Object
- Object
- Snapsync::Snapshot
- Defined in:
- lib/snapsync/snapshot.rb
Overview
Representation of a single Snapper snapshot
Constant Summary collapse
- PARTIAL_MARKER =
"snapsync-partial"
Instance Attribute Summary collapse
-
#date ⇒ DateTime
readonly
The snapshot’s date.
-
#num ⇒ Object
readonly
The snapshot number.
-
#snapshot_dir ⇒ Pathname
readonly
The path to the snapshot directory.
-
#user_data ⇒ Hash<String,String>
readonly
The snapshot’s user data.
Class Method Summary collapse
-
.each(snapshot_dir, with_partial: false) ⇒ Object
Enumerate the snapshots from the given directory.
- .partial_marker_path(snapshot_dir) ⇒ Object
Instance Method Summary collapse
-
#initialize(snapshot_dir) ⇒ Snapshot
constructor
A new instance of Snapshot.
-
#load_info ⇒ Object
Loads snapper’s info.xml, validates it and assigns the information to the relevant attributes.
-
#partial? ⇒ Boolean
Whether this snapshot has only been partially synchronized.
-
#partial_marker_path ⇒ Pathname
A file that is used to mark the snapshot has having only been partially synchronized.
-
#size ⇒ Object
Compute the size of the snapshot.
-
#size_diff_from(snapshot) ⇒ Object
Compute the size difference between the given snapshot and self.
- #size_diff_from_gen(gen) ⇒ Object
-
#subvolume_dir ⇒ Pathname
The path to the snapshot’s subvolume.
-
#synchronization_point? ⇒ Boolean
Whether this snapshot is one of snapsync’s synchronization points.
-
#synchronization_point_for?(target) ⇒ Boolean
Whether this snapshot is one of snapsync’s synchronization points for the given target.
-
#to_time ⇒ Object
This snapshot’s reference time.
Constructor Details
#initialize(snapshot_dir) ⇒ Snapshot
62 63 64 65 66 67 68 69 70 71 72 73 74 |
# File 'lib/snapsync/snapshot.rb', line 62 def initialize(snapshot_dir) @snapshot_dir = snapshot_dir if !snapshot_dir.directory? raise InvalidSnapshot, "#{snapshot_dir} does not exist" elsif !subvolume_dir.directory? raise InvalidSnapshot, "#{snapshot_dir}'s subvolume directory does not exist (#{subvolume_dir})" end # This loads the information and also validates that snapshot_dir is # indeed a snapper snapshot load_info end |
Instance Attribute Details
#date ⇒ DateTime (readonly)
The snapshot’s date
17 18 19 |
# File 'lib/snapsync/snapshot.rb', line 17 def date @date end |
#num ⇒ Object (readonly)
The snapshot number
20 21 22 |
# File 'lib/snapsync/snapshot.rb', line 20 def num @num end |
#snapshot_dir ⇒ Pathname (readonly)
The path to the snapshot directory
7 8 9 |
# File 'lib/snapsync/snapshot.rb', line 7 def snapshot_dir @snapshot_dir end |
#user_data ⇒ Hash<String,String> (readonly)
The snapshot’s user data
25 26 27 |
# File 'lib/snapsync/snapshot.rb', line 25 def user_data @user_data end |
Class Method Details
.each(snapshot_dir, with_partial: false) ⇒ Object
Enumerate the snapshots from the given directory
The directory is supposed to be maintained in a snapper-compatible foramt, meaning that the snapshot directory name must be the snapshot’s number
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
# File 'lib/snapsync/snapshot.rb', line 106 def self.each(snapshot_dir, with_partial: false) return enum_for(__method__, snapshot_dir, with_partial: with_partial) if !block_given? snapshot_dir.each_child do |path| if path.directory? && path.basename.to_s =~ /^\d+$/ begin snapshot = Snapshot.new(path) rescue InvalidSnapshot => e Snapsync.warn "ignored #{path} in #{self}: #{e}" end if snapshot if snapshot.num != Integer(path.basename.to_s) Snapsync.warn "ignored #{path} in #{self}: the snapshot reports num=#{snapshot.num} but its directory is called #{path.basename}" elsif !with_partial && snapshot.partial? Snapsync.warn "ignored #{path} in #{self}: this is a partial snapshot" else yield snapshot end end end end end |
.partial_marker_path(snapshot_dir) ⇒ Object
29 30 31 |
# File 'lib/snapsync/snapshot.rb', line 29 def self.partial_marker_path(snapshot_dir) snapshot_dir + PARTIAL_MARKER end |
Instance Method Details
#load_info ⇒ Object
Loads snapper’s info.xml, validates it and assigns the information to the relevant attributes
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 157 158 159 160 161 |
# File 'lib/snapsync/snapshot.rb', line 130 def load_info info_xml = snapshot_dir + "info.xml" if !info_xml.file? raise InvalidSnapshot, "#{snapshot_dir}/info.xml does not exist, is this really a snapper snapshot ?" end xml = REXML::Document.new(info_xml.read) if xml.root.name != 'snapshot' raise InvalidInfoFile, "#{snapshot_dir}/info.xml does not look like a snapper info file (root is not 'snapshot')" end date = xml.root.elements.to_a('date') if date.empty? raise InvalidInfoFile, "#{snapshot_dir}/info.xml does not have a date element" else @date = DateTime.parse(date.first.text) end num = xml.root.elements.to_a('num') if num.empty? raise InvalidInfoFile, "#{snapshot_dir}/info.xml does not have a num element" else @num = Integer(num.first.text) end @user_data = Hash.new xml.root.elements.to_a('userdata').each do |node| k = node.elements['key'].text v = node.elements['value'].text user_data[k] = v end end |
#partial? ⇒ Boolean
Whether this snapshot has only been partially synchronized
42 43 44 |
# File 'lib/snapsync/snapshot.rb', line 42 def partial? partial_marker_path.exist? end |
#partial_marker_path ⇒ Pathname
A file that is used to mark the snapshot has having only been partially synchronized
37 38 39 |
# File 'lib/snapsync/snapshot.rb', line 37 def partial_marker_path self.class.partial_marker_path(snapshot_dir) end |
#size ⇒ Object
Compute the size of the snapshot
87 88 89 |
# File 'lib/snapsync/snapshot.rb', line 87 def size size_diff_from_gen(0) end |
#size_diff_from(snapshot) ⇒ Object
Compute the size difference between the given snapshot and self
This is an estimate of the size required to send this snapshot using the given snapshot as parent
80 81 82 83 84 |
# File 'lib/snapsync/snapshot.rb', line 80 def size_diff_from(snapshot) info = Btrfs.run('subvolume', 'show', snapshot.subvolume_dir.to_s) info =~ /Generation[^:]*:\s+(\d+)/ size_diff_from_gen(Integer($1)) end |
#size_diff_from_gen(gen) ⇒ Object
91 92 93 94 95 96 97 98 99 |
# File 'lib/snapsync/snapshot.rb', line 91 def size_diff_from_gen(gen) new = Btrfs.run('subvolume', 'find-new', subvolume_dir.to_s, gen.to_s) new.split("\n").inject(0) do |size, line| if line.strip =~ /len (\d+)/ size + Integer($1) else size end end end |
#subvolume_dir ⇒ Pathname
The path to the snapshot’s subvolume
12 |
# File 'lib/snapsync/snapshot.rb', line 12 def subvolume_dir; snapshot_dir + "snapshot" end |
#synchronization_point? ⇒ Boolean
Whether this snapshot is one of snapsync’s synchronization points
52 53 54 |
# File 'lib/snapsync/snapshot.rb', line 52 def synchronization_point? user_data['snapsync'] end |
#synchronization_point_for?(target) ⇒ Boolean
Whether this snapshot is one of snapsync’s synchronization points for the given target
58 59 60 |
# File 'lib/snapsync/snapshot.rb', line 58 def synchronization_point_for?(target) user_data['snapsync'] == target.uuid end |
#to_time ⇒ Object
This snapshot’s reference time
47 48 49 |
# File 'lib/snapsync/snapshot.rb', line 47 def to_time date.to_time end |