heroku_hatchet 0.0.2 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +14 -0
- data/CHANGELOG.md +4 -0
- data/README.md +2 -2
- data/Rakefile +6 -0
- data/hatchet.gemspec +3 -1
- data/hatchet.json +3 -2
- data/lib/hatchet.rb +2 -0
- data/lib/hatchet/anvil_app.rb +28 -18
- data/lib/hatchet/app.rb +19 -5
- data/lib/hatchet/git_app.rb +5 -2
- data/lib/hatchet/tasks.rb +17 -7
- data/lib/hatchet/version.rb +1 -1
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/.gitignore +4 -0
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/CHANGELOG.md +378 -0
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/Gemfile +10 -0
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/LICENSE +9 -0
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/README.md +192 -0
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/Rakefile +358 -0
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/bin/compile +13 -0
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/bin/detect +12 -0
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/bin/release +9 -0
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/hatchet.json +25 -0
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/lib/language_pack.rb +27 -0
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/lib/language_pack/base.rb +175 -0
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/lib/language_pack/bundler_lockfile.rb +19 -0
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/lib/language_pack/disable_deploys.rb +17 -0
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/lib/language_pack/no_lockfile.rb +16 -0
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/lib/language_pack/rack.rb +43 -0
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/lib/language_pack/rails2.rb +91 -0
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/lib/language_pack/rails3.rb +86 -0
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/lib/language_pack/rails4.rb +66 -0
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/lib/language_pack/ruby.rb +681 -0
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/lib/language_pack/shell_helpers.rb +62 -0
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/spec/bugs_spec.rb +11 -0
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/spec/no_lockfile_spec.rb +10 -0
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/spec/rails23_spec.rb +11 -0
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/spec/rails3_spec.rb +22 -0
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/spec/rails4_spec.rb +12 -0
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/spec/rubies_spec.rb +38 -0
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/spec/spec_helper.rb +35 -0
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/support/s3/hmac +79 -0
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/support/s3/s3 +223 -0
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/vendor/syck_hack.rb +64 -0
- data/test/hatchet/allow_failure_anvil_test.rb +21 -0
- data/test/hatchet/allow_failure_git_test.rb +17 -0
- data/test/hatchet/anvil_test.rb +7 -7
- data/test/hatchet/config_test.rb +4 -2
- data/test/hatchet/git_test.rb +2 -2
- metadata +89 -8
@@ -0,0 +1,62 @@
|
|
1
|
+
module LanguagePack
|
2
|
+
module ShellHelpers
|
3
|
+
# display error message and stop the build process
|
4
|
+
# @param [String] error message
|
5
|
+
def error(message)
|
6
|
+
Kernel.puts " !"
|
7
|
+
message.split("\n").each do |line|
|
8
|
+
Kernel.puts " ! #{line.strip}"
|
9
|
+
end
|
10
|
+
Kernel.puts " !"
|
11
|
+
log "exit", :error => message
|
12
|
+
exit 1
|
13
|
+
end
|
14
|
+
|
15
|
+
# run a shell comannd and pipe stderr to stdout
|
16
|
+
# @param [String] command to be run
|
17
|
+
# @return [String] output of stdout and stderr
|
18
|
+
def run(command)
|
19
|
+
%x{ #{command} 2>&1 }
|
20
|
+
end
|
21
|
+
|
22
|
+
# run a shell command and pipe stderr to /dev/null
|
23
|
+
# @param [String] command to be run
|
24
|
+
# @return [String] output of stdout
|
25
|
+
def run_stdout(command)
|
26
|
+
%x{ #{command} 2>/dev/null }
|
27
|
+
end
|
28
|
+
|
29
|
+
# run a shell command and stream the output
|
30
|
+
# @param [String] command to be run
|
31
|
+
def pipe(command)
|
32
|
+
output = ""
|
33
|
+
IO.popen(command) do |io|
|
34
|
+
until io.eof?
|
35
|
+
buffer = io.gets
|
36
|
+
output << buffer
|
37
|
+
puts buffer
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
output
|
42
|
+
end
|
43
|
+
|
44
|
+
# display a topic message
|
45
|
+
# (denoted by ----->)
|
46
|
+
# @param [String] topic message to be displayed
|
47
|
+
def topic(message)
|
48
|
+
Kernel.puts "-----> #{message}"
|
49
|
+
$stdout.flush
|
50
|
+
end
|
51
|
+
|
52
|
+
# display a message in line
|
53
|
+
# (indented by 6 spaces)
|
54
|
+
# @param [String] message to be displayed
|
55
|
+
def puts(message)
|
56
|
+
message.split("\n").each do |line|
|
57
|
+
super " #{line.strip}"
|
58
|
+
end
|
59
|
+
$stdout.flush
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
|
3
|
+
describe "Bugs" do
|
4
|
+
context "MRI 1.8.7" do
|
5
|
+
it "should install nokogiri" do
|
6
|
+
Hatchet::AnvilApp.new("mri_187_nokogiri", :buildpack => buildpack).deploy do |app, heroku, output|
|
7
|
+
expect(app).to be_deployed
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "No Lockfile" do
|
4
|
+
it "should not deploy" do
|
5
|
+
Hatchet::AnvilApp.new("no_lockfile", :buildpack => buildpack).deploy do |app, heroku, output|
|
6
|
+
expect(app).not_to be_deployed
|
7
|
+
expect(output).to include("ERROR: Gemfile.lock required")
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
|
3
|
+
describe "Rails 2.3.x" do
|
4
|
+
it "should deploy on ruby 1.8.7" do
|
5
|
+
Hatchet::AnvilApp.new("rails23_mri_187", :buildpack => buildpack).deploy do |app, heroku|
|
6
|
+
add_database(app, heroku)
|
7
|
+
expect(app).to be_deployed
|
8
|
+
expect(successful_body(app)).to eq("hello")
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
|
3
|
+
describe "Rails 3.x" do
|
4
|
+
it "should deploy on ruby 1.9.3" do
|
5
|
+
Hatchet::AnvilApp.new("rails3_mri_193", :buildpack => buildpack).deploy do |app, heroku|
|
6
|
+
add_database(app, heroku)
|
7
|
+
expect(app).to be_deployed
|
8
|
+
expect(successful_body(app)).to eq("hello")
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
context "when not using the rails gem" do
|
13
|
+
it "should deploy on ruby 1.9.3" do
|
14
|
+
Hatchet::AnvilApp.new("railties3_mri_193", :buildpack => buildpack).deploy do |app, heroku, output|
|
15
|
+
add_database(app, heroku)
|
16
|
+
expect(app).to be_deployed
|
17
|
+
expect(output).to match("Ruby/Rails")
|
18
|
+
expect(successful_body(app)).to eq("hello")
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
|
3
|
+
describe "Rails 4.x" do
|
4
|
+
it "should deploy on ruby 1.9.3" do
|
5
|
+
Hatchet::AnvilApp.new("rails4-manifest", :buildpack => buildpack).deploy do |app, heroku, output|
|
6
|
+
add_database(app, heroku)
|
7
|
+
expect(app).to be_deployed
|
8
|
+
expect(output).to include("Detected manifest file, assuming assets were compiled locally")
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
|
3
|
+
describe "Ruby Versions" do
|
4
|
+
it "should deploy ruby 1.8.7 properly" do
|
5
|
+
Hatchet::AnvilApp.new("mri_187", :buildpack => buildpack).deploy do |app, heroku, output|
|
6
|
+
expect(app).to be_deployed
|
7
|
+
expect(successful_body(app)).to match("ruby 1.8.7")
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should deploy ruby 1.9.2 properly" do
|
12
|
+
Hatchet::AnvilApp.new("mri_192", :buildpack => buildpack).deploy do |app, heroku, output|
|
13
|
+
expect(app).to be_deployed
|
14
|
+
expect(successful_body(app)).to match("ruby 1.9.2")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should deploy ruby 1.9.2 properly (git)" do
|
19
|
+
Hatchet::GitApp.new("mri_192", :buildpack => git_repo).deploy do |app, heroku, output|
|
20
|
+
expect(app).to be_deployed
|
21
|
+
expect(successful_body(app)).to match("ruby 1.9.2")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should deploy ruby 1.9.3 properly" do
|
26
|
+
Hatchet::AnvilApp.new("mri_193", :buildpack => buildpack).deploy do |app, heroku, output|
|
27
|
+
expect(app).to be_deployed
|
28
|
+
expect(successful_body(app)).to match("ruby 1.9.3")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should deploy ruby 2.0.0 properly" do
|
33
|
+
Hatchet::AnvilApp.new("mri_200", :buildpack => buildpack).deploy do |app, heroku|
|
34
|
+
expect(app).to be_deployed
|
35
|
+
expect(successful_body(app)).to match("ruby 2.0.0")
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'rspec/core'
|
2
|
+
require 'hatchet'
|
3
|
+
require 'fileutils'
|
4
|
+
require 'hatchet'
|
5
|
+
|
6
|
+
ENV['RACK_ENV'] = 'test'
|
7
|
+
|
8
|
+
RSpec.configure do |config|
|
9
|
+
config.filter_run :focused => true
|
10
|
+
config.run_all_when_everything_filtered = true
|
11
|
+
config.alias_example_to :fit, :focused => true
|
12
|
+
|
13
|
+
config.expect_with :rspec do |c|
|
14
|
+
c.syntax = :expect
|
15
|
+
end
|
16
|
+
config.mock_with :none
|
17
|
+
end
|
18
|
+
|
19
|
+
def buildpack
|
20
|
+
File.expand_path(File.dirname(__FILE__) + "/..")
|
21
|
+
end
|
22
|
+
|
23
|
+
def git_repo
|
24
|
+
"https://github.com/heroku/heroku-buildpack-ruby.git"
|
25
|
+
end
|
26
|
+
|
27
|
+
def add_database(app, heroku)
|
28
|
+
heroku.post_addon(app.name, 'heroku-postgresql:dev')
|
29
|
+
_, value = heroku.get_config_vars(app.name).body.detect {|key, value| key.match(/HEROKU_POSTGRESQL_[A-Z]+_URL/) }
|
30
|
+
heroku.put_config_vars(app.name, 'DATABASE_URL' => value)
|
31
|
+
end
|
32
|
+
|
33
|
+
def successful_body(app)
|
34
|
+
Excon.get("http://#{app.name}.herokuapp.com", :idempotent => true, :expects => 200, :retry_limit => 10).body
|
35
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
# Implement HMAC functionality on top of the OpenSSL digest functions.
|
3
|
+
# licensed under the terms of the GNU GPL v2
|
4
|
+
# Copyright 2007 Victor Lowther <victor.lowther@gmail.com>
|
5
|
+
|
6
|
+
die() {
|
7
|
+
echo $*
|
8
|
+
exit 1
|
9
|
+
}
|
10
|
+
|
11
|
+
check_deps() {
|
12
|
+
local res=0
|
13
|
+
while [ $# -ne 0 ]; do
|
14
|
+
which "${1}" >& /dev/null || { res=1; echo "${1} not found."; }
|
15
|
+
shift
|
16
|
+
done
|
17
|
+
(( res == 0 )) || die "aborting."
|
18
|
+
}
|
19
|
+
|
20
|
+
# write a byte (passed as hex) to stdout
|
21
|
+
write_byte() {
|
22
|
+
# $1 = byte to write
|
23
|
+
printf "\\x$(printf "%x" ${1})"
|
24
|
+
}
|
25
|
+
|
26
|
+
# make an hmac pad out of a key.
|
27
|
+
# this is not the most secure way of doing it, but it is
|
28
|
+
# the most expedient.
|
29
|
+
make_hmac_pad() {
|
30
|
+
# using key in file $1 and byte in $2, create the appropriate hmac pad
|
31
|
+
# Pad keys out to $3 bytes
|
32
|
+
# if key is longer than $3, use hash $4 to hash the key first.
|
33
|
+
local x y a size remainder oifs
|
34
|
+
(( remainder = ${3} ))
|
35
|
+
# in case someone else was messing with IFS.
|
36
|
+
for x in $(echo -n "${1}" | od -v -t u1 | cut -b 9-);
|
37
|
+
do
|
38
|
+
write_byte $((${x} ^ ${2}))
|
39
|
+
(( remainder -= 1 ))
|
40
|
+
done
|
41
|
+
for ((y=0; remainder - y ;y++)); do
|
42
|
+
write_byte $((0 ^ ${2}))
|
43
|
+
done
|
44
|
+
}
|
45
|
+
|
46
|
+
# utility functions for making hmac pads
|
47
|
+
hmac_ipad() {
|
48
|
+
make_hmac_pad "${1}" 0x36 ${2} "${3}"
|
49
|
+
}
|
50
|
+
|
51
|
+
hmac_opad() {
|
52
|
+
make_hmac_pad "${1}" 0x5c ${2} "${3}"
|
53
|
+
}
|
54
|
+
|
55
|
+
# hmac something
|
56
|
+
do_hmac() {
|
57
|
+
# $1 = algo to use. Must be one that openssl knows about
|
58
|
+
# $2 = keyfile to use
|
59
|
+
# $3 = file to hash. uses stdin if none is given.
|
60
|
+
# accepts input on stdin, leaves it on stdout.
|
61
|
+
# Output is binary, if you want something else pipe it accordingly.
|
62
|
+
local blocklen keysize x
|
63
|
+
case "${1}" in
|
64
|
+
sha) blocklen=64 ;;
|
65
|
+
sha1) blocklen=64 ;;
|
66
|
+
md5) blocklen=64 ;;
|
67
|
+
md4) blocklen=64 ;;
|
68
|
+
sha256) blocklen=64 ;;
|
69
|
+
sha512) blocklen=128 ;;
|
70
|
+
*) die "Unknown hash ${1} passed to hmac!" ;;
|
71
|
+
esac
|
72
|
+
cat <(hmac_ipad ${2} ${blocklen} "${1}") "${3:--}" | openssl dgst "-${1}" -binary | \
|
73
|
+
cat <(hmac_opad ${2} ${blocklen} "${1}") - | openssl dgst "-${1}" -binary
|
74
|
+
}
|
75
|
+
|
76
|
+
[[ ${1} ]] || die "Must pass the name of the hash function to use to ${0}".
|
77
|
+
|
78
|
+
check_deps od openssl
|
79
|
+
do_hmac "${@}"
|
@@ -0,0 +1,223 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
# basic amazon s3 operations
|
3
|
+
# Licensed under the terms of the GNU GPL v2
|
4
|
+
# Copyright 2007 Victor Lowther <victor.lowther@gmail.com>
|
5
|
+
|
6
|
+
set -e
|
7
|
+
|
8
|
+
basedir="$( cd -P "$( dirname "$0" )" && pwd )"
|
9
|
+
PATH="$basedir:$PATH"
|
10
|
+
|
11
|
+
# print a message and bail
|
12
|
+
die() {
|
13
|
+
echo $*
|
14
|
+
exit 1
|
15
|
+
}
|
16
|
+
|
17
|
+
# check to see if the variable name passed exists and holds a value.
|
18
|
+
# Die if it does not.
|
19
|
+
check_or_die() {
|
20
|
+
[[ ${!1} ]] || die "Environment variable ${1} is not set."
|
21
|
+
}
|
22
|
+
|
23
|
+
# check to see if we have all the needed S3 variables defined.
|
24
|
+
# Bail if we do not.
|
25
|
+
check_s3() {
|
26
|
+
local sak x
|
27
|
+
for x in S3_ACCESS_KEY_ID S3_SECRET_ACCESS_KEY; do
|
28
|
+
check_or_die ${x};
|
29
|
+
done
|
30
|
+
sak="$(echo -n $S3_SECRET_ACCESS_KEY | wc -c)"
|
31
|
+
(( ${sak%%[!0-9 ]*} == 40 )) || \
|
32
|
+
die "S3 Secret Access Key is not exactly 40 bytes long. Please fix it."
|
33
|
+
}
|
34
|
+
# check to see if our external dependencies exist
|
35
|
+
check_dep() {
|
36
|
+
local res=0
|
37
|
+
while [[ $# -ne 0 ]]; do
|
38
|
+
which "${1}" >& /dev/null || { res=1; echo "${1} not found."; }
|
39
|
+
shift
|
40
|
+
done
|
41
|
+
(( res == 0 )) || die "aborting."
|
42
|
+
}
|
43
|
+
|
44
|
+
check_deps() {
|
45
|
+
check_dep openssl date hmac cat grep curl
|
46
|
+
check_s3
|
47
|
+
}
|
48
|
+
|
49
|
+
urlenc() {
|
50
|
+
# $1 = string to url encode
|
51
|
+
# output is on stdout
|
52
|
+
# we don't urlencode everything, just enough stuff.
|
53
|
+
echo -n "${1}" |
|
54
|
+
sed 's/%/%25/g
|
55
|
+
s/ /%20/g
|
56
|
+
s/#/%23/g
|
57
|
+
s/\$/%24/g
|
58
|
+
s/\&/%26/g
|
59
|
+
s/+/%2b/g
|
60
|
+
s/,/%2c/g
|
61
|
+
s/:/%3a/g
|
62
|
+
s/;/%3b/g
|
63
|
+
s/?/%3f/g
|
64
|
+
s/@/%40/g
|
65
|
+
s/ /%09/g'
|
66
|
+
}
|
67
|
+
|
68
|
+
xmldec() {
|
69
|
+
# no parameters.
|
70
|
+
# accept input on stdin, put it on stdout.
|
71
|
+
# patches accepted to get more stuff
|
72
|
+
sed 's/\"/\"/g
|
73
|
+
s/\&/\&/g
|
74
|
+
s/\</</g
|
75
|
+
s/\>/>/g'
|
76
|
+
}
|
77
|
+
|
78
|
+
## basic S3 functionality. x-amz-header functionality is not implemented.
|
79
|
+
# make an S3 signature string, which will be output on stdout.
|
80
|
+
s3_signature_string() {
|
81
|
+
# $1 = HTTP verb
|
82
|
+
# $2 = date string, must be in UTC
|
83
|
+
# $3 = bucket name, if any
|
84
|
+
# $4 = resource path, if any
|
85
|
+
# $5 = content md5, if any
|
86
|
+
# $6 = content MIME type, if any
|
87
|
+
# $7 = canonicalized headers, if any
|
88
|
+
# signature string will be output on stdout
|
89
|
+
local verr="Must pass a verb to s3_signature_string!"
|
90
|
+
local verb="${1:?verr}"
|
91
|
+
local bucket="${3}"
|
92
|
+
local resource="${4}"
|
93
|
+
local derr="Must pass a date to s3_signature_string!"
|
94
|
+
local date="${2:?derr}"
|
95
|
+
local mime="${6}"
|
96
|
+
local md5="${5}"
|
97
|
+
local headers="${7}"
|
98
|
+
printf "%s\n%s\n%s\n%s\n%s\n%s%s" \
|
99
|
+
"${verb}" "${md5}" "${mime}" "${date}" \
|
100
|
+
"${headers}" "${bucket}" "${resource}" | \
|
101
|
+
hmac sha1 "${S3_SECRET_ACCESS_KEY}" | openssl base64 -e -a
|
102
|
+
}
|
103
|
+
|
104
|
+
# cheesy, but it is the best way to have multiple headers.
|
105
|
+
curl_headers() {
|
106
|
+
# each arg passed will be output on its own line
|
107
|
+
local parms=$#
|
108
|
+
for ((;$#;)); do
|
109
|
+
echo "header = \"${1}\""
|
110
|
+
shift
|
111
|
+
done
|
112
|
+
}
|
113
|
+
|
114
|
+
s3_curl() {
|
115
|
+
# invoke curl to do all the heavy HTTP lifting
|
116
|
+
# $1 = method (one of GET, PUT, or DELETE. HEAD is not handled yet.)
|
117
|
+
# $2 = remote bucket.
|
118
|
+
# $3 = remote name
|
119
|
+
# $4 = local name.
|
120
|
+
local bucket remote date sig md5 arg inout headers
|
121
|
+
# header handling is kinda fugly, but it works.
|
122
|
+
bucket="${2:+/${2}}/" # slashify the bucket
|
123
|
+
remote="$(urlenc "${3}")" # if you don't, strange things may happen.
|
124
|
+
stdopts="--connect-timeout 10 --fail --silent"
|
125
|
+
[[ $CURL_S3_DEBUG == true ]] && stdopts="${stdopts} --show-error --fail"
|
126
|
+
case "${1}" in
|
127
|
+
GET) arg="-o" inout="${4:--}" # stdout if no $4
|
128
|
+
;;
|
129
|
+
PUT) [[ ${2} ]] || die "PUT can has bucket?"
|
130
|
+
if [[ ! ${3} ]]; then
|
131
|
+
arg="-X PUT"
|
132
|
+
headers[${#headers[@]}]="Content-Length: 0"
|
133
|
+
elif [[ -f ${4} ]]; then
|
134
|
+
md5="$(openssl dgst -md5 -binary "${4}"|openssl base64 -e -a)"
|
135
|
+
arg="-T" inout="${4}"
|
136
|
+
headers[${#headers[@]}]="x-amz-acl: public-read"
|
137
|
+
headers[${#headers[@]}]="Expect: 100-continue"
|
138
|
+
else
|
139
|
+
die "Cannot write non-existing file ${4}"
|
140
|
+
fi
|
141
|
+
;;
|
142
|
+
DELETE) arg="-X DELETE"
|
143
|
+
;;
|
144
|
+
HEAD) arg="-I" ;;
|
145
|
+
*) die "Unknown verb ${1}. It probably would not have worked anyways." ;;
|
146
|
+
esac
|
147
|
+
date="$(TZ=UTC date '+%a, %e %b %Y %H:%M:%S %z')"
|
148
|
+
sig=$(s3_signature_string ${1} "${date}" "${bucket}" "${remote}" "${md5}" "" "x-amz-acl:public-read")
|
149
|
+
|
150
|
+
headers[${#headers[@]}]="Authorization: AWS ${S3_ACCESS_KEY_ID}:${sig}"
|
151
|
+
headers[${#headers[@]}]="Date: ${date}"
|
152
|
+
[[ ${md5} ]] && headers[${#headers[@]}]="Content-MD5: ${md5}"
|
153
|
+
curl ${arg} "${inout}" ${stdopts} -o - -K <(curl_headers "${headers[@]}") \
|
154
|
+
"http://s3.amazonaws.com${bucket}${remote}"
|
155
|
+
return $?
|
156
|
+
}
|
157
|
+
|
158
|
+
s3_put() {
|
159
|
+
# $1 = remote bucket to put it into
|
160
|
+
# $2 = remote name to put
|
161
|
+
# $3 = file to put. This must be present if $2 is.
|
162
|
+
s3_curl PUT "${1}" "${2}" "${3:-${2}}"
|
163
|
+
return $?
|
164
|
+
}
|
165
|
+
|
166
|
+
s3_get() {
|
167
|
+
# $1 = bucket to get file from
|
168
|
+
# $2 = remote file to get
|
169
|
+
# $3 = local file to get into. Will be overwritten if it exists.
|
170
|
+
# If this contains a path, that path must exist before calling this.
|
171
|
+
s3_curl GET "${1}" "${2}" "${3:-${2}}"
|
172
|
+
return $?
|
173
|
+
}
|
174
|
+
|
175
|
+
s3_test() {
|
176
|
+
# same args as s3_get, but uses the HEAD verb instead of the GET verb.
|
177
|
+
s3_curl HEAD "${1}" "${2}" >/dev/null
|
178
|
+
return $?
|
179
|
+
}
|
180
|
+
|
181
|
+
# Hideously ugly, but it works well enough.
|
182
|
+
s3_buckets() {
|
183
|
+
s3_get |grep -o '<Name>[^>]*</Name>' |sed 's/<[^>]*>//g' |xmldec
|
184
|
+
return $?
|
185
|
+
}
|
186
|
+
|
187
|
+
# this will only return the first thousand entries, alas
|
188
|
+
# Mabye some kind soul can fix this without writing an XML parser in bash?
|
189
|
+
# Also need to add xml entity handling.
|
190
|
+
s3_list() {
|
191
|
+
# $1 = bucket to list
|
192
|
+
[ "x${1}" == "x" ] && return 1
|
193
|
+
s3_get "${1}" |grep -o '<Key>[^>]*</Key>' |sed 's/<[^>]*>//g'| xmldec
|
194
|
+
return $?
|
195
|
+
}
|
196
|
+
|
197
|
+
s3_delete() {
|
198
|
+
# $1 = bucket to delete from
|
199
|
+
# $2 = item to delete
|
200
|
+
s3_curl DELETE "${1}" "${2}"
|
201
|
+
return $?
|
202
|
+
}
|
203
|
+
|
204
|
+
# because this uses s3_list, it suffers from the same flaws.
|
205
|
+
s3_rmrf() {
|
206
|
+
# $1 = bucket to delete everything from
|
207
|
+
s3_list "${1}" | while read f; do
|
208
|
+
s3_delete "${1}" "${f}";
|
209
|
+
done
|
210
|
+
}
|
211
|
+
|
212
|
+
check_deps
|
213
|
+
case $1 in
|
214
|
+
put) shift; s3_put "$@" ;;
|
215
|
+
get) shift; s3_get "$@" ;;
|
216
|
+
rm) shift; s3_delete "$@" ;;
|
217
|
+
ls) shift; s3_list "$@" ;;
|
218
|
+
test) shift; s3_test "$@" ;;
|
219
|
+
buckets) s3_buckets ;;
|
220
|
+
rmrf) shift; s3_rmrf "$@" ;;
|
221
|
+
*) die "Unknown command ${1}."
|
222
|
+
;;
|
223
|
+
esac
|