flame 4.18.1 → 5.0.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/flame +7 -62
- data/lib/flame.rb +1 -0
- data/lib/flame/application.rb +75 -17
- data/lib/flame/application/config.rb +6 -0
- data/lib/flame/controller.rb +36 -76
- data/lib/flame/controller/path_to.rb +39 -0
- data/lib/flame/dispatcher.rb +25 -66
- data/lib/flame/dispatcher/cookies.rb +10 -2
- data/lib/flame/dispatcher/routes.rb +53 -0
- data/lib/flame/dispatcher/static.rb +15 -8
- data/lib/flame/errors/argument_not_assigned_error.rb +6 -0
- data/lib/flame/errors/route_arguments_order_error.rb +6 -0
- data/lib/flame/errors/route_extra_arguments_error.rb +10 -0
- data/lib/flame/errors/route_not_found_error.rb +10 -4
- data/lib/flame/errors/template_not_found_error.rb +6 -0
- data/lib/flame/path.rb +63 -33
- data/lib/flame/render.rb +21 -8
- data/lib/flame/router.rb +112 -66
- data/lib/flame/router/route.rb +9 -56
- data/lib/flame/router/routes.rb +86 -0
- data/lib/flame/validators.rb +7 -1
- data/lib/flame/version.rb +1 -1
- data/template/.editorconfig +15 -0
- data/template/.gitignore +19 -2
- data/template/.rubocop.yml +14 -0
- data/template/Gemfile +48 -8
- data/template/Rakefile +824 -0
- data/template/{app.rb.erb → application.rb.erb} +4 -1
- data/template/config.ru.erb +62 -10
- data/template/config/config.rb.erb +44 -2
- data/template/config/database.example.yml +1 -1
- data/template/config/deploy.example.yml +2 -0
- data/template/config/puma.rb +56 -0
- data/template/config/sequel.rb.erb +13 -6
- data/template/config/server.example.yml +32 -0
- data/template/config/session.example.yml +7 -0
- data/template/controllers/{_base_controller.rb.erb → _controller.rb.erb} +5 -4
- data/template/controllers/site/_controller.rb.erb +18 -0
- data/template/controllers/site/index_controller.rb.erb +12 -0
- data/template/filewatchers.yml +12 -0
- data/template/server +172 -21
- data/template/services/.keep +0 -0
- data/template/views/site/index.html.erb.erb +1 -0
- data/template/views/site/layout.html.erb.erb +10 -0
- metadata +112 -54
- data/template/Rakefile.erb +0 -64
- data/template/config/thin.example.yml +0 -18
data/template/config.ru.erb
CHANGED
@@ -1,20 +1,72 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
environment = ENV['RACK_ENV'].to_sym
|
4
|
+
|
5
|
+
is_development = environment == :development
|
6
|
+
|
3
7
|
## Require gems
|
4
8
|
require 'bundler'
|
5
|
-
Bundler.require
|
9
|
+
Bundler.require :default, environment
|
10
|
+
|
11
|
+
## Require libs
|
12
|
+
# require 'money/bank/google_currency'
|
6
13
|
|
7
|
-
## Require
|
8
|
-
|
9
|
-
|
10
|
-
)
|
14
|
+
## Require dirs
|
15
|
+
Flame::Application.require_dirs(
|
16
|
+
%w[config lib models helpers exports mailers services controllers]
|
17
|
+
)
|
11
18
|
|
12
19
|
## Require application
|
13
|
-
|
20
|
+
require './application'
|
21
|
+
|
22
|
+
## Use session middleware
|
23
|
+
if <%= @short_module_name %>::Application.config[:session]
|
24
|
+
use Rack::Session::Cookie, <%= @short_module_name %>::Application.config[:session][:cookie]
|
25
|
+
end
|
26
|
+
|
27
|
+
## Logger
|
28
|
+
require 'logger'
|
29
|
+
logs_dir = File.join(
|
30
|
+
__dir__,
|
31
|
+
<%= @short_module_name %>::Application.config[:server][environment.to_s][:logs_dir]
|
32
|
+
)
|
33
|
+
|
34
|
+
<%= @short_module_name %>::Application.config[:logger] = Logger.new(
|
35
|
+
is_development ? $stdout : File.join(logs_dir, 'stdout'),
|
36
|
+
'weekly'
|
37
|
+
)
|
38
|
+
|
39
|
+
## Access Logger
|
40
|
+
unless is_development
|
41
|
+
use Rack::CommonLogger, Logger.new(
|
42
|
+
File.join(logs_dir, 'access'),
|
43
|
+
'weekly'
|
44
|
+
)
|
45
|
+
end
|
46
|
+
|
47
|
+
if <%= @short_module_name %>.const_defined?(:DB)
|
48
|
+
## SQL Logger
|
49
|
+
if is_development
|
50
|
+
<%= @short_module_name %>::DB.loggers <<
|
51
|
+
if ENV['RACK_CONSOLE_INTRO']
|
52
|
+
Logger.new($stdout)
|
53
|
+
else
|
54
|
+
<%= @short_module_name %>.logger
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
## Freeze DB (not for `rake console`)
|
59
|
+
<%= @short_module_name %>::DB.freeze unless ENV['RACK_CONSOLE_INTRO']
|
60
|
+
end
|
61
|
+
|
62
|
+
## Remove invalid UTF-8 characters from requests
|
63
|
+
use Rack::UTF8Sanitizer
|
64
|
+
|
65
|
+
## Remove trailing slashes from request path (and redirect)
|
66
|
+
# use Rack::RemoveTrailingSlashes
|
14
67
|
|
15
|
-
##
|
16
|
-
use Rack::
|
17
|
-
use Rack::CommonLogger
|
68
|
+
## CSRF
|
69
|
+
# use Rack::Csrf, raise: is_development
|
18
70
|
|
19
71
|
## Run application
|
20
|
-
run <%= @
|
72
|
+
run <%= @short_module_name %>::Application
|
@@ -1,14 +1,56 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
## Module for Application configuration
|
3
4
|
module <%= @module_name %>
|
4
5
|
## Constants
|
5
|
-
SITE_NAME = '<%= @module_name %>'
|
6
|
+
SITE_NAME = '<%= @module_name %>'
|
7
|
+
ORGANIZATION_NAME = '<%= @module_name %> LLC'
|
8
|
+
::<%= @short_module_name %> = ::<%= @module_name %>
|
9
|
+
|
10
|
+
## Helpers
|
11
|
+
def self.logger
|
12
|
+
<%= @short_module_name %>::Application.config[:logger]
|
13
|
+
end
|
6
14
|
|
7
15
|
## Configuration for application
|
8
16
|
module Config
|
9
17
|
def self.included(app)
|
10
18
|
## Translations
|
11
|
-
# Flame::R18n
|
19
|
+
# app.include Flame::R18n::Configuration
|
20
|
+
|
21
|
+
## Mail
|
22
|
+
# app.include Config::Mail
|
23
|
+
|
24
|
+
## Sentry
|
25
|
+
# app.include Config::Sentry
|
26
|
+
|
27
|
+
## Threads (for mails)
|
28
|
+
Thread.abort_on_exception = true
|
29
|
+
|
30
|
+
## Currencies rates
|
31
|
+
# Money.default_bank = Money::Bank::GoogleCurrency.new
|
32
|
+
### https://github.com/RubyMoney/money#troubleshooting
|
33
|
+
# I18n.enforce_available_locales = false
|
34
|
+
|
35
|
+
## Required configs
|
36
|
+
load_configs(app, :server, require: true)
|
37
|
+
|
38
|
+
## Not-required configs
|
39
|
+
# load_configs(app, :google_maps_api)
|
40
|
+
|
41
|
+
## Mails directory
|
42
|
+
# app.config[:mails_dir] = proc { File.join config[:views_dir], 'mail' }
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.load_configs(app, *keys, require: false)
|
46
|
+
keys.each do |key|
|
47
|
+
begin
|
48
|
+
app.config.load_yaml key
|
49
|
+
rescue => exception
|
50
|
+
next unless require
|
51
|
+
raise exception
|
52
|
+
end
|
53
|
+
end
|
12
54
|
end
|
13
55
|
end
|
14
56
|
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
#!/usr/bin/env puma
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'yaml'
|
5
|
+
config = YAML.load_file(File.join(__dir__, 'server.yml'))
|
6
|
+
|
7
|
+
environment = ENV['RACK_ENV'] || config[:environment]
|
8
|
+
env_config = config[environment]
|
9
|
+
|
10
|
+
root_dir = File.join(__dir__, '..')
|
11
|
+
directory root_dir
|
12
|
+
|
13
|
+
prune_bundler
|
14
|
+
|
15
|
+
rackup 'config.ru'
|
16
|
+
|
17
|
+
require 'fileutils'
|
18
|
+
|
19
|
+
raise 'Unknown directory for pid files!' unless env_config[:pids_dir]
|
20
|
+
pids_dir = File.join root_dir, env_config[:pids_dir]
|
21
|
+
FileUtils.mkdir_p pids_dir
|
22
|
+
|
23
|
+
pidfile File.join pids_dir, env_config[:pid_file]
|
24
|
+
state_path File.join pids_dir, 'puma.state'
|
25
|
+
|
26
|
+
raise 'Unknown directory for log files!' unless env_config[:logs_dir]
|
27
|
+
log_dir = File.join root_dir, env_config[:logs_dir]
|
28
|
+
FileUtils.mkdir_p log_dir
|
29
|
+
|
30
|
+
if env_config[:daemonize]
|
31
|
+
stdout_redirect(
|
32
|
+
File.join(log_dir, 'stdout'),
|
33
|
+
File.join(log_dir, 'stderr'),
|
34
|
+
true # append to file
|
35
|
+
)
|
36
|
+
end
|
37
|
+
|
38
|
+
environment environment
|
39
|
+
|
40
|
+
# preload_app! if config['environment'] != 'production'
|
41
|
+
|
42
|
+
cores = Etc.nprocessors
|
43
|
+
workers_count = env_config[:workers_count] || (cores < 2 ? 1 : 2)
|
44
|
+
|
45
|
+
workers workers_count
|
46
|
+
worker_timeout env_config[:daemonize] ? 15 : 1_000_000
|
47
|
+
threads 0, env_config[:threads_count] || 4
|
48
|
+
daemonize env_config[:daemonize]
|
49
|
+
|
50
|
+
# bind 'unix://' + File.join(%w[tmp sockets puma.sock])
|
51
|
+
env_config[:binds].each do |type, value|
|
52
|
+
value = "#{value[:host]}:#{value[:port]}" if type == :tcp
|
53
|
+
FileUtils.mkdir_p File.join(root_dir, File.dirname(value)) if type == :unix
|
54
|
+
bind "#{type}://#{value}"
|
55
|
+
end
|
56
|
+
# activate_control_app 'tcp://0.0.0.0:3000'
|
@@ -4,12 +4,19 @@ require 'yaml'
|
|
4
4
|
|
5
5
|
## Database initialize for Sequel
|
6
6
|
module <%= @module_name %>
|
7
|
-
|
8
|
-
|
7
|
+
database_config_file = File.join(__dir__, 'database.yml')
|
8
|
+
if File.exist?(database_config_file)
|
9
|
+
Sequel::Model.plugin :timestamps
|
10
|
+
Sequel::Model.plugin :json_serializer
|
11
|
+
Sequel::Model.raise_on_save_failure = false
|
9
12
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
+
database_config = YAML.load_file(database_config_file)
|
14
|
+
env_db_name = ENV['DB_NAME']
|
15
|
+
database_config[:database] = env_db_name if env_db_name
|
16
|
+
DB = Sequel.connect database_config
|
13
17
|
|
14
|
-
|
18
|
+
|
19
|
+
# DB.extension :pg_enum
|
20
|
+
DB.extension :error_sql
|
21
|
+
end
|
15
22
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
:environment: development
|
2
|
+
# :environment: production
|
3
|
+
|
4
|
+
:default: &default
|
5
|
+
:binds:
|
6
|
+
:tcp:
|
7
|
+
:host: '0.0.0.0'
|
8
|
+
:port: 3000
|
9
|
+
# :unix: 'tmp/sockets/puma.sock'
|
10
|
+
:daemonize: false
|
11
|
+
:pids_dir: tmp/pids
|
12
|
+
:logs_dir: log
|
13
|
+
:pid_file: puma.pid
|
14
|
+
# :workers_count: 1
|
15
|
+
# :threads_count: 4
|
16
|
+
|
17
|
+
development: &development
|
18
|
+
<<: *default
|
19
|
+
:workers_count: 1
|
20
|
+
:threads_count: 4
|
21
|
+
|
22
|
+
test: &test
|
23
|
+
<<: *default
|
24
|
+
:daemonize: false
|
25
|
+
|
26
|
+
production: &production
|
27
|
+
<<: *default
|
28
|
+
:binds:
|
29
|
+
# :tcp:
|
30
|
+
# :host: '0.0.0.0'
|
31
|
+
# :port: 3000
|
32
|
+
:unix: 'tmp/sockets/puma.sock'
|
@@ -3,11 +3,12 @@
|
|
3
3
|
module <%= @module_name %>
|
4
4
|
## Base controller for any others controllers
|
5
5
|
class Controller < Flame::Controller
|
6
|
-
# include Flame::R18n
|
6
|
+
# include Flame::R18n::Initialization
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
8
|
+
private
|
9
|
+
|
10
|
+
def logger
|
11
|
+
<%= @short_module_name %>.logger
|
11
12
|
end
|
12
13
|
end
|
13
14
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module <%= @module_name %>
|
4
|
+
module Site
|
5
|
+
## Base controller for site-section
|
6
|
+
class Controller < <%= @short_module_name %>::Controller
|
7
|
+
# include Flame::Flash
|
8
|
+
# include Flame::R18n::LocaleInPath
|
9
|
+
|
10
|
+
protected
|
11
|
+
|
12
|
+
def execute(method)
|
13
|
+
response.headers[Rack::CONTENT_TYPE] = 'text/html; charset=utf-8'
|
14
|
+
super
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
- :pattern: '**/{Gemfile,*.{rb,ru,yml}}'
|
2
|
+
:exclude: '**/{spec/**/*,config/**/*.example*}'
|
3
|
+
:command: bundle exec pumactl restart -F config/puma.rb
|
4
|
+
|
5
|
+
# - :pattern: 'assets/styles/**/*'
|
6
|
+
# :command: rake assets:build:styles
|
7
|
+
#
|
8
|
+
# - :pattern: '{assets/scripts/**/*,{.babelrc,webpack.config.js}}'
|
9
|
+
# :command: rake assets:build:scripts
|
10
|
+
#
|
11
|
+
# - :pattern: 'package.json'
|
12
|
+
# :command: yarn install && rake assets:build:scripts
|
data/template/server
CHANGED
@@ -1,49 +1,200 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
|
2
3
|
# frozen_string_literal: true
|
3
4
|
|
5
|
+
require 'shellwords'
|
6
|
+
require 'yaml'
|
7
|
+
|
4
8
|
## Functons
|
5
9
|
def show_usage
|
6
|
-
puts
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
10
|
+
puts <<~USAGE
|
11
|
+
Usage: ./server COMMAND
|
12
|
+
|
13
|
+
COMMAND is one of:
|
14
|
+
start - Start server
|
15
|
+
stop - Stop server
|
16
|
+
kill - Kill server (and filewatcher)
|
17
|
+
restart - Restart server
|
18
|
+
monitor - Show log
|
19
|
+
devel - Restart and monitor server
|
20
|
+
ps - Show processes of server
|
21
|
+
USAGE
|
22
|
+
end
|
23
|
+
|
24
|
+
def bash(command, print: true)
|
25
|
+
puts command if print
|
26
|
+
system bash_command(command)
|
27
|
+
end
|
28
|
+
|
29
|
+
def bash_command(command)
|
30
|
+
escaped_command = Shellwords.escape(command)
|
31
|
+
"bash -c #{escaped_command}"
|
32
|
+
end
|
33
|
+
|
34
|
+
def bash_spawn(command)
|
35
|
+
puts "spawn #{command}"
|
36
|
+
spawn bash_command command
|
37
|
+
end
|
38
|
+
|
39
|
+
def server(command)
|
40
|
+
if %i[start restart].include?(command) &&
|
41
|
+
!(dependencies_check && assets_build)
|
42
|
+
exit
|
43
|
+
end
|
44
|
+
if %i[stop restart].include?(command)
|
45
|
+
kill_each read_filewatcher_pids
|
46
|
+
delete_filewatcher_pids_file
|
47
|
+
end
|
48
|
+
web_server(command)
|
49
|
+
end
|
50
|
+
|
51
|
+
def web_server(command)
|
52
|
+
pumactl_command = "bundle exec pumactl #{command} -F #{puma_config_file}"
|
53
|
+
if environment == 'production' || command != :restart
|
54
|
+
waiting_mailing_lock if %i[stop restart].include?(command)
|
55
|
+
return bash pumactl_command
|
56
|
+
end
|
57
|
+
development_restart pumactl_command
|
58
|
+
end
|
59
|
+
|
60
|
+
def development_restart(pumactl_command)
|
61
|
+
filewatcher_pids =
|
62
|
+
development_filewatchers.map { |command| bash_spawn command }
|
63
|
+
dump_filewatcher_pids filewatcher_pids
|
64
|
+
# web_server :stop if File.exist? puma_pid_file
|
65
|
+
# web_server :start
|
66
|
+
File.exist?(puma_pid_file) ? bash(pumactl_command) : web_server(:start)
|
67
|
+
rescue SystemExit, Interrupt
|
68
|
+
kill_each filewatcher_pids
|
69
|
+
delete_filewatcher_pids_file
|
70
|
+
end
|
71
|
+
|
72
|
+
def kill_each(pids)
|
73
|
+
Array(pids).each do |pid|
|
74
|
+
bash "kill #{pid}"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def filewatcher_command(pattern, execute, exclude: nil)
|
79
|
+
<<-CMD.split.join(' ')
|
80
|
+
bundle exec "
|
81
|
+
filewatcher
|
82
|
+
'#{pattern}'
|
83
|
+
#{"--exclude '#{exclude}'" unless exclude.nil?}
|
84
|
+
'#{execute}'
|
85
|
+
"
|
86
|
+
CMD
|
87
|
+
end
|
88
|
+
|
89
|
+
def development_filewatchers
|
90
|
+
YAML.load_file(File.join(__dir__, 'filewatchers.yml')).map do |args|
|
91
|
+
filewatcher_command args[:pattern], args[:command], exclude: args[:exclude]
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def dump_filewatcher_pids(filewatcher_pids)
|
96
|
+
FileUtils.mkdir_p server_config_pids_dir
|
97
|
+
File.write(
|
98
|
+
filewatcher_pids_file,
|
99
|
+
filewatcher_pids.join($RS)
|
100
|
+
)
|
101
|
+
end
|
102
|
+
|
103
|
+
def read_filewatcher_pids
|
104
|
+
return unless File.exist?(filewatcher_pids_file)
|
105
|
+
File.read(filewatcher_pids_file).split($RS)
|
106
|
+
end
|
107
|
+
|
108
|
+
def delete_filewatcher_pids_file
|
109
|
+
return unless File.exist?(filewatcher_pids_file)
|
110
|
+
File.delete filewatcher_pids_file
|
111
|
+
end
|
112
|
+
|
113
|
+
def server_config
|
114
|
+
@server_config ||= YAML.load_file(File.join(__dir__, 'config', 'server.yml'))
|
115
|
+
end
|
116
|
+
|
117
|
+
def puma_config_file
|
118
|
+
@puma_config_file ||= File.join(__dir__, 'config', 'puma.rb')
|
119
|
+
end
|
120
|
+
|
121
|
+
def puma_pid_file
|
122
|
+
File.join(
|
123
|
+
__dir__, *server_config[environment].values_at(:pids_dir, :pid_file)
|
124
|
+
)
|
13
125
|
end
|
14
126
|
|
15
|
-
def
|
16
|
-
|
17
|
-
system 'thin -C config/thin.yml start'
|
127
|
+
def server_config_pids_dir
|
128
|
+
server_config[environment][:pids_dir]
|
18
129
|
end
|
19
130
|
|
20
|
-
def
|
21
|
-
|
131
|
+
def filewatcher_pids_file
|
132
|
+
File.join server_config_pids_dir, 'filewatcher.pids'
|
22
133
|
end
|
23
134
|
|
24
|
-
def
|
25
|
-
|
26
|
-
|
135
|
+
def environment
|
136
|
+
ENV['RACK_ENV'] || server_config[:environment]
|
137
|
+
end
|
138
|
+
|
139
|
+
def log_files
|
140
|
+
File.join(__dir__, %w[log {stdout,stderr}])
|
141
|
+
end
|
142
|
+
|
143
|
+
def waiting_mailing_lock
|
144
|
+
while Dir[File.join(__dir__, 'tmp', 'mailing_*')].any?
|
145
|
+
puts "\e[31m\e[1mMails sending in progress!\e[22m\e[0m\nWaiting..."
|
146
|
+
sleep 1
|
147
|
+
end
|
27
148
|
end
|
28
149
|
|
29
150
|
def monitor_server
|
30
|
-
|
151
|
+
bash "tail -f #{log_files}"
|
152
|
+
end
|
153
|
+
|
154
|
+
def dependencies_check
|
155
|
+
bash('bundle check || bundle install') # && bash('yarn install')
|
156
|
+
end
|
157
|
+
|
158
|
+
def assets_build
|
159
|
+
bash 'rake assets:build', print: false
|
160
|
+
end
|
161
|
+
|
162
|
+
def ps_with_grep(pattern)
|
163
|
+
bash "ps aux | grep #{pattern} --color", print: false
|
31
164
|
end
|
32
165
|
|
33
166
|
## Runtime
|
34
167
|
case ARGV[0]
|
35
168
|
when 'start'
|
36
|
-
|
169
|
+
server :start
|
37
170
|
when 'stop'
|
38
|
-
|
171
|
+
server :stop
|
39
172
|
when 'restart'
|
40
|
-
|
173
|
+
server :restart
|
174
|
+
when 'kill'
|
175
|
+
server :stop
|
176
|
+
bash 'pkill -f filewatcher'
|
177
|
+
bash 'pkill -f puma'
|
41
178
|
when 'monitor'
|
42
179
|
monitor_server
|
43
180
|
when 'devel'
|
44
|
-
|
45
|
-
|
181
|
+
server :restart
|
182
|
+
if environment == 'production'
|
183
|
+
puts 'Waiting for logs...'
|
184
|
+
sleep 1.5
|
185
|
+
monitor_server
|
186
|
+
end
|
187
|
+
when 'ps'
|
188
|
+
puts
|
189
|
+
puts 'Filewatcher:'
|
190
|
+
puts
|
191
|
+
ps_with_grep '[f]ilewatcher'
|
192
|
+
puts
|
193
|
+
puts 'Puma:'
|
194
|
+
puts
|
195
|
+
ps_with_grep '[p]uma[\ :]'
|
46
196
|
else
|
47
197
|
puts "Unknown command #{ARGV[0]}"
|
198
|
+
puts
|
48
199
|
show_usage
|
49
200
|
end
|