dated_backup 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,41 @@
1
+
2
+ module DatedBackup
3
+ class DSL
4
+ module Main
5
+
6
+ attr_reader :hash, :procs
7
+
8
+ def initialize
9
+ @hash = {}
10
+ @procs = {}
11
+ end
12
+
13
+ def before &blk
14
+ raise_without_block &blk
15
+ @procs[:before] = blk
16
+ end
17
+
18
+ def after &blk
19
+ raise_without_block &blk
20
+ @procs[:after] = blk
21
+ end
22
+
23
+ def method_missing sym, *args
24
+ if RSYNC_OPTIONS.include?(sym)
25
+ @hash[sym] = args
26
+ else
27
+ raise InvalidKeyError, "The key '#{sym}' is not a recognized expression"
28
+ end
29
+ end
30
+
31
+ protected
32
+
33
+ def raise_without_block &blk
34
+ raise NoBlockGiven, "A block (do...end) must be given" if !block_given?
35
+ end
36
+
37
+ RSYNC_OPTIONS = [:source, :sources, :destination, :options, :user_domain]
38
+
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,122 @@
1
+
2
+ module DatedBackup
3
+ class DSL
4
+
5
+ # After a run through the DSL,
6
+ # the TimeExtensions#kept method should contain an array
7
+ # of all of the items to keep. Each item will be a hash
8
+ # with two keys: a :constraint key, which contains a
9
+ # range of Times (from oldest to newest), and a :scope
10
+ # key, which will indicate whether the backup to look
11
+ # at is a weekly, monthly, etc. If no :scope key is given,
12
+ # then all of the backups in the time range given by
13
+ # the :constraint key will be assumed to be kept.
14
+ module TimeExtensions
15
+
16
+ attr_reader :last_time, :time_range
17
+ attr_reader :kept
18
+
19
+ def initialize
20
+ @kept = []
21
+ @time_range = {}
22
+ @last_time = nil
23
+ end
24
+
25
+ def backup *args; return self; end
26
+ def from *args; return self; end
27
+
28
+ alias :backups :backup
29
+
30
+ TimeSymbol.valid_symbols.each do |sym|
31
+ time_sym = TimeSymbol.new sym
32
+
33
+ define_method time_sym.singular do |*args|
34
+ self.send :time_component, time_sym.singular
35
+ end
36
+
37
+ alias_method time_sym.plural, time_sym.singular
38
+
39
+ define_method time_sym.adverb do
40
+ @time_range[:scope] = time_sym.adverb
41
+ end
42
+ end
43
+
44
+
45
+ def this arg, now=Time.now
46
+ set_time_range :this, now
47
+ end
48
+
49
+ def last arg, now=Time.now
50
+ set_time_range :last, now
51
+ end
52
+
53
+ def keep arg, now=Time.now
54
+ all(self, now) unless time_range[:constraint]
55
+
56
+ @kept << time_range
57
+ reset_times
58
+ self
59
+ end
60
+
61
+ def all arg=self, now=Time.now
62
+ @time_range[:constraint] = Time.epoch...now
63
+ self
64
+ end
65
+
66
+ protected
67
+
68
+
69
+ def set_time_range sym, now
70
+ if sym == :last
71
+ year, month, week, day = now.last_year, now.last_month, now.last_week, now.yesterday
72
+ elsif sym == :this
73
+ add_end_of_star_singletons(now)
74
+
75
+ # This is another little trick. Normally we would just call the methods
76
+ # below something like: Time.now.beginning_of_year...Time.now.end_of_year
77
+ year, month, week, day = now, now, now, now
78
+ end
79
+
80
+ @time_range[:constraint] =
81
+ case last_time
82
+ when :year
83
+ year.beginning_of_year...year.end_of_year
84
+ when :month
85
+ month.beginning_of_month...month.end_of_month
86
+ when :week
87
+ week.beginning_of_week...week.end_of_week
88
+ when :day
89
+ day.beginning_of_day...day.end_of_day
90
+ end
91
+
92
+ self
93
+ end
94
+
95
+ # This method adds the end_of_* methods to the object passed in. They are used in the default case
96
+ # of the modifyer being "this" and not "last". In the 'this' case, the time
97
+ # *is* now, so end_of_* (end_of_year, end_of_day), etc. should *NOT* need to be called
98
+ # (and in fact, we do not want them to be called, because that would represent
99
+ # some time period in the future). Those methods are overrided to return self
100
+ def add_end_of_star_singletons(now)
101
+ class << now
102
+ [:end_of_year, :end_of_month, :end_of_week, :end_of_day].each do |end_of|
103
+ define_method end_of do
104
+ return self
105
+ end
106
+ end
107
+ end
108
+ end
109
+
110
+ def time_component(type)
111
+ @last_time = type
112
+ self
113
+ end
114
+
115
+ def reset_times
116
+ @time_range = {}
117
+ @last_time = nil
118
+ end
119
+ end
120
+
121
+ end
122
+ end
@@ -0,0 +1,4 @@
1
+
2
+ require File.dirname(__FILE__) + "/dsl/execution_context"
3
+ require File.dirname(__FILE__) + "/dsl/main"
4
+ require File.dirname(__FILE__) + "/dsl/time_extensions"
@@ -0,0 +1,27 @@
1
+
2
+ class Array
3
+ def car
4
+ first
5
+ end
6
+
7
+ def cdr
8
+ self.[](1..self.length)
9
+ end
10
+
11
+ def to_backup_set
12
+ DatedBackup::Core::BackupSet.new(self)
13
+ end
14
+ end
15
+
16
+ # A subclass of Array, but it calls uniq!, sort!, and reverse!
17
+ # (in that order) after the instance is created
18
+ class ReverseSortedUniqueArray < Array
19
+
20
+ def initialize *args, &blk
21
+ super *args, &blk
22
+ uniq!
23
+ sort!
24
+ reverse!
25
+ end
26
+
27
+ end
@@ -0,0 +1,10 @@
1
+
2
+ class TimeSymbolError < RuntimeError; end
3
+
4
+ class DatedBackupError < RuntimeError; end
5
+
6
+ class DirectoryError < DatedBackupError; end
7
+ class InvalidDirectoryError < DirectoryError; end
8
+ class NoBlockGiven < DatedBackupError; end
9
+ class InvalidKeyError < DatedBackupError; end
10
+
@@ -0,0 +1,8 @@
1
+
2
+ class String
3
+ def to_time
4
+ string = self.dup
5
+ string.sub!(/^(.*?)([\d\-\h\m\s]+)(.*?)$/) { $2 }
6
+ Time.gm(*(string.split('-').map { |element| element.sub /h|m|s/, ''}))
7
+ end
8
+ end
@@ -0,0 +1,50 @@
1
+ require 'active_support/core_ext/time/calculations'
2
+ require 'active_support/core_ext/numeric/time'
3
+
4
+ class Time
5
+ class << self
6
+ include ActiveSupport::CoreExtensions::Time::Calculations::ClassMethods
7
+
8
+ def epoch
9
+ Time.at(0)
10
+ end
11
+
12
+ end
13
+
14
+ include ActiveSupport::CoreExtensions::Time::Calculations
15
+
16
+ def end_of_day
17
+ tomorrow.beginning_of_day - 1
18
+ end
19
+
20
+ def end_of_month
21
+ next_month.beginning_of_month - 1
22
+ end
23
+
24
+ def end_of_year
25
+ next_year.beginning_of_year - 1
26
+ end
27
+
28
+ def end_of_week
29
+ next_week.beginning_of_week - 1
30
+ end
31
+
32
+ def last_week
33
+ 1.week.ago.beginning_of_week
34
+ end
35
+
36
+ alias :at_end_of_week :end_of_week
37
+ alias :at_end_of_month :end_of_month
38
+ alias :at_end_of_day :end_of_day
39
+ alias :at_end_of_year :end_of_year
40
+
41
+ def week
42
+ beginning_of_week...end_of_week
43
+ end
44
+
45
+ end
46
+
47
+ class Fixnum
48
+ include ActiveSupport::CoreExtensions::Numeric::Time
49
+ end
50
+
@@ -0,0 +1,54 @@
1
+
2
+ # Used to change the the TimeSymbols (:year, :month, :day, and :week) into the
3
+ # various natural language forms (the symbols singular, plural, and adverb).
4
+ # Initialize with the singular symbol name, or call TimeSymbol.valid_symbols
5
+ # to give an array of valid symbols.
6
+ class TimeSymbol
7
+ VALID_TIME_COMPONENTS = [:year, :month, :week, :day]
8
+
9
+ class << self
10
+ def all
11
+ VALID_TIME_COMPONENTS.dup
12
+ end
13
+
14
+ alias :valid_symbols :all
15
+ end
16
+
17
+ def initialize(sym)
18
+ if VALID_TIME_COMPONENTS.include? sym
19
+ @sym = sym
20
+ else
21
+ raise TimeSymbolError, "The symbol given must be a valid TimeSymbol (:year, :month, :week, or :day)"
22
+ end
23
+ end
24
+
25
+ def singular
26
+ @sym
27
+ end
28
+
29
+ def plural
30
+ "#{@sym}s".to_sym
31
+ end
32
+
33
+ def adverb
34
+ if @sym == :day
35
+ :daily
36
+ else
37
+ "#{@sym}ly".to_sym
38
+ end
39
+ end
40
+
41
+ def to_sym
42
+ @sym.to_sym
43
+ end
44
+
45
+ def to_s
46
+ @sym.to_s
47
+ end
48
+
49
+ def inspect
50
+ @sym.inspect
51
+ end
52
+ end
53
+
54
+ TimeSymbols = TimeSymbol.all
@@ -0,0 +1,6 @@
1
+
2
+ require File.dirname(__FILE__) + "/extensions/array"
3
+ require File.dirname(__FILE__) + "/extensions/time"
4
+ require File.dirname(__FILE__) + "/extensions/error"
5
+ require File.dirname(__FILE__) + "/extensions/time_symbol"
6
+ require File.dirname(__FILE__) + "/extensions/string"
data/lib/dated_backup.rb CHANGED
@@ -1,2 +1,22 @@
1
+ # DatedBackup, A snapshot backup utility
2
+ # Copyright (C) Scott Taylor (scott@railsnewbie.com), 2007
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+ #
1
17
 
