crackup 1.0.0 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/HISTORY +7 -0
- data/README +2 -2
- data/bin/crackup +3 -3
- data/bin/crackup-restore +3 -3
- data/lib/crackup.rb +99 -45
- data/lib/crackup/{dirobject.rb → directory_object.rb} +34 -17
- data/lib/crackup/{fileobject.rb → file_object.rb} +12 -5
- data/lib/crackup/fs_object.rb +43 -0
- data/lib/crackup/symlink_object.rb +66 -0
- metadata +6 -5
- data/lib/crackup/fsobject.rb +0 -18
data/HISTORY
CHANGED
@@ -1,4 +1,11 @@
|
|
1
1
|
Crackup Release History
|
2
2
|
|
3
|
+
Version 1.0.1 (11/21/2006)
|
4
|
+
* Fix broken handling of symbolic links.
|
5
|
+
* Expand relative paths before backing up.
|
6
|
+
* Win32: If gpg.exe isn't in the system path, look for it at the path
|
7
|
+
specified in the HKCU\Software\GNU\GnuPG\gpgProgram registry key (if the key
|
8
|
+
exists) before failing.
|
9
|
+
|
3
10
|
Version 1.0.0 (11/16/2006)
|
4
11
|
* First release.
|
data/README
CHANGED
@@ -13,12 +13,12 @@ transferred to the remote location over a variety of protocols, including FTP.
|
|
13
13
|
Additional storage drivers can easily be written in Ruby.
|
14
14
|
|
15
15
|
Author:: Ryan Grove (mailto:ryan@wonko.com)
|
16
|
-
Version:: 1.0.
|
16
|
+
Version:: 1.0.1
|
17
17
|
Copyright:: Copyright (c) 2006 Ryan Grove. All rights reserved.
|
18
18
|
License:: New BSD License (http://opensource.org/licenses/bsd-license.php)
|
19
19
|
Website:: http://wonko.com/software/crackup
|
20
20
|
|
21
21
|
== Dependencies
|
22
22
|
|
23
|
-
- Ruby 1.8.
|
23
|
+
- Ruby 1.8.4+
|
24
24
|
- GPG 1.4.2+ (if you want to encrypt your backups)
|
data/bin/crackup
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
# <tt>crackup -h</tt> for usage information.
|
5
5
|
#
|
6
6
|
# Author:: Ryan Grove (mailto:ryan@wonko.com)
|
7
|
-
# Version:: 1.0.
|
7
|
+
# Version:: 1.0.1
|
8
8
|
# Copyright:: Copyright (c) 2006 Ryan Grove. All rights reserved.
|
9
9
|
# License:: New BSD License (http://opensource.org/licenses/bsd-license.php)
|
10
10
|
#
|
@@ -13,7 +13,7 @@ require 'crackup'
|
|
13
13
|
require 'optparse'
|
14
14
|
|
15
15
|
APP_NAME = 'crackup'
|
16
|
-
APP_VERSION = '1.0.
|
16
|
+
APP_VERSION = '1.0.1'
|
17
17
|
APP_COPYRIGHT = 'Copyright (c) 2006 Ryan Grove (ryan@wonko.com). All rights reserved.'
|
18
18
|
APP_URL = 'http://wonko.com/software/crackup'
|
19
19
|
|
@@ -116,7 +116,7 @@ module Crackup
|
|
116
116
|
@options[:from] = []
|
117
117
|
|
118
118
|
while filename = ARGV.shift
|
119
|
-
@options[:from] <<
|
119
|
+
@options[:from] << File.expand_path(filename)
|
120
120
|
end
|
121
121
|
end
|
122
122
|
|
data/bin/crackup-restore
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
# See <tt>crackup-restore -h</tt> for usage information.
|
5
5
|
#
|
6
6
|
# Author:: Ryan Grove (mailto:ryan@wonko.com)
|
7
|
-
# Version:: 1.0.
|
7
|
+
# Version:: 1.0.1
|
8
8
|
# Copyright:: Copyright (c) 2006 Ryan Grove. All rights reserved.
|
9
9
|
# License:: New BSD License (http://opensource.org/licenses/bsd-license.php)
|
10
10
|
#
|
@@ -13,7 +13,7 @@ require 'crackup'
|
|
13
13
|
require 'optparse'
|
14
14
|
|
15
15
|
APP_NAME = 'crackup-restore'
|
16
|
-
APP_VERSION = '1.0.
|
16
|
+
APP_VERSION = '1.0.1'
|
17
17
|
APP_COPYRIGHT = 'Copyright (c) 2006 Ryan Grove (ryan@wonko.com). All rights reserved.'
|
18
18
|
APP_URL = 'http://wonko.com/software/crackup'
|
19
19
|
|
@@ -134,7 +134,7 @@ module Crackup
|
|
134
134
|
|
135
135
|
# List remote files if the --list option was given.
|
136
136
|
if @options[:list]
|
137
|
-
puts get_list(@remote_files)
|
137
|
+
puts get_list(@remote_files)
|
138
138
|
exit
|
139
139
|
end
|
140
140
|
|
data/lib/crackup.rb
CHANGED
@@ -1,19 +1,21 @@
|
|
1
|
-
ENV['PATH'] = "#{File.dirname(__FILE__)};#{ENV['PATH']}"
|
2
|
-
|
3
1
|
require 'crackup/errors'
|
4
|
-
require 'crackup/
|
2
|
+
require 'crackup/directory_object'
|
5
3
|
require 'crackup/driver'
|
6
|
-
require 'crackup/
|
7
|
-
require '
|
4
|
+
require 'crackup/file_object'
|
5
|
+
require 'crackup/symlink_object'
|
6
|
+
require 'find'
|
7
|
+
require 'tmpdir'
|
8
8
|
require 'zlib'
|
9
9
|
|
10
10
|
module Crackup
|
11
11
|
|
12
|
-
GPG_DECRYPT = 'echo :passphrase | gpg --batch --quiet --no-tty --no-secmem-warning --cipher-algo aes256 --compress-algo bzip2 --passphrase-fd 0 --output :output_file :input_file'
|
13
|
-
GPG_ENCRYPT = 'echo :passphrase | gpg --batch --quiet --no-tty --no-secmem-warning --cipher-algo aes256 --compress-algo bzip2 --passphrase-fd 0 --output :output_file --symmetric :input_file'
|
12
|
+
GPG_DECRYPT = 'echo :passphrase | :gpg --batch --quiet --no-tty --no-secmem-warning --cipher-algo aes256 --compress-algo bzip2 --passphrase-fd 0 --output :output_file :input_file'
|
13
|
+
GPG_ENCRYPT = 'echo :passphrase | :gpg --batch --quiet --no-tty --no-secmem-warning --cipher-algo aes256 --compress-algo bzip2 --passphrase-fd 0 --output :output_file --symmetric :input_file'
|
14
14
|
|
15
15
|
attr_accessor :driver, :local_files, :options, :remote_files
|
16
16
|
|
17
|
+
@gpg_path = nil
|
18
|
+
|
17
19
|
# Reads _infile_ and compresses it to _outfile_ using zlib compression.
|
18
20
|
def self.compress_file(infile, outfile)
|
19
21
|
File.open(infile, 'rb') do |input|
|
@@ -52,10 +54,11 @@ module Crackup
|
|
52
54
|
File.delete(outfile) if File.exist?(outfile)
|
53
55
|
|
54
56
|
gpg_command = String.new(GPG_DECRYPT)
|
55
|
-
gpg_command.gsub!(':
|
57
|
+
gpg_command.gsub!(':gpg', find_gpg())
|
58
|
+
gpg_command.gsub!(':input_file', escapeshellarg(infile))
|
56
59
|
gpg_command.gsub!(':output_file', escapeshellarg(outfile))
|
57
|
-
gpg_command.gsub!(':passphrase',
|
58
|
-
|
60
|
+
gpg_command.gsub!(':passphrase', escapeshellarg(@options[:passphrase]))
|
61
|
+
|
59
62
|
unless system(gpg_command)
|
60
63
|
raise Crackup::EncryptionError, "Unable to decrypt file: #{infile}"
|
61
64
|
end
|
@@ -70,9 +73,10 @@ module Crackup
|
|
70
73
|
File.delete(outfile) if File.exist?(outfile)
|
71
74
|
|
72
75
|
gpg_command = String.new(GPG_ENCRYPT)
|
73
|
-
gpg_command.gsub!(':
|
76
|
+
gpg_command.gsub!(':gpg', find_gpg())
|
77
|
+
gpg_command.gsub!(':input_file', escapeshellarg(infile))
|
74
78
|
gpg_command.gsub!(':output_file', escapeshellarg(outfile))
|
75
|
-
gpg_command.gsub!(':passphrase',
|
79
|
+
gpg_command.gsub!(':passphrase', escapeshellarg(@options[:passphrase]))
|
76
80
|
|
77
81
|
unless system(gpg_command)
|
78
82
|
raise Crackup::EncryptionError, "Unable to encrypt file: #{infile}"
|
@@ -85,12 +89,64 @@ module Crackup
|
|
85
89
|
abort "#{APP_NAME}: #{message}"
|
86
90
|
end
|
87
91
|
|
88
|
-
# Wraps _arg_ in single quotes, escaping any
|
89
|
-
# thus making it safe for use as a shell argument.
|
92
|
+
# Wraps _arg_ in single quotes (double quotes in Windows), escaping any quotes
|
93
|
+
# contained therein, thus making it safe for use as a shell argument.
|
90
94
|
def self.escapeshellarg(arg)
|
91
|
-
|
95
|
+
if RUBY_PLATFORM =~ /mswin32/
|
96
|
+
return "\"#{arg.gsub('"', '\\"')}\""
|
97
|
+
else
|
98
|
+
return "'#{arg.gsub("'", "\\'")}'"
|
99
|
+
end
|
92
100
|
end
|
93
101
|
|
102
|
+
# Returns the name of the GnuPG executable to use. First we search for +gpg+
|
103
|
+
# or <tt>gpg.exe</tt> in the path. On Windows, if it isn't in the system path,
|
104
|
+
# we try to find a pointer to it in the registry. If everything fails, a
|
105
|
+
# Crackup::Error is raised.
|
106
|
+
def self.find_gpg
|
107
|
+
# Don't bother finding gpg again if we've already found it.
|
108
|
+
return @gpg_path unless @gpg_path.nil?
|
109
|
+
|
110
|
+
# First, check to see if gpg is in the path.
|
111
|
+
if RUBY_PLATFORM =~ /mswin32/
|
112
|
+
path_dirs = ENV['PATH'].split(';')
|
113
|
+
filename = 'gpg.exe'
|
114
|
+
else
|
115
|
+
path_dirs = ENV['PATH'].split(':')
|
116
|
+
filename = 'gpg'
|
117
|
+
end
|
118
|
+
|
119
|
+
Find.find(*path_dirs) do |path|
|
120
|
+
return @gpg_path = filename if File.executable?(File.join(path, filename))
|
121
|
+
end
|
122
|
+
|
123
|
+
# Okay, it's not in the path. Unix users are screwed, but if we're on
|
124
|
+
# Windows, we'll make a last-ditch attempt to find it by checking for its
|
125
|
+
# registry key.
|
126
|
+
if RUBY_PLATFORM =~ /mswin32/
|
127
|
+
# Bail out if we can't load the Win32::Registry library.
|
128
|
+
unless require('win32/registry')
|
129
|
+
raise Crackup::Error, 'GnuPG not found.'
|
130
|
+
end
|
131
|
+
|
132
|
+
# Try to read the GnuPG registry key.
|
133
|
+
begin
|
134
|
+
gpg_path = nil
|
135
|
+
Win32::Registry.open(Win32::Registry::HKEY_CURRENT_USER,
|
136
|
+
'Software\GNU\GnuPG') {|reg| gpg_path = reg.read_s('gpgProgram') }
|
137
|
+
rescue => e
|
138
|
+
raise Crackup::Error, 'GnuPG not found.'
|
139
|
+
end
|
140
|
+
|
141
|
+
if File.executable?(gpg_path)
|
142
|
+
return @gpg_path = "\"#{gpg_path}\""
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
# No luck. Bail out.
|
147
|
+
raise Crackup::Error, 'GnuPG not found.'
|
148
|
+
end
|
149
|
+
|
94
150
|
# Gets an array of files in the remote file index whose local paths match
|
95
151
|
# _pattern_.
|
96
152
|
def self.find_remote_files(pattern)
|
@@ -103,8 +159,7 @@ module Crackup
|
|
103
159
|
next
|
104
160
|
end
|
105
161
|
|
106
|
-
|
107
|
-
files += file.find(pattern)
|
162
|
+
files += file.find(pattern) if file.is_a?(Crackup::DirectoryObject)
|
108
163
|
end
|
109
164
|
|
110
165
|
return files
|
@@ -117,16 +172,14 @@ module Crackup
|
|
117
172
|
|
118
173
|
if files.is_a?(Hash)
|
119
174
|
files.each_value {|value| list += get_list(value) }
|
120
|
-
elsif files.is_a?(Crackup::
|
121
|
-
list +=
|
122
|
-
elsif files.is_a?(Crackup::FileObject)
|
123
|
-
list << files.name
|
175
|
+
elsif files.is_a?(Crackup::FileSystemObject)
|
176
|
+
list += files.to_s.split("\n")
|
124
177
|
end
|
125
178
|
|
126
|
-
return list
|
179
|
+
return list.sort
|
127
180
|
end
|
128
181
|
|
129
|
-
# Gets a Hash of Crackup::
|
182
|
+
# Gets a Hash of {Crackup::FileSystemObject}s representing the files and
|
130
183
|
# directories on the local system in the locations specified by the array of
|
131
184
|
# filenames in <tt>options[:from]</tt>.
|
132
185
|
def self.get_local_files
|
@@ -143,13 +196,8 @@ module Crackup
|
|
143
196
|
end
|
144
197
|
end
|
145
198
|
|
146
|
-
|
147
|
-
|
148
|
-
local_files[filename] = Crackup::DirectoryObject.new(filename)
|
149
|
-
elsif File.file?(filename)
|
150
|
-
debug "--> #{filename}"
|
151
|
-
local_files[filename] = Crackup::FileObject.new(filename)
|
152
|
-
end
|
199
|
+
debug "--> #{filename}"
|
200
|
+
local_files[filename] = Crackup::FileSystemObject.from(filename)
|
153
201
|
end
|
154
202
|
|
155
203
|
return local_files
|
@@ -227,10 +275,24 @@ module Crackup
|
|
227
275
|
# Creates a new temporary file in the system's temporary directory and returns
|
228
276
|
# its name. All temporary files will be deleted when the program exits.
|
229
277
|
def self.get_tempfile
|
230
|
-
tempfile
|
231
|
-
|
278
|
+
# We would use Ruby's tempfile library here, but for some reason it
|
279
|
+
# sometimes deletes temp files before the program exits, which can cause all
|
280
|
+
# kinds of problems.
|
281
|
+
i = -1
|
282
|
+
|
283
|
+
while tempfile = File.join(Dir.tmpdir(),
|
284
|
+
".crackup.#{Process.pid}.#{i += 1}") do
|
285
|
+
break unless File.exist?(tempfile)
|
286
|
+
end
|
232
287
|
|
233
|
-
|
288
|
+
at_exit do
|
289
|
+
begin
|
290
|
+
File.delete(tempfile)
|
291
|
+
rescue => e
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
return tempfile
|
234
296
|
end
|
235
297
|
|
236
298
|
# Gets an Array of Crackup::FileSystemObjects representing files and
|
@@ -253,12 +315,8 @@ module Crackup
|
|
253
315
|
# Add to the list all updated files contained in the directory and its
|
254
316
|
# subdirectories.
|
255
317
|
updated += get_updated_files(localfile.children, remotefile.children)
|
256
|
-
elsif localfile
|
257
|
-
|
258
|
-
# Add the file to the list if the local file has been modified.
|
259
|
-
unless localfile.file_hash == remotefile.file_hash
|
260
|
-
updated << localfile
|
261
|
-
end
|
318
|
+
elsif localfile != remotefile
|
319
|
+
updated << localfile
|
262
320
|
end
|
263
321
|
end
|
264
322
|
|
@@ -279,17 +337,13 @@ module Crackup
|
|
279
337
|
# Deletes each Crackup::FileSystemObject specified in the _files_ array from
|
280
338
|
# the remote location.
|
281
339
|
def self.remove_files(files)
|
282
|
-
files.each
|
283
|
-
file.remove
|
284
|
-
end
|
340
|
+
files.each {|file| file.remove }
|
285
341
|
end
|
286
342
|
|
287
343
|
# Uploads each Crackup::FileSystemObject specified in the _files_ array to the
|
288
344
|
# remote location.
|
289
345
|
def self.update_files(files)
|
290
|
-
files.each
|
291
|
-
file.update
|
292
|
-
end
|
346
|
+
files.each {|file| file.update }
|
293
347
|
end
|
294
348
|
|
295
349
|
# Brings the remote file index up to date with the local one.
|
@@ -1,16 +1,17 @@
|
|
1
|
-
require 'crackup/
|
1
|
+
require 'crackup/fs_object'
|
2
2
|
|
3
3
|
module Crackup
|
4
4
|
|
5
5
|
# Represents a directory on the local filesystem. Can contain any number of
|
6
6
|
# Crackup::FileSystemObjects as children.
|
7
7
|
class DirectoryObject
|
8
|
+
include Enumerable
|
8
9
|
include FileSystemObject
|
9
10
|
|
10
11
|
attr_reader :children
|
11
12
|
|
12
13
|
#--
|
13
|
-
# Public
|
14
|
+
# Public Instance Methods
|
14
15
|
#++
|
15
16
|
|
16
17
|
def initialize(name)
|
@@ -20,12 +21,24 @@ module Crackup
|
|
20
21
|
|
21
22
|
super(name)
|
22
23
|
|
23
|
-
refresh_children
|
24
|
+
refresh_children()
|
24
25
|
end
|
25
26
|
|
26
|
-
|
27
|
-
#
|
28
|
-
|
27
|
+
# Compares the specified Crackup::DirectoryObject to this one. Returns
|
28
|
+
# +true+ if the directories and all their children are the same, +false+
|
29
|
+
# otherwise.
|
30
|
+
def ==(directory)
|
31
|
+
return false unless directory.name == @name
|
32
|
+
return directory.all?{|child| child == @children[child.name] }
|
33
|
+
end
|
34
|
+
|
35
|
+
def [](key)
|
36
|
+
return @children[key]
|
37
|
+
end
|
38
|
+
|
39
|
+
def each
|
40
|
+
@children.each {|child| yield child }
|
41
|
+
end
|
29
42
|
|
30
43
|
# Gets an array of files contained in this directory or its children whose
|
31
44
|
# local filenames match _pattern_.
|
@@ -38,8 +51,9 @@ module Crackup
|
|
38
51
|
next
|
39
52
|
end
|
40
53
|
|
41
|
-
|
42
|
-
|
54
|
+
if child.is_a?(Crackup::DirectoryObject)
|
55
|
+
files << result if result = child.find(pattern)
|
56
|
+
end
|
43
57
|
end
|
44
58
|
|
45
59
|
return files
|
@@ -54,22 +68,20 @@ module Crackup
|
|
54
68
|
dir.each do |filename|
|
55
69
|
next if filename == '.' || filename == '..'
|
56
70
|
|
57
|
-
|
71
|
+
path = File.join(dir.path, filename).gsub("\\", "/")
|
58
72
|
|
59
73
|
# Skip this file if it's in the exclusion list.
|
60
74
|
unless Crackup::options[:exclude].nil?
|
61
75
|
next if Crackup::options[:exclude].any? do |pattern|
|
62
|
-
File.fnmatch?(pattern,
|
76
|
+
File.fnmatch?(pattern, path)
|
63
77
|
end
|
64
78
|
end
|
65
79
|
|
66
|
-
|
67
|
-
@children[filename.chomp('/')] = Crackup::DirectoryObject.new(filename)
|
68
|
-
elsif File.file?(filename)
|
69
|
-
@children[filename] = Crackup::FileObject.new(filename)
|
70
|
-
end
|
80
|
+
@children[path] = Crackup::FileSystemObject.from(path)
|
71
81
|
end
|
72
82
|
end
|
83
|
+
|
84
|
+
return @children
|
73
85
|
end
|
74
86
|
|
75
87
|
# Removes the remote copy of this directory and all its children.
|
@@ -77,12 +89,17 @@ module Crackup
|
|
77
89
|
@children.each_value {|child| child.remove }
|
78
90
|
end
|
79
91
|
|
80
|
-
# Restores the remote copy of this directory to the specified local
|
81
|
-
# <em>path</em>.
|
92
|
+
# Restores the remote copy of this directory to the specified local _path_.
|
82
93
|
def restore(path)
|
83
94
|
@children.each_value {|child| child.restore(path) }
|
84
95
|
end
|
85
96
|
|
97
|
+
def to_s
|
98
|
+
childnames = []
|
99
|
+
@children.each_value {|child| childnames << child.to_s }
|
100
|
+
return childnames.join("\n")
|
101
|
+
end
|
102
|
+
|
86
103
|
# Uploads this directory and all its children to the remote location.
|
87
104
|
def update
|
88
105
|
@children.each_value {|child| child.update }
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require 'crackup/
|
1
|
+
require 'crackup/fs_object'
|
2
2
|
require 'digest/sha2'
|
3
3
|
require 'fileutils'
|
4
4
|
|
@@ -18,18 +18,25 @@ module Crackup
|
|
18
18
|
super(filename)
|
19
19
|
|
20
20
|
# Get the file's SHA256 hash.
|
21
|
-
digest = Digest::SHA256.new
|
21
|
+
digest = Digest::SHA256.new
|
22
22
|
|
23
23
|
File.open(filename, 'rb') do |file|
|
24
|
-
|
25
|
-
digest <<
|
24
|
+
while buffer = file.read(1048576) do
|
25
|
+
digest << buffer
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
29
29
|
@file_hash = digest.hexdigest()
|
30
30
|
@url = "#{Crackup.driver.url}/crackup_#{@name_hash}"
|
31
31
|
end
|
32
|
-
|
32
|
+
|
33
|
+
# Compares the specified Crackup::FileObject to this one. Returns +false+ if
|
34
|
+
# _file_ is different, +true+ if _file_ is the same. The comparison is
|
35
|
+
# performed using an SHA256 hash of the file contents.
|
36
|
+
def ==(file)
|
37
|
+
return file.name == @name && file.file_hash == @file_hash
|
38
|
+
end
|
39
|
+
|
33
40
|
# Removes this file from the remote location.
|
34
41
|
def remove
|
35
42
|
Crackup.debug "--> #{@name}"
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'digest/sha2'
|
2
|
+
|
3
|
+
module Crackup
|
4
|
+
|
5
|
+
# Represents a filesystem object on the local filesystem.
|
6
|
+
module FileSystemObject
|
7
|
+
attr_reader :name, :name_hash
|
8
|
+
|
9
|
+
#--
|
10
|
+
# Public Class Methods
|
11
|
+
#++
|
12
|
+
|
13
|
+
# Returns an instance of the appropriate FileSystemObject subclass to
|
14
|
+
# represent _path_.
|
15
|
+
def self.from(path)
|
16
|
+
return Crackup::SymlinkObject.new(path) if File.symlink?(path)
|
17
|
+
return Crackup::DirectoryObject.new(path) if File.directory?(path)
|
18
|
+
return Crackup::FileObject.new(path) if File.file?(path)
|
19
|
+
|
20
|
+
raise Crackup::Error, "Unsupported filesystem object: #{path}"
|
21
|
+
end
|
22
|
+
|
23
|
+
#--
|
24
|
+
# Public Instance Methods
|
25
|
+
#++
|
26
|
+
|
27
|
+
def initialize(name)
|
28
|
+
@name = name.chomp('/')
|
29
|
+
@name_hash = Digest::SHA256.hexdigest(name)
|
30
|
+
end
|
31
|
+
|
32
|
+
def ==(fs_object); end
|
33
|
+
def remove; end
|
34
|
+
def restore(path); end
|
35
|
+
|
36
|
+
def to_s
|
37
|
+
return @name
|
38
|
+
end
|
39
|
+
|
40
|
+
def update; end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'crackup/fs_object'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
module Crackup
|
5
|
+
|
6
|
+
# Represents a symbolic link on the local filesystem.
|
7
|
+
class SymlinkObject
|
8
|
+
include FileSystemObject
|
9
|
+
|
10
|
+
attr_reader :file_hash, :target, :url
|
11
|
+
|
12
|
+
#--
|
13
|
+
# Public Instance Methods
|
14
|
+
#++
|
15
|
+
|
16
|
+
def initialize(linkname)
|
17
|
+
unless File.symlink?(linkname)
|
18
|
+
raise ArgumentError, "#{linkname} is not a symbolic link"
|
19
|
+
end
|
20
|
+
|
21
|
+
super(linkname)
|
22
|
+
|
23
|
+
@target = File.readlink(linkname)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Compares the specified Crackup::SymlinkObject to this one. Returns +true+
|
27
|
+
# if they're the same, +false+ if _symlink_ is different.
|
28
|
+
def ==(symlink)
|
29
|
+
return symlink.name == @name && symlink.target == @target
|
30
|
+
end
|
31
|
+
|
32
|
+
# Removes this link from the remote location. This is actually a noop, since
|
33
|
+
# link data is just stored in the index.
|
34
|
+
def remove
|
35
|
+
Crackup.debug "--> #{@name}"
|
36
|
+
end
|
37
|
+
|
38
|
+
# Restores the remote copy of this link to the local path specified by
|
39
|
+
# _path_.
|
40
|
+
def restore(path)
|
41
|
+
path = path.chomp('/') + '/' + File.dirname(@name).delete(':')
|
42
|
+
linkname = path + '/' + File.basename(@name)
|
43
|
+
|
44
|
+
Crackup.debug "--> #{linkname}"
|
45
|
+
|
46
|
+
# Create the path if it doesn't exist.
|
47
|
+
unless File.directory?(path)
|
48
|
+
begin
|
49
|
+
FileUtils.mkdir_p(path)
|
50
|
+
rescue => e
|
51
|
+
raise Crackup::Error, "Unable to create local directory: #{path}"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# Create the link.
|
56
|
+
File.symlink(@target, linkname)
|
57
|
+
end
|
58
|
+
|
59
|
+
# Uploads this link to the remote location. This is actually a noop, since
|
60
|
+
# link data is just stored in the index.
|
61
|
+
def update
|
62
|
+
Crackup.debug "--> #{@name}"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.0
|
|
3
3
|
specification_version: 1
|
4
4
|
name: crackup
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 1.0.
|
7
|
-
date: 2006-11-
|
6
|
+
version: 1.0.1
|
7
|
+
date: 2006-11-20 00:00:00 -08:00
|
8
8
|
summary: Crackup is a pretty simple, pretty secure remote backup solution for folks who want to keep their data securely backed up but aren't particularly concerned about bandwidth usage.
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -33,12 +33,13 @@ files:
|
|
33
33
|
- bin/crackup-restore
|
34
34
|
- lib/crackup
|
35
35
|
- lib/crackup.rb
|
36
|
-
- lib/crackup/
|
36
|
+
- lib/crackup/directory_object.rb
|
37
37
|
- lib/crackup/driver.rb
|
38
38
|
- lib/crackup/drivers
|
39
39
|
- lib/crackup/errors.rb
|
40
|
-
- lib/crackup/
|
41
|
-
- lib/crackup/
|
40
|
+
- lib/crackup/file_object.rb
|
41
|
+
- lib/crackup/fs_object.rb
|
42
|
+
- lib/crackup/symlink_object.rb
|
42
43
|
- lib/crackup/drivers/file.rb
|
43
44
|
- lib/crackup/drivers/ftp.rb
|
44
45
|
- LICENSE
|
data/lib/crackup/fsobject.rb
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
require 'digest/sha2'
|
2
|
-
|
3
|
-
module Crackup
|
4
|
-
|
5
|
-
# Represents a filesystem object on the local filesystem.
|
6
|
-
module FileSystemObject
|
7
|
-
attr_reader :name, :name_hash
|
8
|
-
|
9
|
-
def initialize(name)
|
10
|
-
@name = name.chomp('/')
|
11
|
-
@name_hash = Digest::SHA256.hexdigest(name)
|
12
|
-
end
|
13
|
-
|
14
|
-
def remove; end
|
15
|
-
def restore(local_path); end
|
16
|
-
end
|
17
|
-
|
18
|
-
end
|