lsync 1.2.1 → 1.2.5

Sign up to get free protection for your applications and to get access to all the features.
data/bin/lsync CHANGED
@@ -7,7 +7,6 @@ require 'optparse'
7
7
 
8
8
  OPTIONS = {
9
9
  :ConfigFiles => [],
10
- :Plan => nil,
11
10
  :LogPath => "/var/log/lsync/backup.log"
12
11
  }
13
12
 
@@ -16,16 +15,17 @@ ARGV.options do |o|
16
15
 
17
16
  o.set_summary_indent(' ')
18
17
  o.banner = "Usage: #{script_name} [options] [directory | config]"
19
- o.define_head "This script is used to run backups. If you specify a directory, files ending in .conf will all be processed."
18
+ o.define_head "This script is used to run lsync scripts and plans. If you specify a directory, files ending in .lsync-script and .lsync-plan will all be processed."
20
19
 
21
20
  o.separator ""
22
21
  o.separator "Help and Copyright information"
23
-
24
- o.on("-p plan", String, "Run the specified backup plan") { |plan| OPTIONS[:Plan] = plan }
25
- o.on("-l log_path", String, "Set the directory for backup logs") { |log_path| OPTIONS[:LogPath] = log_path }
22
+
23
+ o.on("-l log_path", String, "Set the directory for backup logs") do |log_path|
24
+ OPTIONS[:LogPath] = log_path
25
+ end
26
26
 
27
27
  o.on_tail("--copy", "Display copyright information") do
28
- puts "#{script_name} v#{LSync::VERSION::STRING}. Copyright (c) 2008-2009 Samuel Williams. Released under the GPLv3."
28
+ puts "#{script_name} v#{LSync::VERSION::STRING}. Copyright (c) 2008-2010 Samuel Williams. Released under the GPLv3."
29
29
  puts "See http://www.oriontransfer.co.nz/ for more information."
30
30
 
31
31
  exit
@@ -90,32 +90,23 @@ def process_config_files
90
90
  end
91
91
 
92
92
  if File.directory? p
93
- OPTIONS[:ConfigFiles] += Dir[File.join(p, "*.conf")]
93
+ OPTIONS[:ConfigFiles] += Dir[File.join(p, "*.{lsync-script,lsync-plan}")]
94
94
  else
95
95
  OPTIONS[:ConfigFiles] << p
96
96
  end
97
97
  end
98
98
  end
99
99
 
100
- def validate_options
101
- if OPTIONS[:Plan] && OPTIONS[:ConfigFiles].size > 0
102
- $logger.error "Please specify either a backup plan or a set of backup scripts, but not both in one run."
103
- exit(27)
104
- end
105
- end
106
-
107
- def run_backups
108
- OPTIONS[:ConfigFiles].each do |c|
109
- config = LSync::BackupScript.load_from_file(c)
110
- config.logger = $logger
111
- config.run_backup
112
- end
113
-
114
- if OPTIONS[:Plan]
115
- config = LSync::BackupPlan.load_from_file(OPTIONS[:Plan])
116
- config.logger = $logger
117
- config.run_backup
118
- end
100
+ def run_backups(config_files)
101
+ if config_files.size == 0
102
+ $logger.warn "No configuration files specified!"
103
+ else
104
+ config_files.each do |c|
105
+ config = LSync::load_from_file(c)
106
+ config.logger = $logger
107
+ config.run_backup
108
+ end
109
+ end
119
110
  end
120
111
 
121
112
  def dump_exception_backtrace ex
@@ -124,17 +115,16 @@ def dump_exception_backtrace ex
124
115
  end
125
116
  end
126
117
 
118
+ # Main Script Execution
127
119
  setup_logging
128
120
 
129
121
  process_config_files
130
122
 
131
- validate_options
132
-
133
123
  $logger.info " Backup beginning at #{Time.now.to_s} ".center(96, "=")
134
124
 
135
125
  begin
