jmstacey-cfbackup 0.5.0 → 0.6.0
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/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
|