lsync 2.1.0 → 2.3.1

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.
@@ -0,0 +1,88 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Copyright (c) 2007, 2011 Samuel G. D. Williams. <http://www.oriontransfer.co.nz>
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
22
+
23
+ module Linux
24
+ Commands = {
25
+ "mount" => "mount",
26
+ "unmount" => "umount"
27
+ }
28
+
29
+ DevicePaths = [
30
+ "/dev/disk/by-label",
31
+ "/dev/disk/by-uuid",
32
+ "/dev"
33
+ ]
34
+
35
+ def self.run(action, disk_name)
36
+ action = ARGV[0]
37
+ disk_name = ARGV[1]
38
+
39
+ mountpoint = File.join('', 'mnt', disk_name)
40
+
41
+ if (action == 'mountpoint')
42
+ puts File.join(mountpoint, ARGV[2..-1])
43
+ else
44
+ puts "#{action.capitalize}ing #{mountpoint}..."
45
+ system Commands[action], mountpoint
46
+
47
+ if $?.exitstatus != 0 or $?.exitstatus != 3383
48
+ exit 5
49
+ end
50
+ end
51
+ end
52
+ end
53
+
54
+ module Darwin
55
+ DISKUTIL = "diskutil"
56
+
57
+ def self.get_disk_id(name)
58
+ begin
59
+ `diskutil list`.match(/#{name}\s*\*?[0-9]+\.[0-9]+ .B\s+(disk[0-9]s[0-9])$/)[1]
60
+ rescue
61
+ exit 5
62
+ end
63
+ end
64
+
65
+ def self.run
66
+ action = ARGV[0]
67
+ disk_name = ARGV[1]
68
+
69
+ if (action == 'mountpoint')
70
+ puts File.join('', 'Volumes', disk_name, ARGV[2..-1])
71
+ else
72
+ system DISKUTIL, action, get_disk_id(disk_name)
73
+ end
74
+ end
75
+ end
76
+
77
+ class UnsupportedPlatformError < StandardError
78
+ end
79
+
80
+ platform = `uname`.chomp.downcase
81
+ case platform
82
+ when "darwin"
83
+ Darwin.run
84
+ when "linux"
85
+ Linux.run
86
+ else
87
+ raise UnsupportedPlatformError.new("Platform #{platform} not supported.")
88
+ end
@@ -1,5 +1,25 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
+ # Copyright (c) 2007, 2011 Samuel G. D. Williams. <http://www.oriontransfer.co.nz>
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
22
+
3
23
  # This script takes a specified directory, and removes any directories that
4
24
  # don't match the supplied policy. Thanks to Scott Lu and his "snapfilter"
5
25
  # command which made me realise how complicated my first attempt at doing this
@@ -1,5 +1,25 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
+ # Copyright (c) 2007, 2011 Samuel G. D. Williams. <http://www.oriontransfer.co.nz>
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
22
+
3
23
  # This script takes a given path, and renames it with the given format.
4
24
  # It then ensures that there is a symlink called "latest" that points
5
25
  # to the renamed directory.
@@ -11,7 +31,7 @@ require 'optparse'
11
31
  OPTIONS = {
12
32
  :Format => "%Y.%m.%d-%H.%M.%S",
13
33
  :Latest => "latest",
14
- :UseGMT => true,
34
+ :UseUTC => false,
15
35
  :Destination => nil
16
36
  }
17
37
 
@@ -25,7 +45,7 @@ ARGV.options do |o|
25
45
  o.separator ""
26
46
  o.separator "Help and Copyright information"
27
47
 
28
- o.on("-f format", String, "Set the format of the rotated directory names. See Time$strftime") do |format|
48
+ o.on("-f format", String, "Set the format of the rotated directory names. See Time\#strftime") do |format|
29
49
  OPTIONS[:Format] = format
30
50
  end
31
51
 
@@ -36,9 +56,13 @@ ARGV.options do |o|
36
56
  o.on("-d destination", String, "Set the directory to move rotated backups.") do |destination|
37
57
  OPTIONS[:Destination] = destination
38
58
  end
59
+
60
+ o.on("-u", "Use UTC time for directory names.") do
61
+ OPTIONS[:UseUTC] = true
62
+ end
39
63
 
40
64
  o.on_tail("--copy", "Display copyright information") do
41
- puts "#{script_name}. Copyright (c) 2008-2009 Samuel Williams. Released under the GPLv3."
65
+ puts "#{script_name}. Copyright (c) 2007-2011 Samuel Williams. Released under the MIT license."
42
66
  puts "See http://www.oriontransfer.co.nz/ for more information."
43
67
 
44
68
  exit
@@ -1,17 +1,22 @@
1
- # Copyright (c) 2007 Samuel Williams. Released under the GNU GPLv2.
2
- #
3
- # This program is free software: you can redistribute it and/or modify
4
- # it under the terms of the GNU General Public License as published by
5
- # the Free Software Foundation, either version 3 of the License, or
6
- # (at your option) any later version.
1
+ # Copyright (c) 2007, 2011 Samuel G. D. Williams. <http://www.oriontransfer.co.nz>
7
2
  #
8
- # This program is distributed in the hope that it will be useful,
9
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
- # GNU General Public License for more details.
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
12
9
  #
13
- # You should have received a copy of the GNU General Public License
14
- # along with this program. If not, see <http://www.gnu.org/licenses/>.
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
15
20
 
16
21
  require 'rubygems'
17
22
 
@@ -0,0 +1,56 @@
1
+ # Copyright (c) 2007, 2011 Samuel G. D. Williams. <http://www.oriontransfer.co.nz>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ require 'pathname'
22
+ require 'fileutils'
23
+
24
+ $connection.run do |object|
25
+ case(object[0])
26
+ when :chdir
27
+ # [:chdir, :path]
28
+ Dir.chdir(object[1])
29
+ when :script
30
+ # [:script, :command, :data]
31
+
32
+ command = object[1]
33
+ script_name = File.basename(command[0])
34
+
35
+ local_path = `mktemp -t #{script_name.gsub(/[^a-z]/i, '')}.XXXX`.chomp
36
+
37
+ File.open(local_path, 'w') { |fp| fp.write(object[2]) }
38
+ system('chmod', '+x', local_path)
39
+
40
+ pid = fork do
41
+ command[0] = local_path
42
+ exec *command
43
+ end
44
+
45
+ # Clean up the script after execution:
46
+ pid, result = Process.wait2(pid)
47
+ # system('rm', '-f', local_path)
48
+
49
+ exit!(result.exitstatus)
50
+ when :exec
51
+ # [:exec, :command]
52
+ command = object[1]
53
+
54
+ exec *command
55
+ end
56
+ end
@@ -1,3 +1,22 @@
1
+ # Copyright (c) 2007, 2011 Samuel G. D. Williams. <http://www.oriontransfer.co.nz>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
1
20
 
2
21
  module LSync
3
22
  class BasicController
@@ -12,32 +31,118 @@ module LSync
12
31
  # The output logger.
13
32
  attr :logger
14
33
  end
15
-
34
+
16
35
  # The server controller provides event handlers with a unified interface
17
36
  # for dealing with servers and associated actions.
18
37
  class ServerController < BasicController
19
38
  def initialize(script, logger, server)
20
39
  super(script, logger)
21
-
40
+
22
41
  @server = server
42
+
43
+ @connection = nil
44
+ @platform = nil
23
45
  end
24
46
 
25
47
  # The current server.
26
48
  attr :server
27
49
 
28
- # Run a given shell script on the server.
29
- def run!(*function)
30
- action = Action.new(function)
31
- action.run_on_server(@server, @logger)
50
+ def run(command, options = {})
51
+ task = nil
52
+
53
+ root ||= options[:root] || @server.root
54
+
55
+ if String === command
56
+ command = [command]
57
+ end
58
+
59
+ begin
60
+ connection, task = @server.shell.connect(@server)
61
+ connection.send_object([:chdir, root])
62
+
63
+ if options[:script]
64
+ data = command[0]
65
+
66
+ command = command.dup
67
+
68
+ # Descriptive name can be provided by options[:script].
69
+ case options[:script]
70
+ when String
71
+ command[0] = options[:script]
72
+ else
73
+ command[0] = "script"
74
+ end
75
+
76
+ @logger.info "Running script #{command.inspect} on #{@server}"
77
+
78
+ connection.send_object([:script, command, data])
79
+ elsif options[:remote]
80
+ @logger.info "Running script #{command.inspect} on #{@server}"
81
+
82
+ data = File.read(command[0])
83
+ connection.send_object([:script, command, data])
84
+ else
85
+ @logger.info "Running command #{command.inspect} on #{@server}"
86
+ connection.send_object([:exec, command])
87
+ end
88
+
89
+ if block_given?
90
+ yield task
91
+ else
92
+ LSync::log_task(task, @logger)
93
+ end
94
+ ensure
95
+ if task
96
+ task.stop
97
+ task.wait
98
+ end
99
+ end
100
+ end
101
+
102
+ # Run a command on the given server using this shell.
103
+ def exec(command, options = {}, &block)
104
+ unless @server.local?
105
+ command = @server.shell.connection_command(@server) + ["--"] + command
106
+ end
107
+
108
+ @logger.debug "Executing #{command.inspect} on #{@server}"
109
+ RExec::Task.open(command, options, &block)
110
+ end
111
+
112
+ def exec!(command, options = {})
113
+ exec(command, options) do |task|
114
+ task.input.close
115
+
116
+ result = task.wait
117
+
118
+ unless result.exitstatus == 0
119
+ raise ShellScriptError.new("Command #{command.inspect} failed: #{result.exitstatus}", result.exitstatus)
120
+ end
121
+
122
+ return task.output.read
123
+ end
124
+ end
125
+
126
+ def ==(other)
127
+ @server == other.server
128
+ end
129
+
130
+ def respond_to?(name)
131
+ @server.respond_to?(name) || super(name)
132
+ end
133
+
134
+ def method_missing(name, *args, &block)
135
+ @server.send(name, *args, &block)
32
136
  end
33
137
  end
34
138
 
35
139
  class CopyController < BasicController
36
- def initialize(script, logger, master, target)
140
+ def initialize(script, logger, master, target, current)
37
141
  super(script, logger)
38
142
 
39
143
  @master = ServerController.new(script, logger, master)
40
144
  @target = ServerController.new(script, logger, target)
145
+ @current = ServerController.new(script, logger, current)
41
146
  end
42
147
 
43
148
  # The master server controller (where the data is being copied from).
@@ -45,13 +150,16 @@ module LSync
45
150
 
46
151
  # The target server controller (where the data is being copied to).
47
152
  attr :target
153
+
154
+ # The current server controller (the controller for the local machine).
155
+ attr :current
48
156
  end
49
157
 
50
158
  # The directory controller provides event handlers with a unified interface
51
159
  # for dealing with a particular backup in a particular directory.
52
160
  class DirectoryController < CopyController
53
- def initialize(script, logger, master, target, directory)
54
- super(script, logger, master, target)
161
+ def initialize(script, logger, master, target, current, directory)
162
+ super(script, logger, master, target, current)
55
163
 
56
164
  @directory = directory
57
165
  end
@@ -1,4 +1,24 @@
1
+ # Copyright (c) 2007, 2011 Samuel G. D. Williams. <http://www.oriontransfer.co.nz>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
1
20
 
21
+ require 'lsync/error'
2
22
  require 'lsync/event_handler'
3
23
  require 'pathname'
4
24
 
@@ -35,7 +55,10 @@ class Pathname
35
55
  end
36
56
 
37
57
  module LSync
38
-
58
+
59
+ class AbsolutePathError < Error
60
+ end
61
+
39
62
  # A specific directory which is relative to the root of a given server. Specific configuration details
40
63
  # such as excludes and other options may be specified.
41
64
  class Directory
@@ -44,6 +67,10 @@ module LSync
44
67
  def initialize(path)
45
68
  @path = Pathname.new(path).cleanpath.normalize_trailing_slash
46
69
  @options = {:arguments => []}
70
+
71
+ if @path.absolute?
72
+ raise AbsolutePathError.new("Path #{path} may not be absolute!", :path => path)
73
+ end
47
74
  end
48
75
 
49
76
  attr :path