136
- run_backups
137
- rescue LSync::BackupError
126
+ run_backups(OPTIONS[:ConfigFiles])
127
+ rescue LSync::Error
138
128
  $logger.error "#{$!.class.name}: #{$!.to_s}. Dumping backtrace:"
139
129
  dump_exception_backtrace($!)
140
130
  exit(230)
data/lib/lsync.rb CHANGED
@@ -26,8 +26,10 @@ require 'logger'
26
26
 
27
27
  require 'lsync/version'
28
28
  require 'lsync/extensions'
29
- require 'lsync/backup_script'
30
- require 'lsync/backup_plan'
29
+
30
+ require 'lsync/script'
31
+ require 'lsync/plan'
32
+
31
33
  require 'lsync/tee_logger'
32
34
 
33
35
  require 'fileutils'
@@ -36,5 +38,19 @@ require 'optparse'
36
38
  require 'open-uri'
37
39
 
38
40
  module LSync
39
-
40
- end
41
+ class InvalidConfigurationPath < StandardError
42
+ end
43
+
44
+ def self.load_from_file(path)
45
+ path = Pathname.new(path)
46
+
47
+ case path.extname
48
+ when ".lsync-script"
49
+ return Script.load_from_file(path)
50
+ when ".lsync-plan"
51
+ return Plan.load_from_file(path)
52
+ else
53
+ raise InvalidConfigurationPath.new(path)
54
+ end
55
+ end
56
+ end
data/lib/lsync/action.rb CHANGED
@@ -1,7 +1,7 @@
1
1
 
2
2
  require 'pathname'
3
3
  require 'lsync/run'
4
- require 'lsync/backup_error'
4
+ require 'lsync/error'
5
5
 
6
6
  module LSync
7
7
 
@@ -6,7 +6,6 @@
6
6
  # was.
7
7
 
8
8
  require 'pathname'
9
- require 'fileutils'
10
9
  require 'optparse'
11
10
 
12
11
  require 'set'
@@ -125,7 +124,7 @@ class Policy
125
124
  filtered_values += period.filter(values, options)
126
125
  end
127
126
 
128
- return filtered_values.to_a, (Set.new(values) - filtered_values).to_a
127
+ return filtered_values, (Set.new(values) - filtered_values)
129
128
  end
130
129
 
131
130
  attr :periods
@@ -133,10 +132,11 @@ end
133
132
 
134
133
  OPTIONS = {
135
134
  :Format => "%Y.%m.%d-%H.%M.%S",
136
- :Destination => "./*",
135
+ :Destination => "./",
137
136
  :Policy => Policy.new,
138
137
  :PolicyOptions => {},
139
- :Wet => true
138
+ :Wet => true,
139
+ :Latest => "latest"
140
140
  }
141
141
 
142
142
  ARGV.options do |o|
@@ -160,6 +160,8 @@ ARGV.options do |o|
160
160
  o.on("--dry-run", "Print out what would be deleted, but don't actually delete anything.") do
161
161
  OPTIONS[:Wet] = false
162
162
  end
163
+
164
+ o.on("-l latest", String, "Specify the symlink name that points to the latest backup, so it won't be deleted.")
163
165
 
164
166
  o.separator ""
165
167
 
@@ -198,11 +200,11 @@ ARGV.options do |o|
198
200
  OPTIONS[:Policy] << Monthly.new(count)
199
201
  end
200
202
 
201
- o.on("--quaterly count", Integer, "Set the number of monthly backups to keep.") do |count|
203
+ o.on("--quaterly count", Integer, "Set the number of quaterly backups to keep.") do |count|
202
204
  OPTIONS[:Policy] << Quarterly.new(count)
203
205
  end
204
206
 
205
- o.on("--yearly count", Integer, "Set the number of monthly backups to keep.") do |count|
207
+ o.on("--yearly count", Integer, "Set the number of yearly backups to keep.") do |count|
206
208
  OPTIONS[:Policy] << Yearly.new(count)
207
209
  end
208
210
 
@@ -223,29 +225,41 @@ end.parse!
223
225
 
224
226
  backups = []
225
227
 
