Class: Mortar::Command::Base

Inherits:
Object
  • Object
show all
Includes:
Helpers
Defined in:
lib/mortar/command/base.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Helpers

#action, #ask, #confirm, #copy_if_not_present_at_dest, #default_host, #deprecate, #display, #display_header, #display_object, #display_row, #display_table, #display_with_indent, #download_to_file, #ensure_dir_exists, #error, error_with_failure, error_with_failure=, extended, extended_into, #format_bytes, #format_date, #format_with_bang, #full_host, #get_terminal_environment, #home_directory, #host, #hprint, #hputs, included, included_into, #installed_with_omnibus?, #json_decode, #json_encode, #line_formatter, #longest, #output_with_bang, #pending_github_team_state_message, #quantify, #redisplay, #retry_on_exception, #running_on_a_mac?, #running_on_windows?, #set_buffer, #shell, #spinner, #status, #string_distance, #styled_array, #styled_error, #styled_hash, #styled_header, #suggestion, #test_name, #ticking, #time_ago, #truncate, #warning, #with_tty, #write_to_file

Constructor Details

#initialize(args = [], options = {}) ⇒ Base

Returns a new instance of Base.



38
39
40
41
42
43
44
45
46
# File 'lib/mortar/command/base.rb', line 38

def initialize(args=[], options={})
  @args = args
  @options = options
  #We never want to override the command line options so we store them.
  @original_options = options.dup

  #Initialize defaults from .mortar-defaults
  load_defaults('DEFAULTS')
end

Instance Attribute Details

#argsObject (readonly)

Returns the value of attribute args.



35
36
37
# File 'lib/mortar/command/base.rb', line 35

def args
  @args
end

#optionsObject (readonly)

Returns the value of attribute options.



36
37
38
# File 'lib/mortar/command/base.rb', line 36

def options
  @options
end

Class Method Details

.namespaceObject



31
32
33
# File 'lib/mortar/command/base.rb', line 31

def self.namespace
  self.to_s.split("::").last.downcase
end

Instance Method Details

#apiObject



82
83
84
# File 'lib/mortar/command/base.rb', line 82

def api
  Mortar::Auth.api
end

#ask_public(is_public) ⇒ Object



223
224
225
226
227
228
229
# File 'lib/mortar/command/base.rb', line 223

def ask_public(is_public)
  if is_public
    unless confirm("Public projects allow anyone to view and fork the code in this project\'s repository. Are you sure? (y/n)")
      error("Mortar project was not registered")
    end
  end
end

#config_parametersObject



90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/mortar/command/base.rb', line 90

def config_parameters
  param_list = []
  begin
    if project.name
      vars = api.get_config_vars(project.name).body['config']
      unless vars.empty?
        vars.each{|k, v| param_list.push({"name"=>k, "value"=>v})}
      end
    end
  rescue Mortar::Command::CommandFailed, Mortar::API::Errors::ErrorWithResponse
      # When running locally we're not guaranteed this is a project
      # or that it has a config, so lets keep running.
      vars = []
  end
  param_list
end

#get_error_message_context(message) ⇒ Object



163
164
165
166
167
168
# File 'lib/mortar/command/base.rb', line 163

def get_error_message_context(message)
  if message.start_with? "Undefined parameter"
    return "Use -p, --parameter NAME=VALUE to set parameter NAME to value VALUE."
  end
  return ""
end

#gitObject



86
87
88
# File 'lib/mortar/command/base.rb', line 86

def git
  @git ||= Mortar::Git::Git.new
end

#initialize_embedded_project(api_registration_result) ⇒ Object



277
278
279
280
281
282
# File 'lib/mortar/command/base.rb', line 277

def initialize_embedded_project(api_registration_result)
  File.open(".mortar-project-remote", "w") do |f|
    f.puts api_registration_result["git_url"]
  end
  git.sync_embedded_project(project, "master", git_organization)
end

#luigi_parametersObject



111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/mortar/command/base.rb', line 111

def luigi_parameters
  parameters = []
  invalid_arguments.each_slice(2) do |arg_pair|
    name_with_dashes = arg_pair[0]
    unless (name_with_dashes.start_with? "--") && (name_with_dashes.length > 2)
      error("Luigi parameter #{name_with_dashes} must begin with --")
    end

    unless arg_pair.length == 2
      error("No value provided for luigi parameter #{name_with_dashes}")
    end

    name = name_with_dashes[2..name_with_dashes.length-1]
    value = arg_pair[1]
    parameters << {"name" => name, "value" => value}
  end

  parameters
end

#pig_parametersObject



131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/mortar/command/base.rb', line 131

def pig_parameters
  paramfile_params = {}
  if options[:param_file]
    File.open(options[:param_file], "r").each do |line|
      line = line.chomp
      # If the line isn't empty
      if not line.empty? and not line.match(/^;/) and not line.start_with?("#")
        name, value = line.split('=', 2)
        if not name or not value
          error("Parameter file is malformed")
        end
        paramfile_params[name] = value
      end
    end
  end
  
  
  paramoption_params = {}
  input_parameters = options[:parameter] ? Array(options[:parameter]) : []
  input_parameters.each do |name_equals_value|
    name, value = name_equals_value.split('=', 2)
    paramoption_params[name] = value
  end

  parameters = []
  paramfile_params.merge(paramoption_params).each do |name, value|
    parameters << {"name" => name, "value" => value}
  end

  return parameters
