cloudfiles-container-sync 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/README.md +42 -0
  2. data/cloudfiles-container-sync.rb +132 -0
  3. metadata +65 -0
@@ -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
+ [![Tech-Angels](http://media.tumblr.com/tumblr_m5ay3bQiER1qa44ov.png)](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: []