226
- Dir[OPTIONS[:Destination]].each do |path|
227
- next if path.match("latest")
228
- date_string = File.basename(path)
228
+ Dir.chdir(OPTIONS[:Destination]) do
229
+ Dir["*"].each do |path|
230
+ next if path.match(OPTIONS[:Latest])
231
+ date_string = File.basename(path)
229
232
 
230
- begin
231
- backups << Rotation.new(path, DateTime.strptime(date_string, OPTIONS[:Format]))
232
- rescue ArgumentError
233
- puts "Skipping #{path}, error parsing #{date_string}: #{$!}"
233
+ begin
234
+ backups << Rotation.new(path, DateTime.strptime(date_string, OPTIONS[:Format]))
235
+ rescue ArgumentError
236
+ puts "Skipping #{path}, error parsing #{date_string}: #{$!}"
237
+ end
234
238
  end
235
- end
236
239
 
237
- keep, erase = OPTIONS[:Policy].filter(backups)
240
+ keep, erase = OPTIONS[:Policy].filter(backups)
238
241
 
239
- if OPTIONS[:Wet]
240
- erase.sort.each do |backup|
241
- puts "Erasing #{backup.path}..."
242
- $stdout.flush
243
- FileUtils.rm_rf(backup.path)
242
+ # We need to retain the latest backup regardless of policy
243
+ if OPTIONS[:Latest]
244
+ latest_backup = Pathname.new(OPTIONS[:Latest]).realpath.basename.to_s
245
+ puts "Retaining latest backup #{latest_backup}"
246
+ erase.delete(latest_backup)
244
247
  end
245
- else
246
- puts "*** Dry Run ***"
247
- puts "\tKeeping:"
248
- keep.sort.each { |backup| puts "\t\t#{backup.path}" }
249
- puts "\tErasing:"
250
- erase.sort.each { |backup| puts "\t\t#{backup.path}" }
251
- end
248
+
249
+ if OPTIONS[:Wet]
250
+ erase.sort.each do |backup|
251
+ puts "Erasing #{backup.path}..."
252
+ $stdout.flush
253
+
254
+ # Ensure that we can remove the backup
255
+ system("chmod", "-R", "ug+rwX", backup.path)
256
+ system("rm", "-rf", backup.path)
257
+ end
258
+ else
259
+ puts "*** Dry Run ***"
260
+ puts "\tKeeping:"
261
+ keep.sort.each { |backup| puts "\t\t#{backup.path}" }
262
+ puts "\tErasing:"
263
+ erase.sort.each { |backup| puts "\t\t#{backup.path}" }
264
+ end
265
+ end
@@ -13,6 +13,22 @@ class Pathname
13
13
  return self.class.new(to_s + "/")
14
14
  end
15
15
  end
16
+
17
+ # Returns the number of path components
18
+ # We need to work with a cleanpath to get an accurate depth
19
+ # "", "/" => 0
20
+ # "bob" => 1
21
+ # "bob/dole" => 2
22
+ # "/bob/dole" => 2
23
+ #
24
+ def depth
25
+ bits = cleanpath.to_s.split(SEPARATOR_PAT)
26
+
27
+ bits.delete("")
28
+ bits.delete(".")
29
+
30
+ return bits.size
31
+ end
16
32
  end
17
33
 
18
34
  module LSync
@@ -29,11 +45,6 @@ module LSync
29
45
  def to_s
30
46
  @path.to_s
31
47
  end
32
-
33
- # Special exception for root path
34
- def depth
35
- return @path.to_s.scan("/").size - 1
36
- end
37
48
  end
38
49
 
39
50
  end
@@ -1,7 +1,7 @@
1
1
 
2
2
  module LSync
3
3
 
4
- class BackupError < StandardError
4
+ class Error < StandardError
5
5
  def initialize(reason, components = {})
6
6
  @reason = reason
7
7
  @components = components
@@ -15,16 +15,16 @@ module LSync
15
15
  attr :components
16
16
  end
17
17
 
18
- class BackupScriptError < BackupError
18
+ class ScriptError < Error
19
19
  end
20
20
 