2
- require File.dirname(__FILE__) + "/dated_backup/dated_backup"
18
+
19
+ require 'rubygems'
20
+ require File.dirname(__FILE__) + "/dated_backup/extensions"
21
+ require File.dirname(__FILE__) + "/dated_backup/dsl"
22
+ require File.dirname(__FILE__) + "/dated_backup/core"
metadata CHANGED
@@ -3,9 +3,9 @@ rubygems_version: 0.9.4
3
3
  specification_version: 1
4
4
  name: dated_backup
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.1.0
7
- date: 2007-07-09 00:00:00 -04:00
8
- summary: Incremental Backups Using Rsync
6
+ version: 0.2.0
7
+ date: 2007-08-02 00:00:00 -04:00
8
+ summary: Incremental Dated Backups Using Rsync
9
9
  require_paths:
10
10
  - lib
11
11
  email: scott@railsnewbie.com
@@ -15,7 +15,7 @@ description:
15
15
  autorequire:
16
16
  default_executable:
17
17
  bindir: bin
18
- has_rdoc: false
18
+ has_rdoc: true
19
19
  required_ruby_version: !ruby/object:Gem::Version::Requirement
20
20
  requirements:
21
21
  - - ">"
@@ -29,24 +29,61 @@ post_install_message:
29
29
  authors:
