Class: ThinOutBackups::Command

Inherits:
Object
  • Object
show all
Defined in:
lib/thin_out_backups.rb

Defined Under Namespace

Classes: Bucket, File

Constant Summary collapse

@@allowed_bucket_names =

[:minutely, :hourly, :daily, :weekly, :monthly, :yearly]
@@options =

Options

[:get_time_from, :ignore_files ,:verbosity, :time_format, :now, :force, :no_color]
@@get_time_from =
:filename
@@ignore_files =
nil
@@verbosity =
1
@@force =
false
@@color =
true
@@now =
Time.now
@@time_format =
/(\d{4})[^\d]?(\d{2})[^\d]?(\d{2})T(\d{2})[^\d]?(\d{2})[^\d]?(\d{2})?/
@@time_format_parts =
[:Y,:m,:d, :H,:M,:S]

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(dir, quotas) ⇒ Command

Returns a new instance of Command.



174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
# File 'lib/thin_out_backups.rb', line 174

def initialize(dir, quotas)
  @align_at_beginning_of_time_interval = true
  @dir = dir
  @buckets = {}
  @@allowed_bucket_names.each do |name|
    quota = quotas[name]
    @buckets[name] = Bucket.new(self, name, quota) unless quota.nil?
  end

  puts "Processing #{@dir}/*".magenta
  files = Dir["#{@dir}/*"].map { |filename|
    file = File.new(filename)
  }
  @files_with_times = files.
    reject {|file| !file.has_time?}.
    sort { |a, b|
           a.time <=> b.time
         }.
    reverse

end

Instance Attribute Details

#align_at_beginning_of_time_intervalObject (readonly)

Returns the value of attribute align_at_beginning_of_time_interval.



171
172
173
# File 'lib/thin_out_backups.rb', line 171

def align_at_beginning_of_time_interval
  @align_at_beginning_of_time_interval
end

#dirObject

Returns the value of attribute dir.



172
173
174
# File 'lib/thin_out_backups.rb', line 172

def dir
  @dir
end

#files_with_timesObject (readonly)

Returns the value of attribute files_with_times.



171
172
173
# File 'lib/thin_out_backups.rb', line 171

def files_with_times
  @files_with_times
end

Class Method Details

.get_time_from=(new) ⇒ Object



28
29
30
31
# File 'lib/thin_out_backups.rb', line 28

def self.get_time_from=(new)
  @@get_time_from = new.to_sym
  raise "Unknown value for #{ThinOutBackups::Command.get_time_from}" unless @@get_time_from.in?([:filename, :file_system])
end

.now=(new) ⇒ Object



39
40
41
42
43
# File 'lib/thin_out_backups.rb', line 39

def self.now=(new)
  time = DateTime.strptime('2008-11-12 07:45:00', '%Y-%m-%d %H:%M:%S').to_time
  @@now = new
  puts "Using alternate now: #{@@now}"
end

.time_format=(new) ⇒ Object

TODO: Maybe use something like this for interpreting time, rather than a regexp? DateTime.strptime(“27/Nov/2007:15:01:43 -0800”, “%d/%b/%Y:%H:%M:%S %z”)



48
49
50
51
# File 'lib/thin_out_backups.rb', line 48

def self.time_format=(new)
  # TODO: accept format strings such as 'H:M:S d.m.Y.' and 'Y-m-d H:M:S'
  # TODO: do error checking
end

Instance Method Details

#bucket(name) ⇒ Object



204
205
206
# File 'lib/thin_out_backups.rb', line 204

def bucket(name)
  @buckets[name] or raise "unknown bucket '#{name}'"
end

#bucket_remaining(bucket_name, decr = nil) ⇒ Object



196
197
198
199
# File 'lib/thin_out_backups.rb', line 196

def bucket_remaining(bucket_name, decr = nil)
  send("#{bucket_name}=", send("#{bucket_name}") - decr) if decr
  send "#{bucket_name}"
end

#bucketsObject



201
202
203
# File 'lib/thin_out_backups.rb', line 201

def buckets
  @buckets.values
end

#buckets_with_file(file) ⇒ Object



237
238
239
# File 'lib/thin_out_backups.rb', line 237

def buckets_with_file(file)
  buckets.find_all {|bucket| bucket.keepers.include?(file)}
end

#delete(files) ⇒ Object



241
242
243
# File 'lib/thin_out_backups.rb', line 241

def delete(files)
  puts "Deleting files: #{files.join(', ')}..."
end

#delete_non_keepersObject



212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
# File 'lib/thin_out_backups.rb', line 212

def delete_non_keepers
  #raise "Didn't find any files to keep?!" unless keepers.any?
  files_with_times.each do |file|
    if (buckets = buckets_with_file(file)).any?
      puts "#{file.full_path}: in buckets: #{buckets.map(&:name).join(', ')}".green
    else
      puts "#{file.full_path}: delete".red
    end
  end

  if @@force == false
    print "Continue with deletions? (yes or no) >".magenta
    response = STDIN.gets
    (puts "Aborting"; return) unless response.chomp.downcase == 'yes'
  end

  files_with_times.each do |file|
    if (buckets = buckets_with_file(file)).any?
      #
    else
      file.unlink
    end
  end
end

#earliest_file_timeObject



245
246
247
# File 'lib/thin_out_backups.rb', line 245

def earliest_file_time
  files_with_times.last.time
end

#nowObject



208
209
210
# File 'lib/thin_out_backups.rb', line 208

def now
  Time.now
end

#runObject



249
250
251
252
253
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
# File 'lib/thin_out_backups.rb', line 249

def run
  raise "Must keep at least 1 file from at least one time bucket" if buckets.empty?
  (puts "Found no files with times! Aborting."; return) if files_with_times.empty?

  # Fill each bucket until its quota is met
  buckets.each do |bucket|
    puts "Trying to fill bucket '#{bucket.name}' (quota: #{bucket.quota})...".magenta

    time_max = bucket.start_time
    time_min = time_max.shift(-1, bucket.unit)

    #puts "Earliest_file_time: #{earliest_file_time}"
    while time_max > earliest_file_time
      print "Checking range (#{time_min} .. #{time_max})... ".yellow if verbosity >= 1
      new_keeper = files_with_times.detect {|file|
        #print "#{file}? "
        time_min <= file.time &&
                    file.time < time_max
      }
      if new_keeper
        puts "found keeper #{new_keeper}".green if verbosity >= 1
        bucket.keep new_keeper
      else
        #puts "found no keepers".red if verbosity >= 1
        puts "" if verbosity >= 1
      end

      time_max = time_min
      #puts "Stepping back from #{time_min} by 1 #{bucket.unit} => #{time_min.shift(-1, bucket.unit)}"
      time_min = time_min.shift(-1, bucket.unit)
      (puts 'Filled quota!'.green; break) if bucket.satisfied?
    end
  end

  delete_non_keepers
end