Class: Fanforce::CLI

Inherits:
Object
  • Object
show all
Includes:
Utils
Defined in:
lib/fanforce/cli/version.rb,
lib/fanforce/cli/commands.rb,
lib/fanforce/cli/commands_support.rb,
lib/fanforce/cli/_base.rb

Defined Under Namespace

Modules: Help, Run, Utils Classes: App, Apps, Env, Files

Constant Summary collapse

VERSION =
'1.7.1'

Instance Method Summary collapse

Methods included from Utils

#confirm, #env, #error, #format, #format_config, #get_heroku_app_name, #unknown

Constructor Details

#initialize(executable) ⇒ CLI

Returns a new instance of CLI.



15
16
17
18
# File 'lib/fanforce/cli/_base.rb', line 15

def initialize(executable)
  @executable = executable
  $HomeDir = Shell.new.pwd
end

Instance Method Details

#auth_heroku(environment) ⇒ Object



118
119
120
121
122
123
124
# File 'lib/fanforce/cli/commands_support.rb', line 118

def auth_heroku(environment)
  @heroku ||= {}
  @heroku[environment] ||= Heroku::API.new(:username => $Config[:heroku][environment][:user], :password => $Config[:heroku][environment][:password])
rescue Exception => e
  raise "Heroku user #{$Config[:heroku][environment][:user]} does not seem to exist: #{e.message}" if e.response.status == 404
  raise
end

#capture_stdoutObject



227
228
229
230
231
232
233
234
235
236
237
238
239
# File 'lib/fanforce/cli/_base.rb', line 227

def capture_stdout
  previous_stdout, previous_stderr = $stdout, $stderr
  io = StringIO.new
  $stdout = io
  $stderr = io
  IronCore::Logger.logger = ::Logger.new(io)
  IronCore::Logger.logger.level = ::Logger::INFO
  yield
  io.string
ensure
  $stdout = previous_stdout
  $stderr = previous_stderr
end

#convert_hash_to_ruby_env(hash) ⇒ Object



201
202
203
# File 'lib/fanforce/cli/commands_support.rb', line 201

def convert_hash_to_ruby_env(hash)
  hash.inject('') {|script, (k,v)| script += "ENV['#{k}']=#{v.to_s.to_json}\n" }
end

#convert_hash_to_shell_env(hash) ⇒ Object



197
198
199
# File 'lib/fanforce/cli/commands_support.rb', line 197

def convert_hash_to_shell_env(hash)
  hash.inject('') {|script, (k,v)| script += "export #{k}=#{v.to_s.to_json}\n" }
end

#countObject



228
229
230
231
232
233
# File 'lib/fanforce/cli/commands.rb', line 228

def count
  puts "\n---------------------------------------------------------------------------------------------------------------"
  puts "#{Apps.count} APPS".format(:bold,:green) + ' IN CURRENT DIRECTORY'
  puts '---------------------------------------------------------------------------------------------------------------'
  puts ''
end

#create_app(app_id) ⇒ Object



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/fanforce/cli/commands.rb', line 15

def create_app(app_id)
  dir_name = "app-#{app_id}"
  dir = "#{$HomeDir}/#{dir_name}"

  if File.exists?("#{dir}/config.ru")
    puts '---------------------------------------------------------------------------------------------------------------'
    puts 'ERROR... '.format(:red,:bold) + "#{dir_name} already exists. You should run: ".format(:red) + "fanforce update #{dir_name}".format(:green)
    puts '---------------------------------------------------------------------------------------------------------------'
    return
  end

  puts "\n---------------------------------------------------------------------------------------------------------------"
  puts 'CREATING FILES...'
  Dir.mkdir(dir) if !File.directory?(dir)
  Dir.chdir(dir)
  puts "#{'Created'.format(:bold, :green)} #{dir_name}/"
  app = App.load(dir)
  setup_files(app)

  puts "\n---------------------------------------------------------------------------------------------------------------"
  puts 'RUNNING BUNDLER...'
  Run.bundle_install(app.dir)

  puts "\n---------------------------------------------------------------------------------------------------------------"
  puts 'CREATING POW DOMAINS...'
  setup_pow(app)

  puts "\n---------------------------------------------------------------------------------------------------------------"
  puts 'CREATING LOCAL GIT REPOSITORY...'
  Run.git_init          and puts '- git init'
  Run.git_add           and puts '- git add .'
  Run.git_first_commit  and puts '- git commit -m "initial fanforce commit"'

  #puts "\n---------------------------------------------------------------------------------------------------------------"
  #puts 'CREATING BITBUCKET REPOSITORY...'
  #setup_bitbucket app
  #
  #puts "\n---------------------------------------------------------------------------------------------------------------"
  #puts 'CREATING HEROKU APPS...'
  #setup_heroku app, :staging
  #setup_heroku app, :production

  puts "\n---------------------------------------------------------------------------------------------------------------"
  puts 'CREATING ENV VARIABLES...'
  setup_envs(app, :development)

  puts "\n---------------------------------------------------------------------------------------------------------------"
  puts 'DONE!'.format(:bold,:green)
  puts "---------------------------------------------------------------------------------------------------------------\n"
end

#create_bitbucket_repo(bitbucket, repo) ⇒ Object



111
112
113
114
115
116
# File 'lib/fanforce/cli/commands_support.rb', line 111

def create_bitbucket_repo(bitbucket, repo)
  bitbucket.repos.create(name: repo, is_private: true)
rescue BitBucket::Error::Unauthorized => e
  raise "Bitbucket user #{$Config[:bitbucket][:user]} does not seem to exist: #{e.message}"
  raise
end