21
- class BackupMethodError < BackupError
21
+ class BackupMethodError < Error
22
22
  end
23
23
 
24
- class ConfigurationError < BackupError
24
+ class ConfigurationError < Error
25
25
  end
26
26
 
27
- class BackupActionError < BackupError
27
+ class BackupActionError < Error
28
28
  def initialize(server, action, exception)
29
29
  super("Backup action failed: #{action} (#{exception.to_s})", :action => action, :exception => exception)
30
30
  end
data/lib/lsync/method.rb CHANGED
@@ -91,6 +91,7 @@ module LSync
91
91
 
92
92
  @logger = logger
93
93
 
94
+ @logger.info "In directory #{Dir.getwd}"
94
95
  Dir.chdir(local_server.root_path) do
95
96
  if run_handler(src, dst, options) == false
96
97
  raise BackupMethodError.new("Backup from #{src.dump} to #{dst.dump} failed.", :method => self)
@@ -127,7 +128,7 @@ module LSync
127
128
  class RSyncSnapshot < RSync
128
129
  def run(master_server, target_server, directory, options, logger)
129
130
  options ||= ""
130
- link_dest = Pathname.new("../" * (directory.depth + 1)) + "latest" + directory.path
131
+ link_dest = Pathname.new("../" * (directory.path.depth + 1)) + "latest" + directory.path
131
132
  options += " --archive --link-dest #{link_dest.to_s.dump}"
132
133
 
133
134
  inprogress_path = ".inprogress"
@@ -68,7 +68,7 @@ module LSync
68
68
  end
69
69
  end
70
70
 
71
- class BackupPlanRulebook < Ruleby::Rulebook
71
+ class PlanRulebook < Ruleby::Rulebook
72
72
  include Facts
73
73
 
74
74
  def rules
@@ -203,7 +203,7 @@ module LSync
203
203
  attr :rules
204
204
  end
205
205
 
206
- class BackupPlan
206
+ class Plan
207
207
  def initialize(config, logger = nil)
208
208
  @logger = logger || Logger.new(STDOUT)
209
209
 
@@ -220,7 +220,7 @@ module LSync
220
220
 
221
221
  puts " Loading Rules ".center(80, "=")
222
222
 
223
- BackupPlanRulebook.new(e).rules
223
+ PlanRulebook.new(e).rules
224
224
 
225
225
  @stages.each do |k,s|
226
226
  StageRulebook.new(e, s).rules
@@ -8,7 +8,7 @@ require 'lsync/directory'
8
8
 
9
9
  module LSync
10
10
 
11
- class BackupScript
11
+ class Script
12
12
  private
13
13
  # Given a name, find out which server config matches it
14
14
  def find_named_server name
@@ -76,7 +76,7 @@ module LSync
76
76
 
77
77
  # At this point we must know the current server or we can't continue
78
78
  if current == nil
79
- raise BackupScriptError.new("Could not determine current server!", :script => self, :master => @master)
79
+ raise ScriptError.new("Could not determine current server!", :script => self, :master => @master)
80
80
  end
81
81
 
82
82
  if @master.is_local?
data/lib/lsync/version.rb CHANGED
@@ -17,7 +17,7 @@ module LSync
17
17
  module VERSION #:nodoc:
18
18
  MAJOR = 1
19
19
  MINOR = 2
20
- TINY = 1
20
+ TINY = 5
21
21
 
22
22
  STRING = [MAJOR, MINOR, TINY].join('.')
23
23
  end
metadata CHANGED
@@ -1,12 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lsync
3
3
  version: !ruby/object:Gem::Version
4
+ hash: 21
4
5
  prerelease: false
5
6
  segments:
6
7
  - 1
7
8
  - 2
8
- - 1
9
- version: 1.2.1
9
+ - 5
10
+ version: 1.2.5
10
11
  platform: ruby
11
12
  authors:
12
13
  - Samuel Williams
@@ -14,16 +15,18 @@ autorequire:
14
15
  bindir: bin
15
16
  cert_chain: []
16
17
 