30
30
  - Scott Taylor
31
31
  files:
32
+ - bin/dbackup
32
33
  - lib/dated_backup
33
- - lib/dated_backup/command_line.rb
34
- - lib/dated_backup/dated_backup.rb
34
+ - lib/dated_backup/core
35
+ - lib/dated_backup/core/backup_remover.rb
36
+ - lib/dated_backup/core/backup_set.rb
37
+ - lib/dated_backup/core/command_line.rb
38
+ - lib/dated_backup/core/dated_backup.rb
39
+ - lib/dated_backup/core/tasks.rb
40
+ - lib/dated_backup/core/warnings.rb
41
+ - lib/dated_backup/core.rb
42
+ - lib/dated_backup/dsl
43
+ - lib/dated_backup/dsl/execution_context.rb
44
+ - lib/dated_backup/dsl/main.rb
45
+ - lib/dated_backup/dsl/time_extensions.rb
46
+ - lib/dated_backup/dsl.rb
47
+ - lib/dated_backup/extensions
48
+ - lib/dated_backup/extensions/array.rb
49
+ - lib/dated_backup/extensions/error.rb
50
+ - lib/dated_backup/extensions/string.rb
51
+ - lib/dated_backup/extensions/time.rb
52
+ - lib/dated_backup/extensions/time_symbol.rb
53
+ - lib/dated_backup/extensions.rb
35
54
  - lib/dated_backup.rb
