jmstacey-cfbackup 0.5.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.markdown +13 -0
- data/README.markdown +33 -6
- data/Rakefile +2 -2
- data/VERSION.yml +2 -2
- data/bin/cfbackup +1 -1
- data/lib/OptCFBackup.rb +11 -10
- data/lib/cfbackup.rb +187 -43
- data/test/cfbackup_test.rb +102 -2
- data/test/cfconfig.yml +2 -0
- data/test/{data.txt → data/data.txt} +0 -0
- data/test/data/folder_1/file1.txt +2 -0
- data/test/data/folder_1/file2.txt +2 -0
- data/test/data/folder_1/folder_3/file1.txt +2 -0
- data/test/data/folder_2/file1.txt +2 -0
- data/test/data/folder_2/file2.txt +2 -0
- data/test/test_helper.rb +1 -1
- metadata +9 -3
data/CHANGELOG.markdown
CHANGED
@@ -1,6 +1,19 @@
|
|
1
1
|
CFBackup ChangeLog
|
2
2
|
==================
|
3
3
|
|
4
|
+
0.6.0 2009-05-03
|
5
|
+
-----------------
|
6
|
+
* Added example_scripts to RDoc.
|
7
|
+
* gem creates cfconfig.yml in /etc for reference
|
8
|
+
* CFBackup looks in multiple places for config file
|
9
|
+
* Hidden directory in $HOME ($HOME/.cfconfig.yml)
|
10
|
+
* Non-hidden in current directory (./cfconfig.yml)
|
11
|
+
* In /etc/cfconfig.yml
|
12
|
+
* Refactoring and new usage with --action push|pull|delete
|
13
|
+
* Pulling files implemented
|
14
|
+
* Deleting files implemented
|
15
|
+
* Initial unit tests completed
|
16
|
+
|
4
17
|
0.5.0 2009-04-18
|
5
18
|
-----------------
|
6
19
|
|
data/README.markdown
CHANGED
@@ -1,9 +1,7 @@
|
|
1
1
|
CFBackup
|
2
2
|
=========
|
3
3
|
|
4
|
-
CFBackup is a small ruby program that transfers files or directories from the
|
5
|
-
local machine to a Cloud Files container. It is meant to serve as a useful tool
|
6
|
-
for automated backups.
|
4
|
+
CFBackup is a small ruby program that transfers files or directories from the local machine to a Cloud Files container. It is meant to serve as a useful tool for automated backups.
|
7
5
|
|
8
6
|
Features
|
9
7
|
-----------
|
@@ -11,21 +9,50 @@ Features
|
|
11
9
|
* Backup a single file or directory (recursion uses pseudo directories)
|
12
10
|
* Pipe data straight to container
|
13
11
|
* Free transfers over local Rackspace network for Slicehost/Cloud Server
|
14
|
-
|
12
|
+
customers in DFW1 datacenter
|
15
13
|
|
16
14
|
Requirements
|
17
15
|
--------------
|
18
16
|
|
19
|
-
TODO: Complete this area
|
20
17
|
* ruby-cloudfiles
|
21
18
|
|
19
|
+
Notes:
|
20
|
+
* If you install CFBackup as a gem, all of the dependencies _should_ automatically be installed for you.
|
21
|
+
* Ubuntu Users: The Ubuntu rubygems package will installs executables outside your normal PATH. You will
|
22
|
+
need to update it or create a symlink to access cfbackup from anywhere. See the wiki for more information.reating a symlink.
|
23
|
+
|
22
24
|
Install
|
23
25
|
-----------
|
24
26
|
|
25
27
|
* gem sources -a http://gems.github.com
|
26
28
|
* sudo gem install jmstacey-cfbackup
|
27
29
|
|
28
|
-
|
30
|
+
Configuration
|
31
|
+
-----------
|
32
|
+
|
33
|
+
CFBackup will look in the following places (in order) for the configuration file named cfconfig.yml
|
34
|
+
|
35
|
+
* Hidden in home directory (~/.cfbackup.yml)
|
36
|
+
* Non-hidden in present working directory (./cfbackup.yml)
|
37
|
+
* In etc (/etc/cfbackup.yml)
|
38
|
+
|
39
|
+
The configuration file can be overridden at any time with the --config_file option
|
40
|
+
|
41
|
+
Configuration
|
42
|
+
-----------
|
43
|
+
|
44
|
+
Usage: cfbackup.rb --action push|pull|delete options --container CONTAINER
|
45
|
+
--action ACTION Action to perform: push, pull, or delete.
|
46
|
+
--pipe_data Pipe data from another application and stream it to Cloud Files
|
47
|
+
-r, --recursive Traverse local path recursivley
|
48
|
+
-v, --verbose Run verbosely
|
49
|
+
--local_path LOCAL_PATH Local path or file
|
50
|
+
--container CONTAINER Cloud Files container name
|
51
|
+
--version Show current version
|
52
|
+
--config_file PATH Use specified config file, rather than the default
|
53
|
+
--local_net Use unmetered connection in DFW1 (only applicable to Slicehost or Mosso Cloud Server customers)
|
54
|
+
|
55
|
+
The wiki has usage examples and some sample automation scripts can be found in the example_scripts directory.
|
29
56
|
|
30
57
|
Copyright
|
31
58
|
------------
|
data/Rakefile
CHANGED
@@ -10,7 +10,7 @@ begin
|
|
10
10
|
gem.homepage = "http://github.com/jmstacey/cfbackup"
|
11
11
|
gem.authors = ["Jon Stacey"]
|
12
12
|
|
13
|
-
#
|
13
|
+
# Dependencies
|
14
14
|
gem.add_dependency('jmstacey-ruby-cloudfiles', '>=1.3.3')
|
15
15
|
|
16
16
|
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
@@ -39,7 +39,6 @@ rescue LoadError
|
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
42
|
-
|
43
42
|
task :default => :test
|
44
43
|
|
45
44
|
require 'rake/rdoctask'
|
@@ -54,6 +53,7 @@ Rake::RDocTask.new do |rdoc|
|
|
54
53
|
rdoc.rdoc_dir = 'rdoc'
|
55
54
|
rdoc.title = "cfbackup #{version}"
|
56
55
|
rdoc.rdoc_files.include('README*')
|
56
|
+
rdoc.rdoc_files.include('example_scripts/**')
|
57
57
|
rdoc.rdoc_files.include('lib/**/*.rb')
|
58
58
|
end
|
59
59
|
|
data/VERSION.yml
CHANGED
data/bin/cfbackup
CHANGED
data/lib/OptCFBackup.rb
CHANGED
@@ -12,14 +12,14 @@ class OptCFBackup
|
|
12
12
|
# Initializes object with command line arguments passed
|
13
13
|
def initialize(args)
|
14
14
|
|
15
|
-
@banner = "Usage: cfbackup.rb
|
15
|
+
@banner = "Usage: cfbackup.rb --action push|pull|delete options --container CONTAINER"
|
16
16
|
|
17
17
|
@options = OpenStruct.new
|
18
|
-
self.options.config = ['
|
18
|
+
self.options.config = ["#{ENV['HOME']}/.cfconfig.yml", './cfconfig.yml', '/etc/cfconfig.yml']
|
19
|
+
self.options.action = ''
|
19
20
|
self.options.pipe_data = false
|
20
21
|
self.options.show_ver = false
|
21
22
|
self.options.recursive = false
|
22
|
-
self.options.restore = false
|
23
23
|
self.options.local_net = false
|
24
24
|
self.options.container = ''
|
25
25
|
self.options.local_path = ''
|
@@ -29,6 +29,10 @@ class OptCFBackup
|
|
29
29
|
opts = OptionParser.new do |opts|
|
30
30
|
opts.banner = self.banner
|
31
31
|
|
32
|
+
opts.on("--action ACTION", "Action to perform: push, pull, or delete.") do |action|
|
33
|
+
self.options.action = action
|
34
|
+
end
|
35
|
+
|
32
36
|
opts.on("--pipe_data", "Pipe data from another application and stream it to Cloud Files") do |pipe|
|
33
37
|
self.options.pipe_data = pipe
|
34
38
|
end
|
@@ -50,15 +54,12 @@ class OptCFBackup
|
|
50
54
|
clean_remote_path unless (self.options.remote_path.nil?)
|
51
55
|
end
|
52
56
|
|
53
|
-
opts.on("--restore", "Restore files to local path") do |restore|
|
54
|
-
self.options.restore = restore
|
55
|
-
end
|
56
|
-
|
57
57
|
opts.on("--version", "Show current version") do |version|
|
58
58
|
self.options.show_ver = version
|
59
59
|
end
|
60
60
|
|
61
|
-
opts.on("--config_file PATH", "Use specified config file, rather than the default") do |config|
|
61
|
+
opts.on("--config_file PATH", "Use specified config file, rather than the default") do |config|
|
62
|
+
self.options.config = Array.new()
|
62
63
|
self.options.config << config
|
63
64
|
end
|
64
65
|
|
@@ -70,7 +71,7 @@ class OptCFBackup
|
|
70
71
|
|
71
72
|
opts.parse!(args)
|
72
73
|
|
73
|
-
end #
|
74
|
+
end # initialize()
|
74
75
|
|
75
76
|
private
|
76
77
|
|
@@ -78,7 +79,7 @@ class OptCFBackup
|
|
78
79
|
if self.options.remote_path[0,1] == "/"
|
79
80
|
self.options.remote_path.slice!(0)
|
80
81
|
end
|
81
|
-
#
|
82
|
+
# Follwoig won't work for piped data. Might result in "text.txt/"
|
82
83
|
# self.options.remote_path = self.options.remote_path + "/" unless (self.options.remote_path[-1,1] == "/")
|
83
84
|
end
|
84
85
|
|
data/lib/cfbackup.rb
CHANGED
@@ -15,8 +15,9 @@
|
|
15
15
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
16
16
|
|
17
17
|
require 'rubygems'
|
18
|
+
require 'ftools'
|
18
19
|
require 'cloudfiles'
|
19
|
-
require '
|
20
|
+
require 'optcfbackup'
|
20
21
|
require 'yaml'
|
21
22
|
|
22
23
|
class CFBackup
|
@@ -27,8 +28,13 @@ class CFBackup
|
|
27
28
|
# Special case if the version is requested
|
28
29
|
if @opts.options.show_ver
|
29
30
|
version_file = File.join(File.dirname(__FILE__), '..', 'VERSION.yml')
|
30
|
-
|
31
|
-
|
31
|
+
if File.exist?(version_file)
|
32
|
+
config = YAML.load(File.read(version_file))
|
33
|
+
version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
|
34
|
+
else
|
35
|
+
version = "unkown version"
|
36
|
+
end
|
37
|
+
show_error("CFBackup #{version}")
|
32
38
|
end
|
33
39
|
|
34
40
|
# Locate and load config file
|
@@ -40,23 +46,26 @@ class CFBackup
|
|
40
46
|
end
|
41
47
|
show_error('Error: Unable to locate config file.') unless (@conf != nil)
|
42
48
|
|
49
|
+
prep_connection
|
50
|
+
|
43
51
|
end # initialize()
|
44
52
|
|
45
53
|
def run
|
46
54
|
|
47
55
|
show_error() unless (@opts.options.container != "")
|
48
56
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
if @opts.options.restore
|
56
|
-
run_restore
|
57
|
+
# Run appropriate action
|
58
|
+
case @opts.options.action
|
59
|
+
when 'push'
|
60
|
+
if @opts.options.pipe_data
|
61
|
+
push_piped_data
|
57
62
|
else
|
58
|
-
|
63
|
+
push_files
|
59
64
|
end
|
65
|
+
when 'pull'
|
66
|
+
pull_files()
|
67
|
+
when 'delete'
|
68
|
+
delete_files
|
60
69
|
else
|
61
70
|
show_error()
|
62
71
|
end
|
@@ -65,8 +74,7 @@ class CFBackup
|
|
65
74
|
|
66
75
|
private
|
67
76
|
|
68
|
-
def
|
69
|
-
|
77
|
+
def prep_connection
|
70
78
|
# Establish connection
|
71
79
|
show_verbose "Establishing connection...", false
|
72
80
|
@cf = CloudFiles::Connection.new(@conf["username"], @conf["api_key"]);
|
@@ -76,30 +84,38 @@ class CFBackup
|
|
76
84
|
if @opts.options.local_net
|
77
85
|
@cf.storagehost = 'snet-storage.clouddrive.com'
|
78
86
|
end
|
87
|
+
end # prep_connection()
|
79
88
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
89
|
+
def prep_container(create_container = true)
|
90
|
+
# Check for the container. If it doesn't exist, create it if allowed
|
91
|
+
if !@cf.container_exists?(@opts.options.container)
|
92
|
+
if create_container
|
93
|
+
show_verbose "Container '#{@opts.options.container}' does not exist. Creating it...", false
|
94
|
+
@cf.create_container(@opts.options.container)
|
95
|
+
show_verbose " done."
|
96
|
+
else
|
97
|
+
show_error("Error: Container '#{@opts.options.container}' does not exist.")
|
98
|
+
end
|
85
99
|
end
|
86
100
|
|
87
101
|
@container = @cf.container(@opts.options.container)
|
88
|
-
|
89
|
-
end # prepConnection()
|
102
|
+
end # prep_cnnection()
|
90
103
|
|
91
|
-
def
|
92
|
-
|
104
|
+
def push_piped_data
|
105
|
+
prep_container
|
106
|
+
|
107
|
+
puts "Warning: 5GB maximum filesize"
|
93
108
|
object = @container.create_object(@opts.options.remote_path, true)
|
94
109
|
object.write("STDIN")
|
95
|
-
end
|
110
|
+
end # push_piped_data()
|
96
111
|
|
97
|
-
def
|
112
|
+
def push_files
|
113
|
+
prep_container
|
98
114
|
|
99
115
|
path = @opts.options.local_path
|
100
|
-
|
116
|
+
pwd = Dir.getwd # Save current directory so we can come back
|
117
|
+
|
101
118
|
if FileTest::file?(path)
|
102
|
-
Dir.chdir(File::dirname(path))
|
103
119
|
glob_options = File.join(File::basename(path))
|
104
120
|
elsif @opts.options.recursive
|
105
121
|
Dir.chdir(path)
|
@@ -111,41 +127,173 @@ class CFBackup
|
|
111
127
|
files = Dir.glob(glob_options)
|
112
128
|
|
113
129
|
# Upload file(s)
|
114
|
-
|
130
|
+
counter = 1
|
131
|
+
show_verbose "There are #{files.length} files to process."
|
132
|
+
files.each do |file|
|
115
133
|
file = file.sub(/\.\//, '')
|
116
134
|
if file == "" || file[0,1] == "." || FileTest.directory?(file)
|
135
|
+
show_verbose "(#{counter}/#{files.length}) Skipping #{file}"
|
136
|
+
counter += 1
|
117
137
|
next
|
118
138
|
end
|
119
139
|
|
120
|
-
show_verbose "
|
121
|
-
|
140
|
+
show_verbose "(#{counter}/#{files.length}) Pushing file #{file}...", false
|
141
|
+
|
142
|
+
if @opts.options.remote_path.to_s == ''
|
143
|
+
remote_path = file
|
144
|
+
else
|
145
|
+
remote_path = File.join(@opts.options.remote_path, file)
|
146
|
+
end
|
147
|
+
|
148
|
+
object = @container.create_object(remote_path, true)
|
122
149
|
object.load_from_filename(file)
|
150
|
+
|
123
151
|
show_verbose " done."
|
152
|
+
counter += 1
|
124
153
|
end # files.each
|
125
154
|
|
126
|
-
|
155
|
+
Dir.chdir(pwd) # Go back to original directory
|
156
|
+
|
157
|
+
end # push_files()
|
158
|
+
|
159
|
+
def pull_files
|
160
|
+
prep_container(false)
|
161
|
+
|
162
|
+
file = object_file?
|
163
|
+
objects = get_objects_array
|
164
|
+
|
165
|
+
# Process objects
|
166
|
+
counter = 1
|
167
|
+
show_verbose "There are #{objects.length} objects to process."
|
168
|
+
objects.each do |object_name|
|
169
|
+
object = @container.object(object_name)
|
170
|
+
if object.content_type == "application/directory"
|
171
|
+
show_verbose "(#{counter}/#{objects.length}) Pseudo directory #{object.name}"
|
172
|
+
counter += 1
|
173
|
+
next
|
174
|
+
end
|
175
|
+
|
176
|
+
path_info = File.split(@opts.options.local_path.to_s)
|
177
|
+
file_info = File.split(object.name.to_s)
|
178
|
+
|
179
|
+
if file # Dealing with a single file pull
|
180
|
+
if @opts.options.local_path.to_s == ''
|
181
|
+
filepath = file_info[1].to_s # Use current directory and original name
|
182
|
+
else
|
183
|
+
if File.exist?(@opts.options.local_path.to_s)
|
184
|
+
# The file exists, so we will overwrite it
|
185
|
+
filepath = File.join(@opts.options.local_path.to_s)
|
186
|
+
else
|
187
|
+
# If the file doesn't exist, a new name may have been given.
|
188
|
+
# Test the path.
|
189
|
+
if File.exist?(path_info[0])
|
190
|
+
# A new name was given with a valid path
|
191
|
+
filepath = File.join(path_info[0], path_info[1])
|
192
|
+
else
|
193
|
+
# The given path is not valid
|
194
|
+
show_error("cfbackup: #{file_info[0]}: No such file or directory.")
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
else # Dealing with a multi-object pull
|
199
|
+
if @opts.options.local_path.to_s == ''
|
200
|
+
filepath = object.name.to_s # Use current directory with object name
|
201
|
+
dir_path = file_info[0]
|
202
|
+
else
|
203
|
+
if File.directory?(@opts.options.local_path.to_s)
|
204
|
+
filepath = File.join(@opts.options.local_path.to_s, object.name.to_s)
|
205
|
+
dir_path = File.join(@opts.options.local_path, file_info[0])
|
206
|
+
else
|
207
|
+
# We can't copy a directory to a file...
|
208
|
+
show_error("cfbackup: #{@container.name}:#{@opts.options.remote_path.to_s}/ is a directory (not copied).")
|
209
|
+
end
|
210
|
+
end
|
211
|
+
File.makedirs(dir_path) # Create subdirectories as needed
|
212
|
+
end
|
213
|
+
|
214
|
+
show_verbose "(#{counter}/#{objects.length}) Pulling object #{object.name}...", false
|
215
|
+
object.save_to_filename(filepath)
|
216
|
+
show_verbose " done"
|
217
|
+
counter += 1
|
218
|
+
end
|
219
|
+
end # pull_files()
|
220
|
+
|
221
|
+
def delete_files
|
222
|
+
prep_container(false)
|
223
|
+
|
224
|
+
if object_file?
|
225
|
+
show_verbose "Deleting object #{@opts.options.remote_path.to_s}"
|
226
|
+
@container.delete_object(@opts.options.remote_path.to_s)
|
227
|
+
else
|
228
|
+
if !@opts.options.recursive
|
229
|
+
show_error("Error: #{@opts.options.remote_path} is a directory but the the recursive option was not specified. Doing nothing.")
|
230
|
+
else
|
231
|
+
objects = get_objects_array
|
232
|
+
|
233
|
+
# Process objects
|
234
|
+
counter = 1
|
235
|
+
show_verbose "There are #{objects.length} objects to process."
|
236
|
+
objects.each do |object_name|
|
237
|
+
show_verbose "(#{counter}/#{objects.length}) Deleting object #{object_name}...", false
|
238
|
+
@container.delete_object(object_name)
|
239
|
+
show_verbose " done"
|
240
|
+
counter += 1
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
end # delete_files()
|
246
|
+
|
247
|
+
|
248
|
+
# Helper methods below
|
249
|
+
|
250
|
+
def object_file?
|
251
|
+
|
252
|
+
file = false
|
253
|
+
unless @opts.options.remote_path.to_s == ''
|
254
|
+
if @container.object_exists?(@opts.options.remote_path)
|
255
|
+
if @container.object(@opts.options.remote_path).content_type != "application/directory"
|
256
|
+
file = true
|
257
|
+
if @opts.options.recursive
|
258
|
+
puts "Warning: This is a file so the recursive option is meaningless."
|
259
|
+
end
|
260
|
+
end
|
261
|
+
else
|
262
|
+
show_error("The object #{@opts.options.remote_path} does not exist")
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
return file
|
267
|
+
end
|
127
268
|
|
128
|
-
def
|
269
|
+
def get_objects_array
|
129
270
|
|
130
|
-
|
131
|
-
# We have to do a bit of fancy footwork to make directories work
|
132
|
-
puts "Oops! Restore hasn't been implemented yet. Help me out and submit a patch :-)"
|
271
|
+
file = object_file?
|
133
272
|
|
134
|
-
|
273
|
+
# Get array of objects to process
|
274
|
+
objects = Array.new
|
275
|
+
if file
|
276
|
+
objects << @opts.options.remote_path.to_s
|
277
|
+
elsif @opts.options.recursive
|
278
|
+
# Use prefix instead of path so that "subdirectories" are included
|
279
|
+
objects = @container.objects(:prefix => @opts.options.remote_path)
|
280
|
+
else
|
281
|
+
objects = @container.objects(:path => @opts.options.remote_path)
|
282
|
+
end
|
283
|
+
|
284
|
+
return objects
|
285
|
+
end
|
135
286
|
|
136
287
|
# Shows given message if verbose output is turned on
|
137
288
|
def show_verbose(message, line_break = true)
|
138
|
-
|
139
289
|
unless !@opts.options.verbose
|
140
290
|
if line_break
|
141
291
|
puts message
|
142
292
|
else
|
143
293
|
print message
|
144
294
|
end
|
145
|
-
|
146
295
|
$stdout.flush
|
147
296
|
end
|
148
|
-
|
149
297
|
end # show_verbose()
|
150
298
|
|
151
299
|
# Show error message, banner and exit
|
@@ -155,8 +303,4 @@ class CFBackup
|
|
155
303
|
exit
|
156
304
|
end # show_error()
|
157
305
|
|
158
|
-
def parse_container_path(container)
|
159
|
-
# Split based on :
|
160
|
-
end # parse_container_path()
|
161
|
-
|
162
306
|
end # class CFBackup
|
data/test/cfbackup_test.rb
CHANGED
@@ -1,7 +1,107 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
3
|
class CfbackupTest < Test::Unit::TestCase
|
4
|
-
|
5
|
-
|
4
|
+
TEST_DIR = 'test/tmp'
|
5
|
+
|
6
|
+
context "A backup" do
|
7
|
+
|
8
|
+
context "with a single file push" do
|
9
|
+
setup do
|
10
|
+
mock_ARGV = ['--action', 'push', '--local_path', 'test/data/data.txt', '--container', 'test', '--config_file', 'test/cfconfig.yml', '-v']
|
11
|
+
@backup = CFBackup.new(mock_ARGV)
|
12
|
+
end
|
13
|
+
|
14
|
+
should "return true when file sucessfully sent" do
|
15
|
+
assert @backup.run
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context "with a recursive directory push" do
|
20
|
+
setup do
|
21
|
+
mock_ARGV = ['--action', 'push', '-r', '--local_path', 'test/data', '--container', 'test', '--config_file', 'test/cfconfig.yml', '-v']
|
22
|
+
@backup = CFBackup.new(mock_ARGV)
|
23
|
+
end
|
24
|
+
|
25
|
+
should "return true when all files/directories successfully sent" do
|
26
|
+
assert @backup.run
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
context "A restore" do
|
33
|
+
|
34
|
+
context "with a single file pull" do
|
35
|
+
file = 'data.txt'
|
36
|
+
filepath = File.join(TEST_DIR, file)
|
37
|
+
|
38
|
+
setup do
|
39
|
+
mock_ARGV = ['--action', 'pull', '--container', "test:#{file}", '--local_path', "#{filepath}", '--config_file', 'test/cfconfig.yml', '-v']
|
40
|
+
@backup = CFBackup.new(mock_ARGV)
|
41
|
+
end
|
42
|
+
|
43
|
+
should "return true when file succesfully pulled" do
|
44
|
+
assert @backup.run
|
45
|
+
end
|
46
|
+
|
47
|
+
# I don't know why this doesn't work. It's like File is caching results
|
48
|
+
# and not updating until the applicaiton exists. Overcoming by
|
49
|
+
# asserting the file deletion during teardown at the loss of shoulda
|
50
|
+
#
|
51
|
+
# should "result in test/tmp/#{file} existing" do
|
52
|
+
# assert File.exist?(filepath)
|
53
|
+
# end
|
54
|
+
|
55
|
+
teardown do
|
56
|
+
assert File.delete(filepath)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
context "with a recursive pull" do
|
61
|
+
setup do
|
62
|
+
mock_ARGV = ['--action', 'pull', '--container', "test", '--local_path', "test/tmp", '--config_file', 'test/cfconfig.yml', '-v']
|
63
|
+
@backup = CFBackup.new(mock_ARGV)
|
64
|
+
end
|
65
|
+
|
66
|
+
should "return true when all files pulled" do
|
67
|
+
assert @backup.run
|
68
|
+
end
|
69
|
+
|
70
|
+
# Todo compare directories
|
71
|
+
|
72
|
+
teardown do
|
73
|
+
system "rm -rf test/tmp/*"
|
74
|
+
# I didn't feel safe with TEST_DIR + '/*'
|
75
|
+
# Disaster waiting to happen. rm -rf is already bad enough.
|
76
|
+
end
|
77
|
+
end # context "A recursive pull"
|
78
|
+
|
6
79
|
end
|
80
|
+
|
81
|
+
context "A deletion" do
|
82
|
+
|
83
|
+
context "of a single file" do
|
84
|
+
setup do
|
85
|
+
mock_ARGV = ['--action', 'delete', '--container', "test:folder_1/file1.txt", '--config_file', 'test/cfconfig.yml', '-v']
|
86
|
+
@backup = CFBackup.new(mock_ARGV)
|
87
|
+
end
|
88
|
+
|
89
|
+
should "return true when file deleted" do
|
90
|
+
assert @backup.run
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
context "of a pseudo directory" do
|
95
|
+
setup do
|
96
|
+
mock_ARGV = ['--action', 'delete', '-r', '--container', "test:folder_2", '--config_file', 'test/cfconfig.yml', '-v']
|
97
|
+
@backup = CFBackup.new(mock_ARGV)
|
98
|
+
end
|
99
|
+
|
100
|
+
should "return true when directory deleted" do
|
101
|
+
assert @backup.run
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
end # context "A deletion"
|
106
|
+
|
7
107
|
end
|
data/test/cfconfig.yml
ADDED
File without changes
|
data/test/test_helper.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jmstacey-cfbackup
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jon Stacey
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-05-03 00:00:00 -07:00
|
13
13
|
default_executable: cfbackup
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -41,7 +41,13 @@ files:
|
|
41
41
|
- lib/OptCFBackup.rb
|
42
42
|
- lib/cfbackup.rb
|
43
43
|
- test/cfbackup_test.rb
|
44
|
-
- test/
|
44
|
+
- test/cfconfig.yml
|
45
|
+
- test/data/data.txt
|
46
|
+
- test/data/folder_1/file1.txt
|
47
|
+
- test/data/folder_1/file2.txt
|
48
|
+
- test/data/folder_1/folder_3/file1.txt
|
49
|
+
- test/data/folder_2/file1.txt
|
50
|
+
- test/data/folder_2/file2.txt
|
45
51
|
- test/test_helper.rb
|
46
52
|
has_rdoc: true
|
47
53
|
homepage: http://github.com/jmstacey/cfbackup
|