mortar 0.15.4 → 0.15.5
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.
- checksums.yaml +15 -0
- data/lib/mortar/command/base.rb +11 -1
- data/lib/mortar/command/projects.rb +1 -1
- data/lib/mortar/command/s3.rb +62 -0
- data/lib/mortar/command/version.rb +1 -1
- data/lib/mortar/git.rb +46 -0
- data/lib/mortar/s3.rb +177 -0
- data/lib/mortar/templates/characterize/gitignore +1 -0
- data/lib/mortar/templates/project/gitignore +1 -0
- data/lib/mortar/version.rb +1 -1
- data/spec/mortar/command/base_spec.rb +18 -0
- data/spec/mortar/command/s3_spec.rb +92 -0
- data/spec/mortar/command/version_spec.rb +2 -2
- data/spec/mortar/git_spec.rb +50 -1
- data/spec/mortar/s3_spec.rb +157 -0
- data/spec/s3_faker.rb +99 -0
- data/spec/spec_helper.rb +9 -0
- metadata +42 -33
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
Zjc5OGFiMTk0NDQxMjg2ZWZhNjI5ZDA2MDU3YTIwNTY4ZDg4ZGU5NQ==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
MzZiOGExYzYwZjE0ZjU3MmUyY2JmY2QwNmM0YmFkNjliMGY4N2I1Zg==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
NWQ2ZTI2NTY1MmFjZDllOTVlZGFkNDExYTk1ODYxMjdhNTgyZDhjNzk2MDlm
|
10
|
+
YjU1MmZiNDU2ZDc0MmI3Mjc1ZDQ0NzM1MWU0ZGI1NGE3NDI0NjMwNzlmNjUx
|
11
|
+
NGFhNzM0ODQ2ZTZlNDQ0ZDcxMzc4YzBlN2U3MTdjNTY5MWZmOGE=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
MDliMjQzZGI2YjkyYTg3Y2M3M2ZmOTNjYzI3ZGY0OGZlYzMwMzA2NDdiODE5
|
14
|
+
ZDJkNGVlYTc2MTg2NDA2M2VkYzU5ZmQwZjM1MjhlODY4NjUxMDA3NzkzMzdl
|
15
|
+
OTAyYWI5ZTAyYzY1Y2I2NDI0NTI5Y2QzNWM3NjU2MTg2YTgwYWM=
|
data/lib/mortar/command/base.rb
CHANGED
@@ -65,10 +65,20 @@ class Mortar::Command::Base
|
|
65
65
|
end
|
66
66
|
|
67
67
|
@project = Mortar::Project::Project.new(project_name, project_dir, remote)
|
68
|
+
|
69
|
+
#Every time we get the project, we're going to check if its a forked version and
|
70
|
+
#if it is we'll check for new updates to the base project.
|
71
|
+
begin
|
72
|
+
if git.is_fork_repo_updated(git_organization)
|
73
|
+
warning("The repository this project was forked from has been updated. To get the latest changes commit all of your work and do:\n\n\tgit merge #{git.fork_base_remote_name}/master\n\nYou may have conflicts that will need to be resolved manually.\n\n")
|
74
|
+
end
|
75
|
+
rescue
|
76
|
+
#Do nothing. We'll repeat this call often enough that we don't care if it fails.
|
77
|
+
end
|
68
78
|
end
|
69
79
|
@project
|
70
80
|
end
|
71
|
-
|
81
|
+
|
72
82
|
def api
|
73
83
|
Mortar::Auth.api
|
74
84
|
end
|
@@ -229,7 +229,7 @@ class Mortar::Command::Projects < Mortar::Command::Base
|
|
229
229
|
end
|
230
230
|
is_public = options[:public]
|
231
231
|
ask_public(is_public)
|
232
|
-
git.clone(git_url, name,
|
232
|
+
git.clone(git_url, name, git.fork_base_remote_name)
|
233
233
|
Dir.chdir(name)
|
234
234
|
# register a nil project id because it hasn't been created yet
|
235
235
|
register_project(name, is_public, nil) do |project_result|
|
@@ -0,0 +1,62 @@
|
|
1
|
+
#
|
2
|
+
# Copyright 2014 Mortar Data Inc.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
#
|
16
|
+
|
17
|
+
require "mortar/command/base"
|
18
|
+
require "mortar/s3"
|
19
|
+
|
20
|
+
# Work with your data on Amazon S3
|
21
|
+
class Mortar::Command::S3 < Mortar::Command::Base
|
22
|
+
|
23
|
+
# s3:get S3_PATH OUTPUT_PATH
|
24
|
+
#
|
25
|
+
# Download files from a path in S3 to your local computer.
|
26
|
+
#
|
27
|
+
#
|
28
|
+
# Examples:
|
29
|
+
#
|
30
|
+
# Download from your bucket with:
|
31
|
+
# $ mortar s3:get s3://mortar-example/out out/
|
32
|
+
def get
|
33
|
+
do_get("get")
|
34
|
+
end
|
35
|
+
|
36
|
+
# s3:getmerge S3_PATH OUTPUT_PATH
|
37
|
+
#
|
38
|
+
# Download and concatenate files from a path in S3 to your local computer. Merges together all of the hadoop output into one file called 'output' at specified OUTPUT_PATH
|
39
|
+
#
|
40
|
+
# Examples:
|
41
|
+
#
|
42
|
+
# Download from your bucket with:
|
43
|
+
# $ mortar s3:getmerge s3://mortar-example/out out/
|
44
|
+
def getmerge
|
45
|
+
do_get("getmerge", true)
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
# get functionality
|
51
|
+
def do_get(command, concat = nil)
|
52
|
+
s3_path = shift_argument
|
53
|
+
output_path = shift_argument
|
54
|
+
unless s3_path and output_path
|
55
|
+
error("Usage: mortar s3:#{command} S3_PATH OUTPUT_PATH\nMust specify S3_PATH and OUTPUT_PATH.")
|
56
|
+
end
|
57
|
+
s3 = Mortar::S3::S3.new
|
58
|
+
bucket, key = s3.get_bucket_and_key(s3_path)
|
59
|
+
s3.do_download(bucket, key, output_path, concat)
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
@@ -53,7 +53,7 @@ class Mortar::Command::Version < Mortar::Command::Base
|
|
53
53
|
shell_url = ENV.fetch("MORTAR_INSTALL", "http://install.mortardata.com")
|
54
54
|
dir = "/opt/mortar/installer"
|
55
55
|
begin
|
56
|
-
cmd = "sudo mkdir -p #{dir} && sudo curl -sS -L -o #{dir}/install.sh #{shell_url} && sudo bash #{dir}/install.sh#{version_number}"
|
56
|
+
cmd = "echo 'Upgrading will prompt for your sudo password.\n' && sudo mkdir -p #{dir} && sudo curl -sS -L -o #{dir}/install.sh #{shell_url} && sudo bash #{dir}/install.sh#{version_number}"
|
57
57
|
Kernel.system cmd
|
58
58
|
ensure
|
59
59
|
end
|
data/lib/mortar/git.rb
CHANGED
@@ -536,6 +536,52 @@ module Mortar
|
|
536
536
|
def clone(git_url, path="", remote_name="origin")
|
537
537
|
git("clone -o %s %s \"%s\"" % [remote_name, git_url, path], true, false)
|
538
538
|
end
|
539
|
+
|
540
|
+
def fork_base_remote_name
|
541
|
+
"base"
|
542
|
+
end
|
543
|
+
|
544
|
+
def is_fork_repo_updated(git_organization)
|
545
|
+
if remotes(git_organization).has_key?(fork_base_remote_name)
|
546
|
+
fetch(fork_base_remote_name)
|
547
|
+
latest_commit = get_latest_hash(fork_base_remote_name)
|
548
|
+
last_commit = get_last_recorded_fork_hash
|
549
|
+
unless latest_commit == last_commit || contains_hash(latest_commit)
|
550
|
+
File.open(mortar_fork_meta_file, "wb") do |f|
|
551
|
+
f.write(latest_commit)
|
552
|
+
end
|
553
|
+
return true
|
554
|
+
end
|
555
|
+
end
|
556
|
+
return false
|
557
|
+
end
|
558
|
+
|
559
|
+
def get_last_recorded_fork_hash
|
560
|
+
if File.exists?(mortar_fork_meta_file)
|
561
|
+
File.open(mortar_fork_meta_file, "r") do |f|
|
562
|
+
file_contents = f.read()
|
563
|
+
file_contents.strip
|
564
|
+
end
|
565
|
+
end
|
566
|
+
end
|
567
|
+
|
568
|
+
def mortar_fork_meta_file
|
569
|
+
".mortar-fork"
|
570
|
+
end
|
571
|
+
|
572
|
+
def fetch(remote)
|
573
|
+
git("fetch #{remote}")
|
574
|
+
end
|
575
|
+
|
576
|
+
def get_latest_hash(remote)
|
577
|
+
git("log --pretty=\"%H\" -n 1 #{remote}")
|
578
|
+
end
|
579
|
+
|
580
|
+
def contains_hash(hash)
|
581
|
+
git("log --pretty=\"%H\"").include?(hash)
|
582
|
+
end
|
583
|
+
|
584
|
+
|
539
585
|
end
|
540
586
|
end
|
541
587
|
end
|
data/lib/mortar/s3.rb
ADDED
@@ -0,0 +1,177 @@
|
|
1
|
+
#
|
2
|
+
# Copyright 2014 Mortar Data Inc.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
#
|
16
|
+
# Portions of this code from heroku (https://github.com/heroku/heroku/) Copyright Heroku 2008 - 2014,
|
17
|
+
# used under an MIT license (https://github.com/heroku/heroku/blob/master/LICENSE).
|
18
|
+
#
|
19
|
+
require 'mortar/local/controller'
|
20
|
+
require "mortar/command/base"
|
21
|
+
require "mortar/helpers"
|
22
|
+
require 'aws-sdk'
|
23
|
+
require 'uri'
|
24
|
+
require 'pathname'
|
25
|
+
|
26
|
+
|
27
|
+
module Mortar
|
28
|
+
module S3
|
29
|
+
class S3
|
30
|
+
include Helpers
|
31
|
+
|
32
|
+
# gets aws::s3 object
|
33
|
+
def get_s3
|
34
|
+
ctrl = Mortar::Local::Controller.new
|
35
|
+
ctrl.require_aws_keys
|
36
|
+
return AWS::S3.new(
|
37
|
+
:access_key_id => ENV['AWS_ACCESS_KEY'],
|
38
|
+
:secret_access_key => ENV['AWS_SECRET_KEY'])
|
39
|
+
end
|
40
|
+
|
41
|
+
# returns bucket and key from s3 path
|
42
|
+
def get_bucket_and_key(s3_path)
|
43
|
+
uri = ''
|
44
|
+
begin
|
45
|
+
uri = URI.parse(s3_path)
|
46
|
+
rescue URI::InvalidURIError => msg
|
47
|
+
error("#{msg}.\nIt is strongly suggested that your bucket name does not contain an underscore character.\nPlease see http://blog.mortardata.com/post/58920122308/s3-hadoop-performance at tip #4.")
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
unless uri != '' && is_valid_s3_path(uri)
|
52
|
+
error("Requested S3 path, #{s3_path}, is invalid. Please ensure that your S3 path begins with 's3://'. Example: s3://my-bucket/my-key.")
|
53
|
+
end
|
54
|
+
return uri.host,uri.path[1, uri.path.length]
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
# checks if string is a valid s3 path
|
59
|
+
def is_valid_s3_path(uri)
|
60
|
+
uri.scheme == 's3' && uri.host && !uri.path[1, uri.path.length].to_s.empty?
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
def remove_slash(str)
|
65
|
+
if str[-1, 1] == "/"
|
66
|
+
str = str[0, str.length-1]
|
67
|
+
end
|
68
|
+
return str
|
69
|
+
end
|
70
|
+
|
71
|
+
def get_file_name(key_str)
|
72
|
+
if !key_str.rindex("/")
|
73
|
+
return key_str
|
74
|
+
else
|
75
|
+
return Pathname.new(key_str).basename.to_s
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def is_file(path, key)
|
80
|
+
if is_not_folder(path,key)
|
81
|
+
res = Pathname.new(path).basename.to_s
|
82
|
+
if !is_hidden_file(res)
|
83
|
+
return true
|
84
|
+
end
|
85
|
+
end
|
86
|
+
return false
|
87
|
+
end
|
88
|
+
|
89
|
+
def is_not_folder(path, key)
|
90
|
+
suffix = ["/", "_$folder$"]
|
91
|
+
# not a folder
|
92
|
+
path[-1,1] != suffix[0] && !path.index(suffix[1]) and !path[key.length+1, path.length].index("/")
|
93
|
+
#path[-1,1] != suffix[0] && !path.index(suffix[1]) and Pathname.new(path).basename.to_s != ''
|
94
|
+
end
|
95
|
+
|
96
|
+
def is_hidden_file(str)
|
97
|
+
str[0,1] == "." || str[0,1] == "_"
|
98
|
+
end
|
99
|
+
|
100
|
+
def remove_file(file_path)
|
101
|
+
if File.file?(file_path)
|
102
|
+
FileUtils.remove(file_path)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# checks s3 bucket to see if bucket and key exists for given aws keys
|
107
|
+
def check_bucket(s3, bucket)
|
108
|
+
s3.buckets[bucket].exists?
|
109
|
+
end
|
110
|
+
|
111
|
+
|
112
|
+
# gets s3 object, where each item is a file in bucket and key
|
113
|
+
def get_s3_objects(s3, bucket, key)
|
114
|
+
buck = s3.buckets[bucket]
|
115
|
+
# removes slash at end if it exists
|
116
|
+
key = remove_slash(key)
|
117
|
+
if buck.objects[key].exists?
|
118
|
+
[buck.objects[key]]
|
119
|
+
else
|
120
|
+
valid_items = Array.new
|
121
|
+
buck.objects.with_prefix(key).each do |obj|
|
122
|
+
if is_file(obj.key, key)
|
123
|
+
valid_items.push(obj)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
return valid_items
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def write_s3_to_file(s3_object, file_name, write_mode)
|
131
|
+
File.open(file_name, write_mode) do |file|
|
132
|
+
s3_object.read do |chunk|
|
133
|
+
file.write(chunk)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
|
139
|
+
def download_s3(s3, bucket, key, output_path, concat = nil)
|
140
|
+
s3_objects = get_s3_objects(s3, bucket,key)
|
141
|
+
concat_file_name = "output"
|
142
|
+
concat_target = "#{output_path}/#{concat_file_name}"
|
143
|
+
if concat
|
144
|
+
remove_file(concat_target)
|
145
|
+
end
|
146
|
+
if !s3_objects.empty?
|
147
|
+
s3_objects.each do |s3_obj|
|
148
|
+
key_str = s3_obj.key
|
149
|
+
out_file = concat ? concat_file_name : get_file_name(key_str)
|
150
|
+
output_target = "#{output_path}/#{out_file}"
|
151
|
+
display "Writing s3://#{bucket}/#{key_str} to #{output_target}"
|
152
|
+
write_s3_to_file(s3_obj, output_target, concat ? "a" : "w+")
|
153
|
+
end
|
154
|
+
else
|
155
|
+
error("No contents were found at path s3://#{bucket}/#{key}. Please specify again.")
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
# Implementation of the download command
|
160
|
+
def do_download(bucket, key, output_path, concat=nil)
|
161
|
+
s3 = get_s3
|
162
|
+
# check and messages for concatting file
|
163
|
+
unless check_bucket(s3, bucket)
|
164
|
+
error("Requested S3 bucket #{bucket} in path, s3://#{bucket}/#{key}, does not exist.")
|
165
|
+
end
|
166
|
+
# creates output directory
|
167
|
+
unless File.directory?(output_path)
|
168
|
+
FileUtils.mkdir_p(output_path)
|
169
|
+
end
|
170
|
+
download_s3(s3, bucket, key, output_path, concat)
|
171
|
+
|
172
|
+
display "All done! "
|
173
|
+
end
|
174
|
+
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
data/lib/mortar/version.rb
CHANGED
@@ -83,6 +83,24 @@ other\tgit@github.com:other.git (push)
|
|
83
83
|
@base.project.name.should == 'myproject-staging'
|
84
84
|
end
|
85
85
|
|
86
|
+
it "errors out on checking for updates to forked project and nobody cares" do
|
87
|
+
stub(@base.git).has_dot_git? {true}
|
88
|
+
stub(@base.git).remotes {{ 'mortar' => 'myproject' }}
|
89
|
+
mock(@base.git).git("config mortar.remote", false).returns("")
|
90
|
+
mock(@base.git).is_fork_repo_updated.with_any_args.returns { raise StandardError.new("meessage") }
|
91
|
+
mock(@base).warning.times(0)
|
92
|
+
@base.project.name.should == 'myproject'
|
93
|
+
end
|
94
|
+
|
95
|
+
it "finds an updated forked project and displays warning" do
|
96
|
+
stub(@base.git).has_dot_git? {true}
|
97
|
+
stub(@base.git).remotes {{ 'mortar' => 'myproject' }}
|
98
|
+
mock(@base.git).git("config mortar.remote", false).returns("")
|
99
|
+
mock(@base.git).is_fork_repo_updated.with_any_args.returns(true)
|
100
|
+
mock(@base).warning.times(1).with_any_args
|
101
|
+
@base.project.name.should == 'myproject'
|
102
|
+
end
|
103
|
+
|
86
104
|
end
|
87
105
|
|
88
106
|
context "method_added" do
|
@@ -0,0 +1,92 @@
|
|
1
|
+
#
|
2
|
+
# Copyright 2014 Mortar Data Inc.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
#
|
16
|
+
|
17
|
+
require 'spec_helper'
|
18
|
+
require 'fakefs/spec_helpers'
|
19
|
+
require 'mortar/command/s3'
|
20
|
+
require 'aws-sdk'
|
21
|
+
require "mortar/s3"
|
22
|
+
require 's3_faker'
|
23
|
+
|
24
|
+
module Mortar::Command
|
25
|
+
describe S3 do
|
26
|
+
context "s3:getmerge" do
|
27
|
+
good_bucket = "good-bucket"
|
28
|
+
bad_bucket = "bad-bucket"
|
29
|
+
key = "direc"
|
30
|
+
s3_path = "s3://#{good_bucket}/#{key}"
|
31
|
+
s3_path_bad = "s3://#{bad_bucket}/key"
|
32
|
+
output_path = "out"
|
33
|
+
concat_file = "#{output_path}/output"
|
34
|
+
keys = [
|
35
|
+
FakeObject.new("key1", true),
|
36
|
+
FakeObject.new("direc/key2", true),
|
37
|
+
FakeObject.new("direc/key3", true),
|
38
|
+
FakeObject.new("direc/another_direc/key", true)
|
39
|
+
]
|
40
|
+
before(:each) do
|
41
|
+
ENV["AWS_ACCESS_KEY"] = "foo"
|
42
|
+
ENV["AWS_SECRET_KEY"] = "bar"
|
43
|
+
buckets = [
|
44
|
+
{:bucket => good_bucket, :keys =>keys, :does_exist => true},
|
45
|
+
{:bucket => bad_bucket, :keys=> [], :does_exist => false}]
|
46
|
+
stub_s3(buckets, ENV["AWS_ACCESS_KEY"], ENV["AWS_SECRET_KEY"])
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
context "s3:get" do
|
51
|
+
it "should specify an s3 bucket" do
|
52
|
+
stderr, stdout = execute("s3:get")
|
53
|
+
stderr.should == <<-STDERR
|
54
|
+
! Usage: mortar s3:get S3_PATH OUTPUT_PATH
|
55
|
+
! Must specify S3_PATH and OUTPUT_PATH.
|
56
|
+
STDERR
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should throw errors at invalid s3_bucket and fetch urls" do
|
60
|
+
stderr, stdout = execute("s3:get s3://#{bad_bucket} out")
|
61
|
+
stderr.should eq(" ! Requested S3 path, s3://#{bad_bucket}, is invalid. Please ensure that your S3 path begins with 's3://'. Example: s3://my-bucket/my-key.\n")
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
it "should throw errors at invalid s3_bucket and fetch urls" do
|
66
|
+
stderr, stdout = execute("s3:get #{s3_path_bad} out")
|
67
|
+
stderr.should eq(" ! Requested S3 bucket #{bad_bucket} in path, #{s3_path_bad}, does not exist.\n")
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should have no errors when ran" do
|
71
|
+
any_instance_of(Mortar::S3::S3) do |s3|
|
72
|
+
mock(s3).do_download(good_bucket, key, output_path, nil)
|
73
|
+
end
|
74
|
+
stderr, stdout = execute("s3:get #{s3_path} #{output_path}")
|
75
|
+
stderr.should eq("")
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
context "s3:getmerge" do
|
80
|
+
it "should have aws-sdk keys properly set for aws-sdk functionality" do
|
81
|
+
any_instance_of(Mortar::S3::S3) do |s3|
|
82
|
+
mock(s3).do_download(good_bucket, key, output_path, true)
|
83
|
+
end
|
84
|
+
stderr, stdout = execute("s3:getmerge #{s3_path} #{output_path}")
|
85
|
+
stderr.should eq("")
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
|
@@ -27,7 +27,7 @@ module Mortar::Command
|
|
27
27
|
base_url = "http://install.mortardata.com"
|
28
28
|
base_version = "0.15.1"
|
29
29
|
tmp_dir_dumm = "/opt/mortar/installer"
|
30
|
-
curl_command = "sudo mkdir -p #{tmp_dir_dumm} && sudo curl -sS -L -o #{tmp_dir_dumm}/install.sh #{base_url} && sudo bash #{tmp_dir_dumm}/install.sh"
|
30
|
+
curl_command = "echo 'Upgrading will prompt for your sudo password.\n' && sudo mkdir -p #{tmp_dir_dumm} && sudo curl -sS -L -o #{tmp_dir_dumm}/install.sh #{base_url} && sudo bash #{tmp_dir_dumm}/install.sh"
|
31
31
|
|
32
32
|
context("version in prod") do
|
33
33
|
mortar_install_env = ENV['MORTAR_INSTALL']
|
@@ -63,7 +63,7 @@ module Mortar::Command
|
|
63
63
|
|
64
64
|
context("version dev") do
|
65
65
|
dev_url = "dev_url.com"
|
66
|
-
dev_curl = "sudo mkdir -p #{tmp_dir_dumm} && sudo curl -sS -L -o #{tmp_dir_dumm}/install.sh #{dev_url} && sudo bash #{tmp_dir_dumm}/install.sh"
|
66
|
+
dev_curl = "echo 'Upgrading will prompt for your sudo password.\n' && sudo mkdir -p #{tmp_dir_dumm} && sudo curl -sS -L -o #{tmp_dir_dumm}/install.sh #{dev_url} && sudo bash #{tmp_dir_dumm}/install.sh"
|
67
67
|
before(:each) do
|
68
68
|
ENV['MORTAR_INSTALL'] = dev_url
|
69
69
|
end
|
data/spec/mortar/git_spec.rb
CHANGED
@@ -405,7 +405,56 @@ STASH
|
|
405
405
|
end
|
406
406
|
end
|
407
407
|
end
|
408
|
-
|
408
|
+
|
409
|
+
context "checking updates for forked projects" do
|
410
|
+
it "skips non forked projects" do
|
411
|
+
with_git_initialized_project do |p|
|
412
|
+
@git.is_fork_repo_updated("mortarcode-dev").should be_false
|
413
|
+
end
|
414
|
+
end
|
415
|
+
|
416
|
+
it "returns true with no .mortar-fork file and new commits" do
|
417
|
+
with_forked_git_project do |p|
|
418
|
+
mock(@git).fetch(@git.fork_base_remote_name)
|
419
|
+
new_commit_hash = "ANewCommitHash"
|
420
|
+
mock(@git).get_latest_hash(@git.fork_base_remote_name) {new_commit_hash}
|
421
|
+
|
422
|
+
@git.is_fork_repo_updated("mortarcode-dev").should be_true
|
423
|
+
File.exists?(@git.mortar_fork_meta_file).should be_true
|
424
|
+
File.open(@git.mortar_fork_meta_file, "r") do |f|
|
425
|
+
file_contents = f.read()
|
426
|
+
file_contents.strip
|
427
|
+
file_contents.eql?(new_commit_hash).should be_true
|
428
|
+
end
|
429
|
+
end
|
430
|
+
end
|
431
|
+
|
432
|
+
it "returns false with up to date .mortar-fork file and new commits" do
|
433
|
+
with_forked_git_project do |p|
|
434
|
+
mock(@git).fetch(@git.fork_base_remote_name)
|
435
|
+
new_commit_hash = "ANewCommitHash"
|
436
|
+
mock(@git).get_latest_hash(@git.fork_base_remote_name) {new_commit_hash}
|
437
|
+
File.open(@git.mortar_fork_meta_file, "wb") do |f|
|
438
|
+
f.write(new_commit_hash)
|
439
|
+
end
|
440
|
+
File.exists?(@git.mortar_fork_meta_file).should be_true
|
441
|
+
|
442
|
+
@git.is_fork_repo_updated("mortarcode-dev").should be_false
|
443
|
+
end
|
444
|
+
end
|
445
|
+
|
446
|
+
it "returns false with no .mortar-fork file and no new commits" do
|
447
|
+
with_forked_git_project do |p|
|
448
|
+
mock(@git).fetch(@git.fork_base_remote_name)
|
449
|
+
current_latest_hash = @git.get_latest_hash("")
|
450
|
+
mock(@git).get_latest_hash(@git.fork_base_remote_name) {current_latest_hash}
|
451
|
+
|
452
|
+
@git.is_fork_repo_updated("mortarcode-dev").should be_false
|
453
|
+
end
|
454
|
+
end
|
455
|
+
end
|
456
|
+
|
457
|
+
|
409
458
|
=begin
|
410
459
|
#TODO: Fix this.
|
411
460
|
|
@@ -0,0 +1,157 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'mortar/s3'
|
3
|
+
require 's3_faker'
|
4
|
+
|
5
|
+
module Mortar
|
6
|
+
describe S3 do
|
7
|
+
before(:each) do
|
8
|
+
@s3 = Mortar::S3::S3.new
|
9
|
+
end
|
10
|
+
context("download s3 commands") do
|
11
|
+
keys = [
|
12
|
+
FakeObject.new("key1", true),
|
13
|
+
FakeObject.new("direc/key2", true),
|
14
|
+
FakeObject.new("direc/key3", true),
|
15
|
+
FakeObject.new("direc/.hidden_key4", true),
|
16
|
+
FakeObject.new("direc/another_direc/key", true)
|
17
|
+
]
|
18
|
+
|
19
|
+
before(:each) do
|
20
|
+
ENV["AWS_ACCESS_KEY"] = "foo"
|
21
|
+
ENV["AWS_SECRET_KEY"] = "bar"
|
22
|
+
buckets = [
|
23
|
+
{:bucket => "good_bucket", :keys =>keys, :does_exist => true},
|
24
|
+
{:bucket => "bad_bucket", :keys=> [], :does_exist => false}]
|
25
|
+
stub_s3(buckets, ENV["AWS_ACCESS_KEY"], ENV["AWS_SECRET_KEY"])
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
context("string functions") do
|
30
|
+
it "should check if the valid path" do
|
31
|
+
bucket, key = @s3.get_bucket_and_key('s3://bucket/key')
|
32
|
+
bucket.should eq('bucket')
|
33
|
+
key.should eq('key')
|
34
|
+
bucket, key = @s3.get_bucket_and_key('s3://bucket/deeper/level/key')
|
35
|
+
bucket.should eq('bucket')
|
36
|
+
key.should eq('deeper/level/key')
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should throw appropriate error if path is not valid" do
|
40
|
+
bad_bucket = 'bad'
|
41
|
+
previous_stderr, $stderr = $stderr, StringIO.new
|
42
|
+
begin
|
43
|
+
expect { @s3.get_bucket_and_key(bad_bucket) }.to raise_error(SystemExit)
|
44
|
+
$stderr.string.should eq(" ! Requested S3 path, #{bad_bucket}, is invalid. Please ensure that your S3 path begins with 's3://'. Example: s3://my-bucket/my-key.\n")
|
45
|
+
ensure
|
46
|
+
$stderr = previous_stderr
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should throw error if bucket has underscore" do
|
51
|
+
path = "s3://will_fail/key"
|
52
|
+
previous_stderr, $stderr = $stderr, StringIO.new
|
53
|
+
begin
|
54
|
+
expect { @s3.get_bucket_and_key(path) }.to raise_error(SystemExit)
|
55
|
+
$stderr.string.should eq(" ! the scheme s3 does not accept registry part: will_fail (or bad hostname?).\n ! It is strongly suggested that your bucket name does not contain an underscore character.\n ! Please see http://blog.mortardata.com/post/58920122308/s3-hadoop-performance at tip #4.\n")
|
56
|
+
ensure
|
57
|
+
$stderr = previous_stderr
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should remove / if at the end" do
|
62
|
+
str = "with/"
|
63
|
+
str = @s3.remove_slash(str)
|
64
|
+
str.should eq("with")
|
65
|
+
end
|
66
|
+
it "should not remove / if not at the end" do
|
67
|
+
str = "without"
|
68
|
+
@s3.remove_slash(str)
|
69
|
+
str.should eq("without")
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should get just the file" do
|
73
|
+
key = "folder"
|
74
|
+
path = "folder/file"
|
75
|
+
@s3.is_file(path, key).should eq(true)
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should get nothing" do
|
80
|
+
key = "folder"
|
81
|
+
path = "folder/file_$folder$"
|
82
|
+
@s3.is_file(path, key).should eq(false)
|
83
|
+
path = "folder/folder/"
|
84
|
+
@s3.is_file(path, key).should eq(false)
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
|
90
|
+
context("s3 functions") do
|
91
|
+
s3 = nil
|
92
|
+
before (:each) do
|
93
|
+
any_instance_of(Mortar::Local::Controller) do |ctrl|
|
94
|
+
mock(ctrl).require_aws_keys
|
95
|
+
end
|
96
|
+
s3 = @s3.get_s3
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should check if bucket and key exists" do
|
100
|
+
bucket = "good_bucket"
|
101
|
+
key = "key1"
|
102
|
+
@s3.check_bucket(s3, bucket).should eq(true)
|
103
|
+
|
104
|
+
|
105
|
+
bucket = "bad_bucket"
|
106
|
+
key = "bad_key"
|
107
|
+
@s3.check_bucket(s3, bucket).should eq(false)
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should get s3_objects" do
|
111
|
+
bucket = "good_bucket"
|
112
|
+
key = "key1"
|
113
|
+
result = @s3.get_s3_objects(s3, bucket, key)
|
114
|
+
result.length.should eq(1)
|
115
|
+
result[0].key.should eq(key)
|
116
|
+
|
117
|
+
bucket = "good_bucket"
|
118
|
+
key = "direc"
|
119
|
+
result = @s3.get_s3_objects(s3, bucket, key)
|
120
|
+
result.length.should eq(2)
|
121
|
+
end
|
122
|
+
|
123
|
+
it "should return emtpy list if s3_objects are empty" do
|
124
|
+
bucket = "good_bucket"
|
125
|
+
key = "dire"
|
126
|
+
result = @s3.get_s3_objects(s3, bucket, key)
|
127
|
+
result.length.should eq(0)
|
128
|
+
end
|
129
|
+
|
130
|
+
it "should check content that is written" do
|
131
|
+
bucket = "good_bucket"
|
132
|
+
key = "key1"
|
133
|
+
mock(@s3).write_s3_to_file(keys[0], 'output/key1', 'w+')
|
134
|
+
@s3.download_s3(s3, bucket, key, 'output')
|
135
|
+
end
|
136
|
+
|
137
|
+
it "should check all files are written" do
|
138
|
+
bucket = "good_bucket"
|
139
|
+
key = "direc"
|
140
|
+
mock(@s3).write_s3_to_file(keys[1], 'output/key2', 'w+')
|
141
|
+
mock(@s3).write_s3_to_file(keys[2], 'output/key3', 'w+')
|
142
|
+
@s3.download_s3(s3, bucket, key, 'output')
|
143
|
+
end
|
144
|
+
|
145
|
+
it "should concat all files to one and delete out file when already exists" do
|
146
|
+
bucket = "good_bucket"
|
147
|
+
key = "direc"
|
148
|
+
mock(File).file?("output/output"){true}
|
149
|
+
mock(FileUtils).remove("output/output")
|
150
|
+
mock(@s3).write_s3_to_file(keys[1], 'output/output', 'a')
|
151
|
+
mock(@s3).write_s3_to_file(keys[2], 'output/output', 'a')
|
152
|
+
@s3.download_s3(s3, bucket, key, 'output', true)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
data/spec/s3_faker.rb
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'aws-sdk'
|
2
|
+
def stub_s3(buckets, access_key_id, secret_access_key)
|
3
|
+
stub(AWS::S3).new(
|
4
|
+
:access_key_id => access_key_id,
|
5
|
+
:secret_access_key => secret_access_key).returns(FakeS3.new(buckets))
|
6
|
+
end
|
7
|
+
|
8
|
+
class FakeS3
|
9
|
+
attr_accessor :buckets
|
10
|
+
|
11
|
+
def initialize(buckets)
|
12
|
+
@buckets = FakeS3Collection.new
|
13
|
+
buckets.each do |buck|
|
14
|
+
@buckets.add(buck[:bucket], FakeBucket.new(buck[:bucket],buck[:keys], buck[:does_exist]))
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
# class that mocks bucket and s3 object collection
|
22
|
+
class FakeS3Collection
|
23
|
+
include Enumerable
|
24
|
+
attr_accessor :objects
|
25
|
+
def initialize
|
26
|
+
@objects = {}
|
27
|
+
end
|
28
|
+
def [](key)
|
29
|
+
if @objects.has_key?(key)
|
30
|
+
return @objects[key]
|
31
|
+
else
|
32
|
+
return FakeObject.new("", false)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def add (key, val)
|
37
|
+
@objects[key] = val
|
38
|
+
end
|
39
|
+
|
40
|
+
def with_prefix(prefix)
|
41
|
+
res = FakeS3Collection.new
|
42
|
+
@objects.keys.each do |key|
|
43
|
+
if key.index(prefix) == 0
|
44
|
+
res.add(key, @objects[key])
|
45
|
+
end
|
46
|
+
end
|
47
|
+
return res
|
48
|
+
end
|
49
|
+
|
50
|
+
def each(options = {}, &block)
|
51
|
+
@objects.keys.each do |key|
|
52
|
+
if @objects[key].does_exist
|
53
|
+
block.call(@objects[key])
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
# Spec class to mock a fake bucket
|
62
|
+
class FakeBucket
|
63
|
+
attr_accessor :name, :keys, :does_exist, :objects
|
64
|
+
|
65
|
+
def initialize(name, keys, does_exist)
|
66
|
+
@name = name
|
67
|
+
@keys = keys
|
68
|
+
@objects = FakeS3Collection.new
|
69
|
+
keys.each do |k|
|
70
|
+
@objects.add(k.key,k)
|
71
|
+
end
|
72
|
+
@does_exist = does_exist
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
def exists?
|
77
|
+
return @does_exist
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
|
84
|
+
# Spec class to mock a fake s3 object
|
85
|
+
class FakeObject
|
86
|
+
attr_accessor :key, :does_exist
|
87
|
+
def initialize(key, does_exist)
|
88
|
+
@key = key
|
89
|
+
@does_exist = does_exist
|
90
|
+
end
|
91
|
+
|
92
|
+
def exists?
|
93
|
+
@does_exist
|
94
|
+
end
|
95
|
+
|
96
|
+
def read
|
97
|
+
return "Content #{@key}"
|
98
|
+
end
|
99
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -200,6 +200,15 @@ def with_blank_project_with_name(name, &block)
|
|
200
200
|
end
|
201
201
|
end
|
202
202
|
|
203
|
+
def with_forked_git_project(&block)
|
204
|
+
with_git_initialized_project do |project|
|
205
|
+
git = Mortar::Git::Git.new
|
206
|
+
remote = git.fork_base_remote_name
|
207
|
+
`git remote add #{remote} git@github.com:mortarcode-dev/fork_#{project.name}.git`
|
208
|
+
block.call(project)
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
203
212
|
def with_git_initialized_project(&block)
|
204
213
|
remote_prefix = "4dbbd83cae8d5bf8a4000000_"
|
205
214
|
with_git_initialized_project_with_remote_prefix(remote_prefix, &block)
|
metadata
CHANGED
@@ -1,20 +1,18 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mortar
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.15.
|
5
|
-
prerelease:
|
4
|
+
version: 0.15.5
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Mortar Data
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date: 2014-
|
11
|
+
date: 2014-04-04 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: rdoc
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
17
|
- - ! '>='
|
20
18
|
- !ruby/object:Gem::Version
|
@@ -22,7 +20,6 @@ dependencies:
|
|
22
20
|
type: :runtime
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
24
|
- - ! '>='
|
28
25
|
- !ruby/object:Gem::Version
|
@@ -30,7 +27,6 @@ dependencies:
|
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: mortar-api-ruby
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
31
|
- - ~>
|
36
32
|
- !ruby/object:Gem::Version
|
@@ -38,7 +34,6 @@ dependencies:
|
|
38
34
|
type: :runtime
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
38
|
- - ~>
|
44
39
|
- !ruby/object:Gem::Version
|
@@ -46,7 +41,6 @@ dependencies:
|
|
46
41
|
- !ruby/object:Gem::Dependency
|
47
42
|
name: netrc
|
48
43
|
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
44
|
requirements:
|
51
45
|
- - ~>
|
52
46
|
- !ruby/object:Gem::Version
|
@@ -54,7 +48,6 @@ dependencies:
|
|
54
48
|
type: :runtime
|
55
49
|
prerelease: false
|
56
50
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
51
|
requirements:
|
59
52
|
- - ~>
|
60
53
|
- !ruby/object:Gem::Version
|
@@ -62,7 +55,6 @@ dependencies:
|
|
62
55
|
- !ruby/object:Gem::Dependency
|
63
56
|
name: launchy
|
64
57
|
requirement: !ruby/object:Gem::Requirement
|
65
|
-
none: false
|
66
58
|
requirements:
|
67
59
|
- - ~>
|
68
60
|
- !ruby/object:Gem::Version
|
@@ -70,7 +62,6 @@ dependencies:
|
|
70
62
|
type: :runtime
|
71
63
|
prerelease: false
|
72
64
|
version_requirements: !ruby/object:Gem::Requirement
|
73
|
-
none: false
|
74
65
|
requirements:
|
75
66
|
- - ~>
|
76
67
|
- !ruby/object:Gem::Version
|
@@ -78,7 +69,6 @@ dependencies:
|
|
78
69
|
- !ruby/object:Gem::Dependency
|
79
70
|
name: parseconfig
|
80
71
|
requirement: !ruby/object:Gem::Requirement
|
81
|
-
none: false
|
82
72
|
requirements:
|
83
73
|
- - ~>
|
84
74
|
- !ruby/object:Gem::Version
|
@@ -86,15 +76,41 @@ dependencies:
|
|
86
76
|
type: :runtime
|
87
77
|
prerelease: false
|
88
78
|
version_requirements: !ruby/object:Gem::Requirement
|
89
|
-
none: false
|
90
79
|
requirements:
|
91
80
|
- - ~>
|
92
81
|
- !ruby/object:Gem::Version
|
93
82
|
version: 1.0.2
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: aws-sdk
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ~>
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '1.0'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ~>
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '1.0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: nokogiri
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ~>
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 1.5.0
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ~>
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 1.5.0
|
94
111
|
- !ruby/object:Gem::Dependency
|
95
112
|
name: excon
|
96
113
|
requirement: !ruby/object:Gem::Requirement
|
97
|
-
none: false
|
98
114
|
requirements:
|
99
115
|
- - ~>
|
100
116
|
- !ruby/object:Gem::Version
|
@@ -102,7 +118,6 @@ dependencies:
|
|
102
118
|
type: :development
|
103
119
|
prerelease: false
|
104
120
|
version_requirements: !ruby/object:Gem::Requirement
|
105
|
-
none: false
|
106
121
|
requirements:
|
107
122
|
- - ~>
|
108
123
|
- !ruby/object:Gem::Version
|
@@ -110,7 +125,6 @@ dependencies:
|
|
110
125
|
- !ruby/object:Gem::Dependency
|
111
126
|
name: fakefs
|
112
127
|
requirement: !ruby/object:Gem::Requirement
|
113
|
-
none: false
|
114
128
|
requirements:
|
115
129
|
- - ~>
|
116
130
|
- !ruby/object:Gem::Version
|
@@ -118,7 +132,6 @@ dependencies:
|
|
118
132
|
type: :development
|
119
133
|
prerelease: false
|
120
134
|
version_requirements: !ruby/object:Gem::Requirement
|
121
|
-
none: false
|
122
135
|
requirements:
|
123
136
|
- - ~>
|
124
137
|
- !ruby/object:Gem::Version
|
@@ -126,7 +139,6 @@ dependencies:
|
|
126
139
|
- !ruby/object:Gem::Dependency
|
127
140
|
name: gem-release
|
128
141
|
requirement: !ruby/object:Gem::Requirement
|
129
|
-
none: false
|
130
142
|
requirements:
|
131
143
|
- - ! '>='
|
132
144
|
- !ruby/object:Gem::Version
|
@@ -134,7 +146,6 @@ dependencies:
|
|
134
146
|
type: :development
|
135
147
|
prerelease: false
|
136
148
|
version_requirements: !ruby/object:Gem::Requirement
|
137
|
-
none: false
|
138
149
|
requirements:
|
139
150
|
- - ! '>='
|
140
151
|
- !ruby/object:Gem::Version
|
@@ -142,23 +153,20 @@ dependencies:
|
|
142
153
|
- !ruby/object:Gem::Dependency
|
143
154
|
name: rake
|
144
155
|
requirement: !ruby/object:Gem::Requirement
|
145
|
-
none: false
|
146
156
|
requirements:
|
147
|
-
- -
|
157
|
+
- - ~>
|
148
158
|
- !ruby/object:Gem::Version
|
149
|
-
version:
|
159
|
+
version: 10.1.1
|
150
160
|
type: :development
|
151
161
|
prerelease: false
|
152
162
|
version_requirements: !ruby/object:Gem::Requirement
|
153
|
-
none: false
|
154
163
|
requirements:
|
155
|
-
- -
|
164
|
+
- - ~>
|
156
165
|
- !ruby/object:Gem::Version
|
157
|
-
version:
|
166
|
+
version: 10.1.1
|
158
167
|
- !ruby/object:Gem::Dependency
|
159
168
|
name: rr
|
160
169
|
requirement: !ruby/object:Gem::Requirement
|
161
|
-
none: false
|
162
170
|
requirements:
|
163
171
|
- - ! '>='
|
164
172
|
- !ruby/object:Gem::Version
|
@@ -166,7 +174,6 @@ dependencies:
|
|
166
174
|
type: :development
|
167
175
|
prerelease: false
|
168
176
|
version_requirements: !ruby/object:Gem::Requirement
|
169
|
-
none: false
|
170
177
|
requirements:
|
171
178
|
- - ! '>='
|
172
179
|
- !ruby/object:Gem::Version
|
@@ -174,7 +181,6 @@ dependencies:
|
|
174
181
|
- !ruby/object:Gem::Dependency
|
175
182
|
name: rspec
|
176
183
|
requirement: !ruby/object:Gem::Requirement
|
177
|
-
none: false
|
178
184
|
requirements:
|
179
185
|
- - ! '>='
|
180
186
|
- !ruby/object:Gem::Version
|
@@ -182,7 +188,6 @@ dependencies:
|
|
182
188
|
type: :development
|
183
189
|
prerelease: false
|
184
190
|
version_requirements: !ruby/object:Gem::Requirement
|
185
|
-
none: false
|
186
191
|
requirements:
|
187
192
|
- - ! '>='
|
188
193
|
- !ruby/object:Gem::Version
|
@@ -222,6 +227,7 @@ files:
|
|
222
227
|
- lib/mortar/command/pigscripts.rb
|
223
228
|
- lib/mortar/command/plugins.rb
|
224
229
|
- lib/mortar/command/projects.rb
|
230
|
+
- lib/mortar/command/s3.rb
|
225
231
|
- lib/mortar/command/validate.rb
|
226
232
|
- lib/mortar/command/version.rb
|
227
233
|
- lib/mortar/conf/luigi/logging.ini
|
@@ -244,6 +250,7 @@ files:
|
|
244
250
|
- lib/mortar/pigversion.rb
|
245
251
|
- lib/mortar/plugin.rb
|
246
252
|
- lib/mortar/project.rb
|
253
|
+
- lib/mortar/s3.rb
|
247
254
|
- lib/mortar/templates/characterize/README.md
|
248
255
|
- lib/mortar/templates/characterize/controlscripts/lib/__init__.py
|
249
256
|
- lib/mortar/templates/characterize/controlscripts/lib/characterize_control.py
|
@@ -304,6 +311,7 @@ files:
|
|
304
311
|
- spec/mortar/command/local_spec.rb
|
305
312
|
- spec/mortar/command/pigscripts_spec.rb
|
306
313
|
- spec/mortar/command/projects_spec.rb
|
314
|
+
- spec/mortar/command/s3_spec.rb
|
307
315
|
- spec/mortar/command/validate_spec.rb
|
308
316
|
- spec/mortar/command/version_spec.rb
|
309
317
|
- spec/mortar/command_spec.rb
|
@@ -317,32 +325,33 @@ files:
|
|
317
325
|
- spec/mortar/local/python_spec.rb
|
318
326
|
- spec/mortar/plugin_spec.rb
|
319
327
|
- spec/mortar/project_spec.rb
|
328
|
+
- spec/mortar/s3_spec.rb
|
320
329
|
- spec/mortar/updater_spec.rb
|
330
|
+
- spec/s3_faker.rb
|
321
331
|
- spec/spec.opts
|
322
332
|
- spec/spec_helper.rb
|
323
333
|
- spec/support/display_message_matcher.rb
|
324
334
|
homepage: http://mortardata.com/
|
325
335
|
licenses: []
|
336
|
+
metadata: {}
|
326
337
|
post_install_message:
|
327
338
|
rdoc_options: []
|
328
339
|
require_paths:
|
329
340
|
- lib
|
330
341
|
required_ruby_version: !ruby/object:Gem::Requirement
|
331
|
-
none: false
|
332
342
|
requirements:
|
333
343
|
- - ! '>='
|
334
344
|
- !ruby/object:Gem::Version
|
335
345
|
version: 1.8.7
|
336
346
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
337
|
-
none: false
|
338
347
|
requirements:
|
339
348
|
- - ! '>='
|
340
349
|
- !ruby/object:Gem::Version
|
341
350
|
version: '0'
|
342
351
|
requirements: []
|
343
352
|
rubyforge_project:
|
344
|
-
rubygems_version:
|
353
|
+
rubygems_version: 2.2.2
|
345
354
|
signing_key:
|
346
|
-
specification_version:
|
355
|
+
specification_version: 4
|
347
356
|
summary: Client library and CLI to interact with the Mortar service.
|
348
357
|
test_files: []
|