mortar 0.14.1 → 0.15.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.
- checksums.yaml +7 -0
- data/lib/mortar/command/base.rb +17 -1
- data/lib/mortar/command/describe.rb +1 -1
- data/lib/mortar/command/illustrate.rb +3 -3
- data/lib/mortar/command/jobs.rb +2 -0
- data/lib/mortar/command/local.rb +39 -2
- data/lib/mortar/conf/luigi/logging.ini +30 -0
- data/lib/mortar/local/controller.rb +8 -2
- data/lib/mortar/local/installutil.rb +54 -0
- data/lib/mortar/local/pig.rb +16 -57
- data/lib/mortar/local/python.rb +60 -5
- data/lib/mortar/project.rb +28 -1
- data/lib/mortar/templates/script/runpython.sh +12 -0
- data/lib/mortar/version.rb +1 -1
- data/spec/mortar/command/base_spec.rb +7 -0
- data/spec/mortar/command/local_spec.rb +46 -2
- data/spec/mortar/local/controller_spec.rb +3 -2
- data/spec/mortar/local/pig_spec.rb +25 -10
- data/spec/mortar/local/python_spec.rb +21 -0
- metadata +19 -41
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: a48ef7a19f19d16af145ed38847a5c316c509361
|
4
|
+
data.tar.gz: 4d554dd57193f50f23b0f98b273695d6e7d1af2c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: d8a722fdcc23c6312b8faac36dba45d9f2399d6bbb64c2187576abd600fead99d0c20dfd7073002d1f4903c9026409b57b219ba49ace184d5334f0b575ab7ba1
|
7
|
+
data.tar.gz: 868f456e447061aaeb90a941a00f2cdf0b0706fa7355fe5753a7554ec99af13d43501bcb553aa3246ff0aa9605382f6cc5f620733ae57327cbe521b1970a5b1c
|
data/lib/mortar/command/base.rb
CHANGED
@@ -399,7 +399,18 @@ protected
|
|
399
399
|
|
400
400
|
pigscript or controlscript
|
401
401
|
end
|
402
|
-
|
402
|
+
|
403
|
+
def validate_luigiscript!(luigiscript_name)
|
404
|
+
shortened_script_name = File.basename(luigiscript_name, ".*")
|
405
|
+
unless luigiscript = project.luigiscripts[shortened_script_name]
|
406
|
+
available_scripts = project.luigiscripts.none? ? "No luigiscripts found" : "Available luigiscripts:\n#{project.luigiscripts.collect{|k,v| v.executable_path}.sort.join("\n")}"
|
407
|
+
error("Unable to find luigiscript #{shortened_script_name}\n#{available_scripts}")
|
408
|
+
end
|
409
|
+
#While validating we can load the defaults that are relevant to this script.
|
410
|
+
load_defaults(shortened_script_name)
|
411
|
+
luigiscript
|
412
|
+
end
|
413
|
+
|
403
414
|
def validate_pigscript!(pigscript_name)
|
404
415
|
shortened_pigscript_name = File.basename(pigscript_name, ".*")
|
405
416
|
unless pigscript = project.pigscripts[shortened_pigscript_name]
|
@@ -467,6 +478,11 @@ protected
|
|
467
478
|
elsif remotes.values.uniq.size == 1
|
468
479
|
# take the only project in the remotes
|
469
480
|
[remotes.first[1], remotes.first[0]]
|
481
|
+
elsif remotes.has_key? 'mortar'
|
482
|
+
# In some cases (like forking a public project in mortar-code)
|
483
|
+
# we'll have more than one possible remote. We'll default to the
|
484
|
+
# one called mortar.
|
485
|
+
[remotes['mortar'], 'mortar']
|
470
486
|
else
|
471
487
|
raise(Mortar::Command::CommandFailed, "Multiple projects in folder and no project specified.\nSpecify which project to use with --project <project name>")
|
472
488
|
end
|
@@ -40,14 +40,14 @@ class Mortar::Command::Illustrate < Mortar::Command::Base
|
|
40
40
|
def index
|
41
41
|
pigscript_name = shift_argument
|
42
42
|
alias_name = shift_argument
|
43
|
-
skip_pruning = options[:skippruning] ||= false
|
44
|
-
|
45
43
|
validate_arguments!
|
46
|
-
|
44
|
+
|
45
|
+
skip_pruning = options[:skippruning] ||= false
|
47
46
|
|
48
47
|
unless pigscript_name
|
49
48
|
error("Usage: mortar illustrate PIGSCRIPT [ALIAS]\nMust specify PIGSCRIPT.")
|
50
49
|
end
|
50
|
+
pigscript = validate_script!(pigscript_name)
|
51
51
|
|
52
52
|
if pigscript.is_a? Mortar::Project::ControlScript
|
53
53
|
error "Currently Mortar does not support illustrating control scripts"
|
data/lib/mortar/command/jobs.rb
CHANGED
@@ -205,6 +205,7 @@ class Mortar::Command::Jobs < Mortar::Command::Base
|
|
205
205
|
unless job_id
|
206
206
|
error("Usage: mortar jobs:status JOB_ID\nMust specify JOB_ID.")
|
207
207
|
end
|
208
|
+
validate_arguments!
|
208
209
|
|
209
210
|
# Inner function to display the hash table when the job is complte
|
210
211
|
def display_job_status(job_status)
|
@@ -313,6 +314,7 @@ class Mortar::Command::Jobs < Mortar::Command::Base
|
|
313
314
|
unless job_id
|
314
315
|
error("Usage: mortar jobs:stop JOB_ID\nMust specify JOB_ID.")
|
315
316
|
end
|
317
|
+
validate_arguments!
|
316
318
|
|
317
319
|
response = api.stop_job(job_id).body
|
318
320
|
|
data/lib/mortar/command/local.rb
CHANGED
@@ -144,7 +144,10 @@ class Mortar::Command::Local < Mortar::Command::Base
|
|
144
144
|
def illustrate
|
145
145
|
pigscript_name = shift_argument
|
146
146
|
alias_name = shift_argument
|
147
|
+
validate_arguments!
|
148
|
+
|
147
149
|
skip_pruning = options[:skippruning] ||= false
|
150
|
+
no_browser = options[:no_browser] ||= false
|
148
151
|
|
149
152
|
unless pigscript_name
|
150
153
|
error("Usage: mortar local:illustrate PIGSCRIPT [ALIAS]\nMust specify PIGSCRIPT.")
|
@@ -157,11 +160,10 @@ class Mortar::Command::Local < Mortar::Command::Base
|
|
157
160
|
end
|
158
161
|
Dir.chdir(project_root)
|
159
162
|
|
160
|
-
validate_arguments!
|
161
163
|
pigscript = validate_pigscript!(pigscript_name)
|
162
164
|
|
163
165
|
ctrl = Mortar::Local::Controller.new
|
164
|
-
ctrl.illustrate(pigscript, alias_name, pig_version, pig_parameters, skip_pruning)
|
166
|
+
ctrl.illustrate(pigscript, alias_name, pig_version, pig_parameters, skip_pruning, no_browser)
|
165
167
|
end
|
166
168
|
|
167
169
|
|
@@ -211,4 +213,39 @@ class Mortar::Command::Local < Mortar::Command::Base
|
|
211
213
|
ctrl.repl(pig_version, pig_parameters)
|
212
214
|
end
|
213
215
|
|
216
|
+
|
217
|
+
# local:luigi SCRIPT
|
218
|
+
#
|
219
|
+
# Run a luigi workflow on your local machine in local scheduler mode.
|
220
|
+
# Any additional command line arguments will be passed directly to the luigi script.
|
221
|
+
#
|
222
|
+
# -p, --parameter NAME=VALUE # Set a pig parameter value in your script.
|
223
|
+
# -f, --param-file PARAMFILE # Load pig parameter values from a file.
|
224
|
+
# --project-root PROJECTDIR # The root directory of the project if not the CWD
|
225
|
+
#
|
226
|
+
#Examples:
|
227
|
+
#
|
228
|
+
# Run the recsys luigi script with a parameter named date-interval
|
229
|
+
# $ mortar local:luigi luigiscripts/recsys.py --date-interval 2012-04
|
230
|
+
def luigi
|
231
|
+
script_name = shift_argument
|
232
|
+
unless script_name
|
233
|
+
error("Usage: mortar local:luigi SCRIPT\nMust specify SCRIPT.")
|
234
|
+
end
|
235
|
+
validate_arguments!
|
236
|
+
|
237
|
+
# cd into the project root
|
238
|
+
project_root = options[:project_root] ||= Dir.getwd
|
239
|
+
unless File.directory?(project_root)
|
240
|
+
error("No such directory #{project_root}")
|
241
|
+
end
|
242
|
+
Dir.chdir(project_root)
|
243
|
+
script = validate_luigiscript!(script_name)
|
244
|
+
ctrl = Mortar::Local::Controller.new
|
245
|
+
luigi_params = pig_parameters.sort_by { |p| p['name'] }
|
246
|
+
luigi_params = luigi_params.map { |arg| ["--#{arg['name']}", "#{arg['value']}"] }.flatten
|
247
|
+
ctrl.run_luigi(script, luigi_params)
|
248
|
+
end
|
249
|
+
|
250
|
+
|
214
251
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
|
2
|
+
[loggers]
|
3
|
+
keys=root,luigi-interface
|
4
|
+
|
5
|
+
[handlers]
|
6
|
+
keys=console
|
7
|
+
|
8
|
+
[formatters]
|
9
|
+
keys=standard,plain
|
10
|
+
|
11
|
+
[logger_root]
|
12
|
+
level=DEBUG
|
13
|
+
handlers=console
|
14
|
+
|
15
|
+
[logger_luigi-interface]
|
16
|
+
level=DEBUG
|
17
|
+
handlers=
|
18
|
+
qualname=luigi-interface
|
19
|
+
|
20
|
+
[handler_console]
|
21
|
+
level=DEBUG
|
22
|
+
class=StreamHandler
|
23
|
+
args=(sys.stderr,)
|
24
|
+
formatter=standard
|
25
|
+
|
26
|
+
[formatter_standard]
|
27
|
+
format=%(asctime)s [%(process)d:%(threadName)s] (%(filename)s:%(lineno)d) %(levelname)-5.5s - %(message)s
|
28
|
+
|
29
|
+
[formatter_plain]
|
30
|
+
format=%(message)s
|
@@ -181,11 +181,11 @@ EOF
|
|
181
181
|
end
|
182
182
|
|
183
183
|
# Main entry point for illustrating a pig alias
|
184
|
-
def illustrate(pig_script, pig_alias, pig_version, pig_parameters, skip_pruning)
|
184
|
+
def illustrate(pig_script, pig_alias, pig_version, pig_parameters, skip_pruning, no_browser)
|
185
185
|
require_aws_keys
|
186
186
|
install_and_configure(pig_version)
|
187
187
|
pig = Mortar::Local::Pig.new()
|
188
|
-
pig.illustrate_alias(pig_script, pig_alias, skip_pruning, pig_version, pig_parameters)
|
188
|
+
pig.illustrate_alias(pig_script, pig_alias, skip_pruning, no_browser, pig_version, pig_parameters)
|
189
189
|
end
|
190
190
|
|
191
191
|
def validate(pig_script, pig_version, pig_parameters)
|
@@ -200,4 +200,10 @@ EOF
|
|
200
200
|
pig.launch_repl(pig_version, pig_parameters)
|
201
201
|
end
|
202
202
|
|
203
|
+
def run_luigi(luigi_script, user_script_args)
|
204
|
+
install_and_configure()
|
205
|
+
py = Mortar::Local::Python.new()
|
206
|
+
py.run_luigi_script(luigi_script, user_script_args)
|
207
|
+
end
|
208
|
+
|
203
209
|
end
|
@@ -165,6 +165,7 @@ module Mortar
|
|
165
165
|
else
|
166
166
|
raise RuntimeError, "Unknown call type: #{call_func}"
|
167
167
|
end
|
168
|
+
|
168
169
|
case response.status
|
169
170
|
when 300..303 then
|
170
171
|
make_call(response.headers['Location'], call_func, redirect_times+1, errors)
|
@@ -207,6 +208,59 @@ module Mortar
|
|
207
208
|
return existing_install_date < remote_archive_date
|
208
209
|
end
|
209
210
|
|
211
|
+
def run_templated_script(template, template_params)
|
212
|
+
# Insert standard template variables
|
213
|
+
template_params['project_home'] = File.expand_path("..", local_install_directory)
|
214
|
+
template_params['local_install_dir'] = local_install_directory
|
215
|
+
|
216
|
+
unset_hadoop_env_vars
|
217
|
+
reset_local_logs
|
218
|
+
# Generate the script for running the command, then
|
219
|
+
# write it to a temp script which will be exectued
|
220
|
+
script_text = render_script_template(template, template_params)
|
221
|
+
script = Tempfile.new("mortar-")
|
222
|
+
script.write(script_text)
|
223
|
+
script.close(false)
|
224
|
+
FileUtils.chmod(0755, script.path)
|
225
|
+
system(script.path)
|
226
|
+
script.unlink
|
227
|
+
return (0 == $?.to_i)
|
228
|
+
end
|
229
|
+
|
230
|
+
def render_script_template(template, template_params)
|
231
|
+
erb = ERB.new(File.read(template), 0, "%<>")
|
232
|
+
erb.result(BindingClazz.new(template_params).get_binding)
|
233
|
+
end
|
234
|
+
|
235
|
+
# so Pig doesn't try to load the wrong hadoop jar/configuration
|
236
|
+
# this doesn't mess up the env vars in the terminal, just this process (ruby)
|
237
|
+
def unset_hadoop_env_vars
|
238
|
+
ENV['HADOOP_HOME'] = ''
|
239
|
+
ENV['HADOOP_CONF_DIR'] = ''
|
240
|
+
end
|
241
|
+
|
242
|
+
def reset_local_logs
|
243
|
+
if File.directory? local_log_dir
|
244
|
+
FileUtils.rm_rf local_log_dir
|
245
|
+
end
|
246
|
+
Dir.mkdir local_log_dir
|
247
|
+
Dir.mkdir local_udf_log_dir
|
248
|
+
end
|
249
|
+
|
250
|
+
|
251
|
+
# Allows us to use a hash for template variables
|
252
|
+
class BindingClazz
|
253
|
+
def initialize(attrs)
|
254
|
+
attrs.each{ |k, v|
|
255
|
+
# set an instance variable with the key name so the binding will find it in scope
|
256
|
+
self.instance_variable_set("@#{k}".to_sym, v)
|
257
|
+
}
|
258
|
+
end
|
259
|
+
def get_binding()
|
260
|
+
binding
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
210
264
|
end
|
211
265
|
end
|
212
266
|
end
|
data/lib/mortar/local/pig.rb
CHANGED
@@ -202,7 +202,7 @@ class Mortar::Local::Pig
|
|
202
202
|
outfile.path
|
203
203
|
end
|
204
204
|
|
205
|
-
# Given a file path, open it and decode the containing
|
205
|
+
# Given a file path, open it and decode the containing text
|
206
206
|
def decode_illustrate_input_file(illustrate_outpath)
|
207
207
|
data_raw = File.read(illustrate_outpath)
|
208
208
|
begin
|
@@ -212,10 +212,9 @@ class Mortar::Local::Pig
|
|
212
212
|
ic = Iconv.new('UTF-8//IGNORE', 'UTF-8')
|
213
213
|
data_encoded = ic.iconv(data_raw)
|
214
214
|
end
|
215
|
-
json_decode(data_encoded)
|
216
215
|
end
|
217
216
|
|
218
|
-
def
|
217
|
+
def show_illustrate_output_browser(illustrate_outpath)
|
219
218
|
ensure_dir_exists("illustrate-output")
|
220
219
|
ensure_dir_exists("illustrate-output/resources")
|
221
220
|
ensure_dir_exists("illustrate-output/resources/css")
|
@@ -229,7 +228,8 @@ class Mortar::Local::Pig
|
|
229
228
|
}
|
230
229
|
|
231
230
|
# Pull in the dumped json file
|
232
|
-
|
231
|
+
illustrate_data_json_text = decode_illustrate_input_file(illustrate_outpath)
|
232
|
+
illustrate_data = json_decode(illustrate_data_json_text)
|
233
233
|
|
234
234
|
# Render a template using it's values
|
235
235
|
template_params = create_illustrate_template_parameters(illustrate_data)
|
@@ -248,7 +248,6 @@ class Mortar::Local::Pig
|
|
248
248
|
require "launchy"
|
249
249
|
Launchy.open(File.expand_path(@resource_destinations["illustrate_html"]))
|
250
250
|
end
|
251
|
-
|
252
251
|
end
|
253
252
|
|
254
253
|
def create_illustrate_template_parameters(illustrate_data)
|
@@ -258,7 +257,7 @@ class Mortar::Local::Pig
|
|
258
257
|
return params
|
259
258
|
end
|
260
259
|
|
261
|
-
def illustrate_alias(pig_script, pig_alias, skip_pruning, pig_version, pig_parameters)
|
260
|
+
def illustrate_alias(pig_script, pig_alias, skip_pruning, no_browser, pig_version, pig_parameters)
|
262
261
|
cmd = "-e 'illustrate "
|
263
262
|
|
264
263
|
# Parameters have to be entered with the illustrate command (as
|
@@ -275,7 +274,11 @@ class Mortar::Local::Pig
|
|
275
274
|
cmd += " -skipPruning "
|
276
275
|
end
|
277
276
|
|
278
|
-
|
277
|
+
if no_browser
|
278
|
+
cmd += " -str '"
|
279
|
+
else
|
280
|
+
cmd += " -json '"
|
281
|
+
end
|
279
282
|
|
280
283
|
if pig_alias
|
281
284
|
cmd += " #{pig_alias} "
|
@@ -283,7 +286,11 @@ class Mortar::Local::Pig
|
|
283
286
|
|
284
287
|
result = run_pig_command(cmd, pig_version, [], false)
|
285
288
|
if result
|
286
|
-
|
289
|
+
if no_browser
|
290
|
+
display decode_illustrate_input_file(illustrate_outpath)
|
291
|
+
else
|
292
|
+
show_illustrate_output_browser(illustrate_outpath)
|
293
|
+
end
|
287
294
|
end
|
288
295
|
end
|
289
296
|
|
@@ -291,42 +298,9 @@ class Mortar::Local::Pig
|
|
291
298
|
# can be appended to the command line invocation of Pig that will
|
292
299
|
# get it to do something interesting, such as '-f some-file.pig'
|
293
300
|
def run_pig_command(cmd, pig_version, parameters = nil, jython_output = true)
|
294
|
-
unset_hadoop_env_vars
|
295
|
-
reset_local_logs
|
296
|
-
# Generate the script for running the command, then
|
297
|
-
# write it to a temp script which will be exectued
|
298
|
-
script_text = script_for_command(cmd, pig_version, parameters)
|
299
|
-
script = Tempfile.new("mortar-")
|
300
|
-
script.write(script_text)
|
301
|
-
script.close(false)
|
302
|
-
FileUtils.chmod(0755, script.path)
|
303
|
-
system(script.path)
|
304
|
-
script.unlink
|
305
|
-
return (0 == $?.to_i)
|
306
|
-
end
|
307
|
-
|
308
|
-
# so Pig doesn't try to load the wrong hadoop jar/configuration
|
309
|
-
# this doesn't mess up the env vars in the terminal, just this process (ruby)
|
310
|
-
def unset_hadoop_env_vars
|
311
|
-
ENV['HADOOP_HOME'] = ''
|
312
|
-
ENV['HADOOP_CONF_DIR'] = ''
|
313
|
-
end
|
314
|
-
|
315
|
-
def reset_local_logs
|
316
|
-
if File.directory? local_log_dir
|
317
|
-
FileUtils.rm_rf local_log_dir
|
318
|
-
end
|
319
|
-
Dir.mkdir local_log_dir
|
320
|
-
Dir.mkdir local_udf_log_dir
|
321
|
-
end
|
322
|
-
|
323
|
-
# Generates a bash script which sets up the necessary environment and
|
324
|
-
# then runs the pig command
|
325
|
-
def script_for_command(cmd, pig_version, parameters, jython_output = true)
|
326
301
|
template_params = pig_command_script_template_parameters(cmd, pig_version, parameters)
|
327
302
|
template_params['pig_opts']['jython.output'] = jython_output
|
328
|
-
|
329
|
-
erb.result(BindingClazz.new(template_params).get_binding)
|
303
|
+
return run_templated_script(pig_command_script_template_path, template_params)
|
330
304
|
end
|
331
305
|
|
332
306
|
# Path to the template which generates the bash script for running pig
|
@@ -355,8 +329,6 @@ class Mortar::Local::Pig
|
|
355
329
|
template_params['pig_classpath'] = "#{pig_directory(pig_version)}/lib-local/*:#{lib_directory}/lib-local/*:#{pig_directory(pig_version)}/lib-pig/*:#{pig_directory(pig_version)}/lib-cluster/*:#{lib_directory}/lib-pig/*:#{lib_directory}/lib-cluster/*:#{jython_directory}/jython.jar"
|
356
330
|
template_params['classpath'] = template_params_classpath
|
357
331
|
template_params['log4j_conf'] = log4j_conf
|
358
|
-
template_params['project_home'] = File.expand_path("..", local_install_directory)
|
359
|
-
template_params['local_install_dir'] = local_install_directory
|
360
332
|
template_params['pig_sub_command'] = cmd
|
361
333
|
template_params['pig_opts'] = pig_options
|
362
334
|
template_params
|
@@ -423,17 +395,4 @@ class Mortar::Local::Pig
|
|
423
395
|
param_file.path
|
424
396
|
end
|
425
397
|
|
426
|
-
# Allows us to use a hash for template variables
|
427
|
-
class BindingClazz
|
428
|
-
def initialize(attrs)
|
429
|
-
attrs.each{ |k, v|
|
430
|
-
# set an instance variable with the key name so the binding will find it in scope
|
431
|
-
self.instance_variable_set("@#{k}".to_sym, v)
|
432
|
-
}
|
433
|
-
end
|
434
|
-
def get_binding()
|
435
|
-
binding
|
436
|
-
end
|
437
|
-
end
|
438
|
-
|
439
398
|
end
|
data/lib/mortar/local/python.rb
CHANGED
@@ -21,8 +21,9 @@ class Mortar::Local::Python
|
|
21
21
|
|
22
22
|
PYTHON_OSX_TGZ_NAME = "mortar-python-osx.tgz"
|
23
23
|
PYTHON_OSX_TGZ_DEFAULT_URL_PATH = "resource/python_osx"
|
24
|
+
PYPI_URL_PATH = "resource/mortar_pypi"
|
24
25
|
|
25
|
-
MORTAR_PYTHON_PACKAGES = ["luigi"]
|
26
|
+
MORTAR_PYTHON_PACKAGES = ["luigi", "mortar-luigi"]
|
26
27
|
|
27
28
|
# Path to the python binary that should be used
|
28
29
|
# for running UDFs
|
@@ -167,8 +168,11 @@ class Mortar::Local::Python
|
|
167
168
|
end
|
168
169
|
|
169
170
|
def has_valid_virtualenv?
|
170
|
-
`#{@command} -m virtualenv #{python_env_dir}`
|
171
|
+
output = `#{@command} -m virtualenv #{python_env_dir} 2>&1`
|
171
172
|
if 0 != $?.to_i
|
173
|
+
File.open(virtualenv_error_log_path, 'w') { |f|
|
174
|
+
f.write(output)
|
175
|
+
}
|
172
176
|
return false
|
173
177
|
end
|
174
178
|
return true
|
@@ -205,6 +209,10 @@ class Mortar::Local::Python
|
|
205
209
|
return ENV.fetch('PIP_ERROR_LOG', "dependency_install.log")
|
206
210
|
end
|
207
211
|
|
212
|
+
def virtualenv_error_log_path
|
213
|
+
return ENV.fetch('VE_ERROR_LOG', "virtualenv.log")
|
214
|
+
end
|
215
|
+
|
208
216
|
# Whether or not we need to do a `pip install -r requirements.txt` because
|
209
217
|
# we've never done one before or the dependencies have changed
|
210
218
|
def should_do_requirements_install
|
@@ -230,7 +238,9 @@ class Mortar::Local::Python
|
|
230
238
|
end
|
231
239
|
|
232
240
|
def mortar_package_url(package)
|
233
|
-
|
241
|
+
full_host = (host =~ /^http/) ? host : "https://api.#{host}"
|
242
|
+
default_url = full_host + "/" + PYPI_URL_PATH
|
243
|
+
"#{ENV.fetch('MORTAR_PACKAGE_URL', default_url)}/#{package}"
|
234
244
|
end
|
235
245
|
|
236
246
|
def update_mortar_package?(package)
|
@@ -266,9 +276,27 @@ class Mortar::Local::Python
|
|
266
276
|
return true
|
267
277
|
end
|
268
278
|
|
279
|
+
def local_activate_path
|
280
|
+
return "#{python_env_dir}/bin/activate"
|
281
|
+
end
|
282
|
+
|
283
|
+
def local_python_bin
|
284
|
+
return "#{python_env_dir}/bin/python"
|
285
|
+
end
|
286
|
+
|
287
|
+
def local_pip_bin
|
288
|
+
return "#{python_env_dir}/bin/pip"
|
289
|
+
end
|
290
|
+
|
269
291
|
def pip_install package_url
|
270
|
-
|
271
|
-
|
292
|
+
# Note that we're executing pip by passing it as a script for python to execute, this is
|
293
|
+
# explicitly done to deal with this command breaking due to the maximum size of the path
|
294
|
+
# to the interpreter in a shebang. Since the containing virtualenv is already buried
|
295
|
+
# several layers deep in the .mortar-local directory we're very likely to (read: have) hit
|
296
|
+
# this limit. This unfortunately leads to very vague errors about pip not existing when
|
297
|
+
# in fact it is the truncated path to the interpreter that does not exist. I would now
|
298
|
+
# like the last day of my life back.
|
299
|
+
pip_output = `. #{local_activate_path} && #{local_python_bin} #{local_pip_bin} install #{package_url} --use-mirrors;`
|
272
300
|
if 0 != $?.to_i
|
273
301
|
File.open(pip_error_log_path, 'w') { |f|
|
274
302
|
f.write(pip_output)
|
@@ -287,4 +315,31 @@ class Mortar::Local::Python
|
|
287
315
|
note_install mortar_package_dir(package_name)
|
288
316
|
end
|
289
317
|
|
318
|
+
def run_luigi_script(luigi_script, user_script_args)
|
319
|
+
template_params = luigi_command_template_parameters(luigi_script, user_script_args)
|
320
|
+
return run_templated_script(python_command_script_template_path, template_params)
|
321
|
+
end
|
322
|
+
|
323
|
+
# Path to the template which generates the bash script for running python
|
324
|
+
def python_command_script_template_path
|
325
|
+
File.expand_path("../../templates/script/runpython.sh", __FILE__)
|
326
|
+
end
|
327
|
+
|
328
|
+
def luigi_logging_config_file_path
|
329
|
+
File.expand_path("../../conf/luigi/logging.ini", __FILE__)
|
330
|
+
end
|
331
|
+
|
332
|
+
def luigi_command_template_parameters(luigi_script, user_script_args)
|
333
|
+
script_args = [
|
334
|
+
"--local-scheduler",
|
335
|
+
"--logging-conf-file #{luigi_logging_config_file_path}",
|
336
|
+
user_script_args.join(" "),
|
337
|
+
]
|
338
|
+
return {
|
339
|
+
:python_arugments => "",
|
340
|
+
:python_script => luigi_script.executable_path(),
|
341
|
+
:script_arguments => script_args.join(" ")
|
342
|
+
}
|
343
|
+
end
|
344
|
+
|
290
345
|
end
|
data/lib/mortar/project.rb
CHANGED
@@ -70,7 +70,20 @@ module Mortar
|
|
70
70
|
:optional => true)
|
71
71
|
@controlscripts
|
72
72
|
end
|
73
|
-
|
73
|
+
|
74
|
+
def luigiscripts_path
|
75
|
+
File.join(@root_path, "luigiscripts")
|
76
|
+
end
|
77
|
+
|
78
|
+
def luigiscripts
|
79
|
+
@luigiscripts ||= LuigiScripts.new(
|
80
|
+
luigiscripts_path,
|
81
|
+
"luigiscripts",
|
82
|
+
".py",
|
83
|
+
:optional => true)
|
84
|
+
@luigiscripts
|
85
|
+
end
|
86
|
+
|
74
87
|
def tmp_path
|
75
88
|
path = File.join(@root_path, "tmp")
|
76
89
|
unless File.directory? path
|
@@ -153,6 +166,12 @@ module Mortar
|
|
153
166
|
end
|
154
167
|
end
|
155
168
|
|
169
|
+
class LuigiScripts < ProjectEntity
|
170
|
+
def element(name, path)
|
171
|
+
LuigiScript.new(name, path)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
156
175
|
class PythonUDFs < ProjectEntity
|
157
176
|
def element(name, path)
|
158
177
|
Script.new(name, path)
|
@@ -180,6 +199,14 @@ module Mortar
|
|
180
199
|
code
|
181
200
|
end
|
182
201
|
end
|
202
|
+
|
203
|
+
class LuigiScript < Script
|
204
|
+
|
205
|
+
def executable_path
|
206
|
+
"luigiscripts/#{self.name}.py"
|
207
|
+
end
|
208
|
+
|
209
|
+
end
|
183
210
|
|
184
211
|
class ControlScript < Script
|
185
212
|
|
@@ -0,0 +1,12 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
|
3
|
+
set -e
|
4
|
+
|
5
|
+
# Setup python environment
|
6
|
+
source <%= @local_install_dir %>/pythonenv/bin/activate
|
7
|
+
|
8
|
+
# Run Python
|
9
|
+
<%= @local_install_dir %>/pythonenv/bin/python \
|
10
|
+
<%= @python_arugments %> \
|
11
|
+
<%= @python_script %> \
|
12
|
+
<%= @script_arguments %>
|
data/lib/mortar/version.rb
CHANGED
@@ -69,6 +69,13 @@ other\tgit@github.com:other.git (push)
|
|
69
69
|
@base.project.name.should == 'myproject'
|
70
70
|
end
|
71
71
|
|
72
|
+
it "gets the project from remotes when there's two projects but one mortar remote" do
|
73
|
+
stub(@base.git).has_dot_git? {true}
|
74
|
+
stub(@base.git).remotes {{ 'mortar' => 'myproject', 'base' => 'my-base-project'}}
|
75
|
+
mock(@base.git).git("config mortar.remote", false).returns("")
|
76
|
+
@base.project.name.should == 'myproject'
|
77
|
+
end
|
78
|
+
|
72
79
|
it "accepts a --remote argument to choose the project from the remote name" do
|
73
80
|
stub(@base.git).has_dot_git?.returns(true)
|
74
81
|
stub(@base.git).remotes.returns({ 'staging' => 'myproject-staging', 'production' => 'myproject' })
|
@@ -44,7 +44,7 @@ STDERR
|
|
44
44
|
pigscript = Mortar::Project::PigScript.new(script_name, script_path)
|
45
45
|
mock(Mortar::Project::PigScript).new(script_name, script_path).returns(pigscript)
|
46
46
|
any_instance_of(Mortar::Local::Controller) do |u|
|
47
|
-
mock(u).illustrate(pigscript, "some_alias", is_a(Mortar::PigVersion::Pig09), [], false).returns(nil)
|
47
|
+
mock(u).illustrate(pigscript, "some_alias", is_a(Mortar::PigVersion::Pig09), [], false, false).returns(nil)
|
48
48
|
end
|
49
49
|
stderr, stdout = execute("local:illustrate #{script_name} some_alias", p)
|
50
50
|
stderr.should == ""
|
@@ -59,7 +59,7 @@ STDERR
|
|
59
59
|
pigscript = Mortar::Project::PigScript.new(script_name, script_path)
|
60
60
|
mock(Mortar::Project::PigScript).new(script_name, script_path).returns(pigscript)
|
61
61
|
any_instance_of(Mortar::Local::Controller) do |u|
|
62
|
-
mock(u).illustrate(pigscript, nil, is_a(Mortar::PigVersion::Pig012), [], false).returns(nil)
|
62
|
+
mock(u).illustrate(pigscript, nil, is_a(Mortar::PigVersion::Pig012), [], false, false).returns(nil)
|
63
63
|
end
|
64
64
|
stderr, stdout = execute("local:illustrate #{script_name} -g 0.12", p)
|
65
65
|
stderr.should == ""
|
@@ -228,6 +228,50 @@ PARAMS
|
|
228
228
|
|
229
229
|
end
|
230
230
|
|
231
|
+
context "local:luigi" do
|
232
|
+
|
233
|
+
it "Exits with error if no script specified" do
|
234
|
+
with_git_initialized_project do |p|
|
235
|
+
stderr, stdout = execute("local:luigi", p)
|
236
|
+
stderr.should == <<-STDERR
|
237
|
+
! Usage: mortar local:luigi SCRIPT
|
238
|
+
! Must specify SCRIPT.
|
239
|
+
STDERR
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
it "Exits with error if script doesn't exist" do
|
244
|
+
with_git_initialized_project do |p|
|
245
|
+
stderr, stdout = execute("local:luigi foobarbaz", p)
|
246
|
+
stderr.should == <<-STDERR
|
247
|
+
! Unable to find luigiscript foobarbaz
|
248
|
+
! No luigiscripts found
|
249
|
+
STDERR
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
it "Runs script forwarding options to luigi script" do
|
254
|
+
with_git_initialized_project do |p|
|
255
|
+
script_name = "some_luigi_script"
|
256
|
+
script_path = File.join(p.luigiscripts_path, "#{script_name}.py")
|
257
|
+
write_file(script_path)
|
258
|
+
luigi_script = Mortar::Project::LuigiScript.new(script_name, script_path)
|
259
|
+
mock(Mortar::Project::LuigiScript).new(script_name, script_path).returns(luigi_script)
|
260
|
+
any_instance_of(Mortar::Local::Python) do |u|
|
261
|
+
mock(u).run_luigi_script(luigi_script, %W{--myoption 2 --myotheroption 3})
|
262
|
+
end
|
263
|
+
any_instance_of(Mortar::Local::Controller) do |u|
|
264
|
+
mock(u).install_and_configure
|
265
|
+
end
|
266
|
+
stderr, stdout = execute("local:luigi some_luigi_script -p myoption=2 -p myotheroption=3", p)
|
267
|
+
stderr.should == ""
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
|
272
|
+
end
|
273
|
+
|
274
|
+
|
231
275
|
end
|
232
276
|
end
|
233
277
|
|
@@ -175,11 +175,12 @@ module Mortar::Local
|
|
175
175
|
test_script = "foobar-script"
|
176
176
|
script_alias = "some_alias"
|
177
177
|
prune = false
|
178
|
+
no_browser = false
|
178
179
|
the_parameters = []
|
179
180
|
any_instance_of(Mortar::Local::Pig) do |p|
|
180
|
-
mock(p).illustrate_alias(test_script, script_alias, prune, "0.9", the_parameters)
|
181
|
+
mock(p).illustrate_alias(test_script, script_alias, prune, no_browser, "0.9", the_parameters)
|
181
182
|
end
|
182
|
-
c.illustrate(test_script, script_alias, "0.9", the_parameters, prune)
|
183
|
+
c.illustrate(test_script, script_alias, "0.9", the_parameters, prune, no_browser)
|
183
184
|
end
|
184
185
|
end
|
185
186
|
|
@@ -19,6 +19,7 @@ require 'fakefs/spec_helpers'
|
|
19
19
|
require 'mortar/local/pig'
|
20
20
|
require 'mortar/auth'
|
21
21
|
require 'launchy'
|
22
|
+
require 'mortar/pigversion'
|
22
23
|
|
23
24
|
class Mortar::Local::Pig
|
24
25
|
attr_reader :command
|
@@ -131,7 +132,9 @@ module Mortar::Local
|
|
131
132
|
template_location = pig.resource_locations["illustrate_template"]
|
132
133
|
template_contents = File.read(template_location)
|
133
134
|
output_path = pig.resource_destinations["illustrate_html"]
|
134
|
-
|
135
|
+
temp_text = "This is temporary text"
|
136
|
+
mock(pig).decode_illustrate_input_file("foo/bar/file.json").returns(temp_text)
|
137
|
+
mock(pig).json_decode(temp_text).returns(fake_illustrate_data)
|
135
138
|
|
136
139
|
# TODO: test that these files are copied
|
137
140
|
["illustrate_css",
|
@@ -149,7 +152,7 @@ module Mortar::Local
|
|
149
152
|
File.open(template_location, 'w') { |f| f.write(template_contents) }
|
150
153
|
begin
|
151
154
|
previous_stdout, $stdout = $stdout, StringIO.new
|
152
|
-
pig.
|
155
|
+
pig.show_illustrate_output_browser("foo/bar/file.json")
|
153
156
|
ensure
|
154
157
|
$stdout = previous_stdout
|
155
158
|
end
|
@@ -172,7 +175,8 @@ module Mortar::Local
|
|
172
175
|
illustrate_output_file = 'illustrate-output.json'
|
173
176
|
FakeFS do
|
174
177
|
File.open(illustrate_output_file, 'w') { |f| f.write(json) }
|
175
|
-
|
178
|
+
actual_data_raw = pig.decode_illustrate_input_file(illustrate_output_file)
|
179
|
+
actual_data = pig.json_decode(actual_data_raw)
|
176
180
|
expect(actual_data).to eq(expected_data)
|
177
181
|
end
|
178
182
|
end
|
@@ -187,7 +191,8 @@ module Mortar::Local
|
|
187
191
|
illustrate_output_file = 'illustrate-output.json'
|
188
192
|
FakeFS do
|
189
193
|
File.open(illustrate_output_file, 'w') { |f| f.write(json) }
|
190
|
-
|
194
|
+
actual_data_raw = pig.decode_illustrate_input_file(illustrate_output_file)
|
195
|
+
actual_data = pig.json_decode(actual_data_raw)
|
191
196
|
expect(actual_data).to eq(expected_data)
|
192
197
|
end
|
193
198
|
end
|
@@ -201,9 +206,19 @@ module Mortar::Local
|
|
201
206
|
script = Mortar::Project::PigScripts.new('/foo/bar/baz.pig', 'baz', 'pig')
|
202
207
|
pig = Mortar::Local::Pig.new
|
203
208
|
mock(pig).run_pig_command.with_any_args.returns(true)
|
204
|
-
mock(pig).
|
209
|
+
mock(pig).show_illustrate_output_browser.with_any_args
|
205
210
|
stub(pig).make_pig_param_file.returns('param.file')
|
206
|
-
pig.illustrate_alias(script, 'my_alias', false, "0.9", [])
|
211
|
+
pig.illustrate_alias(script, 'my_alias', false, false, "0.9", [])
|
212
|
+
end
|
213
|
+
|
214
|
+
it "displays text results if illustrate was successful with no_browser" do
|
215
|
+
any_instance_of(Mortar::Project::PigScripts, :elements => nil, :path => "/foo/bar/baz.pig")
|
216
|
+
script = Mortar::Project::PigScripts.new('/foo/bar/baz.pig', 'baz', 'pig')
|
217
|
+
pig = Mortar::Local::Pig.new
|
218
|
+
stub(pig).run_pig_command.with_any_args.returns(true)
|
219
|
+
mock(pig).display.with_any_args
|
220
|
+
stub(pig).make_pig_param_file.returns('param.file')
|
221
|
+
pig.illustrate_alias(script, 'my_alias', false, true, "0.9", [])
|
207
222
|
end
|
208
223
|
|
209
224
|
it "skips results if illustrate was unsuccessful" do
|
@@ -211,9 +226,9 @@ module Mortar::Local
|
|
211
226
|
script = Mortar::Project::PigScripts.new('/foo/bar/baz.pig', 'baz', 'pig')
|
212
227
|
pig = Mortar::Local::Pig.new
|
213
228
|
mock(pig).run_pig_command.with_any_args.returns(false)
|
214
|
-
mock(pig).
|
229
|
+
mock(pig).show_illustrate_output_browser.with_any_args.never
|
215
230
|
stub(pig).make_pig_param_file.returns('param.file')
|
216
|
-
pig.illustrate_alias(script, 'my_alias', false, "0.9", [])
|
231
|
+
pig.illustrate_alias(script, 'my_alias', false, false, "0.9", [])
|
217
232
|
end
|
218
233
|
|
219
234
|
it "does not require login credentials for illustration" do
|
@@ -222,8 +237,8 @@ module Mortar::Local
|
|
222
237
|
pig = Mortar::Local::Pig.new
|
223
238
|
mock(Mortar::Auth).user_s3_safe(true).returns('notloggedin-user-org')
|
224
239
|
mock(pig).run_pig_command.with_any_args.returns(true)
|
225
|
-
mock(pig).
|
226
|
-
pig.illustrate_alias(script, 'my_alias', false, "0.9", [])
|
240
|
+
mock(pig).show_illustrate_output_browser.with_any_args
|
241
|
+
pig.illustrate_alias(script, 'my_alias', false, false, "0.9", [])
|
227
242
|
end
|
228
243
|
|
229
244
|
end
|
@@ -128,5 +128,26 @@ module Mortar::Local
|
|
128
128
|
|
129
129
|
end
|
130
130
|
|
131
|
+
context "running python commands" do
|
132
|
+
|
133
|
+
it "Generates the appropriate tempate variables" do
|
134
|
+
with_git_initialized_project do |p|
|
135
|
+
script_name = "some_luigi_script"
|
136
|
+
script_path = File.join(p.luigiscripts_path, "#{script_name}.py")
|
137
|
+
write_file(script_path)
|
138
|
+
luigi_script = Mortar::Project::LuigiScript.new(script_name, script_path)
|
139
|
+
args = %W{--myoption 2 --myotheroption 3}
|
140
|
+
py = Mortar::Local::Python.new
|
141
|
+
expected_hash = {
|
142
|
+
:python_arugments => "",
|
143
|
+
:python_script => "luigiscripts/#{script_name}.py",
|
144
|
+
:script_arguments => "--local-scheduler --logging-conf-file #{py.luigi_logging_config_file_path} --myoption 2 --myotheroption 3",
|
145
|
+
}
|
146
|
+
expect(py.luigi_command_template_parameters(luigi_script, args)).to eq(expected_hash)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
end
|
151
|
+
|
131
152
|
end
|
132
153
|
end
|
metadata
CHANGED
@@ -1,36 +1,32 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mortar
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.15.0
|
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-02-
|
11
|
+
date: 2014-02-25 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
|
21
19
|
version: 4.0.0
|
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
|
29
26
|
version: 4.0.0
|
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,7 +76,6 @@ 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
|
@@ -94,7 +83,6 @@ dependencies:
|
|
94
83
|
- !ruby/object:Gem::Dependency
|
95
84
|
name: excon
|
96
85
|
requirement: !ruby/object:Gem::Requirement
|
97
|
-
none: false
|
98
86
|
requirements:
|
99
87
|
- - ~>
|
100
88
|
- !ruby/object:Gem::Version
|
@@ -102,7 +90,6 @@ dependencies:
|
|
102
90
|
type: :development
|
103
91
|
prerelease: false
|
104
92
|
version_requirements: !ruby/object:Gem::Requirement
|
105
|
-
none: false
|
106
93
|
requirements:
|
107
94
|
- - ~>
|
108
95
|
- !ruby/object:Gem::Version
|
@@ -110,7 +97,6 @@ dependencies:
|
|
110
97
|
- !ruby/object:Gem::Dependency
|
111
98
|
name: fakefs
|
112
99
|
requirement: !ruby/object:Gem::Requirement
|
113
|
-
none: false
|
114
100
|
requirements:
|
115
101
|
- - ~>
|
116
102
|
- !ruby/object:Gem::Version
|
@@ -118,7 +104,6 @@ dependencies:
|
|
118
104
|
type: :development
|
119
105
|
prerelease: false
|
120
106
|
version_requirements: !ruby/object:Gem::Requirement
|
121
|
-
none: false
|
122
107
|
requirements:
|
123
108
|
- - ~>
|
124
109
|
- !ruby/object:Gem::Version
|
@@ -126,65 +111,57 @@ dependencies:
|
|
126
111
|
- !ruby/object:Gem::Dependency
|
127
112
|
name: gem-release
|
128
113
|
requirement: !ruby/object:Gem::Requirement
|
129
|
-
none: false
|
130
114
|
requirements:
|
131
|
-
- -
|
115
|
+
- - '>='
|
132
116
|
- !ruby/object:Gem::Version
|
133
117
|
version: '0'
|
134
118
|
type: :development
|
135
119
|
prerelease: false
|
136
120
|
version_requirements: !ruby/object:Gem::Requirement
|
137
|
-
none: false
|
138
121
|
requirements:
|
139
|
-
- -
|
122
|
+
- - '>='
|
140
123
|
- !ruby/object:Gem::Version
|
141
124
|
version: '0'
|
142
125
|
- !ruby/object:Gem::Dependency
|
143
126
|
name: rake
|
144
127
|
requirement: !ruby/object:Gem::Requirement
|
145
|
-
none: false
|
146
128
|
requirements:
|
147
|
-
- -
|
129
|
+
- - '>='
|
148
130
|
- !ruby/object:Gem::Version
|
149
131
|
version: '0'
|
150
132
|
type: :development
|
151
133
|
prerelease: false
|
152
134
|
version_requirements: !ruby/object:Gem::Requirement
|
153
|
-
none: false
|
154
135
|
requirements:
|
155
|
-
- -
|
136
|
+
- - '>='
|
156
137
|
- !ruby/object:Gem::Version
|
157
138
|
version: '0'
|
158
139
|
- !ruby/object:Gem::Dependency
|
159
140
|
name: rr
|
160
141
|
requirement: !ruby/object:Gem::Requirement
|
161
|
-
none: false
|
162
142
|
requirements:
|
163
|
-
- -
|
143
|
+
- - '>='
|
164
144
|
- !ruby/object:Gem::Version
|
165
145
|
version: '0'
|
166
146
|
type: :development
|
167
147
|
prerelease: false
|
168
148
|
version_requirements: !ruby/object:Gem::Requirement
|
169
|
-
none: false
|
170
149
|
requirements:
|
171
|
-
- -
|
150
|
+
- - '>='
|
172
151
|
- !ruby/object:Gem::Version
|
173
152
|
version: '0'
|
174
153
|
- !ruby/object:Gem::Dependency
|
175
154
|
name: rspec
|
176
155
|
requirement: !ruby/object:Gem::Requirement
|
177
|
-
none: false
|
178
156
|
requirements:
|
179
|
-
- -
|
157
|
+
- - '>='
|
180
158
|
- !ruby/object:Gem::Version
|
181
159
|
version: '0'
|
182
160
|
type: :development
|
183
161
|
prerelease: false
|
184
162
|
version_requirements: !ruby/object:Gem::Requirement
|
185
|
-
none: false
|
186
163
|
requirements:
|
187
|
-
- -
|
164
|
+
- - '>='
|
188
165
|
- !ruby/object:Gem::Version
|
189
166
|
version: '0'
|
190
167
|
description: Client library and command-line tool to interact with the Mortar service.
|
@@ -224,6 +201,7 @@ files:
|
|
224
201
|
- lib/mortar/command/projects.rb
|
225
202
|
- lib/mortar/command/validate.rb
|
226
203
|
- lib/mortar/command/version.rb
|
204
|
+
- lib/mortar/conf/luigi/logging.ini
|
227
205
|
- lib/mortar/errors.rb
|
228
206
|
- lib/mortar/generators/characterize_generator.rb
|
229
207
|
- lib/mortar/generators/controlscript_generator.rb
|
@@ -283,6 +261,7 @@ files:
|
|
283
261
|
- lib/mortar/templates/project/vendor/udfs/python/gitkeep
|
284
262
|
- lib/mortar/templates/report/illustrate-report.html
|
285
263
|
- lib/mortar/templates/script/runpig.sh
|
264
|
+
- lib/mortar/templates/script/runpython.sh
|
286
265
|
- lib/mortar/templates/udf/python_udf.py
|
287
266
|
- lib/mortar/updater.rb
|
288
267
|
- lib/mortar/version.rb
|
@@ -320,26 +299,25 @@ files:
|
|
320
299
|
- spec/support/display_message_matcher.rb
|
321
300
|
homepage: http://mortardata.com/
|
322
301
|
licenses: []
|
302
|
+
metadata: {}
|
323
303
|
post_install_message:
|
324
304
|
rdoc_options: []
|
325
305
|
require_paths:
|
326
306
|
- lib
|
327
307
|
required_ruby_version: !ruby/object:Gem::Requirement
|
328
|
-
none: false
|
329
308
|
requirements:
|
330
|
-
- -
|
309
|
+
- - '>='
|
331
310
|
- !ruby/object:Gem::Version
|
332
311
|
version: 1.8.7
|
333
312
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
334
|
-
none: false
|
335
313
|
requirements:
|
336
|
-
- -
|
314
|
+
- - '>='
|
337
315
|
- !ruby/object:Gem::Version
|
338
316
|
version: '0'
|
339
317
|
requirements: []
|
340
318
|
rubyforge_project:
|
341
|
-
rubygems_version:
|
319
|
+
rubygems_version: 2.0.6
|
342
320
|
signing_key:
|
343
|
-
specification_version:
|
321
|
+
specification_version: 4
|
344
322
|
summary: Client library and CLI to interact with the Mortar service.
|
345
323
|
test_files: []
|