#delete_all_iron_workers(environment) ⇒ Object



439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
# File 'lib/fanforce/cli/commands.rb', line 439

def delete_all_iron_workers(environment)
  puts ''
  environments = environment == :all ? [:development, :staging, :production] : [environment]

  iron_auths = {}
  Apps.each do |app, cur_count, total|
    environments.each do |environment|
      vars = Env.vars_by_app(environment)[app.dir_name]
      iron_auths[environment] ||= {}
      iron_auths[environment][vars['IRON_PROJECT_ID']] = vars['IRON_TOKEN'] if vars['IRON_PROJECT_ID'].present?
    end
  end

  environments.each do |environment|
    puts '---------------------------------------------------------------------------------------------------------------'
    puts "REMOVING WORKERS IN #{environment.to_s.upcase}..."

    workers_found = false
    iron_auths[environment].each do |iron_project_id, iron_token|
      iron_worker = IronWorkerNG::Client.new(:token => iron_token, :project_id => iron_project_id)
      iron_worker.codes.list.each do |code|
        workers_found = true
        iron_worker.codes.delete(code.id)
        puts "#{'Removed'.format(:red,:bold)} #{code.name}"
      end
    end
    puts 'No workers were found' if !workers_found
  end

  puts '---------------------------------------------------------------------------------------------------------------'
end

#delete_app(app_id) ⇒ Object



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/fanforce/cli/commands.rb', line 86

def delete_app(app_id)
  app_dir_name = "app-#{app_id}"
  app_dir = "#{$HomeDir}/#{app_dir_name}"

  if !File.directory?("#{app_dir}")
    puts '---------------------------------------------------------------------------------------------------------------'
    puts 'OOPS... '.format(:red,:bold) + "#{app_dir_name} does not exist and therefore cannot be deleted!"
    puts '---------------------------------------------------------------------------------------------------------------'
    return
  end

  app = App.load(app_dir)

  puts "\n---------------------------------------------------------------------------------------------------------------"
  puts 'DELETING HEROKU APPS...'
  [:staging,:production].each do |environment|
    next if $Config[:heroku].blank? or $Config[:heroku][environment].blank?
    heroku = auth_heroku(environment)
    heroku_app_name = get_heroku_app_name(app, environment)
    begin
      heroku.delete_app(heroku_app_name)
      puts "#{'Removed  '.format(:green,:bold)}" + " #{heroku_app_name}"
    rescue Exception => e
      puts "#{'Already Removed'.format(:green,:bold)}" + " #{heroku_app_name}"
    end
  end

  puts "\n---------------------------------------------------------------------------------------------------------------"
  puts 'DELETING BITBUCKET REPOSITORY...'
  if $Config[:bitbucket].present?
    bitbucket = BitBucket.new(login: $Config[:bitbucket][:user], password: $Config[:bitbucket][:password])
    begin
      repo = bitbucket.repos.find($Config[:bitbucket][:user], app.dir_name)
      RestClient.delete("https://#{$Config[:bitbucket][:user]}:#{$Config[:bitbucket][:password]}@api.bitbucket.org/1.0/repositories/#{$Config[:bitbucket][:user]}/#{app.dir_name}")
      puts "#{'Removed'.format(:green,:bold)}" + " #{app.dir_name}"
    rescue
      puts "#{'Already Removed'.format(:green,:bold)}" + " #{app.dir_name}"
    end
  end

  puts "\n---------------------------------------------------------------------------------------------------------------"
  puts 'DELETING POW DOMAINS...'
  Run.pow_destroy(app, app.root_domain)
  Run.pow_destroy(app, Fanforce.default_short_domain)

  puts "\n---------------------------------------------------------------------------------------------------------------"
  puts 'DELETING FILES...'
  if File.directory?(app_dir)
    FileUtils.rm_rf(app_dir)
    puts "#{'Removed'.format(:bold, :green)} #{app_dir_name}/"
  else
    puts "#{'Already Removed'.format(:bold, :green)} #{app_dir_name}/"
  end

  puts "\n---------------------------------------------------------------------------------------------------------------"
  puts 'DONE! (note: iron workers were not deleted)'
  puts '---------------------------------------------------------------------------------------------------------------'

end

#destroy_counter(counter_id) ⇒ Object



258
259
260
# File 'lib/fanforce/cli/_base.rb', line 258

def destroy_counter(counter_id)
  File.delete("#{$HomeDir}/.forked-counter-#{counter_id}")
end

#find_bitbucket_repo(bitbucket, repo) ⇒ Object



107
108
109
# File 'lib/fanforce/cli/commands_support.rb', line 107

def find_bitbucket_repo(bitbucket, repo)
  bitbucket.repos.find($Config[:bitbucket][:user], repo)
end

#incr_counter(counter_id) ⇒ Object



245
246
247
248
249
250
251
252
253
254
255
256
# File 'lib/fanforce/cli/_base.rb', line 245

def incr_counter(counter_id)
  new_count = nil
  File.open("#{$HomeDir}/.forked-counter-#{counter_id}", File::RDWR|File::CREAT, 0644) do |f|
    f.flock(File::LOCK_EX)
    new_count = f.read.to_i + 1
    f.rewind
    f.write("#{new_count}\n")
    f.flush
    f.truncate(f.pos)
  end
  new_count
end

#init_counter(counter_id) ⇒ Object



241
242
243
# File 'lib/fanforce/cli/_base.rb', line 241

def init_counter(counter_id)
  File.open("#{$HomeDir}/.forked-counter-#{counter_id}", 'w') {|f| f.write('0') }
end

#list_appsObject



