s3cp 0.1.1 → 0.1.2

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.
@@ -1,3 +1,14 @@
1
+ === 0.1.3 / (Pending)
2
+
3
+ === 0.1.2 / 2011-09-29
4
+
5
+ * s3ls now displays entries with s3://@bucket/ prefix (Josh Carver)
6
+ * s3cp now supports passig headers (--headers) (Donnie Flood)
7
+
8
+ === 0.1.1 / 2011-09-22
9
+
10
+ * Added s3mod command (Josh Carver)
11
+
1
12
  === 0.1 / 2011-04-05
2
13
 
3
14
  * First release
@@ -10,11 +10,35 @@ require 's3cp/utils'
10
10
 
11
11
  # Parse arguments
12
12
  options = {}
13
- options[:verbose] = true if $stdout.isatty
13
+ options[:verbose] = $stdout.isatty ? true : false
14
+ options[:headers] = []
14
15
 
15
16
  op = OptionParser.new do |opts|
16
- opts.banner = "s3cp [path]"
17
+ opts.banner = <<-BANNER
18
+ s3cp supports 4 coyping use cases:
19
+ 1. Copy from local machine to S3
20
+ 2. Copy from S3 to local machine
21
+ 3. Copy from S3 to S3
22
+ 4. Copy from local machine to another path on local machine (for completeness)
23
+
24
+ Local to S3:
25
+ s3cp LOCAL_PATH S3_PATH
26
+
27
+ S3 to Local:
28
+ s3cp S3_PATH LOCAL_PATH
29
+
30
+ S3 to S3:
31
+ s3cp S3_PATH S3_PATH2
32
+
33
+ Local to Local:
34
+ s3cp LOCAL_PATH LOCAL_PATH2
35
+
36
+ BANNER
17
37
  opts.separator ''
38
+
39
+ opts.on("-h", '--headers \'Header1: Header1Value\',\'Header2: Header2Value\'', Array, "Headers to set on the item in S3. This can include http headers like \'Content-Type: image/jpg\' or AMZ headers like: \'x-amz-acl: public-read\'" ) do |h|
40
+ options[:headers] = h
41
+ end
18
42
 
19
43
  opts.on("-r", "Recursive mode") do
20
44
  options[:recursive] = true
@@ -52,6 +76,10 @@ if options[:debug]
52
76
  puts "Options: \n#{options.inspect}"
53
77
  end
54
78
 
79
+ if options[:verbose]
80
+ @verbose = true
81
+ end
82
+
55
83
  @bucket = $1
56
84
  @prefix = $2
57
85
 
@@ -78,6 +106,63 @@ def relative(base, path)
78
106
  no_slash(path[base.length..-1])
79
107
  end
80
108
 
109
+ def log(msg)
110
+ puts msg if @verbose
111
+ end
112
+
113
+ def headers_array_to_hash(header_array)
114
+ headers = {}
115
+ header_array.each do |header|
116
+ header_parts = header.split(": ", 2)
117
+ if header_parts.size == 2
118
+ headers[header_parts[0]] = header_parts[1]
119
+ else
120
+ log("Header ignored because of error splitting [#{header}]. Expected colon delimiter; e.g. Header: Value")
121
+ end
122
+ end
123
+ headers
124
+ end
125
+ @headers = headers_array_to_hash(options[:headers])
126
+
127
+ def with_headers(msg)
128
+ unless @headers.empty?
129
+ msg += " with headers:"
130
+ msg += @headers.collect{|k,v| "'#{k}: #{v}'"}.join(", ")
131
+ end
132
+ msg
133
+ end
134
+
135
+ def s3_to_s3(bucket_from, key, bucket_to, dest)
136
+ log(with_headers("Copy s3://#{bucket_from}/#{key} to s3://#{bucket_to}/#{dest}"))
137
+ if @headers.empty?
138
+ @s3.interface.copy(bucket_from, key, bucket_to, dest)
139
+ else
140
+ @s3.interface.copy(bucket_from, key, bucket_to, dest, :copy, @headers)
141
+ end
142
+ end
143
+
144
+ def local_to_s3(bucket_to, key, file)
145
+ log(with_headers("Copy #{file} to s3://#{bucket_to}/#{key}"))
146
+ f = File.open(file)
147
+ begin
148
+ @s3.interface.put(bucket_to, key, f, @headers)
149
+ ensure
150
+ f.close()
151
+ end
152
+ end
153
+
154
+ def s3_to_local(bucket_from, key_from, dest)
155
+ log("Copy s3://#{bucket_from}/#{key_from} to #{dest}")
156
+ f = File.new(dest, File::CREAT|File::RDWR)
157
+ begin
158
+ @s3.interface.get(bucket_from, key_from) do |chunk|
159
+ f.write(chunk)
160
+ end
161
+ ensure
162
+ f.close()
163
+ end
164
+ end
165
+
81
166
  def copy(from, to, options)
