crackup 1.0.0 → 1.0.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.
- 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
|