hanami-cli 2.2.0.beta1 → 2.2.0.rc1
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 +4 -4
- data/.github/workflows/ci.yml +13 -2
- data/.rubocop.yml +2 -0
- data/CHANGELOG.md +38 -2
- data/Gemfile +3 -0
- data/README.md +2 -0
- data/docker-compose.yml +6 -1
- data/lib/hanami/cli/command.rb +1 -1
- data/lib/hanami/cli/commands/app/command.rb +9 -3
- data/lib/hanami/cli/commands/app/console.rb +1 -5
- data/lib/hanami/cli/commands/app/db/command.rb +139 -31
- data/lib/hanami/cli/commands/app/db/create.rb +6 -2
- data/lib/hanami/cli/commands/app/db/drop.rb +6 -2
- data/lib/hanami/cli/commands/app/db/migrate.rb +49 -8
- data/lib/hanami/cli/commands/app/db/prepare.rb +36 -8
- data/lib/hanami/cli/commands/app/db/seed.rb +17 -1
- data/lib/hanami/cli/commands/app/db/structure/dump.rb +11 -6
- data/lib/hanami/cli/commands/app/db/structure/load.rb +9 -5
- data/lib/hanami/cli/commands/app/db/utils/database.rb +44 -14
- data/lib/hanami/cli/commands/app/db/utils/mysql.rb +57 -4
- data/lib/hanami/cli/commands/app/db/utils/postgres.rb +13 -8
- data/lib/hanami/cli/commands/app/db/version.rb +6 -3
- data/lib/hanami/cli/commands/app/generate/action.rb +12 -2
- data/lib/hanami/cli/commands/app/generate/command.rb +13 -2
- data/lib/hanami/cli/commands/app/generate/migration.rb +20 -0
- data/lib/hanami/cli/commands/app/generate/relation.rb +0 -6
- data/lib/hanami/cli/commands/app/generate/repo.rb +3 -7
- data/lib/hanami/cli/commands/app/generate/slice.rb +16 -3
- data/lib/hanami/cli/commands/app.rb +21 -9
- data/lib/hanami/cli/files.rb +22 -0
- data/lib/hanami/cli/generators/app/action.rb +27 -15
- data/lib/hanami/cli/generators/app/migration.rb +8 -9
- data/lib/hanami/cli/generators/app/operation.rb +5 -4
- data/lib/hanami/cli/generators/app/relation.rb +5 -4
- data/lib/hanami/cli/generators/app/repo.rb +5 -4
- data/lib/hanami/cli/generators/app/ruby_file_writer.rb +39 -37
- data/lib/hanami/cli/generators/app/slice.rb +5 -3
- data/lib/hanami/cli/generators/app/slice_context.rb +6 -0
- data/lib/hanami/cli/generators/app/struct.rb +5 -4
- data/lib/hanami/cli/generators/context.rb +4 -4
- data/lib/hanami/cli/generators/gem/app/gitignore.erb +3 -0
- data/lib/hanami/cli/generators/gem/app/operation.erb +0 -4
- data/lib/hanami/cli/generators/gem/app/seeds.erb +15 -0
- data/lib/hanami/cli/generators/gem/app.rb +3 -2
- data/lib/hanami/cli/repl/irb.rb +2 -2
- data/lib/hanami/cli/version.rb +1 -1
- metadata +4 -4
- data/lib/hanami/cli/generators/app/slice/entities.erb +0 -9
@@ -11,13 +11,15 @@ module Hanami
|
|
11
11
|
class Dump < DB::Command
|
12
12
|
desc "Dumps database structure to config/db/structure.sql file"
|
13
13
|
|
14
|
+
option :gateway, required: false, desc: "Use database for gateway"
|
15
|
+
|
14
16
|
# @api private
|
15
|
-
def call(app: false, slice: nil, command_exit: method(:exit), **)
|
17
|
+
def call(app: false, slice: nil, gateway: nil, command_exit: method(:exit), **)
|
16
18
|
exit_codes = []
|
17
19
|
|
18
|
-
databases(app: app, slice: slice).each do |database|
|
19
|
-
|
20
|
-
|
20
|
+
databases(app: app, slice: slice, gateway: gateway).each do |database|
|
21
|
+
relative_structure_path = database.structure_file
|
22
|
+
.relative_path_from(database.slice.app.root)
|
21
23
|
|
22
24
|
measure("#{database.name} structure dumped to #{relative_structure_path}") do
|
23
25
|
catch :dump_failed do
|
@@ -29,8 +31,11 @@ module Hanami
|
|
29
31
|
throw :dump_failed, false
|
30
32
|
end
|
31
33
|
|
32
|
-
|
33
|
-
|
34
|
+
migrations_sql = database.schema_migrations_sql_dump
|
35
|
+
if migrations_sql
|
36
|
+
File.open(database.structure_file, "a") do |f|
|
37
|
+
f.puts "#{migrations_sql}\n"
|
38
|
+
end
|
34
39
|
end
|
35
40
|
|
36
41
|
true
|
@@ -14,15 +14,17 @@ module Hanami
|
|
14
14
|
|
15
15
|
desc "Loads database from config/db/structure.sql file"
|
16
16
|
|
17
|
+
option :gateway, required: false, desc: "Use database for gateway"
|
18
|
+
|
17
19
|
# @api private
|
18
|
-
def call(app: false, slice: nil, command_exit: method(:exit), **)
|
20
|
+
def call(app: false, slice: nil, gateway: nil, command_exit: method(:exit), **)
|
19
21
|
exit_codes = []
|
20
22
|
|
21
|
-
databases(app: app, slice: slice).each do |database|
|
22
|
-
|
23
|
-
next unless structure_path.exist?
|
23
|
+
databases(app: app, slice: slice, gateway: gateway).each do |database|
|
24
|
+
next unless database.structure_file.exist?
|
24
25
|
|
25
|
-
relative_structure_path =
|
26
|
+
relative_structure_path = database.structure_file
|
27
|
+
.relative_path_from(database.slice.app.root)
|
26
28
|
|
27
29
|
measure("#{database.name} structure loaded from #{relative_structure_path}") do
|
28
30
|
catch :load_failed do
|
@@ -42,6 +44,8 @@ module Hanami
|
|
42
44
|
exit_codes.each do |code|
|
43
45
|
break command_exit.(code) if code > 0
|
44
46
|
end
|
47
|
+
|
48
|
+
re_run_development_command_in_test
|
45
49
|
end
|
46
50
|
end
|
47
51
|
end
|
@@ -11,9 +11,6 @@ module Hanami
|
|
11
11
|
# @api private
|
12
12
|
# @since 2.2.0
|
13
13
|
class Database
|
14
|
-
MIGRATIONS_DIR = "config/db/migrate"
|
15
|
-
private_constant :MIGRATIONS_DIR
|
16
|
-
|
17
14
|
DATABASE_CLASS_RESOLVER = Hash.new { |_, key|
|
18
15
|
raise "#{key} is not a supported db scheme"
|
19
16
|
}.update(
|
@@ -29,27 +26,40 @@ module Hanami
|
|
29
26
|
require_relative("postgres")
|
30
27
|
Postgres
|
31
28
|
},
|
32
|
-
"
|
29
|
+
"mysql2" => -> {
|
33
30
|
require_relative("mysql")
|
34
31
|
Mysql
|
35
32
|
}
|
36
33
|
).freeze
|
37
34
|
|
38
|
-
def self.
|
35
|
+
def self.database_class(database_url)
|
36
|
+
database_scheme = URI(database_url).scheme
|
37
|
+
DATABASE_CLASS_RESOLVER[database_scheme].call
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.from_slice(slice:, system_call:)
|
39
41
|
provider = slice.container.providers[:db]
|
40
|
-
raise "
|
42
|
+
raise "No :db provider for #{slice}" unless provider
|
41
43
|
|
42
|
-
|
43
|
-
|
44
|
-
|
44
|
+
provider.source.database_urls.map { |(gateway_name, database_url)|
|
45
|
+
database = database_class(database_url).new(
|
46
|
+
slice: slice,
|
47
|
+
gateway_name: gateway_name,
|
48
|
+
system_call: system_call
|
49
|
+
)
|
50
|
+
|
51
|
+
[gateway_name, database]
|
52
|
+
}.to_h
|
45
53
|
end
|
46
54
|
|
47
55
|
attr_reader :slice
|
56
|
+
attr_reader :gateway_name
|
48
57
|
|
49
58
|
attr_reader :system_call
|
50
59
|
|
51
|
-
def initialize(slice:, system_call:)
|
60
|
+
def initialize(slice:, gateway_name:, system_call:)
|
52
61
|
@slice = slice
|
62
|
+
@gateway_name = gateway_name
|
53
63
|
@system_call = system_call
|
54
64
|
end
|
55
65
|
|
@@ -58,7 +68,7 @@ module Hanami
|
|
58
68
|
end
|
59
69
|
|
60
70
|
def database_url
|
61
|
-
slice.container.providers[:db].source.
|
71
|
+
slice.container.providers[:db].source.database_urls.fetch(gateway_name)
|
62
72
|
end
|
63
73
|
|
64
74
|
def database_uri
|
@@ -66,7 +76,7 @@ module Hanami
|
|
66
76
|
end
|
67
77
|
|
68
78
|
def gateway
|
69
|
-
slice["db.config"].gateways[
|
79
|
+
slice["db.config"].gateways[gateway_name]
|
70
80
|
end
|
71
81
|
|
72
82
|
def connection
|
@@ -127,8 +137,20 @@ module Hanami
|
|
127
137
|
sequel_migrator.applied_migrations
|
128
138
|
end
|
129
139
|
|
140
|
+
def db_config_path
|
141
|
+
slice.root.join("config", "db")
|
142
|
+
end
|
143
|
+
|
144
|
+
def db_config_dir?
|
145
|
+
db_config_path.directory?
|
146
|
+
end
|
147
|
+
|
130
148
|
def migrations_path
|
131
|
-
|
149
|
+
if gateway_name == :default
|
150
|
+
db_config_path.join("migrate")
|
151
|
+
else
|
152
|
+
db_config_path.join("#{gateway_name}_migrate")
|
153
|
+
end
|
132
154
|
end
|
133
155
|
|
134
156
|
def migrations_dir?
|
@@ -136,10 +158,18 @@ module Hanami
|
|
136
158
|
end
|
137
159
|
|
138
160
|
def structure_file
|
139
|
-
slice.root.join("config
|
161
|
+
path = slice.root.join("config", "db")
|
162
|
+
|
163
|
+
if gateway_name == :default
|
164
|
+
path.join("structure.sql")
|
165
|
+
else
|
166
|
+
path.join("#{gateway_name}_structure.sql")
|
167
|
+
end
|
140
168
|
end
|
141
169
|
|
142
170
|
def schema_migrations_sql_dump
|
171
|
+
return unless migrations_dir?
|
172
|
+
|
143
173
|
sql = +"INSERT INTO schema_migrations (filename) VALUES\n"
|
144
174
|
sql << applied_migrations.map { |v| "('#{v}')" }.join(",\n")
|
145
175
|
sql << ";"
|
@@ -11,18 +11,71 @@ module Hanami
|
|
11
11
|
# @api private
|
12
12
|
class Mysql < Database
|
13
13
|
# @api private
|
14
|
-
def
|
15
|
-
|
14
|
+
def exec_create_command
|
15
|
+
return true if exists?
|
16
|
+
|
17
|
+
exec_cli("mysql", %(-e "CREATE DATABASE #{escaped_name}"))
|
18
|
+
end
|
19
|
+
|
20
|
+
# @api private
|
21
|
+
# @since 2.2.0
|
22
|
+
def exec_drop_command
|
23
|
+
return true unless exists?
|
24
|
+
|
25
|
+
exec_cli("mysql", %(-e "DROP DATABASE #{escaped_name}"))
|
26
|
+
end
|
27
|
+
|
28
|
+
# @api private
|
29
|
+
# @since 2.2.0
|
30
|
+
def exists?
|
31
|
+
result = exec_cli("mysql", %(-e "SHOW DATABASES LIKE '#{name}'" --batch))
|
32
|
+
|
33
|
+
result.successful? && result.out != ""
|
16
34
|
end
|
17
35
|
|
18
36
|
# @api private
|
37
|
+
# @since 2.2.0
|
19
38
|
def exec_dump_command
|
20
|
-
|
39
|
+
exec_cli(
|
40
|
+
"mysqldump",
|
41
|
+
"--no-data --routines --skip-comments --result-file=#{structure_file} #{escaped_name}"
|
42
|
+
)
|
21
43
|
end
|
22
44
|
|
23
45
|
# @api private
|
46
|
+
# @since 2.2.0
|
24
47
|
def exec_load_command
|
25
|
-
|
48
|
+
exec_cli(
|
49
|
+
"mysql",
|
50
|
+
%(--execute "SET FOREIGN_KEY_CHECKS = 0; SOURCE #{structure_file}; SET FOREIGN_KEY_CHECKS = 1" --database #{escaped_name})
|
51
|
+
)
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def escaped_name
|
57
|
+
Shellwords.escape(name)
|
58
|
+
end
|
59
|
+
|
60
|
+
def exec_cli(cli_name, cli_args)
|
61
|
+
system_call.call(
|
62
|
+
"#{cli_name} #{cli_options} #{cli_args}",
|
63
|
+
env: cli_env_vars
|
64
|
+
)
|
65
|
+
end
|
66
|
+
|
67
|
+
def cli_options
|
68
|
+
[].tap { |opts|
|
69
|
+
opts << "--host=#{Shellwords.escape(database_uri.host)}" if database_uri.host
|
70
|
+
opts << "--port=#{Shellwords.escape(database_uri.port)}" if database_uri.port
|
71
|
+
opts << "--user=#{Shellwords.escape(database_uri.user)}" if database_uri.user
|
72
|
+
}.join(" ")
|
73
|
+
end
|
74
|
+
|
75
|
+
def cli_env_vars
|
76
|
+
@cli_env_vars ||= {}.tap do |vars|
|
77
|
+
vars["MYSQL_PWD"] = database_uri.password.to_s if database_uri.password
|
78
|
+
end
|
26
79
|
end
|
27
80
|
end
|
28
81
|
end
|
@@ -54,6 +54,19 @@ module Hanami
|
|
54
54
|
)
|
55
55
|
end
|
56
56
|
|
57
|
+
def schema_migrations_sql_dump
|
58
|
+
migrations_sql = super
|
59
|
+
return unless migrations_sql
|
60
|
+
|
61
|
+
search_path = gateway.connection
|
62
|
+
.fetch("SHOW search_path").to_a.first
|
63
|
+
.fetch(:search_path)
|
64
|
+
|
65
|
+
+"SET search_path TO #{search_path};\n\n" << migrations_sql
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
57
70
|
def escaped_name
|
58
71
|
Shellwords.escape(name)
|
59
72
|
end
|
@@ -66,14 +79,6 @@ module Hanami
|
|
66
79
|
vars["PGPASSWORD"] = database_uri.password.to_s if database_uri.password
|
67
80
|
end
|
68
81
|
end
|
69
|
-
|
70
|
-
def schema_migrations_sql_dump
|
71
|
-
search_path = slice["db.gateway"].connection
|
72
|
-
.fetch("SHOW search_path").to_a.first
|
73
|
-
.fetch(:search_path)
|
74
|
-
|
75
|
-
+"SET search_path TO #{search_path};\n\n" << super
|
76
|
-
end
|
77
82
|
end
|
78
83
|
end
|
79
84
|
end
|
@@ -9,11 +9,14 @@ module Hanami
|
|
9
9
|
class Version < DB::Command
|
10
10
|
desc "Print schema version"
|
11
11
|
|
12
|
+
option :gateway, required: false, desc: "Use database for gateway"
|
13
|
+
|
12
14
|
# @api private
|
13
|
-
def call(app: false, slice: nil, **)
|
14
|
-
databases(app: app, slice: slice).each do |database|
|
15
|
+
def call(app: false, slice: nil, gateway: nil, **)
|
16
|
+
databases(app: app, slice: slice, gateway: gateway).each do |database|
|
15
17
|
unless database.migrations_dir?
|
16
|
-
|
18
|
+
relative_migrations_path = database.migrations_path.relative_path_from(database.slice.app.root)
|
19
|
+
out.puts "=> Cannot find version for database #{database.name}: no migrations directory at #{relative_migrations_path}/"
|
17
20
|
return
|
18
21
|
end
|
19
22
|
|
@@ -25,6 +25,9 @@ module Hanami
|
|
25
25
|
DEFAULT_SKIP_TESTS = false
|
26
26
|
private_constant :DEFAULT_SKIP_TESTS
|
27
27
|
|
28
|
+
DEFAULT_SKIP_ROUTE = false
|
29
|
+
private_constant :DEFAULT_SKIP_ROUTE
|
30
|
+
|
28
31
|
argument :name, required: true, desc: "Action name"
|
29
32
|
option :url, required: false, type: :string, desc: "Action URL"
|
30
33
|
option :http, required: false, type: :string, desc: "Action HTTP method"
|
@@ -41,6 +44,12 @@ module Hanami
|
|
41
44
|
type: :flag,
|
42
45
|
default: DEFAULT_SKIP_TESTS,
|
43
46
|
desc: "Skip test generation"
|
47
|
+
option \
|
48
|
+
:skip_route,
|
49
|
+
required: false,
|
50
|
+
type: :flag,
|
51
|
+
default: DEFAULT_SKIP_ROUTE,
|
52
|
+
desc: "Skip route generation"
|
44
53
|
option :slice, required: false, desc: "Slice name"
|
45
54
|
|
46
55
|
# rubocop:disable Layout/LineLength
|
@@ -83,7 +92,8 @@ module Hanami
|
|
83
92
|
http: nil,
|
84
93
|
format: DEFAULT_FORMAT,
|
85
94
|
skip_view: DEFAULT_SKIP_VIEW,
|
86
|
-
skip_tests: DEFAULT_SKIP_TESTS, # rubocop:disable Lint/UnusedMethodArgument
|
95
|
+
skip_tests: DEFAULT_SKIP_TESTS, # rubocop:disable Lint/UnusedMethodArgument,
|
96
|
+
skip_route: DEFAULT_SKIP_ROUTE,
|
87
97
|
slice: nil,
|
88
98
|
context: nil,
|
89
99
|
**
|
@@ -96,7 +106,7 @@ module Hanami
|
|
96
106
|
raise InvalidActionNameError.new(name)
|
97
107
|
end
|
98
108
|
|
99
|
-
generator.call(app.namespace, controller, action, url, http, format, skip_view, slice, context: context)
|
109
|
+
generator.call(app.namespace, controller, action, url, http, format, skip_view, skip_route, slice, context: context)
|
100
110
|
end
|
101
111
|
|
102
112
|
# rubocop:enable Metrics/ParameterLists
|
@@ -38,8 +38,19 @@ module Hanami
|
|
38
38
|
# @since 2.2.0
|
39
39
|
# @api private
|
40
40
|
def call(name:, slice: nil, **)
|
41
|
-
|
42
|
-
|
41
|
+
if slice
|
42
|
+
generator.call(
|
43
|
+
key: name,
|
44
|
+
namespace: slice,
|
45
|
+
base_path: fs.join("slices", inflector.underscore(slice))
|
46
|
+
)
|
47
|
+
else
|
48
|
+
generator.call(
|
49
|
+
key: name,
|
50
|
+
namespace: app.namespace,
|
51
|
+
base_path: "app"
|
52
|
+
)
|
53
|
+
end
|
43
54
|
end
|
44
55
|
end
|
45
56
|
end
|
@@ -9,16 +9,36 @@ module Hanami
|
|
9
9
|
# @api private
|
10
10
|
class Migration < Command
|
11
11
|
argument :name, required: true, desc: "Migration name"
|
12
|
+
option :gateway, desc: "Generate migration for gateway"
|
12
13
|
|
13
14
|
example [
|
14
15
|
%(create_posts),
|
15
16
|
%(add_published_at_to_posts),
|
16
17
|
%(create_users --slice=admin),
|
18
|
+
%(create_comments --slice=admin --gateway=extra),
|
17
19
|
]
|
18
20
|
|
19
21
|
def generator_class
|
20
22
|
Generators::App::Migration
|
21
23
|
end
|
24
|
+
|
25
|
+
def call(name:, slice: nil, gateway: nil)
|
26
|
+
if slice
|
27
|
+
generator.call(
|
28
|
+
key: name,
|
29
|
+
namespace: slice,
|
30
|
+
base_path: fs.join("slices", inflector.underscore(slice)),
|
31
|
+
gateway: gateway
|
32
|
+
)
|
33
|
+
else
|
34
|
+
generator.call(
|
35
|
+
key: name,
|
36
|
+
namespace: app.namespace,
|
37
|
+
base_path: "app",
|
38
|
+
gateway: gateway
|
39
|
+
)
|
40
|
+
end
|
41
|
+
end
|
22
42
|
end
|
23
43
|
end
|
24
44
|
end
|
@@ -30,13 +30,9 @@ module Hanami
|
|
30
30
|
|
31
31
|
# @since 2.2.0
|
32
32
|
# @api private
|
33
|
-
def call(name:,
|
34
|
-
|
35
|
-
|
36
|
-
else
|
37
|
-
"#{inflector.singularize(name)}_repo"
|
38
|
-
end
|
39
|
-
super(name: normalized_name, slice: slice, **opts)
|
33
|
+
def call(name:, **opts)
|
34
|
+
name = "#{inflector.singularize(name)}_repo" unless name.end_with?("_repo")
|
35
|
+
super
|
40
36
|
end
|
41
37
|
end
|
42
38
|
end
|
@@ -21,13 +21,25 @@ module Hanami
|
|
21
21
|
SKIP_DB_DEFAULT = false
|
22
22
|
private_constant :SKIP_DB_DEFAULT
|
23
23
|
|
24
|
+
# @since 2.2.0
|
25
|
+
# @api private
|
26
|
+
DEFAULT_SKIP_ROUTE = false
|
27
|
+
private_constant :DEFAULT_SKIP_ROUTE
|
28
|
+
|
24
29
|
# @since 2.2.0
|
25
30
|
# @api private
|
26
31
|
option :skip_db,
|
27
|
-
type: :
|
32
|
+
type: :flag,
|
28
33
|
required: false,
|
29
34
|
default: SKIP_DB_DEFAULT,
|
30
35
|
desc: "Skip database"
|
36
|
+
# @since 2.2.0
|
37
|
+
# @api private
|
38
|
+
option :skip_route,
|
39
|
+
type: :flag,
|
40
|
+
required: false,
|
41
|
+
default: DEFAULT_SKIP_ROUTE,
|
42
|
+
desc: "Skip route generation"
|
31
43
|
|
32
44
|
example [
|
33
45
|
"admin # Admin slice (/admin URL prefix)",
|
@@ -50,7 +62,8 @@ module Hanami
|
|
50
62
|
def call(
|
51
63
|
name:,
|
52
64
|
url: nil,
|
53
|
-
skip_db: SKIP_DB_DEFAULT
|
65
|
+
skip_db: SKIP_DB_DEFAULT,
|
66
|
+
skip_route: DEFAULT_SKIP_ROUTE
|
54
67
|
)
|
55
68
|
require "hanami/setup"
|
56
69
|
|
@@ -58,7 +71,7 @@ module Hanami
|
|
58
71
|
name = inflector.underscore(Shellwords.shellescape(name))
|
59
72
|
url = sanitize_url_prefix(name, url)
|
60
73
|
|
61
|
-
generator.call(app, name, url, skip_db: skip_db)
|
74
|
+
generator.call(app, name, url, skip_db: skip_db, skip_route: skip_route)
|
62
75
|
end
|
63
76
|
|
64
77
|
private
|
@@ -41,16 +41,28 @@ module Hanami
|
|
41
41
|
end
|
42
42
|
|
43
43
|
register "generate", aliases: ["g"] do |prefix|
|
44
|
-
prefix.register "action", Generate::Action
|
45
|
-
prefix.register "component", Generate::Component
|
46
|
-
prefix.register "migration", Generate::Migration
|
47
|
-
prefix.register "operation", Generate::Operation
|
48
|
-
prefix.register "part", Generate::Part
|
49
|
-
prefix.register "relation", Generate::Relation
|
50
|
-
prefix.register "repo", Generate::Repo
|
51
44
|
prefix.register "slice", Generate::Slice
|
52
|
-
prefix.register "
|
53
|
-
|
45
|
+
prefix.register "component", Generate::Component
|
46
|
+
|
47
|
+
if Hanami.bundled?("hanami-controller")
|
48
|
+
prefix.register "action", Generate::Action
|
49
|
+
end
|
50
|
+
|
51
|
+
if Hanami.bundled?("dry-operation")
|
52
|
+
prefix.register "operation", Generate::Operation
|
53
|
+
end
|
54
|
+
|
55
|
+
if Hanami.bundled?("hanami-view")
|
56
|
+
prefix.register "view", Generate::View
|
57
|
+
prefix.register "part", Generate::Part
|
58
|
+
end
|
59
|
+
|
60
|
+
if Hanami.bundled?("hanami-db")
|
61
|
+
prefix.register "migration", Generate::Migration
|
62
|
+
prefix.register "relation", Generate::Relation
|
63
|
+
prefix.register "repo", Generate::Repo
|
64
|
+
prefix.register "struct", Generate::Struct
|
65
|
+
end
|
54
66
|
end
|
55
67
|
end
|
56
68
|
end
|
data/lib/hanami/cli/files.rb
CHANGED
@@ -18,7 +18,11 @@ module Hanami
|
|
18
18
|
# @api private
|
19
19
|
def write(path, *content)
|
20
20
|
already_exists = exist?(path)
|
21
|
+
|
21
22
|
super
|
23
|
+
|
24
|
+
delete_keepfiles(path) unless already_exists
|
25
|
+
|
22
26
|
if already_exists
|
23
27
|
updated(path)
|
24
28
|
else
|
@@ -46,6 +50,24 @@ module Hanami
|
|
46
50
|
|
47
51
|
attr_reader :out
|
48
52
|
|
53
|
+
# Removes .keep files in any directories leading up to the given path.
|
54
|
+
#
|
55
|
+
# Does not attempt to remove `.keep` files in the following scenarios:
|
56
|
+
# - When the given path is a `.keep` file itself.
|
57
|
+
# - When the given path is absolute, since ascending up this path may lead to removal of
|
58
|
+
# files outside the Hanami project directory.
|
59
|
+
def delete_keepfiles(path)
|
60
|
+
path = Pathname(path)
|
61
|
+
|
62
|
+
return if path.absolute?
|
63
|
+
return if path.relative_path_from(path.dirname).to_s == ".keep"
|
64
|
+
|
65
|
+
path.dirname.ascend do |part|
|
66
|
+
keepfile = (part + ".keep").to_path
|
67
|
+
delete(keepfile) if exist?(keepfile)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
49
71
|
def updated(path)
|
50
72
|
out.puts "Updated #{path}"
|
51
73
|
end
|
@@ -21,12 +21,12 @@ module Hanami
|
|
21
21
|
|
22
22
|
# @since 2.0.0
|
23
23
|
# @api private
|
24
|
-
def call(app, controller, action, url, http, format, skip_view, slice, context: nil)
|
24
|
+
def call(app, controller, action, url, http, format, skip_view, skip_route, slice, context: nil)
|
25
25
|
context ||= ActionContext.new(inflector, app, slice, controller, action)
|
26
26
|
if slice
|
27
|
-
generate_for_slice(controller, action, url, http, format, skip_view, slice, context)
|
27
|
+
generate_for_slice(controller, action, url, http, format, skip_view, skip_route, slice, context)
|
28
28
|
else
|
29
|
-
generate_for_app(controller, action, url, http, format, skip_view, context)
|
29
|
+
generate_for_app(controller, action, url, http, format, skip_view, skip_route, context)
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
@@ -72,15 +72,17 @@ module Hanami
|
|
72
72
|
attr_reader :inflector
|
73
73
|
|
74
74
|
# rubocop:disable Metrics/AbcSize
|
75
|
-
def generate_for_slice(controller, action, url, http, format, skip_view, slice, context)
|
75
|
+
def generate_for_slice(controller, action, url, http, format, skip_view, skip_route, slice, context)
|
76
76
|
slice_directory = fs.join("slices", slice)
|
77
77
|
raise MissingSliceError.new(slice) unless fs.directory?(slice_directory)
|
78
78
|
|
79
|
-
|
80
|
-
fs.
|
81
|
-
|
82
|
-
|
83
|
-
|
79
|
+
if generate_route?(skip_route)
|
80
|
+
fs.inject_line_at_block_bottom(
|
81
|
+
fs.join("config", "routes.rb"),
|
82
|
+
slice_matcher(slice),
|
83
|
+
route(controller, action, url, http)
|
84
|
+
)
|
85
|
+
end
|
84
86
|
|
85
87
|
fs.mkdir(directory = fs.join(slice_directory, "actions", controller))
|
86
88
|
fs.write(fs.join(directory, "#{action}.rb"), t("slice_action.erb", context))
|
@@ -95,12 +97,14 @@ module Hanami
|
|
95
97
|
end
|
96
98
|
end
|
97
99
|
|
98
|
-
def generate_for_app(controller, action, url, http, format, skip_view, context)
|
99
|
-
|
100
|
-
fs.
|
101
|
-
|
102
|
-
|
103
|
-
|
100
|
+
def generate_for_app(controller, action, url, http, format, skip_view, skip_route, context)
|
101
|
+
if generate_route?(skip_route)
|
102
|
+
fs.inject_line_at_class_bottom(
|
103
|
+
fs.join("config", "routes.rb"),
|
104
|
+
"class Routes",
|
105
|
+
route(controller, action, url, http)
|
106
|
+
)
|
107
|
+
end
|
104
108
|
|
105
109
|
fs.mkdir(directory = fs.join("app", "actions", controller))
|
106
110
|
fs.write(fs.join(directory, "#{action}.rb"), t("action.erb", context))
|
@@ -137,6 +141,14 @@ module Hanami
|
|
137
141
|
true
|
138
142
|
end
|
139
143
|
|
144
|
+
# @api private
|
145
|
+
# @since 2.2.0
|
146
|
+
def generate_route?(skip_route)
|
147
|
+
return false if skip_route
|
148
|
+
|
149
|
+
true
|
150
|
+
end
|
151
|
+
|
140
152
|
# @api private
|
141
153
|
# @since 2.1.0
|
142
154
|
def generate_restful_view?(view, directory)
|