36
- - example_scripts/example.com.rb
37
- - example_scripts/local_etc_backup.rb
38
- - example_scripts/samba_shares.rb
55
+ - example_configs/example.com
56
+ - example_configs/local_etc_backup
57
+ - example_configs/samba_shares
58
+ - README
59
+ - COPYRIGHT
60
+ - RELEASES
61
+ - CHANGELOG
39
62
  test_files: []
40
63
 
41
64
  rdoc_options: []
42
65
 
43
- extra_rdoc_files: []
44
-
45
- executables: []
46
-
66
+ extra_rdoc_files:
67
+ - example_configs/example.com
68
+ - example_configs/local_etc_backup
69
+ - example_configs/samba_shares
70
+ - README
71
+ - COPYRIGHT
72
+ - RELEASES
73
+ - CHANGELOG
74
+ executables:
75
+ - dbackup
47
76
  extensions: []
48
77
 
49
78
  requirements: []
50
79
 
51
- dependencies: []
52
-
80
+ dependencies:
81
+ - !ruby/object:Gem::Dependency
82
+ name: activesupport
83
+ version_requirement:
84
+ version_requirements: !ruby/object:Gem::Version::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: 1.4.2
89
+ version:
@@ -1,10 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- # A script to back up etc, locally, in /root/etc_backup
4
-
5
- require "dated_backup"
6
-
7
- DatedBackup.new(
8
- :source => "/etc",
9
- :destination => "/root/etc_backup"
10
- ).run
@@ -1,8 +0,0 @@
1
- class DatedBackup
2
- module CommandLine
3
- def execute(cmd)
4
- puts "* running: #{cmd}"
5
- puts %x(#{cmd})
6
- end
7
- end
8
- end
@@ -1,80 +0,0 @@
1
- require File.dirname(__FILE__) + "/command_line"
2
-
3
- class DatedBackup
4
-
5
- include DatedBackup::CommandLine
6
-
7
- attr_accessor :source, :destination, :opts, :backup_root, :user_domain
8
-
9
- def initialize(h={})
10
- @backup_root = h[:destination]
11
- @opts = h[:options] || ""
12
- @user_domain = h[:user_domain]
13
- @destination = generate_backup_filename
14
-
15
- @sources = h[:sources] || [h[:source]]
16
-
17
- if @user_domain
18
- @sources.map! { |src| "#{@user_domain}:#{src}" }
19
- end
20
-
21
- end
22
-
23
- # create the first backup, if non-existent
24
- # otherwise cp -al (or # replace cp -al a b with cd a && find . -print | cpio -dpl ../b )
25
- # and then create the backup of the dirs using rsync -a --delete
26
- # the files, in the end, should be read only and undeletable
27
- def run
28
- create_main_backup_directory
29
- cp_last_backup_to_new_backup unless Dir.glob("#{@backup_root}/*").empty?
30
- create_backup
31
- #set_permissions(dest)
32
- end
33
-
34
- def create_backup
35
- @sources.each do |source|
36
- cmd = "rsync -a --delete #{opts} #{source} #{@destination}"
37
- execute(cmd)
38
- puts "\n\n"
39
- end
40
- end
41
-
42
- def cp_last_backup_to_new_backup
43
- last_backup_dir = find_last_backup_filename
44
-
45
- cmd = "cp -al #{last_backup_dir} #{@destination}"
46
- execute(cmd)
47
- end
48
-
49
- def create_main_backup_directory
50
- begin
51
- unless File.exists? backup_root
52
- puts "* Creating main backup directory #{backup_root}"
53
- Dir.mkdir backup_root
54
- end
55
- rescue Errno::EACCES => e
56
- puts "-- Exiting script because main directory could not be created. \n Error Message: #{e}"
57
- exit
58
- end
59
- end
60
-
61
- #def set_permissions(file, permission="400", user="root", group="root")
62
- # cmd = "chmod -R #{permission} #{file}"
63
- # execute(cmd)
64
- # cmd = "chown -R #{user}:#{group} #{file}"
65
- # execute(cmd)
66
- #end
67
-
68
- private
69
-
70
- def generate_backup_filename
71
- timestamp = Time.now.strftime "%Y-%m-%d-%Hh-%Mm-%Ss"
72
- "#{@backup_root}/#{timestamp}"
73
- end
74
-
75
- def find_last_backup_filename
76
- Dir.glob("#{@backup_root}/*").sort.last
77
- end
78
- end
79
-
80
-