4
5
6
7
8
9
10
11
12
13
# File 'lib/fanforce/cli/commands.rb', line 4

def list_apps
  puts "\n---------------------------------------------------------------------------------------------------------------\n"
  puts "#{Apps.count} APPS".format(:bold,:green) + ' IN CURRENT DIRECTORY'
  puts "---------------------------------------------------------------------------------------------------------------\n"
  Apps.each do |app, cur_count, total|
    printf "- %s\n", app.dir_name.format(:green)
  end

  puts "---------------------------------------------------------------------------------------------------------------\n\n" if Apps.count > 0
end

#parse_app_filterObject



35
36
37
38
39
40
# File 'lib/fanforce/cli/_base.rb', line 35

def parse_app_filter
  if ARGV[0] =~ /^:((app)-(.+))$/
    $Filter = {dir_name: $1}
    ARGV.shift
  end
end

#parse_commandObject



44
45
46
47
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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
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
162
163
164
165
166
167
168
169
170
171
# File 'lib/fanforce/cli/_base.rb', line 44

def parse_command

  #################################################################

  if ARGV.length == 0 or !@allowed_commands.include?(ARGV[0].to_sym)
    puts Fanforce::CLI::Help.intro(@executable, @runtype)
    puts Fanforce::CLI::Help.commands(@allowed_commands)

    #################################################################

  elsif ARGV[0] == 'list'
    list_apps

  #################################################################

  elsif ARGV[0] == 'create'
    ARGV[1] =~ /^app-([a-z0-9-]+)$/i || error('You supplied an invalid create command.', :create)
    create_app($1)

  #################################################################

  elsif ARGV[0] == 'update'
    ARGV[1] =~ /^(all|files|bundle|pow|get|env)$/i || error('You supplied an invalid update command.', :update)
    run(:update, $1.to_sym)

  #################################################################

  elsif ARGV[0] == 'delete'
    ARGV[1] =~ /^app-([a-z0-9-]+)$/ || error('You supplied an invalid delete command.', :delete)
    confirm("Are you sure you want to delete all files, repositories, and other items for #{ARGV[1]}?")
    delete_app($1)

  #################################################################

  elsif ARGV[0] == 'push'
    ARGV[1] =~ /^(all|development|staging|production)$/i || error('You supplied an invalid push command.', :push)
    environment = $1.to_sym

    ARGV[2] =~ /^(all|heroku|iron|bitbucket)$/i || error('You supplied an invalid push command.', :push)
    command = $1.to_sym

    confirm('Are you sure you want to push to all environments, including production?') if environment == :all
    confirm('Are you sure you want to push to production?') if environment == :production
    confirm("Are you sure you want to push to all services on #{environment}?") if command == :all

    run(:push, environment, command)

    #################################################################

  elsif ARGV[0] == 'restart'
    if ARGV[1].present?
      ARGV[1] =~ /^(development|staging|production|all)?$/ || error('You supplied an invalid restart command.', :restart)
      environment = $1.to_sym
    else
      environment = :development
    end

    confirm('Are you sure you want to restart all environments?') if environment == :all
    run(:restart, environment)

  #################################################################

  elsif ARGV[0] == 'count'
    count

  #################################################################

  elsif ARGV[0] == 'bundle'
    ARGV[1] =~ /^(install|update)$/ || error('You supplied an invalid bundle command.', :bundle)

    run(:bundle, $1.to_sym, ARGV[3..-1] || [])

  #################################################################

  elsif ARGV[0] == 'git' and ARGV[1] == 'status:overview'
    run(:git_overview)

  elsif ARGV[0] == 'git'
    run(:git, ARGV[1..-1] || [])

  #################################################################

  elsif ARGV[0] == 'iron'
    ARGV[1] =~ /^(upload|reset|delete)$/i || error('You supplied an invalid iron command.', :iron)
    command = $1.to_sym

    ARGV[2] =~ /^(all|development|staging|production)$/i || error('You supplied an invalid iron environment.', :iron)
    environment = $1.to_sym
    confirm("Are you sure you want to #{command} workers in all environments?") if environment == :all

    if command == :delete
      delete_all_iron_workers(environment)
    else
      run(:iron, command, environment)
    end

  #################################################################

  elsif ARGV[0] == 'cleanorgs'
    ARGV[1] =~ /^(development|staging|production)$/ || error('You supplied an invalid cleanorgs command.', :cleanorgs)
    environment = $1.to_sym

    supercore_api_key = ARGV[2] || error('You supplied an invalid cleanorgs command.', :cleanorgs)

    run(:cleanorgs, environment, supercore_api_key)

   #################################################################

  elsif ARGV[0] == 'version'
    puts '---------------------------------------------------------------------------------------------------------------'
    puts "You are using version #{Fanforce::CLI::VERSION} of Fanforce CLI"
    puts '---------------------------------------------------------------------------------------------------------------'

  elsif ARGV[0] == 'config'
    puts '---------------------------------------------------------------------------------------------------------------'
    if !File.exists?("#{$HomeDir}/.fanforce-cli")
      puts 'Oops'.format(:red,:bold) + '... no ".fanforce-cli" file was found in this directory.'.format(:red)
    else
      puts $Config
    end
    puts '---------------------------------------------------------------------------------------------------------------'

  elsif ARGV[0] == 'upgrade'
    run(:upgrade)

  end

end

#postprocess_git_overviewObject



339
340
341
342
# File 'lib/fanforce/cli/commands.rb', line 339

def postprocess_git_overview
  puts '------------------------------------------------------------------------'
  puts 'DONE'
end

#preprocess_git_overviewObject



332
333
334
335
336
337
# File 'lib/fanforce/cli/commands.rb', line 332

