lsync 1.2.1 → 1.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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