fanforce-cli 1.1.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/.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
|