cloudfiles-container-sync 0.1.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/README.md +42 -0
- data/cloudfiles-container-sync.rb +132 -0
- metadata +65 -0
data/README.md
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
# cloudfiles-container-sync
|
2
|
+
|
3
|
+
Synchronizes files from a Rackspace Cloudfiles container to another.
|
4
|
+
|
5
|
+
[![Dependency Status][2]][1]
|
6
|
+
|
7
|
+
[1]: https://gemnasium.com/tech-angels/cloudfiles-container-sync
|
8
|
+
[2]: https://gemnasium.com/tech-angels/cloudfiles-container-sync.png
|
9
|
+
|
10
|
+
## Getting started
|
11
|
+
|
12
|
+
Install the cloudfiles-container-sync gem:
|
13
|
+
|
14
|
+
gem install cloudfiles-container-sync
|
15
|
+
|
16
|
+
Use the sync_to method it adds to your Cloudfiles container objects:
|
17
|
+
|
18
|
+
cf = CloudFiles::Connection.new(:username => "your username", :api_key => "your api key")
|
19
|
+
container_source = cf.container('source')
|
20
|
+
container_destination = cf.container('destination')
|
21
|
+
|
22
|
+
container_source.sync_to(container_destination)
|
23
|
+
|
24
|
+
|
25
|
+
## Method arguments
|
26
|
+
|
27
|
+
You can pass arguments to the method through an hash.
|
28
|
+
|
29
|
+
- fast: if true, only files missing in the destination are copied. Good if your files are never updated.
|
30
|
+
|
31
|
+
- filter: a regexp to select files to copy.
|
32
|
+
|
33
|
+
- delete: if true, files in the destination that are not present in the source will be deleted.
|
34
|
+
|
35
|
+
|
36
|
+
## Credits
|
37
|
+
|
38
|
+
Gilbert Roulot @ Tech-angels - http://www.tech-angels.com/
|
39
|
+
|
40
|
+
[](http://www.tech-angels.com)
|
41
|
+
|
42
|
+
|
@@ -0,0 +1,132 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'cloudfiles'
|
3
|
+
require 'thread'
|
4
|
+
require 'set'
|
5
|
+
|
6
|
+
module CloudFilesContainerSync
|
7
|
+
|
8
|
+
# Adapts the data stream to an IO interface to
|
9
|
+
# copy one object into another
|
10
|
+
class ReaderIO
|
11
|
+
attr_reader :bytesize
|
12
|
+
@eof = false
|
13
|
+
|
14
|
+
def initialize(storage_object)
|
15
|
+
@bytesize = storage_object.bytes
|
16
|
+
@buffer = ""
|
17
|
+
@m = Mutex.new
|
18
|
+
@resource = ConditionVariable.new
|
19
|
+
Thread.new do
|
20
|
+
begin
|
21
|
+
storage_object.data_stream do |chunk|
|
22
|
+
@m.synchronize do
|
23
|
+
@buffer += chunk
|
24
|
+
@resource.signal
|
25
|
+
end
|
26
|
+
end
|
27
|
+
@m.synchronize do
|
28
|
+
@eof = true
|
29
|
+
@resource.signal
|
30
|
+
end
|
31
|
+
rescue Exception => ex
|
32
|
+
$stderr.puts("Exception: " + ex.to_s)
|
33
|
+
raise ex
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def read(length=nil, buf=nil)
|
39
|
+
@m.synchronize do
|
40
|
+
if @buffer.size == 0 and not @eof
|
41
|
+
# Wait for more data
|
42
|
+
@resource.wait(@m)
|
43
|
+
end
|
44
|
+
stop = if length.nil?
|
45
|
+
-1
|
46
|
+
else
|
47
|
+
length
|
48
|
+
end
|
49
|
+
result = if @buffer.size == 0
|
50
|
+
nil
|
51
|
+
else
|
52
|
+
@buffer[0..stop]
|
53
|
+
end
|
54
|
+
@buffer = @buffer[stop..-1] || ""
|
55
|
+
buf = result unless buf.nil?
|
56
|
+
result
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
module CloudFiles
|
63
|
+
class Container
|
64
|
+
|
65
|
+
# Sync this container to the target container
|
66
|
+
# options:
|
67
|
+
# :delete : if true files in the target that don't exist in source will be deleted
|
68
|
+
# :fast : don't compare last modification date or size, assume files are never modified in the source.
|
69
|
+
# :filter : a regexp to select which file to synchronize
|
70
|
+
def sync_to(target, options={})
|
71
|
+
filter = options[:filter] || //
|
72
|
+
self.populate
|
73
|
+
target.populate
|
74
|
+
|
75
|
+
# Don't sync to same container
|
76
|
+
if (self.connection == target.connection and self.name == target.name)
|
77
|
+
raise "Can't sync to the same container: %s to %s" % [self.name, target.name]
|
78
|
+
end
|
79
|
+
|
80
|
+
target_objects = Set.new(target.objects())
|
81
|
+
source_objects = Set.new(self.objects().select{|name| filter =~ name})
|
82
|
+
source_objects.each do |object_name|
|
83
|
+
# Unfreeze
|
84
|
+
object_name = object_name.dup
|
85
|
+
exists = target_objects.include?(object_name)
|
86
|
+
begin
|
87
|
+
next if exists and options[:fast] == true
|
88
|
+
source_object = self.object(object_name)
|
89
|
+
source_metadata = source_object.metadata
|
90
|
+
content_type = source_object.content_type
|
91
|
+
target_object = target.create_object(object_name)
|
92
|
+
if !exists or (options[:fast] != true and (target_object.last_modified.nil? or target_object.last_modified < source_object.last_modified or target_object.bytes != source_object.bytes)) then
|
93
|
+
begin
|
94
|
+
print("Syncing #{object_name}.. ")
|
95
|
+
if source_object.container.connection == target_object.container.connection
|
96
|
+
# Same connection, use the copy function
|
97
|
+
source_object.copy(:container => target.name)
|
98
|
+
print("done (using copy).\n")
|
99
|
+
else
|
100
|
+
# Download and upload the data to copy
|
101
|
+
io = CloudFilesContainerSync::ReaderIO.new(source_object)
|
102
|
+
target_object.write(io, { 'Content-Type' => content_type })
|
103
|
+
# Copy the metadata too
|
104
|
+
target_object.set_metadata(source_metadata)
|
105
|
+
print("done (downloaded/uploaded).")
|
106
|
+
end
|
107
|
+
ensure
|
108
|
+
print("\n")
|
109
|
+
end
|
110
|
+
end
|
111
|
+
rescue NoSuchObjectException => ex
|
112
|
+
$stderr.print("Failed syncing %s: No such object.\n" % [object_name])
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
if options[:delete] then
|
117
|
+
# Delete files that don't exist in the source container
|
118
|
+
to_delete = target_objects - source_objects
|
119
|
+
to_delete.each do |object_name|
|
120
|
+
begin
|
121
|
+
target.delete_object(object_name)
|
122
|
+
print("Deleted %s\n" % [object_name])
|
123
|
+
rescue NoSuchObjectException => ex
|
124
|
+
$stderr.print("Failed deleting %s: No such object.\n" % [object_name])
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
|
metadata
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cloudfiles-container-sync
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Gilbert Roulot
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-11-12 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: cloudfiles
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 1.5.0.1
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 1.5.0.1
|
30
|
+
description: Adds a method to Rackspace Cloudfiles containers to synchronize files
|
31
|
+
from a container to another.
|
32
|
+
email: gilbert.roulot@tech-angels.com
|
33
|
+
executables: []
|
34
|
+
extensions: []
|
35
|
+
extra_rdoc_files: []
|
36
|
+
files:
|
37
|
+
- README.md
|
38
|
+
- cloudfiles-container-sync.rb
|
39
|
+
homepage: https://github.com/tech-angels/cloudfiles-container-sync
|
40
|
+
licenses:
|
41
|
+
- MIT
|
42
|
+
post_install_message:
|
43
|
+
rdoc_options: []
|
44
|
+
require_paths:
|
45
|
+
- .
|
46
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
47
|
+
none: false
|
48
|
+
requirements:
|
49
|
+
- - ! '>='
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: '0'
|
52
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ! '>='
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: '0'
|
58
|
+
requirements: []
|
59
|
+
rubyforge_project:
|
60
|
+
rubygems_version: 1.8.24
|
61
|
+
signing_key:
|
62
|
+
specification_version: 3
|
63
|
+
summary: Adds a method to Rackspace Cloudfiles containers to synchronize files from
|
64
|
+
a container to another.
|
65
|
+
test_files: []
|