17
- date: 2010-03-18 00:00:00 +13:00
18
+ date: 2010-09-09 00:00:00 +12:00
18
19
  default_executable: lsync
19
20
  dependencies:
20
21
  - !ruby/object:Gem::Dependency
21
22
  name: termios
22
23
  prerelease: false
23
24
  requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
24
26
  requirements:
25
27
  - - ">="
26
28
  - !ruby/object:Gem::Version
29
+ hash: 3
27
30
  segments:
28
31
  - 0
29
32
  version: "0"
@@ -33,9 +36,11 @@ dependencies:
33
36
  name: net-ssh
34
37
  prerelease: false
35
38
  requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
36
40
  requirements:
37
41
  - - ">="
38
42
  - !ruby/object:Gem::Version
43
+ hash: 3
39
44
  segments:
40
45
  - 0
41
46
  version: "0"
@@ -45,9 +50,11 @@ dependencies:
45
50
  name: ruleby
46
51
  prerelease: false
47
52
  requirement: &id003 !ruby/object:Gem::Requirement
53
+ none: false
48
54
  requirements:
49
55
  - - ">="
50
56
  - !ruby/object:Gem::Version
57
+ hash: 3
51
58
  segments:
52
59
  - 0
53
60
  version: "0"
@@ -57,9 +64,11 @@ dependencies:
57
64
  name: rexec
58
65
  prerelease: false
59
66
  requirement: &id004 !ruby/object:Gem::Requirement
67
+ none: false
60
68
  requirements:
61
69
  - - ">="
62
70
  - !ruby/object:Gem::Version
71
+ hash: 3
63
72
  segments:
64
73
  - 0
65
74
  version: "0"
@@ -82,15 +91,15 @@ files:
82
91
  - lib/lsync/actions/generic/rotate
83
92
  - lib/lsync/actions/linux/disk
84
93
  - lib/lsync/actions/linux/terminal
85
- - lib/lsync/backup_error.rb
86
- - lib/lsync/backup_plan.rb
87
- - lib/lsync/backup_script.rb
88
94
  - lib/lsync/directory.rb
95
+ - lib/lsync/error.rb
89
96
  - lib/lsync/extensions.rb
90
97
  - lib/lsync/lb.py
91
98
  - lib/lsync/method.rb
92
99
  - lib/lsync/password.rb
100
+ - lib/lsync/plan.rb
93
101
  - lib/lsync/run.rb
102
+ - lib/lsync/script.rb
94
103
  - lib/lsync/server.rb
95
104
  - lib/lsync/shell.rb
96
105
  - lib/lsync/shell_client.rb
@@ -98,7 +107,7 @@ files:
98
107
  - lib/lsync/version.rb
99
108
  - lib/lsync.rb
100
109
  has_rdoc: true
101
- homepage: http://wiki.oriontransfer.org/?lsync
110
+ homepage: http://www.oriontransfer.co.nz/software/lsync
102
111
  licenses: []
103
112
 
104
113
  post_install_message:
@@ -107,25 +116,29 @@ rdoc_options: []
107
116
  require_paths:
108
117
  - lib
109
118
  required_ruby_version: !ruby/object:Gem::Requirement
119
+ none: false
110
120
  requirements:
111
121
  - - ">="
112
122
  - !ruby/object:Gem::Version
123
+ hash: 3
113
124
  segments:
114
125
  - 0
115
126
  version: "0"
116
127
  required_rubygems_version: !ruby/object:Gem::Requirement
128
+ none: false
117
129
  requirements:
118
130
  - - ">="
119
131
  - !ruby/object:Gem::Version
132
+ hash: 3
120
133
  segments:
121
134
  - 0
122
135
  version: "0"
123
136
  requirements: []
124
137
 
125
138
  rubyforge_project:
126
- rubygems_version: 1.3.6
139
+ rubygems_version: 1.3.7
127
140
  signing_key:
128
- specification_version: 2
141
+ specification_version: 3
129
142
  summary: LSync is a tool for scripted synchronization and backups.
130
143
  test_files: []
131
144