fanforce-cli 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +19 -0
- data/.rbenv-gemsets +1 -0
- data/.rbenv-version +1 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +91 -0
- data/LICENSE.txt +22 -0
- data/README.md +144 -0
- data/Rakefile +1 -0
- data/bin/fanforce +20 -0
- data/bin/fanforce-supercharge +7 -0
- data/fanforce-cli.gemspec +31 -0
- data/lib/fanforce/cli/_base.rb +264 -0
- data/lib/fanforce/cli/app.rb +57 -0
- data/lib/fanforce/cli/apps.rb +41 -0
- data/lib/fanforce/cli/commands.rb +506 -0
- data/lib/fanforce/cli/commands_support.rb +210 -0
- data/lib/fanforce/cli/env.rb +41 -0
- data/lib/fanforce/cli/files.rb +266 -0
- data/lib/fanforce/cli/help.rb +93 -0
- data/lib/fanforce/cli/run.rb +51 -0
- data/lib/fanforce/cli/utils.rb +51 -0
- data/lib/fanforce/cli/version.rb +5 -0
- data/lib/fanforce/cli.rb +12 -0
- metadata +194 -0
@@ -0,0 +1,210 @@
|
|
1
|
+
class Fanforce::CLI
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
def get_heroku_app_name(app, environment)
|
5
|
+
heroku_app_name = "#{environment==:production ? 'prd' : 'stg'}-#{app.dir_name}"
|
6
|
+
heroku_app_name.length > 30 ? heroku_app_name.gsub!(/(a|e|i|o|u)/, '') : heroku_app_name
|
7
|
+
end
|
8
|
+
|
9
|
+
def setup_files(app)
|
10
|
+
if File.directory?("#{app.dir}/tmp")
|
11
|
+
puts "#{'Found '.format(:green,:bold)} #{app.dir_name}/tmp/"
|
12
|
+
else
|
13
|
+
Dir.mkdir("#{app.dir}/tmp")
|
14
|
+
puts "#{'Created'.format(:green,:bold)} #{app.dir_name}/tmp/"
|
15
|
+
end
|
16
|
+
|
17
|
+
if File.exists?("#{app.dir}/config.ru")
|
18
|
+
app.update_file(:config_ru)
|
19
|
+
puts "#{'Updated'.format(:green,:bold)} #{app.dir_name}/config.ru"
|
20
|
+
else
|
21
|
+
app.create_file(:config_ru)
|
22
|
+
puts "#{'Created'.format(:green,:bold)} #{app.dir_name}/config.ru"
|
23
|
+
end
|
24
|
+
|
25
|
+
if File.exists?("#{app.dir}/.gitignore")
|
26
|
+
app.update_file(:gitignore)
|
27
|
+
puts "#{'Updated'.format(:green,:bold)} #{app.dir_name}/.gitignore"
|
28
|
+
else
|
29
|
+
app.create_file(:gitignore)
|
30
|
+
puts "#{'Created'.format(:green,:bold)} #{app.dir_name}/.gitignore"
|
31
|
+
end
|
32
|
+
|
33
|
+
if File.exists?("#{app.dir}/Gemfile")
|
34
|
+
app.update_file(:gemfile)
|
35
|
+
puts "#{'Updated'.format(:green,:bold)} #{app.dir_name}/Gemfile"
|
36
|
+
else
|
37
|
+
app.create_file(:gemfile)
|
38
|
+
puts "#{'Created'.format(:green,:bold)} #{app.dir_name}/Gemfile"
|
39
|
+
end
|
40
|
+
|
41
|
+
if File.exists?("#{app.dir}/Rakefile")
|
42
|
+
app.update_file(:rakefile)
|
43
|
+
puts "#{'Updated'.format(:green,:bold)} #{app.dir_name}/Rakefile"
|
44
|
+
else
|
45
|
+
app.create_file(:rakefile)
|
46
|
+
puts "#{'Created'.format(:green,:bold)} #{app.dir_name}/Rakefile"
|
47
|
+
end
|
48
|
+
|
49
|
+
restart(app, :development)
|
50
|
+
end
|
51
|
+
|
52
|
+
def setup_envs(app, environment)
|
53
|
+
environments = environment == :all ? [:development, :staging, :production] : [environment]
|
54
|
+
|
55
|
+
if !File.exists?("#{$HomeDir}/.env/_bind.yml")
|
56
|
+
return puts "#{'Oops'.format(:bold)}... you must setup .env/_bind.yml before trying to update env variables."
|
57
|
+
end
|
58
|
+
|
59
|
+
environments.each do |environment|
|
60
|
+
vars = Env.vars_by_app(environment)[app.dir_name]
|
61
|
+
has_workers = File.directory?("#{app.dir}/workers") ? true : false
|
62
|
+
|
63
|
+
next puts "#{'Skipped'.format(:bold)} #{environment.to_s.titleize} has 0 env variables" if vars.blank? or vars.size == 0
|
64
|
+
puts "#{'Updated'.format(:green,:bold)} #{environment.to_s.titleize}#{has_workers ? '... and workers have' : ' has'} #{vars.size} env variables"
|
65
|
+
|
66
|
+
push_env_to(environment, app, vars)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def setup_pow(app)
|
71
|
+
Run.pow_create(app, app.root_domain)
|
72
|
+
Run.pow_create(app, Fanforce.default_short_domain)
|
73
|
+
end
|
74
|
+
|
75
|
+
def setup_local_git(app)
|
76
|
+
if Run.git_init.include?('Reinitialized')
|
77
|
+
puts "#{'Found '.format(:green,:bold)}" + 'local repository'
|
78
|
+
else
|
79
|
+
puts "#{'Initialized '.format(:green,:bold)}" + 'local repository'
|
80
|
+
Run.git_add
|
81
|
+
Run.git_first_commit
|
82
|
+
puts "#{'Created '.format(:green,:bold)}" + 'initial fanforce commit'
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def setup_bitbucket(app)
|
87
|
+
bitbucket = BitBucket.new(login: $Config[:bitbucket][:user], password: $Config[:bitbucket][:password])
|
88
|
+
begin
|
89
|
+
find_bitbucket_repo(bitbucket, app.dir_name)
|
90
|
+
"#{'Found '.format(:green,:bold)}" + "#{app.dir_name} repository already exists on bitbucket"
|
91
|
+
rescue
|
92
|
+
create_bitbucket_repo(bitbucket, app.dir_name)
|
93
|
+
puts "#{'Created '.format(:green,:bold)}" + "#{app.dir_name} repository on bitbucket"
|
94
|
+
end
|
95
|
+
|
96
|
+
if (`git remote`).split(/\r?\n/).include?($Config[:bitbucket][:user])
|
97
|
+
puts "#{'Updated '.format(:green,:bold)}" + "git remote for #{$Config[:bitbucket][:user]}"
|
98
|
+
`git remote rm #{$Config[:bitbucket][:user]}`
|
99
|
+
elsif (`git remote`).split(/\r?\n/).include?('bitbucket')
|
100
|
+
`git remote rm bitbucket`
|
101
|
+
puts "#{'Removed '.format(:red,:bold)}" + "git remote for #{$Config[:bitbucket][:user]}"
|
102
|
+
puts "#{'Created '.format(:green,:bold)}" + "git remote for bitbucket"
|
103
|
+
else
|
104
|
+
puts "#{'Created '.format(:green,:bold)}" + "git remote for bitbucket"
|
105
|
+
end
|
106
|
+
`git remote add bitbucket git@bitbucket.org:#{$Config[:bitbucket][:user]}/#{app.dir_name}.git`
|
107
|
+
|
108
|
+
puts "#{'Pushing '.format(:green,:bold)}" + "latest commit to #{$Config[:bitbucket][:user]}..."
|
109
|
+
Run.command("git push bitbucket --all")
|
110
|
+
end
|
111
|
+
|
112
|
+
def find_bitbucket_repo(bitbucket, repo)
|
113
|
+
bitbucket.repos.find($Config[:bitbucket][:user], repo)
|
114
|
+
end
|
115
|
+
|
116
|
+
def create_bitbucket_repo(bitbucket, repo)
|
117
|
+
bitbucket.repos.create(name: repo, is_private: true)
|
118
|
+
rescue BitBucket::Error::Unauthorized => e
|
119
|
+
raise "Bitbucket user #{$Config[:bitbucket][:user]} does not seem to exist: #{e.message}"
|
120
|
+
raise
|
121
|
+
end
|
122
|
+
|
123
|
+
def auth_heroku(environment)
|
124
|
+
@heroku ||= {}
|
125
|
+
@heroku[environment] ||= Heroku::API.new(:username => $Config[:heroku][environment][:user], :password => $Config[:heroku][environment][:password])
|
126
|
+
rescue Exception => e
|
127
|
+
raise "Heroku user #{$Config[:heroku][environment][:user]} does not seem to exist: #{e.message}" if e.response.status == 404
|
128
|
+
raise
|
129
|
+
end
|
130
|
+
|
131
|
+
def setup_heroku(app, environment)
|
132
|
+
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?
|
133
|
+
|
134
|
+
heroku = auth_heroku(environment)
|
135
|
+
heroku_app_name = get_heroku_app_name(app, environment)
|
136
|
+
begin
|
137
|
+
heroku.get_app(heroku_app_name)
|
138
|
+
puts "#{'Found '.format(:green,:bold)}" + "#{environment} app on heroku (#{heroku_app_name})"
|
139
|
+
rescue
|
140
|
+
heroku.post_app(name: heroku_app_name)
|
141
|
+
puts "#{'Created '.format(:green,:bold)}" + "#{environment} on heroku (#{heroku_app_name})"
|
142
|
+
end
|
143
|
+
|
144
|
+
vars = Env.vars_by_app(environment)[app.dir_name]
|
145
|
+
heroku.put_config_vars(heroku_app_name, vars) if vars
|
146
|
+
|
147
|
+
# Setup standard app domain
|
148
|
+
domain = "#{app._id}.#{Fanforce.apps_base_domain}"
|
149
|
+
domain_found = heroku.get_domains(heroku_app_name).body.inject(false) {|result, d| d['domain'] == domain ? (break true) : false }
|
150
|
+
if domain_found
|
151
|
+
puts "#{'Found '.format(:green,:bold)}" + "#{domain} domain on #{environment}"
|
152
|
+
else
|
153
|
+
heroku.post_domain(heroku_app_name, domain)
|
154
|
+
puts "#{'Added '.format(:green,:bold)}" + "#{domain} domain to #{environment}"
|
155
|
+
end
|
156
|
+
|
157
|
+
# Setup default short domain
|
158
|
+
domain = "#{app._id}.#{Fanforce.default_short_domain}"
|
159
|
+
domain_found = heroku.get_domains(heroku_app_name).body.inject(false) {|result, d| d['domain'] == domain ? (break true) : false }
|
160
|
+
if domain_found
|
161
|
+
puts "#{'Found '.format(:green,:bold)}" + "#{domain} domain on #{environment}"
|
162
|
+
else
|
163
|
+
heroku.post_domain(heroku_app_name, domain)
|
164
|
+
puts "#{'Added '.format(:green,:bold)}" + "#{domain} domain to #{environment}"
|
165
|
+
end
|
166
|
+
|
167
|
+
remote_name = "#{environment==:staging ? 'stg' : 'prd'}-heroku"
|
168
|
+
if (`git remote`).split(/\r?\n/).include?(remote_name)
|
169
|
+
puts "#{'Updated '.format(:green,:bold)}" + "git remote for #{remote_name}"
|
170
|
+
`git remote rm #{remote_name}`
|
171
|
+
else
|
172
|
+
puts "#{'Created '.format(:green,:bold)}" + "git remote for #{remote_name}"
|
173
|
+
end
|
174
|
+
`git remote add #{remote_name} git@#{$Config[:heroku][environment][:git_ssh_domain] || 'heroku.com'}:#{heroku_app_name}.git`
|
175
|
+
|
176
|
+
puts "#{'Pushing '.format(:green,:bold)}" + "latest commit to #{remote_name}..."
|
177
|
+
Run.command("git push #{remote_name} master")
|
178
|
+
end
|
179
|
+
|
180
|
+
######################################################################################################################
|
181
|
+
|
182
|
+
def push_env_to(environment, app, vars, create_worker_env=true)
|
183
|
+
vars.each {|k,v| puts " - #{k}" }
|
184
|
+
workers_dir = "#{app.dir}/workers"
|
185
|
+
workers_env_dir = "#{workers_dir}/.env"
|
186
|
+
if create_worker_env and File.directory?(workers_dir) and vars['IRON_PROJECT_ID']
|
187
|
+
FileUtils.mkdir_p(workers_env_dir) unless File.directory?(workers_env_dir)
|
188
|
+
File.open("#{workers_env_dir}/#{environment}.rb", 'w') {|f| f.write convert_hash_to_ruby_env(vars) }
|
189
|
+
end
|
190
|
+
if environment == :development
|
191
|
+
app.update_file(:powenv)
|
192
|
+
File.open("#{app.dir}/.appenv", 'w') {|f| f.write convert_hash_to_shell_env(vars) }
|
193
|
+
else
|
194
|
+
return if $Config[:heroku][environment].blank?
|
195
|
+
heroku = auth_heroku(environment)
|
196
|
+
heroku_app_name = get_heroku_app_name(app, environment)
|
197
|
+
heroku.put_config_vars(heroku_app_name, vars)
|
198
|
+
end
|
199
|
+
restart(app, environment)
|
200
|
+
end
|
201
|
+
|
202
|
+
def convert_hash_to_shell_env(hash)
|
203
|
+
hash.inject('') {|script, (k,v)| script += "export #{k}=#{v.to_s.to_json}\n" }
|
204
|
+
end
|
205
|
+
|
206
|
+
def convert_hash_to_ruby_env(hash)
|
207
|
+
hash.inject('') {|script, (k,v)| script += "ENV['#{k}']=#{v.to_s.to_json}\n" }
|
208
|
+
end
|
209
|
+
|
210
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
class Fanforce::CLI::Env
|
2
|
+
require 'singleton'
|
3
|
+
require 'forwardable'
|
4
|
+
include Singleton
|
5
|
+
|
6
|
+
def load_vars_by_app(environment)
|
7
|
+
vars = {}
|
8
|
+
Fanforce::CLI::Apps.dir_names.each do |dir_name|
|
9
|
+
vars[dir_name] ||= {}
|
10
|
+
vars[dir_name]['FANFORCE_APP_ID'] = Fanforce::CLI::App.parse_dir_name(dir_name)[:_id]
|
11
|
+
end
|
12
|
+
|
13
|
+
raw_yaml = File.read("#{$HomeDir}/.env/_bind.yml")
|
14
|
+
bindings = (raw_yaml.present?) ? YAML.load(raw_yaml) : {}
|
15
|
+
bindings.each do |filename, dir_names|
|
16
|
+
file = YAML.load_file("#{$HomeDir}/.env/#{filename}.yml").symbolize_keys
|
17
|
+
next if file[environment].blank?
|
18
|
+
|
19
|
+
dir_names = Fanforce::CLI::Apps.dir_names if dir_names.is_a?(String) and dir_names.upcase == 'ALL'
|
20
|
+
file[environment].each do |k,v|
|
21
|
+
dir_names.each do |dir_name|
|
22
|
+
vars[dir_name] ||= {}
|
23
|
+
vars[dir_name]["#{filename}_#{k}".upcase] = v
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
return vars
|
29
|
+
end
|
30
|
+
|
31
|
+
def vars_by_app(environment)
|
32
|
+
@vars ||= {}
|
33
|
+
@vars[environment] ||= load_vars_by_app(environment)
|
34
|
+
end
|
35
|
+
|
36
|
+
class << self
|
37
|
+
extend Forwardable
|
38
|
+
def_delegators :instance, *Fanforce::CLI::Env.instance_methods(false)
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
@@ -0,0 +1,266 @@
|
|
1
|
+
class Fanforce::CLI::Files
|
2
|
+
|
3
|
+
# CONFIG.RU #######################################################################
|
4
|
+
|
5
|
+
def self.create_config_ru(app)
|
6
|
+
file = config_ru_required_lines.join("\n") + "\n\n"
|
7
|
+
if (fanforce_config_lines = fanforce_config_lines(app._id)).size > 0
|
8
|
+
file += "FanforceApp.config do |config|\n"
|
9
|
+
file += fanforce_config_lines.map {|k,v| " #{k} = #{v}"}.join("\n") + "\n"
|
10
|
+
file += "end\n"
|
11
|
+
end
|
12
|
+
file += "run FanforceApp\n"
|
13
|
+
File.open("#{app.dir}/config.ru", 'w') {|f| f.write file }
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.update_config_ru(app)
|
17
|
+
return create_config_ru(app) if !File.exists?("#{app.dir}/config.ru")
|
18
|
+
|
19
|
+
lines = File.open("#{app.dir}/config.ru", 'r') {|f| f.readlines}
|
20
|
+
|
21
|
+
lines.clone.each {|l| lines.delete(l) if config_ru_required_lines.include?(l.strip) }
|
22
|
+
config_ru_required_lines.reverse.each {|l| lines.unshift(l+"\n") }
|
23
|
+
|
24
|
+
config_options = extract_fanforce_config_options(lines, 'config.ru')
|
25
|
+
|
26
|
+
fanforce_config_keys_to_require.each do |k|
|
27
|
+
config_options[k] = fanforce_config_lines(app._id)[k] if config_options[k].blank?
|
28
|
+
end
|
29
|
+
|
30
|
+
fanforce_config_keys_to_overwrite.each do |k|
|
31
|
+
config_options[k] = fanforce_config_lines(app._id)[k]
|
32
|
+
end
|
33
|
+
|
34
|
+
lines = replace_fanforce_config_options_in_config_ru(lines, config_options)
|
35
|
+
|
36
|
+
File.open("#{app.dir}/config.ru", 'w') {|f| f.write(lines.join('')) }
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.replace_fanforce_config_options_in_config_ru(lines, config_options)
|
40
|
+
if (block = extract_fanforce_config_block(lines, 'config.ru'))
|
41
|
+
new_block = "FanforceApp.config do |config|\n"
|
42
|
+
new_block += config_options.map {|k,v| " #{k} = #{v}"}.join("\n") + "\n"
|
43
|
+
new_block += "end\n"
|
44
|
+
new_block += "run FanforceApp"
|
45
|
+
else
|
46
|
+
block = extract_run_fanforce_line(lines)
|
47
|
+
new_block = "run FanforceApp"
|
48
|
+
end
|
49
|
+
lines.join('').gsub(block[:code], new_block).lines.to_a
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.config_ru_required_lines
|
53
|
+
[
|
54
|
+
"require 'bundler'; Bundler.setup",
|
55
|
+
"require 'fanforce/app_factory'"
|
56
|
+
]
|
57
|
+
end
|
58
|
+
|
59
|
+
# RAKEFILE #######################################################################
|
60
|
+
|
61
|
+
def self.create_rakefile(app)
|
62
|
+
file = rakefile_required_lines.join("\n") + "\n\n"
|
63
|
+
if (fanforce_config_lines = fanforce_config_lines(app._id)).size > 0
|
64
|
+
file += "FanforceApp.config do |config|\n"
|
65
|
+
file += fanforce_config_lines.map {|k,v| " #{k} = #{v}"}.join("\n") + "\n"
|
66
|
+
file += "end\n"
|
67
|
+
end
|
68
|
+
file += "load 'fanforce/app_factory.rake'\n"
|
69
|
+
File.open("#{app.dir}/Rakefile", 'w') {|f| f.write file }
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.update_rakefile(app)
|
73
|
+
return create_rakefile(app) if !File.exists?("#{app.dir}/Rakefile")
|
74
|
+
|
75
|
+
lines = File.open("#{app.dir}/Rakefile", 'r') {|f| f.readlines}
|
76
|
+
|
77
|
+
lines.clone.each {|l| lines.delete(l) if rakefile_required_lines.include?(l.strip) }
|
78
|
+
rakefile_required_lines.reverse.each {|l| lines.unshift(l+"\n") }
|
79
|
+
|
80
|
+
config_options = extract_fanforce_config_options(lines, 'Rakefile')
|
81
|
+
|
82
|
+
fanforce_config_keys_to_require.each do |k|
|
83
|
+
config_options[k] = fanforce_config_lines(app._id)[k] if config_options[k].blank?
|
84
|
+
end
|
85
|
+
|
86
|
+
fanforce_config_keys_to_overwrite.each do |k|
|
87
|
+
config_options[k] = fanforce_config_lines(app._id)[k]
|
88
|
+
end
|
89
|
+
|
90
|
+
lines = replace_fanforce_config_options_in_rakefile(lines, config_options)
|
91
|
+
|
92
|
+
File.open("#{app.dir}/Rakefile", 'w') {|f| f.write(lines.join('')) }
|
93
|
+
end
|
94
|
+
|
95
|
+
def self.replace_fanforce_config_options_in_rakefile(lines, config_options)
|
96
|
+
if (block = extract_fanforce_config_block(lines, 'Rakefile'))
|
97
|
+
new_block = "FanforceApp.config do |config|\n"
|
98
|
+
new_block += config_options.map {|k,v| " #{k} = #{v}"}.join("\n") + "\n"
|
99
|
+
new_block += "end\n"
|
100
|
+
new_block += "load 'fanforce/app_factory.rake'"
|
101
|
+
else
|
102
|
+
block = extract_load_fanforce_line(lines)
|
103
|
+
new_block = "load 'fanforce/app_factory.rake'"
|
104
|
+
end
|
105
|
+
lines.join('').gsub(block[:code], new_block).lines.to_a
|
106
|
+
end
|
107
|
+
|
108
|
+
def self.rakefile_required_lines
|
109
|
+
[
|
110
|
+
"require 'bundler'; Bundler.setup",
|
111
|
+
"require 'fanforce/app_factory'"
|
112
|
+
]
|
113
|
+
end
|
114
|
+
|
115
|
+
########################################################################
|
116
|
+
|
117
|
+
def self.extract_load_fanforce_line(lines)
|
118
|
+
code = lines.join('')
|
119
|
+
regex = Regexp.compile('( *load\s+(\'|")fanforce/app_factory.rake(\'|"))', Regexp::MULTILINE)
|
120
|
+
if code !~ regex
|
121
|
+
raise "No valid \"load 'fanforce/app_factory.rake'\" line was found in your Rakefile."
|
122
|
+
end
|
123
|
+
{:code => $1}
|
124
|
+
end
|
125
|
+
|
126
|
+
def self.extract_run_fanforce_line(lines)
|
127
|
+
code = lines.join('')
|
128
|
+
regex = Regexp.compile('( *run\s+FanforceApp)', Regexp::MULTILINE)
|
129
|
+
if code !~ regex
|
130
|
+
raise "No valid \"run FanforceApp\" line was found in your config.ru."
|
131
|
+
end
|
132
|
+
{:code => $1}
|
133
|
+
end
|
134
|
+
|
135
|
+
def self.extract_fanforce_config_block(lines, filename)
|
136
|
+
code = lines.join('')
|
137
|
+
regex = Regexp.compile('( *FanforceApp\.config\s*(do|{)\s*\|\s*([A-Za-z]+)\s*\|(.*)(end|})\s*(run\s+FanforceApp|load\s+(\'|")fanforce/app_factory.rake(\'|")))', Regexp::MULTILINE)
|
138
|
+
if code !~ regex || ($2 == '{' and $5 != '}') || ($2 == 'do' and $5 != 'end')
|
139
|
+
return nil
|
140
|
+
end
|
141
|
+
{
|
142
|
+
:code => $1,
|
143
|
+
:start_keyword => $2,
|
144
|
+
:config_var => $3,
|
145
|
+
:config_code => $4,
|
146
|
+
:end_keyword => $5
|
147
|
+
}
|
148
|
+
end
|
149
|
+
|
150
|
+
def self.extract_fanforce_config_options(lines, filename)
|
151
|
+
block = extract_fanforce_config_block(lines, filename)
|
152
|
+
return [] if !block
|
153
|
+
regex = Regexp.compile(block[:config_var]+'\.([\w]+)\s*=\s*(((?!'+block[:config_var]+'\.).)+)', Regexp::MULTILINE)
|
154
|
+
block[:config_code].scan(regex).inject({}) {|result, match| result.update "config.#{match[0]}" => match[1].strip }
|
155
|
+
end
|
156
|
+
|
157
|
+
def self.fanforce_config_lines(app_id)
|
158
|
+
lines = {}
|
159
|
+
return lines
|
160
|
+
end
|
161
|
+
|
162
|
+
def self.fanforce_config_keys_to_require
|
163
|
+
[]
|
164
|
+
end
|
165
|
+
|
166
|
+
def self.fanforce_config_keys_to_overwrite
|
167
|
+
keys = []
|
168
|
+
return keys
|
169
|
+
end
|
170
|
+
|
171
|
+
# GEMFILE #######################################################################
|
172
|
+
|
173
|
+
def self.create_gemfile(app)
|
174
|
+
file = gemfile_source_lines.join("\n") + "\n"
|
175
|
+
file += gemfile_ruby_version + "\n\n"
|
176
|
+
file += gemfile_factory_line + "\n\n"
|
177
|
+
File.open("#{app.dir}/Gemfile", 'w') {|f| f.write file }
|
178
|
+
end
|
179
|
+
|
180
|
+
def self.update_gemfile(app)
|
181
|
+
return create_gemfile(app) if !File.exists?("#{app.dir}/Gemfile")
|
182
|
+
|
183
|
+
lines = File.open("#{app.dir}/Gemfile", 'r') {|f| f.readlines}.map {|l| l.strip }
|
184
|
+
gemfile_source_lines.reverse.each {|l| lines.delete(l); lines.unshift(l) }
|
185
|
+
|
186
|
+
lines.clone.each {|l| lines.delete(l) if l =~ /^ruby .+/ }
|
187
|
+
lines.each_with_index do |l,i|
|
188
|
+
next if l =~ /^source .+/
|
189
|
+
lines.insert(i, gemfile_ruby_version) and break
|
190
|
+
end
|
191
|
+
|
192
|
+
lines = lines.map do |l|
|
193
|
+
l.include?("gem 'fanforce-app-factory'") ? gemfile_factory_line : l
|
194
|
+
end
|
195
|
+
lines << gemfile_factory_line if !lines.include?(gemfile_factory_line)
|
196
|
+
|
197
|
+
File.open("#{app.dir}/Gemfile", 'w') {|f| f.write(lines.join "\n") }
|
198
|
+
end
|
199
|
+
|
200
|
+
def self.gemfile_source_lines
|
201
|
+
[
|
202
|
+
"source 'https://rubygems.org'",
|
203
|
+
]
|
204
|
+
end
|
205
|
+
|
206
|
+
def self.gemfile_ruby_version
|
207
|
+
"ruby '1.9.3'"
|
208
|
+
end
|
209
|
+
|
210
|
+
def self.gemfile_factory_line
|
211
|
+
line = "gem 'fanforce-app-factory'"
|
212
|
+
return line if !$Config[:app_factory_gem].is_a?(Hash)
|
213
|
+
|
214
|
+
line += ", '#{$Config[:app_factory_gem][:version]}'" if $Config[:app_factory_gem][:version].present?
|
215
|
+
line += ", :path => '#{$Config[:app_factory_gem][:path]}'" if $Config[:app_factory_gem][:path].present?
|
216
|
+
line += ", :git => '#{$Config[:app_factory_gem][:git]}'" if $Config[:app_factory_gem][:git].present?
|
217
|
+
line
|
218
|
+
end
|
219
|
+
|
220
|
+
# .GITIGNORE #######################################################################
|
221
|
+
|
222
|
+
def self.create_gitignore(app)
|
223
|
+
file = gitignore_lines.join("\n") + "\n"
|
224
|
+
File.open("#{app.dir}/.gitignore", 'w') {|f| f.write file }
|
225
|
+
end
|
226
|
+
|
227
|
+
def self.update_gitignore(app)
|
228
|
+
return create_gitignore(app) if !File.exists?("#{app.dir}/.gitignore")
|
229
|
+
|
230
|
+
lines = File.open("#{app.dir}/.gitignore", 'r') {|f| f.readlines}.map {|l| l.strip }
|
231
|
+
|
232
|
+
gitignore_lines.each do |line|
|
233
|
+
lines << line if !lines.include?(line)
|
234
|
+
end
|
235
|
+
|
236
|
+
File.open("#{app.dir}/.gitignore", 'w') {|f| f.write(lines.join "\n") }
|
237
|
+
end
|
238
|
+
|
239
|
+
def self.gitignore_lines
|
240
|
+
%w(*.gem *.rbc .bundle .config coverage InstalledFiles lib/bundler/man pkg rdoc spec/reports test/tmp test/version_tmp tmp .idea/ .sass-cache/ .DS_STORE .powenv .pluginenv .appenv .widgetenv .*env.rb .yardoc _yardoc doc/)
|
241
|
+
end
|
242
|
+
|
243
|
+
# .POWENV #######################################################################
|
244
|
+
|
245
|
+
def self.create_powenv(app)
|
246
|
+
file = powenv_lines.join("\n") + "\n"
|
247
|
+
File.open("#{app.dir}/.powenv", 'w') {|f| f.write file }
|
248
|
+
end
|
249
|
+
|
250
|
+
def self.update_powenv(app)
|
251
|
+
return create_powenv(app) if !File.exists?("#{app.dir}/.powenv")
|
252
|
+
|
253
|
+
lines = File.open("#{app.dir}/.powenv", 'r') {|f| f.readlines}.map {|l| l.strip }
|
254
|
+
|
255
|
+
powenv_lines.each do |line|
|
256
|
+
lines << line if !lines.include?(line)
|
257
|
+
end
|
258
|
+
|
259
|
+
File.open("#{app.dir}/.powenv", 'w') {|f| f.write(lines.join "\n") }
|
260
|
+
end
|
261
|
+
|
262
|
+
def self.powenv_lines
|
263
|
+
['source .appenv']
|
264
|
+
end
|
265
|
+
|
266
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
module Fanforce::CLI::Help
|
2
|
+
extend Fanforce::CLI::Help
|
3
|
+
|
4
|
+
def intro(executable, runtype)
|
5
|
+
response = "-----------------------------------------------------------------------------------------------------------------------\n"
|
6
|
+
response += "USAGE: #{executable} <command>\n"
|
7
|
+
end
|
8
|
+
|
9
|
+
def commands(allowed_commands)
|
10
|
+
response = "\n\nAVAILABLE COMMANDS...\n-----------------------------------------------------------------------------------------------------------------------\n"
|
11
|
+
commands = allowed_commands.inject([]) do |results, c|
|
12
|
+
results << self.send(:"#{c}_command") rescue next results
|
13
|
+
end
|
14
|
+
response += commands.join("-----------------------------------------------------------------------------------------------------------------------\n")
|
15
|
+
response += "-----------------------------------------------------------------------------------------------------------------------\n\n"
|
16
|
+
end
|
17
|
+
|
18
|
+
def for(command, allowed_commands)
|
19
|
+
response = "\n#{command.to_s.upcase} COMMAND...\n-----------------------------------------------------------------------------------------------------------------------\n"
|
20
|
+
response += "-----------------------------------------------------------------------------------------------------------------------\n\n"
|
21
|
+
end
|
22
|
+
|
23
|
+
def list_command; <<-eos
|
24
|
+
list Show a list of all apps in the current directory
|
25
|
+
eos
|
26
|
+
end
|
27
|
+
|
28
|
+
def create_command; <<-eos
|
29
|
+
create app-ID Creates a new app folder and sets up the file structure
|
30
|
+
eos
|
31
|
+
end
|
32
|
+
|
33
|
+
def update_command; <<-eos
|
34
|
+
update *all|app-ID Similar to the create command, except it updates existing files
|
35
|
+
eos
|
36
|
+
end
|
37
|
+
|
38
|
+
def delete_command; <<-eos
|
39
|
+
delete app-ID Delete the app folder and all related services
|
40
|
+
eos
|
41
|
+
end
|
42
|
+
|
43
|
+
def push_command; <<-eos
|
44
|
+
push development|RACK_ENV [*all|OR...] Push all changes to the environment specified
|
45
|
+
|env Update environment vars in remote environments
|
46
|
+
|bitbucket Push the latest commit to bitbucket
|
47
|
+
|heroku Push the latest commit to heroku and restart
|
48
|
+
|iron Push changes to workers
|
49
|
+
eos
|
50
|
+
end
|
51
|
+
|
52
|
+
def restart_command; <<-eos
|
53
|
+
restart [*development|RACK_ENV|all] Runs `touch tmp/restart` if development or else `heroku restart`
|
54
|
+
eos
|
55
|
+
end
|
56
|
+
|
57
|
+
def count_command; <<-eos
|
58
|
+
count Display the number of fanforce apps in the current directory
|
59
|
+
eos
|
60
|
+
end
|
61
|
+
|
62
|
+
def bundle_command; <<-eos
|
63
|
+
bundle (install|update) Run bundle on all apps in current fanforce
|
64
|
+
eos
|
65
|
+
end
|
66
|
+
|
67
|
+
def git_command; <<-eos
|
68
|
+
git [ANY GIT COMMAND] Run the same git command across all apps in current fanforce
|
69
|
+
git status:overview A custom git command that displays a simple status for each app
|
70
|
+
eos
|
71
|
+
end
|
72
|
+
|
73
|
+
def iron_command; <<-eos
|
74
|
+
iron (upload|reset|delete) [*all|RACK_ENV] Updates env variables and upload one or more workers to iron.io
|
75
|
+
eos
|
76
|
+
end
|
77
|
+
|
78
|
+
def version_command; <<-eos
|
79
|
+
version Display your current Fanforce CLI version number
|
80
|
+
eos
|
81
|
+
end
|
82
|
+
|
83
|
+
def config_command; <<-eos
|
84
|
+
config Display your Fanforce CLI config in the current directory
|
85
|
+
eos
|
86
|
+
end
|
87
|
+
|
88
|
+
def cleanorgs_command; <<-eos
|
89
|
+
cleanorgs environment supercore_api_key Remove installs that are no longer valid in the db
|
90
|
+
eos
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Fanforce::CLI::Run
|
2
|
+
require 'pty'
|
3
|
+
|
4
|
+
def self.bundle_install(dir)
|
5
|
+
Dir.chdir(dir) do
|
6
|
+
command('gem install bundler') if Gem::Specification::find_all_by_name('bundler').empty?
|
7
|
+
command('bundle install')
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.pow_create(app, root_domain)
|
12
|
+
domain = "#{app._id}.#{root_domain}"
|
13
|
+
|
14
|
+
symbolic_link = "#{ENV['HOME']}/.pow/#{domain.gsub('.gg','')}"
|
15
|
+
File.delete(symbolic_link) if File.exists?(symbolic_link)
|
16
|
+
`ln -s #{app.dir} #{symbolic_link}`
|
17
|
+
puts "#{'Connected'.format(:bold,:green)} #{domain} to #{app.dir}/"
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.pow_destroy(app, root_domain)
|
21
|
+
domain = "#{app._id}.#{root_domain}"
|
22
|
+
symbolic_link = "#{ENV['HOME']}/.pow/#{domain.gsub('.gg','')}"
|
23
|
+
if File.exists?(symbolic_link)
|
24
|
+
File.delete(symbolic_link)
|
25
|
+
puts "#{'Removed'.format(:bold,:green)} #{domain}"
|
26
|
+
else
|
27
|
+
puts "#{'Already Removed'.format(:bold,:green)} #{domain} to #{app.dir}/"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.git_init
|
32
|
+
`git init`
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.git_add
|
36
|
+
`git add .`
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.git_first_commit
|
40
|
+
`git commit -m "initial fanforce commit"`
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.command(command, print_now=true)
|
44
|
+
output = []
|
45
|
+
PTY.spawn(command) do |stdin, stdout, pid|
|
46
|
+
stdin.each { |line| output << line; print line if print_now }
|
47
|
+
end
|
48
|
+
output.join("\n")
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|