82
167
  bucket_from, key_from = S3CP.bucket_and_key(from)
83
168
  bucket_to, key_to = S3CP.bucket_and_key(to)
@@ -95,12 +180,10 @@ def copy(from, to, options)
95
180
  end
96
181
  keys.each do |key|
97
182
  dest = no_slash(key_to) + '/' + relative(key_from, key)
98
- puts "Copy s3://#{bucket_from}/#{key} to s3://#{bucket_to}/#{dest}"
99
- @s3.interface.copy(bucket_from, key, bucket_to, dest)
183
+ s3_to_s3(bucket_from, key, bucket_to, dest)
100
184
  end
101
185
  else
102
- puts "Copy s3://#{bucket_from}/#{key_from} to s3://#{bucket_to}/#{key_to}"
103
- @s3.interface.copy(bucket_from, key_from, bucket_to, key_to)
186
+ s3_to_s3(bucket_from, key_from, bucket_to, key_to)
104
187
  end
105
188
  when :local_to_s3
106
189
  if options[:recursive]
@@ -108,18 +191,10 @@ def copy(from, to, options)
108
191
  files.each do |f|
109
192
  f = File.expand_path(f)
110
193
  key = no_slash(key_to) + '/' + relative(from, f)
111
- puts "Copy #{f} to s3://#{bucket_to}/#{key}"
112
- @s3.interface.put(bucket_to, key, File.open(f))
194
+ local_to_s3(bucket_to, key, f)
113
195
  end
114
196
  else
115
- f = File.expand_path(from)
116
- puts "Copy #{f} to s3://#{bucket_to}/#{key_to}"
117
- f = File.open(f)
118
- begin
119
- @s3.interface.put(bucket_to, key_to, f)
120
- ensure
121
- f.close()
122
- end
197
+ local_to_s3(bucket_to, key_to, File.expand_path(from))
123
198
  end
124
199
  when :s3_to_local
125
200
  if options[:recursive]
@@ -130,31 +205,15 @@ def copy(from, to, options)
130
205
  keys.each do |key|
131
206
  dest = File.expand_path(to) + '/' + relative(key_from, key)
132
207
  dest = File.join(dest, File.basename(key)) if File.directory?(dest)
133
- puts "Copy s3://#{bucket_from}/#{key} to #{dest}"
134
208
  dir = File.dirname(dest)
135
209
  FileUtils.mkdir_p dir unless File.exist? dir
136
210
  fail "Destination path is not a directory: #{dir}" unless File.directory?(dir)
137
- f = File.new(dest, File::CREAT|File::RDWR)
138
- begin
139
- @s3.interface.get(bucket_from, key) do |chunk|
140
- f.write(chunk)
141
- end
142
- ensure
143
- f.close()
144
- end
211
+ s3_to_local(bucket_from, key, dest)
145
212
  end
146
213
  else
147
214
  dest = File.expand_path(to)
148
215
  dest = File.join(dest, File.basename(key_from)) if File.directory?(dest)
149
- puts "Copy s3://#{bucket_from}/#{key_from} to #{dest}"
150
- f = File.new(dest, File::CREAT|File::RDWR)
151
- begin
152
- @s3.interface.get(bucket_from, key_from) do |chunk|
153
- f.write(chunk)
154
- end
155
- ensure
156
- f.close()
157
- end
216
+ s3_to_local(bucket_from, key_from, dest)
158
217
  end
159
218
  when :local_to_local
160
219
  if options[:recursive]
@@ -64,7 +64,7 @@ end
64
64
  rows = 0
65
65
  @s3.interface.incrementally_list_bucket(@bucket, :prefix => @key) do |page|
66
66
  page[:contents].each do |entry|
67
- key = entry[:key]
67
+ key = "s3://#{@bucket}/#{entry[:key]}"
68
68
  last_modified = DateTime.parse(entry[:last_modified])
69
69
  if options[:long_format]
70
70
  puts "#{last_modified.strftime(options[:date_format])} #{key}"
@@ -1,4 +1,4 @@
1
1
 
2
2
  module S3CP
3
- VERSION = "0.1.1"
3
+ VERSION = "0.1.2"
4
4
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: s3cp
3
3
  version: !ruby/object:Gem::Version
4
- hash: 25
4
+ hash: 31
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 1
9
- - 1
10
- version: 0.1.1
9
+ - 2
10
+ version: 0.1.2
11
11
  platform: ruby
12
12
  authors:
13
13
  - Alex Boisvert
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-09-22 00:00:00 Z
18
+ date: 2011-09-29 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  version_requirements: &id001 !ruby/object:Gem::Requirement