jaxx 0.0.3

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/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rvmrc ADDED
@@ -0,0 +1,2 @@
1
+ rvm use --create 1.9.3@jaxx
2
+
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in jaxx.gemspec
4
+ gemspec
data/Guardfile ADDED
@@ -0,0 +1,9 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard 'rspec' do
5
+ watch(%r{^spec/.+_spec\.rb$})
6
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
7
+ watch('spec/spec_helper.rb') { "spec" }
8
+ end
9
+
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Marc Watts
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # Jaxx
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'jaxx'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install jaxx
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
data/bin/jaxx ADDED
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ require 'optparse'
4
+ $:.unshift File.expand_path('../../lib', __FILE__)
5
+ opts = {}
6
+ OptionParser.new do |o|
7
+ o.banner = "Jaxx file distributor: jaxx [options]"
8
+
9
+ o.on('-b', '--bucket BUCKET') { |b| opts['bucket'] = b }
10
+ o.on('-k', '--access-key [ACCESS_KEY]') { |k| opts['access_key'] = k }
11
+ o.on('-s', '--access-secret [ACCESS_SECRET]') { |s| opts['access_secret'] = s }
12
+ o.on('-f', '--file FILE') { |f| opts['file'] = f }
13
+ o.on('-p', '--privacy [PRIVACY]') { |p| opts['privacy'] = p }
14
+ o.on('-h', '--help') { puts o; exit }
15
+ end.parse!
16
+
17
+ require 'jaxx'
18
+ Jaxx.save(opts)
data/jaxx.gemspec ADDED
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/jaxx/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Marc Watts"]
6
+ gem.email = ["marcky.sharky@googlemail.com"]
7
+ gem.description = %q{Command line wrapper for pushing files to S3}
8
+ gem.summary = %q{RubyGems to allow any file to be pushed to S3 in the simplist way}
9
+ gem.homepage = "https://github.com/marckysharky/jaxx"
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.name = "jaxx"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = Jaxx::VERSION
17
+
18
+ gem.add_dependency 'fog'
19
+ gem.add_development_dependency 'rake'
20
+ gem.add_development_dependency 'guard'
21
+ gem.add_development_dependency 'guard-rspec'
22
+ gem.add_development_dependency 'rspec'
23
+ gem.add_development_dependency 'fakeweb'
24
+ end
@@ -0,0 +1,36 @@
1
+ require 'timeout'
2
+ require 'socket'
3
+ require 'net/http'
4
+ require 'json'
5
+
6
+ module Jaxx
7
+ class Environment
8
+
9
+ DEFAULT_ARGS = {
10
+ 'service_domain' => '169.254.169.254',
11
+ 'service_path' => '/latest/meta-data/iam/security-credentials/default',
12
+ 'service_timeout' => 5
13
+ }
14
+
15
+ attr_reader :service_domain, :service_path, :service_timeout
16
+
17
+ def initialize args = {}
18
+ @service_domain, @service_path, @service_timeout = DEFAULT_ARGS.dup.merge(args).values_at 'service_domain', 'service_path', 'service_timeout'
19
+ end
20
+
21
+ def ami?
22
+ credentials[:code] == 'Success'
23
+ end
24
+
25
+ def credentials
26
+ return @credentials unless @credentials.nil?
27
+
28
+ http = Net::HTTP.new service_domain
29
+ http.open_timeout = http.read_timeout = service_timeout
30
+ resp = JSON.parse http.get(service_path).body
31
+ @credentials = { :access_key => resp['AccessKeyId'], :access_secret => resp['SecretAccessKey'], :code => resp['Code'] }
32
+ rescue Errno::EHOSTDOWN, Errno::EHOSTUNREACH, Timeout::Error
33
+ @credentials = { :access_key => nil, :access_secret => nil, :code => 'Failure' }
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,85 @@
1
+ require 'fog'
2
+
3
+ module Jaxx
4
+
5
+ class Transaction
6
+
7
+ PRIVACIES = %w[public private]
8
+
9
+ attr_reader :bucket, :access_key, :access_secret, :file, :privacy
10
+
11
+ def initialize args = {}
12
+ @bucket, @access_key, @access_secret, @file, @privacy = args.values_at 'bucket', 'access_key', 'access_secret', 'file', 'privacy'
13
+ end
14
+
15
+ def privacy
16
+ @privacy || 'private'
17
+ end
18
+
19
+ def private?
20
+ privacy.to_s == 'private'
21
+ end
22
+
23
+ def public?
24
+ !private?
25
+ end
26
+
27
+ def credentials
28
+ return @credentials unless @credentials.nil?
29
+
30
+ key, secret = access_key.to_s, access_secret.to_s
31
+ if Jaxx.environment.ami? and (key.empty? or secret.empty?)
32
+ creds = Jaxx.environment.credentials
33
+ key = creds[:access_key]
34
+ secret = creds[:access_secret]
35
+ end
36
+ @credentials = { access_key: key, access_secret: secret }
37
+ end
38
+
39
+ def process
40
+ errs = errors
41
+ if errs.empty?
42
+ remote_directory.files.create(:key => File.basename(file), :body => File.read(file), :public => public?)
43
+ else
44
+ raise RuntimeError, "Unable to process transaction: #{errs.inspect}"
45
+ end
46
+ end
47
+
48
+ def validate
49
+ err = {}
50
+ err[:bucket] = "is required" unless validate_bucket
51
+ err[:file] = "given cannot be processed" unless validate_file
52
+ err[:credentials] = "for access key and access secret required" unless validate_credentials
53
+ err[:privacy] = "#{privacy} is not supported" unless validate_privacy
54
+ err
55
+ end
56
+
57
+ alias :errors :validate
58
+
59
+ private
60
+
61
+ def remote_directory
62
+ s3 = Fog::Storage::AWS.new :aws_access_key_id => credentials[:access_key], :aws_secret_access_key => credentials[:access_secret], :use_iam_profile => Jaxx.environment.ami?
63
+ dir = s3.directories.get(bucket)
64
+ dir ||= s3.directories.create(:key => bucket, :public => public?)
65
+ dir
66
+ end
67
+
68
+ def validate_bucket
69
+ !bucket.to_s.empty?
70
+ end
71
+
72
+ def validate_file
73
+ !file.to_s.empty? and File.exist?(file.to_s)
74
+ end
75
+
76
+ def validate_credentials
77
+ !credentials[:access_key].empty? and !credentials[:access_secret].empty?
78
+ end
79
+
80
+ def validate_privacy
81
+ PRIVACIES.include?(privacy.to_s)
82
+ end
83
+
84
+ end
85
+ end
@@ -0,0 +1,3 @@
1
+ module Jaxx
2
+ VERSION = "0.0.3"
3
+ end
data/lib/jaxx.rb ADDED
@@ -0,0 +1,14 @@
1
+ require "jaxx/version"
2
+ require "jaxx/transaction"
3
+ require "jaxx/environment"
4
+
5
+ module Jaxx
6
+
7
+ def self.save args = {}
8
+ Jaxx::Transaction.new(args).process
9
+ end
10
+
11
+ def self.environment
12
+ @environment ||= Environment.new
13
+ end
14
+ end
@@ -0,0 +1,9 @@
1
+ module ServiceHelper
2
+
3
+ def stub_credentials_service
4
+ FakeWeb.register_uri :get,
5
+ /#{Jaxx.environment.service_domain}#{Jaxx.environment.service_path}/,
6
+ :body => '{"AccessKeyId" : "foo", "SecretAccessKey" : "bar", "Code" : "Success"}'
7
+ end
8
+
9
+ end
@@ -0,0 +1,45 @@
1
+ require 'spec_helper'
2
+
3
+ module Jaxx
4
+ describe Environment do
5
+
6
+ it "#service_domain" do
7
+ subject.service_domain.should_not be_nil
8
+ end
9
+
10
+ it "#service_path" do
11
+ subject.service_path.should_not be_nil
12
+ end
13
+
14
+ it "#service_timeout" do
15
+ subject.service_timeout.should_not be_nil
16
+ end
17
+
18
+ context "outside ami instance" do
19
+
20
+ it "#ami?" do
21
+ subject.ami?.should be_false
22
+ end
23
+
24
+ it "#credentials" do
25
+ subject.credentials.should be_kind_of(Hash)
26
+ subject.credentials[:code].should eq 'Failure'
27
+ end
28
+ end
29
+
30
+ context "within ami instance" do
31
+
32
+ before :each do
33
+ stub_credentials_service
34
+ end
35
+
36
+ it "#ami?" do
37
+ subject.ami?.should be_true
38
+ end
39
+
40
+ it "#credentials" do
41
+ subject.credentials.should be_kind_of(Hash)
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,104 @@
1
+ require 'spec_helper'
2
+ require 'fog/aws/models/storage/directory'
3
+
4
+ module Jaxx
5
+ describe Transaction do
6
+
7
+ it "raises RuntimeError on invalid process" do
8
+ -> { described_class.new.process }.should raise_error(RuntimeError)
9
+ end
10
+
11
+ it "accepts bucket" do
12
+ described_class.new('bucket' => 'foo').bucket.should == 'foo'
13
+ end
14
+
15
+ it "raises error on missing bucket" do
16
+ described_class.new.errors.should include(:bucket => 'is required')
17
+ end
18
+
19
+ it "raises error on local authentication, when not on AMI"
20
+
21
+ it "accepts access key" do
22
+ described_class.new('access_key' => 'abc').access_key.should == 'abc'
23
+ end
24
+
25
+ it "accepts access secret" do
26
+ described_class.new('access_secret' => 'abc').access_secret.should == 'abc'
27
+ end
28
+
29
+ it "accepts file" do
30
+ file = double 'file'
31
+ described_class.new('file' => file).file.should == file
32
+ end
33
+
34
+ context "passing a file path" do
35
+
36
+ it "raises error on missing file" do
37
+ described_class.new.errors.should include(:file => "given cannot be processed")
38
+ end
39
+
40
+ it "includes error when file does not exist" do
41
+ file = "foo"
42
+ described_class.new('file' => file).errors.should include(:file => "given cannot be processed")
43
+ end
44
+
45
+ it "includes error when path is empty" do
46
+ described_class.new('file' => "").errors.should include(:file => "given cannot be processed")
47
+ end
48
+ end
49
+
50
+ it "accepts privacy level" do
51
+ described_class.new('privacy' => 'private').privacy.should == 'private'
52
+ end
53
+
54
+ it "defaults privacy level to private" do
55
+ described_class.new.privacy.should == 'private'
56
+ end
57
+
58
+ it "raises error on invalid privacy level" do
59
+ described_class.new('privacy' => 'foo').errors.should include(:privacy => "foo is not supported")
60
+ end
61
+
62
+ context "non-ami environment" do
63
+
64
+ it "raises error on missing access key" do
65
+ described_class.new.errors.should include(:credentials => "for access key and access secret required")
66
+ end
67
+
68
+ it "raises error on missing access secret" do
69
+ described_class.new.errors.should include(:credentials => "for access key and access secret required")
70
+ end
71
+ end
72
+
73
+ context "ami environment" do
74
+
75
+ before :each do
76
+ stub_credentials_service
77
+ end
78
+
79
+ it "allows access key to be empty" do
80
+ described_class.new.errors.should_not include(:access_key)
81
+ end
82
+
83
+ it "allows access secret to be empty" do
84
+ described_class.new.errors.should_not include(:access_secret)
85
+ end
86
+ end
87
+
88
+ describe "#process" do
89
+ let(:args) { ({ 'access_key' => 'foo', 'access_secret' => 'bar', 'file' => File.expand_path('bar.txt', __FILE__), 'bucket' => 'temp' }) }
90
+
91
+ subject { described_class.new(args) }
92
+
93
+ it "sends file to storage" do
94
+ Fog.mock!
95
+
96
+ File.stub(:exist?).with(args['file']).and_return(true)
97
+ File.should_receive(:read).with(args['file']).and_return("")
98
+ File.should_receive(:basename).with(args['file']).and_return('bar.txt')
99
+
100
+ subject.process
101
+ end
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+
3
+ describe Jaxx do
4
+
5
+ describe ".save" do
6
+
7
+ it "creates a new transaction" do
8
+ trans = double 'trans', :process => true
9
+ Jaxx::Transaction.should_receive(:new).and_return(trans)
10
+ Jaxx.save
11
+ end
12
+
13
+ end
14
+
15
+ describe ".environment" do
16
+ it "returns instance of Jaxx::Environment" do
17
+ Jaxx.environment.should be_kind_of(Jaxx::Environment)
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,14 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ require 'fakeweb'
4
+ $:.unshift File.expand_path('../lib', __FILE__)
5
+ require 'jaxx'
6
+
7
+ require_relative 'helpers/service'
8
+
9
+ RSpec.configure do |c|
10
+ c.include ServiceHelper
11
+ c.after(:each) do
12
+ FakeWeb.clean_registry
13
+ end
14
+ end
metadata ADDED
@@ -0,0 +1,171 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jaxx
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.3
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Marc Watts
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-01-18 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: fog
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
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: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rake
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: guard
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: guard-rspec
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: rspec
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ - !ruby/object:Gem::Dependency
95
+ name: fakeweb
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ description: Command line wrapper for pushing files to S3
111
+ email:
112
+ - marcky.sharky@googlemail.com
113
+ executables:
114
+ - jaxx
115
+ extensions: []
116
+ extra_rdoc_files: []
117
+ files:
118
+ - .gitignore
119
+ - .rvmrc
120
+ - Gemfile
121
+ - Guardfile
122
+ - LICENSE
123
+ - README.md
124
+ - Rakefile
125
+ - bin/jaxx
126
+ - jaxx.gemspec
127
+ - lib/jaxx.rb
128
+ - lib/jaxx/environment.rb
129
+ - lib/jaxx/transaction.rb
130
+ - lib/jaxx/version.rb
131
+ - spec/helpers/service.rb
132
+ - spec/lib/jaxx/environment_spec.rb
133
+ - spec/lib/jaxx/transaction_spec.rb
134
+ - spec/lib/jaxx_spec.rb
135
+ - spec/spec_helper.rb
136
+ homepage: https://github.com/marckysharky/jaxx
137
+ licenses: []
138
+ post_install_message:
139
+ rdoc_options: []
140
+ require_paths:
141
+ - lib
142
+ required_ruby_version: !ruby/object:Gem::Requirement
143
+ none: false
144
+ requirements:
145
+ - - ! '>='
146
+ - !ruby/object:Gem::Version
147
+ version: '0'
148
+ segments:
149
+ - 0
150
+ hash: -94777366135890808
151
+ required_rubygems_version: !ruby/object:Gem::Requirement
152
+ none: false
153
+ requirements:
154
+ - - ! '>='
155
+ - !ruby/object:Gem::Version
156
+ version: '0'
157
+ segments:
158
+ - 0
159
+ hash: -94777366135890808
160
+ requirements: []
161
+ rubyforge_project:
162
+ rubygems_version: 1.8.24
163
+ signing_key:
164
+ specification_version: 3
165
+ summary: RubyGems to allow any file to be pushed to S3 in the simplist way
166
+ test_files:
167
+ - spec/helpers/service.rb
168
+ - spec/lib/jaxx/environment_spec.rb
169
+ - spec/lib/jaxx/transaction_spec.rb
170
+ - spec/lib/jaxx_spec.rb
171
+ - spec/spec_helper.rb