def preprocess_git_overview
  puts ''
  length = Apps.dir_names.inject(0) {|length, dir_name| dir_name.length > length ? dir_name.length : length }
  puts sprintf("%-#{length+3}s %-20s %s", 'Directory', 'Plugin Type', 'Status').format(:bold)
  length
end

#push_env_to(environment, app, vars, create_worker_env = true) ⇒ Object



177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
# File 'lib/fanforce/cli/commands_support.rb', line 177

def push_env_to(environment, app, vars, create_worker_env=true)
  vars.each {|k,v| puts "  - #{k}" }
  workers_dir = "#{app.dir}/workers"
  workers_env_dir = "#{workers_dir}/.env"
  if create_worker_env and File.directory?(workers_dir) and vars['IRON_PROJECT_ID']
    FileUtils.mkdir_p(workers_env_dir) unless File.directory?(workers_env_dir)
    File.open("#{workers_env_dir}/#{environment}.rb", 'w') {|f| f.write convert_hash_to_ruby_env(vars) }
  end
  if environment == :development
    app.update_file(:powenv)
    File.open("#{app.dir}/.appenv", 'w') {|f| f.write convert_hash_to_shell_env(vars) }
  else
    return if $Config[:heroku][environment].blank?
    heroku = auth_heroku(environment)
    heroku_app_name = get_heroku_app_name(app, environment)
    heroku.put_config_vars(heroku_app_name, vars)
  end
  restart(app, environment)
end

#remove_single_worker(code_name, iron_worker, environment) ⇒ Object



428
429
430
431
432
433
434
435
# File 'lib/fanforce/cli/commands.rb', line 428

def remove_single_worker(code_name, iron_worker, environment)
  iron_worker.codes.list.each do |code|
    next if code.name != code_name
    iron_worker.codes.delete(code.id)
    puts "#{'Removing '.format(:green,:bold)} #{code_name} from #{environment.to_s.titleize}..."
    return true
  end
end

#restart(app, environment) ⇒ Object



253
254
255
256
257
258
259
260
261
262
263
264
265
266
# File 'lib/fanforce/cli/commands.rb', line 253

def restart(app, environment)
  if environment == :development
    File.mkdir("#{app.dir}/tmp") if !File.directory?("#{app.dir}/tmp")
    FileUtils.touch("#{app.dir}/tmp/restart.txt")
  elsif [:production, :staging].include?(environment)
    if $Config[:heroku].blank? or $Config[:heroku][environment].blank?
      puts "#{'OOPS...'.format(:red,:bold)} #{environment} has not been setup on heroku"
      return false
    end
    heroku = auth_heroku(environment)
    heroku.post_ps_restart get_heroku_app_name(app, environment)
  end
  return true
end

#run(method, *args) ⇒ Object



175
176
177
# File 'lib/fanforce/cli/_base.rb', line 175

def run(method, *args)
  (@runtype == :forked) ? run_forked(method, *args) : run_multiple(method, *args)
end

#run_bundle(app_dir, processed_count, total_count, arg, extra_args) ⇒ Object



270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
# File 'lib/fanforce/cli/commands.rb', line 270

def run_bundle(app_dir, processed_count, total_count, arg, extra_args)
  app = App.load(app_dir)
  puts "\n---------------------------------------------------------------------------------------------------------------"
  puts "#{'app'.upcase.format(:bold)} - #{app._id.upcase.gsub('-',' ').format(:bold)} (#{processed_count} of #{total_count})... "

  Dir.chdir(app_dir) do
    if Gem::Specification::find_all_by_name('bundler').empty?
      puts 'Installing Bundler... '
      `gem install bundler`
      puts 'DONE'
    end

    app.update_file(:gemfile)
    Run.command("bundle #{arg} #{extra_args.join(' ')}")
    restart(app, :development)
    puts 'DONE'.format(:green)
  end
end

#run_cleanorgs(app_dir, processed_count, total_count, environment, supercore_api_key) ⇒ Object



291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
# File 'lib/fanforce/cli/commands.rb', line 291