end

#projectObject



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/mortar/command/base.rb', line 48

def project
  unless @project
    project_name, project_dir, remote = 
    if project_from_dir = extract_project_in_dir()
      [project_from_dir[0], Dir.pwd, project_from_dir[1]]
    elsif project_from_dir = extract_project_in_dir_no_git()
      [project_from_dir[0], Dir.pwd, project_from_dir[1]]
    else
      raise Mortar::Command::CommandFailed, "No project found.\nThis command must be run from within a project folder."
    end
    
    # if we only have a project name, look for the remote in the current dir
    unless remote
      if project_from_dir = extract_project_in_dir(project_name)
        project_dir = Dir.pwd
        remote = project_from_dir[1]
      end
    end
    
    @project = Mortar::Project::Project.new(project_name, project_dir, remote)

    #Every time we get the project, we're going to check if its a forked version and
    #if it is we'll check for new updates to the base project.
    begin
      if git.is_fork_repo_updated(git_organization)
        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")
      end
    rescue 
      #Do nothing.  We'll repeat this call often enough that we don't care if it fails.
    end
  end
  @project
end

#register_api_call(name, is_public) ⇒ Object



231
232
233
234
235
236
237
238
239
240
241
# File 'lib/mortar/command/base.rb', line 231

def register_api_call(name, is_public)
  project_id = nil
  
  is_private = !is_public # is private required by restful api
  validate_project_name(name)
  'registering project....\n'
  action("Sending request to register project: #{name}") do
    project_id = api.post_project(name, is_private).body["project_id"]
  end
  return project_id
end

#register_do(name, is_public, is_embedded, project_id) ⇒ Object

Register logic

if project id is not created, just pass in nil



189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
# File 'lib/mortar/command/base.rb', line 189

def register_do(name, is_public, is_embedded, project_id)
  if is_embedded
    validate_project_structure()

    register_project(name, is_public, project_id) do |project_result|
      initialize_embedded_project(project_result)
    end
  else
    unless git.has_dot_git?
    # check if we're in the parent directory
      if File.exists? name
        error("mortar projects:register must be run from within the project directory.\nPlease \"cd #{name}\" and rerun this command.")
      else
        error("No git repository found in the current directory.\nTo register a project that is not its own git repository, use the --embedded option.\nIf you do want this project to be its own git repository, please initialize git in this directory, and then rerun the register command.\nTo initialize your project in git, use:\n\ngit init\ngit add .\ngit commit -a -m \"first commit\"")
      end
    end


    unless git.remotes(git_organization).empty?
      begin
        error("Currently in project: #{project.name}.  You can not register a new project inside of an existing mortar project.")
      rescue Mortar::Command::CommandFailed => cf
        error("Currently in an existing Mortar project.  You can not register a new project inside of an existing mortar project.")
      end
    end

    register_project(name, is_public, project_id) do |project_result|
      git.remote_add("mortar", project_result['git_url'])
      git.push_master
      display "Your project is ready for use.  Type 'mortar help' to see the commands you can perform on the project.\n\n"
    end
  end
end

#register_project(name, is_public, project_id) ⇒ Object



243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
# File 'lib/mortar/command/base.rb', line 243

def register_project(name, is_public, project_id)
  if project_id == nil      
    project_id = register_api_call(name, is_public)
  end
  
  project_result = nil
  project_status = nil
  display
  ticking(polling_interval) do |ticks|
    project_result = api.get_project(project_id).body
    project_status = project_result.fetch("status_code", project_result["status"])
    project_description = project_result.fetch("status_description", project_status)
    is_finished = Mortar::API::Projects::STATUSES_COMPLETE.include?(project_status)

    redisplay("Status: %s %s" % [
      project_description + (is_finished ? "" : "..."),
      is_finished ? " " : spinner(ticks)],
      is_finished) # only display newline on last message
    if is_finished
      display
      break
    end
  end
  
  case project_status
  when Mortar::API::Projects::STATUS_FAILED
    error("Project registration failed.\nError message: #{project_result['error_message']}")
  when Mortar::API::Projects::STATUS_ACTIVE
    yield project_result
  else
    raise RuntimeError, "Unknown project status: #{project_status} for project_id: #{project_id}"
  end
end

#spark_script_argumentsObject



107
108
109
# File 'lib/mortar/command/base.rb', line 107

def spark_script_arguments
  invalid_arguments.join(" ")
end

#validate_project_name(name) ⇒ Object



170
171
172
173
174
175
# File 'lib/mortar/command/base.rb', line 170

def validate_project_name(name)
  project_names = api.get_projects().body["projects"].collect{|p| p['name']}
  if project_names.include? name
    error("Your account already contains a project named #{name}.\nPlease choose a different name for your new project, or clone the existing #{name} code using:\n\nmortar projects:clone #{name}")
  end
end

#validate_project_structureObject



177
178
179
180
181
182
183
184
185
# File 'lib/mortar/command/base.rb', line 177

def validate_project_structure()
  present_dirs = Dir.glob("*").select { |path| File.directory? path }
  required_dirs = ["pigscripts", "macros", "udfs"]
  missing_dirs = required_dirs - present_dirs

  if missing_dirs.length > 0
    error("Project missing required directories: #{missing_dirs.to_s}")
  end
end