lsync 2.1.0 → 2.3.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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