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.
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: []