def run_cleanorgs(app_dir, processed_count, total_count, environment, supercore_api_key)
  ENV['RACK_ENV'] = environment.to_s
  app = App.load(app_dir)
  puts "\n---------------------------------------------------------------------------------------------------------------"
  puts "#{'app'.upcase.format(:bold)} - #{app._id.upcase.gsub('-',' ').format(:bold)} (#{processed_count} of #{total_count})... "

  require 'redis'
  require 'fanforce/api'
  ff = Fanforce::API.new(supercore_api_key)

  Dir.chdir(app_dir) do
    app = App.load(app_dir)
    vars = Env.vars_by_app(environment)[app.dir_name] || {}
    redis = Redis.new(url: vars['REDIS_URL'])

    installs = redis.keys("installed:#{app.dir_name}:*")
    organizations = {}
    redis.multi do
      organizations = installs.inject({}) do |result, key|
        next result if key !~ /^(installed:#{app.dir_name}:(.+))$/
        result.update $2 => redis.get($1)
      end
    end
    puts "#{organizations.size} installs found..."
    processed_count = 0
    organizations.each do |organization_id, api_key|
      print "- checking organization #{processed_count+=1}... "
      if ff.get("/organizations/#{organization_id}", fields: '_id')
        puts 'VALID'
      else
        print 'INVALID... '
        redis.del("installed:#{app.dir_name}:#{organization_id}")
        puts 'UNINSTALLED'
      end
    end

  end
end

#run_forked(method, *args) ⇒ Object



202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
# File 'lib/fanforce/cli/_base.rb', line 202

def run_forked(method, *args)
  counter_id = Process.pid
  processes = []
  dirs = Apps.dirs
  puts "\n---------------------------------------------------------------------------------------------------------------"
  dirs.each_with_index do |app_dir, i|
    puts "#{'Forking'.format(:white,:bold)} #{app_dir}"
  end
  dirs.each_with_index do |app_dir, i|
    processes << fork do
      response = capture_stdout do
        self.method(:"run_#{method}").call(app_dir, 'PROCESSED_APPS_COUNT', dirs.size, *args)
      end
      puts response.gsub('PROCESSED_APPS_COUNT', incr_counter(counter_id).to_s)
    end
    sleep(0.25)
  end

  processes.each { |pid| Process.waitpid(pid) }
  puts "\n---------------------------------------------------------------------------------------------------------------"
  puts 'DONE!'
  puts '---------------------------------------------------------------------------------------------------------------'
end

#run_git(app_dir, processed_count, total_count, extra_args) ⇒ Object



353
354
355
356
357
358
359
360
361
362
363
364
365
# File 'lib/fanforce/cli/commands.rb', line 353

def run_git(app_dir, processed_count, total_count, extra_args)
  app = App.load(app_dir)
  puts "\n---------------------------------------------------------------------------------------------------------------"
  puts "#{'app'.upcase.format(:bold)} - #{app._id.upcase.gsub('-',' ').format(:bold)} (#{processed_count} of #{total_count})... "

  extra_args = extra_args.map {|c| c.include?(' ') ? c.to_json : c }.join(' ')
  extra_args = '--no-pager ' + extra_args if extra_args !~ /--no-pager/

  Dir.chdir(app_dir) do
    Run.command("git #{extra_args}")
    puts 'DONE'.format(:green)
  end
end

#run_git_overview(app_dir, processed_count, total_count, length) ⇒ Object



344
345
346
347
348
349
350
351
# File 'lib/fanforce/cli/commands.rb', line 344

def run_git_overview(app_dir, processed_count, total_count, length)
  app = App.load(app_dir)
  puts '------------------------------------------------------------------------'
  Dir.chdir(app_dir) do
    committed = `git status`.include?('nothing to commit') ? true : false
    printf "%-#{length+3}s %s\n", app.dir_name, committed ? 'Committed'.format(:green) : 'Uncommitted'.format(:red)
  end
end

#run_iron(app_dir, processed_count, total_count, command, environment) ⇒ Object



369
370
371
372
373
374
375
376
# File 'lib/fanforce/cli/commands.rb', line 369

def run_iron(app_dir, processed_count, total_count, command, environment)
  environments = environment == :all ? [:development, :staging, :production] : [environment]
  app = App.load(app_dir)
  puts "\n---------------------------------------------------------------------------------------------------------------"
  puts "#{'app'.upcase.format(:bold)} - #{app._id.upcase.gsub('-',' ').format(:bold)} (#{processed_count} of #{total_count})... "

  upload_iron(app, command, environments)
end

#run_multiple(method, *args) ⇒ Object



179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
# File 'lib/fanforce/cli/_base.rb', line 179

def run_multiple(method, *args)
  if (dirs = Apps.dirs).size == 0
    puts "\n---------------------------------------------------------------------------------------------------------------"
    puts "#{'Oops'.format(:bold)}... no fanforce apps were found in this directory."
    puts "---------------------------------------------------------------------------------------------------------------\n"
    return
  end

  if self.respond_to?(:"preprocess_#{method}")
    args << self.method(:"preprocess_#{method}").call
  end
  Apps.each do |app, processed_count, total_count|
    self.method(:"run_#{method}").call(app.dir, processed_count, total_count, *args)
  end
  if self.respond_to?(:"postprocess_#{method}")
    self.method(:"postprocess_#{method}").call
  else
    puts "\n---------------------------------------------------------------------------------------------------------------"
    puts 'DONE!'
    puts '---------------------------------------------------------------------------------------------------------------'
  end
end

#run_push(app_dir, processed_count, total_count, environment, command) ⇒ Object



188
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
222
223
224
# File 'lib/fanforce/cli/commands.rb', line 188

def run_push(app_dir, processed_count, total_count, environment, command)
  app = App.load(app_dir)
  puts "\n---------------------------------------------------------------------------------------------------------------"
  puts "#{'app'.upcase.format(:bold)} - #{app._id.upcase.gsub('-',' ').format(:bold)} (#{processed_count} of #{total_count})... "

  Dir.chdir(app_dir) do
    if [:all,:bitbucket].include?(command) and $Config[:bitbucket].present?
      if !(`git remote`).split(/\r?\n/).include?('bitbucket')
        setup_bitbucket(app)
      else
        puts "\n#{'Pushing '.format(:green,:bold)}" + "latest commit to Bitbucket (#{$Config[:bitbucket][:user]})..."
        Run.command('git push bitbucket --all')
      end
    end

    environments = (environment==:all) ? [:staging,:production] : [environment]
    environments.each do |environment|
      if [:all,:heroku].include?(command)
        remote_name = "#{env(environment)}-heroku"
        setup_heroku(app, environment) if !(`git remote`).split(/\r?\n/).include?(remote_name)

        vars = Env.vars_by_app(environment)[app.dir_name] || {}
        puts "\n#{"Updating Env Vars".format(:green,:bold)} on Heroku #{environment.to_s.titleize} (#{vars.size} variables)..."
        push_env_to(environment, app, vars)

        puts "\n#{'Pushing '.format(:green,:bold)}" + "latest commit to Heroku #{environment.to_s.titleize} (#{remote_name})..."
        Run.command("git push #{remote_name} master")
      end

      if [:all,:iron].include?(command)
        puts ''
        upload_iron(app, command, [environment])
      end
    end

  end
end

#run_restart(app_dir, processed_count, total_count, environment) ⇒ Object



237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
# File 'lib/fanforce/cli/commands.rb', line 237

def run_restart(app_dir, processed_count, total_count, environment)
  app = App.load(app_dir)
  puts "---------------------------------------------------------------------------------------------------------------"
  Dir.chdir(app_dir) do
    if [:all, :development].include?(environment)
      puts "#{'DEVELOPMENT '.format(:bold)}#{app.dir_name.format(:green)} restarted" if restart(app, :development)
    end
    if [:all, :staging].include?(environment)
      puts "#{'STAGING     '.format(:bold)}#{app.dir_name.format(:green)} restarted" if restart(app, :staging)
    end
    if [:all, :production].include?(environment)
      puts "#{'PRODUCTION  '.format(:bold)}#{app.dir_name.format(:green)} restarted" if restart(app, :production)
    end
  end
end

#run_update(app_dir, processed_count, total_count, command) ⇒ Object



148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
# File 'lib/fanforce/cli/commands.rb', line 148

def run_update(app_dir, processed_count, total_count, command)
  app = App.load(app_dir)
  puts "\n---------------------------------------------------------------------------------------------------------------"
  puts "#{'app'.upcase.format(:bold)} - #{app._id.upcase.gsub('-',' ').format(:bold)} (#{processed_count} of #{total_count})... "

  Dir.chdir(app_dir) do
    if [:all,:files].include?(command)
      puts "\nUPDATING FILES..."
      setup_files(app)
    end

    if [:all,:bundle].include?(command)
      puts "\nRUNNING BUNDLER..."
      Run.bundle_install(app.dir)
    end

    if [:all,:pow].include?(command)
      puts "\nUPDATING POW DOMAINS..."
      setup_pow(app)
    end

    if [:all,:git].include?(command)
      puts "\nUPDATING LOCAL GIT REPOSITORY..."
      setup_local_git(app)
    end

    if [:all,:env].include?(command)
      puts "\nUPDATING ENV VARIABLES..."
      setup_envs(app, :development)
    end

    print "\nRESTARTING POW... "
    restart(app, :development)
    puts 'DONE'
  end

end

#run_upgrade(app_dir, processed_count, total_count) ⇒ Object



473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
# File 'lib/fanforce/cli/commands.rb', line 473

def run_upgrade(app_dir, processed_count, total_count)
  environment = :qa
  app = App.load(app_dir)
  puts "\n---------------------------------------------------------------------------------------------------------------"
  puts "#{'app'.upcase.format(:bold)} - #{app._id.upcase.gsub('-',' ').format(:bold)} (#{processed_count} of #{total_count})... "

  #heroku = auth_heroku(:staging)
  #heroku_app_name = get_heroku_app_qa_name(app, environment)
  #begin
  #  heroku.delete_app(heroku_app_name)
  #  puts "#{'Deleted   '.format(:green,:bold)}" + "#{environment} app on heroku (#{heroku_app_name})"
  #rescue
  #  heroku.post_app(name: heroku_app_name)
  #  puts "#{'Not Found '.format(:green,:bold)}" + "#{environment} on heroku (#{heroku_app_name})"
  #end

  if (`git remote`).split(/\r?\n/).include?($Config[:bitbucket][:user])
    puts "#{'Removed '.format(:red,:bold)}" + "git remote for #{$Config[:bitbucket][:user]}"
    `git remote rm #{$Config[:bitbucket][:user]}`
  end
  if (`git remote`).split(/\r?\n/).include?('qa-heroku')
    puts "#{'Removed '.format(:red,:bold)}" + "git remote for qa-heroku"
    `git remote rm qa-heroku`
  end
  if (`git remote`).split(/\r?\n/).include?('bitbucket')
    puts "#{'Updated '.format(:green,:bold)}" + "git remote for bitbucket"
    `git remote rm bitbucket`
    `git remote add bitbucket [email protected]:#{$Config[:bitbucket][:user]}/#{app.dir_name}.git`
  else
    `git remote add bitbucket [email protected]:#{$Config[:bitbucket][:user]}/#{app.dir_name}.git`
    puts "#{'Created '.format(:green,:bold)}" + "git remote for bitbucket"
  end

  `git config --remove-section branch.master`
  `git push --set-upstream bitbucket master`

end

#setup_bitbucket(app) ⇒ Object



81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/fanforce/cli/commands_support.rb', line 81

def setup_bitbucket(app)
  bitbucket = BitBucket.new(login: $Config[:bitbucket][:user], password: $Config[:bitbucket][:password])
  begin
    find_bitbucket_repo(bitbucket, app.dir_name)
    "#{'Found   '.format(:green,:bold)}" + "#{app.dir_name} repository already exists on bitbucket"
  rescue
    create_bitbucket_repo(bitbucket, app.dir_name)
    puts "#{'Created '.format(:green,:bold)}" + "#{app.dir_name} repository on bitbucket"
  end

  if (`git remote`).split(/\r?\n/).include?($Config[:bitbucket][:user])
    puts "#{'Updated '.format(:green,:bold)}" + "git remote for #{$Config[:bitbucket][:user]}"
    `git remote rm #{$Config[:bitbucket][:user]}`
  elsif (`git remote`).split(/\r?\n/).include?('bitbucket')
    `git remote rm bitbucket`
    puts "#{'Removed '.format(:red,:bold)}" + "git remote for #{$Config[:bitbucket][:user]}"
    puts "#{'Created '.format(:green,:bold)}" + "git remote for bitbucket"
  else
    puts "#{'Created '.format(:green,:bold)}" + "git remote for bitbucket"
  end
  `git remote add bitbucket [email protected]:#{$Config[:bitbucket][:user]}/#{app.dir_name}.git`

  puts "#{'Pushing '.format(:green,:bold)}" + "latest commit to #{$Config[:bitbucket][:user]}..."
  Run.command("git push bitbucket --all")
end

#setup_configObject



30
31
32
33
# File 'lib/fanforce/cli/_base.rb', line 30

def setup_config
  puts 'ERROR: Fanforce CLI could not find the required config file.'.format(:red) if !File.exists?("#{$HomeDir}/.fanforce-cli")
  $Config = format_config(YAML.load_file("#{$HomeDir}/.fanforce-cli"))
end

#setup_envs(app, environment) ⇒ Object



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/fanforce/cli/commands_support.rb', line 47

def setup_envs(app, environment)
  environments = environment == :all ? [:development, :staging, :production] : [environment]

  if !File.exists?("#{$HomeDir}/.env/_bind.yml")
    return puts "#{'Oops'.format(:bold)}... you must setup .env/_bind.yml before trying to update env variables."
  end

  environments.each do |environment|
    vars = Env.vars_by_app(environment)[app.dir_name]
    has_workers = File.directory?("#{app.dir}/workers") ? true : false

    next puts "#{'Skipped'.format(:bold)} #{environment.to_s.titleize} has 0 env variables" if vars.blank? or vars.size == 0
    puts "#{'Updated'.format(:green,:bold)} #{environment.to_s.titleize}#{has_workers ? '... and workers have' : ' has'} #{vars.size} env variables"

    push_env_to(environment, app, vars)
  end
end

#setup_files(app) ⇒ Object



4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/fanforce/cli/commands_support.rb', line 4

def setup_files(app)
  if File.directory?("#{app.dir}/tmp")
    puts "#{'Found  '.format(:green,:bold)} #{app.dir_name}/tmp/"
  else
    Dir.mkdir("#{app.dir}/tmp")
    puts "#{'Created'.format(:green,:bold)} #{app.dir_name}/tmp/"
  end

  if File.exists?("#{app.dir}/config.ru")
    app.update_file(:config_ru)
    puts "#{'Updated'.format(:green,:bold)} #{app.dir_name}/config.ru"
  else
    app.create_file(:config_ru)
    puts "#{'Created'.format(:green,:bold)} #{app.dir_name}/config.ru"
  end

  if File.exists?("#{app.dir}/.gitignore")
    app.update_file(:gitignore)
    puts "#{'Updated'.format(:green,:bold)} #{app.dir_name}/.gitignore"
  else
    app.create_file(:gitignore)
    puts "#{'Created'.format(:green,:bold)} #{app.dir_name}/.gitignore"
  end

  if File.exists?("#{app.dir}/Gemfile")
    app.update_file(:gemfile)
    puts "#{'Updated'.format(:green,:bold)} #{app.dir_name}/Gemfile"
  else
    app.create_file(:gemfile)
    puts "#{'Created'.format(:green,:bold)} #{app.dir_name}/Gemfile"
  end

  if File.exists?("#{app.dir}/Rakefile")
    app.update_file(:rakefile)
    puts "#{'Updated'.format(:green,:bold)} #{app.dir_name}/Rakefile"
  else
    app.create_file(:rakefile)
    puts "#{'Created'.format(:green,:bold)} #{app.dir_name}/Rakefile"
  end

  restart(app, :development)
end

#setup_heroku(app, environment) ⇒ Object



126
127
128
129
130
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
162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/fanforce/cli/commands_support.rb', line 126

def setup_heroku(app, environment)
  return puts "OOPS...  #{environment.to_s.upcase}".format(:red,:bold) + ' has not been setup for Heroku' if $Config[:heroku].blank? or $Config[:heroku][environment].blank?

  heroku = auth_heroku(environment)
  heroku_app_name = get_heroku_app_name(app, environment)
  begin
    heroku.get_app(heroku_app_name)
    puts "#{'Found   '.format(:green,:bold)}" + "#{environment} app on heroku (#{heroku_app_name})"
  rescue
    heroku.post_app(name: heroku_app_name)
    puts "#{'Created '.format(:green,:bold)}" + "#{environment} on heroku (#{heroku_app_name})"
  end

  vars = Env.vars_by_app(environment)[app.dir_name]
  heroku.put_config_vars(heroku_app_name, vars) if vars

  # Setup standard app domain
  domain = "#{app._id}.#{Fanforce::DomainEnvironments.method(environment).call[:apps_base]}"
  domain_found = heroku.get_domains(heroku_app_name).body.inject(false) {|result, d| d['domain'] == domain ? (break true) : false }
  if domain_found
    puts "#{'Found   '.format(:green,:bold)}" + "#{domain} domain on #{environment}"
  else
    heroku.post_domain(heroku_app_name, domain)
    puts "#{'Added   '.format(:green,:bold)}" + "#{domain} domain to #{environment}"
  end

  # Setup default short domain
  domain = "#{app._id}.#{Fanforce::DomainEnvironments.method(environment).call[:default_short_domain]}"
  domain_found = heroku.get_domains(heroku_app_name).body.inject(false) {|result, d| d['domain'] == domain ? (break true) : false }
  if domain_found
    puts "#{'Found   '.format(:green,:bold)}" + "#{domain} domain on #{environment}"
  else
    heroku.post_domain(heroku_app_name, domain)
    puts "#{'Added   '.format(:green,:bold)}" + "#{domain} domain to #{environment}"
  end

  remote_name = "#{env(environment)}-heroku"
  if (`git remote`).split(/\r?\n/).include?(remote_name)
    puts "#{'Updated '.format(:green,:bold)}" + "git remote for #{remote_name}"
    `git remote rm #{remote_name}`
  else
    puts "#{'Created '.format(:green,:bold)}" + "git remote for #{remote_name}"
  end
  `git remote add #{remote_name} git@#{$Config[:heroku][environment][:git_ssh_domain] || 'heroku.com'}:#{heroku_app_name}.git`

  puts "#{'Pushing '.format(:green,:bold)}" + "latest commit to #{remote_name}..."
  Run.command("git push #{remote_name} master")
end

#setup_local_git(app) ⇒ Object



70
71
72
73
74
75
76
77
78
79
# File 'lib/fanforce/cli/commands_support.rb', line 70

def setup_local_git(app)
  if Run.git_init.include?('Reinitialized')
    puts "#{'Found '.format(:green,:bold)}" + 'local repository'
  else
    puts "#{'Initialized '.format(:green,:bold)}" + 'local repository'
    Run.git_add
    Run.git_first_commit
    puts "#{'Created     '.format(:green,:bold)}" + 'initial fanforce commit'
  end
end

#setup_pow(app) ⇒ Object



65
66
67
68
# File 'lib/fanforce/cli/commands_support.rb', line 65

def setup_pow(app)
  Run.pow_create(app, app.root_domain)
  Run.pow_create(app, Fanforce.default_short_domain)
end

#start(options) ⇒ Object



20
21
22
23
24
25
26
27
28
# File 'lib/fanforce/cli/_base.rb', line 20

def start(options)
  @runtype = options[:runtype]
  @allowed_commands = options[:allowed]
  setup_config
  init_counter(Process.pid) if @runtype == :forked
  parse_app_filter
  parse_command
  destroy_counter(Process.pid) if @runtype == :forked
end

#update_app(app_id, command) ⇒ Object



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/fanforce/cli/commands.rb', line 66

def update_app(app_id, command)
  app_dir_name = "app-#{app_id}"
  app_dir = "#{$HomeDir}/#{app_dir_name}"

  if !File.exists?("#{app_dir}/config.ru")
    puts '---------------------------------------------------------------------------------------------------------------'
    puts 'ERROR... '.format(:red,:bold) + "#{app_dir_name} does not exist. You should run: ".format(:red) + "fanforce create #{app_dir_name}".format(:green)
    puts '---------------------------------------------------------------------------------------------------------------'
    return
  end

  run_update(app_dir, 1, 1, command)

  puts "\n---------------------------------------------------------------------------------------------------------------"
  puts 'DONE!'.format(:bold,:green)
  puts "---------------------------------------------------------------------------------------------------------------\n"
end

#upload_iron(app, command, environments) ⇒ Object



378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
# File 'lib/fanforce/cli/commands.rb', line 378

def upload_iron(app, command, environments)
  if !File.directory?("#{app.dir}/workers")
    return puts "#{'Skipped '.format(:bold)} no workers folder was found"
  end

  environments.each do |environment|
    vars = Env.vars_by_app(environment)[app.dir_name] || {}
    next puts "#{'Skipped '.format(:bold)} #{environment.to_s.titleize} is missing IRON_TOKEN and/or IRON_PROJECT_ID env variables" if vars['IRON_TOKEN'].blank? or vars['IRON_PROJECT_ID'].blank?

    puts "#{'Updating Env'.format(:green,:bold)} #{environment.to_s.titleize}... and workers have #{vars.size} env variables"
    push_env_to(environment, app, vars, true)

    iron_worker = IronWorkerNG::Client.new(:token => vars['IRON_TOKEN'], :project_id => vars['IRON_PROJECT_ID'])
    Dir.chdir("#{app.dir}/workers") do
      workers = Dir['*.worker']
      next puts "#{'Skipped  '.format(:bold)} #{environment.to_s.titleize} has 0 workers" if workers.size == 0

      upload_processes = []
      FileUtils.cp("#{app.dir}/workers/.env/#{environment}.rb", "#{app.dir}/workers/.env/.#{environment}env.rb")
      workers.each do |filename|
        code_name = filename.gsub('.worker', '')
        remove_single_worker(code_name, iron_worker, environment) if command == :reset

        puts "#{'Uploading'.format(:green,:bold)} #{filename.gsub('.worker', '')} to #{environment.to_s.titleize}..."
        code = IronWorkerNG::Code::Base.new(:workerfile => "#{app.dir}/workers/#{filename}")
        code.remote
        code.name = code_name
        code.file("#{app.dir}/workers/.env/.#{environment}env.rb")

        upload_processes << upload_iron_worker(app, iron_worker, code, filename, environment)
      end
      upload_processes.each { |pid| Process.waitpid(pid) }
      FileUtils.remove_file("#{app.dir}/workers/.env/.#{environment}env.rb")
    end
  end
end

#upload_iron_worker(app, iron_worker, code, filename, environment) ⇒ Object



415
416
417
418
419
420
421
422
423
424
425
426
# File 'lib/fanforce/cli/commands.rb', line 415

def upload_iron_worker(app, iron_worker, code, filename, environment)
  fork do
    begin
      iron_worker.codes.create(code, max_concurrency: 5)
    rescue Exception => e
      puts "#{'Aborted  '.format(:red,:bold)} upload of #{filename.gsub('.worker', '')} to #{environment.to_s.titleize}..."
      puts e.message
      puts e.backtrace
      puts ''
    end
  end
end