hanami-cli 2.1.0.beta1 → 2.1.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/CHANGELOG.md +37 -0
- data/Gemfile +5 -2
- data/hanami-cli.gemspec +1 -1
- data/lib/hanami/cli/bundler.rb +19 -5
- data/lib/hanami/cli/command.rb +4 -4
- data/lib/hanami/cli/commands/app/assets/command.rb +69 -0
- data/lib/hanami/cli/commands/app/assets/compile.rb +32 -0
- data/lib/hanami/cli/commands/app/assets/watch.rb +32 -0
- data/lib/hanami/cli/commands/app/assets.rb +16 -0
- data/lib/hanami/cli/commands/app/command.rb +2 -2
- data/lib/hanami/cli/commands/app/dev.rb +45 -0
- data/lib/hanami/cli/commands/app/generate/action.rb +3 -2
- data/lib/hanami/cli/commands/app/generate/part.rb +49 -0
- data/lib/hanami/cli/commands/app/install.rb +16 -1
- data/lib/hanami/cli/commands/app.rb +9 -0
- data/lib/hanami/cli/commands/gem/new.rb +57 -7
- data/lib/hanami/cli/errors.rb +30 -0
- data/lib/hanami/cli/files.rb +8 -2
- data/lib/hanami/cli/generators/app/action/action.erb +5 -1
- data/lib/hanami/cli/generators/app/action/slice_action.erb +5 -1
- data/lib/hanami/cli/generators/app/action.rb +49 -12
- data/lib/hanami/cli/generators/app/part/app_base_part.erb +9 -0
- data/lib/hanami/cli/generators/app/part/app_part.erb +13 -0
- data/lib/hanami/cli/generators/app/part/slice_base_part.erb +9 -0
- data/lib/hanami/cli/generators/app/part/slice_part.erb +13 -0
- data/lib/hanami/cli/generators/app/part.rb +101 -0
- data/lib/hanami/cli/generators/app/part_context.rb +98 -0
- data/lib/hanami/cli/generators/app/slice/app_css.erb +5 -0
- data/lib/hanami/cli/generators/app/slice/app_js.erb +1 -0
- data/lib/hanami/cli/generators/app/slice/app_layout.erb +18 -0
- data/lib/hanami/cli/generators/app/slice.rb +9 -3
- data/lib/hanami/cli/generators/app/slice_context.rb +18 -0
- data/lib/hanami/cli/generators/context.rb +70 -3
- data/lib/hanami/cli/generators/gem/app/404.html +76 -5
- data/lib/hanami/cli/generators/gem/app/500.html +76 -5
- data/lib/hanami/cli/generators/gem/app/app_css.erb +5 -0
- data/lib/hanami/cli/generators/gem/app/app_js.erb +1 -0
- data/lib/hanami/cli/generators/gem/app/app_layout.erb +18 -0
- data/lib/hanami/cli/generators/gem/app/assets.mjs +14 -0
- data/lib/hanami/cli/generators/gem/app/dev +8 -0
- data/lib/hanami/cli/generators/gem/app/favicon.ico +0 -0
- data/lib/hanami/cli/generators/gem/app/gemfile.erb +14 -8
- data/lib/hanami/cli/generators/gem/app/gitignore.erb +4 -0
- data/lib/hanami/cli/generators/gem/app/package.json.erb +10 -0
- data/lib/hanami/cli/generators/gem/app/procfile.erb +4 -0
- data/lib/hanami/cli/generators/gem/app/puma.erb +37 -7
- data/lib/hanami/cli/generators/gem/app/routes.erb +1 -1
- data/lib/hanami/cli/generators/gem/app.rb +21 -4
- data/lib/hanami/cli/generators/version.rb +12 -0
- data/lib/hanami/cli/interactive_system_call.rb +64 -0
- data/lib/hanami/cli/system_call.rb +8 -2
- data/lib/hanami/cli/version.rb +1 -1
- metadata +28 -6
- data/lib/hanami/cli/generators/app/slice/layouts_app.html.erb +0 -1
- data/lib/hanami/cli/generators/gem/app/layouts_app.html.erb +0 -1
|
@@ -12,9 +12,10 @@ module Hanami
|
|
|
12
12
|
class Context
|
|
13
13
|
# @since 2.0.0
|
|
14
14
|
# @api private
|
|
15
|
-
def initialize(inflector, app)
|
|
15
|
+
def initialize(inflector, app, **options)
|
|
16
16
|
@inflector = inflector
|
|
17
17
|
@app = app
|
|
18
|
+
@options = options
|
|
18
19
|
end
|
|
19
20
|
|
|
20
21
|
# @since 2.0.0
|
|
@@ -23,10 +24,30 @@ module Hanami
|
|
|
23
24
|
binding
|
|
24
25
|
end
|
|
25
26
|
|
|
27
|
+
def hanami_gem(name)
|
|
28
|
+
gem_name = name == "hanami" ? "hanami" : "hanami-#{name}"
|
|
29
|
+
|
|
30
|
+
%(gem "#{gem_name}", #{hanami_gem_version(name)})
|
|
31
|
+
end
|
|
32
|
+
|
|
26
33
|
# @since 2.0.0
|
|
27
34
|
# @api private
|
|
28
|
-
def
|
|
29
|
-
|
|
35
|
+
def hanami_gem_version(gem_name)
|
|
36
|
+
if hanami_head?
|
|
37
|
+
%(github: "hanami/#{gem_name}", branch: "main")
|
|
38
|
+
else
|
|
39
|
+
%("#{Version.gem_requirement}")
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# @since 2.1.0
|
|
44
|
+
# @api private
|
|
45
|
+
def hanami_assets_npm_package
|
|
46
|
+
if hanami_head?
|
|
47
|
+
%("hanami-assets": "hanami/assets-js#main")
|
|
48
|
+
else
|
|
49
|
+
%("hanami-assets": "#{Version.npm_package_requirement}")
|
|
50
|
+
end
|
|
30
51
|
end
|
|
31
52
|
|
|
32
53
|
# @since 2.0.0
|
|
@@ -41,11 +62,57 @@ module Hanami
|
|
|
41
62
|
inflector.underscore(app)
|
|
42
63
|
end
|
|
43
64
|
|
|
65
|
+
# @since 2.1.0
|
|
66
|
+
# @api private
|
|
67
|
+
def humanized_app_name
|
|
68
|
+
inflector.humanize(app)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# @since 2.1.0
|
|
72
|
+
# @api private
|
|
73
|
+
def hanami_head?
|
|
74
|
+
options.fetch(:head)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# @since 2.1.0
|
|
78
|
+
# @api private
|
|
79
|
+
def generate_assets?
|
|
80
|
+
!options.fetch(:skip_assets, false)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# @since 2.1.0
|
|
84
|
+
# @api private
|
|
85
|
+
def bundled_views?
|
|
86
|
+
Hanami.bundled?("hanami-view")
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# @since 2.1.0
|
|
90
|
+
# @api private
|
|
91
|
+
def bundled_assets?
|
|
92
|
+
Hanami.bundled?("hanami-assets")
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# @since 2.1.0
|
|
96
|
+
# @api private
|
|
97
|
+
#
|
|
98
|
+
# @see https://rubyreferences.github.io/rubychanges/3.1.html#values-in-hash-literals-and-keyword-arguments-can-be-omitted
|
|
99
|
+
def ruby_omit_hash_values?
|
|
100
|
+
RUBY_VERSION >= "3.1"
|
|
101
|
+
end
|
|
102
|
+
|
|
44
103
|
private
|
|
45
104
|
|
|
105
|
+
# @since 2.0.0
|
|
106
|
+
# @api private
|
|
46
107
|
attr_reader :inflector
|
|
47
108
|
|
|
109
|
+
# @since 2.0.0
|
|
110
|
+
# @api private
|
|
48
111
|
attr_reader :app
|
|
112
|
+
|
|
113
|
+
# @since 2.1.0
|
|
114
|
+
# @api private
|
|
115
|
+
attr_reader :options
|
|
49
116
|
end
|
|
50
117
|
end
|
|
51
118
|
end
|
|
@@ -1,11 +1,82 @@
|
|
|
1
1
|
<!DOCTYPE html>
|
|
2
|
-
<html>
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>The page you were looking for doesn’t exist (404)</title>
|
|
7
|
+
<style>
|
|
8
|
+
:root {
|
|
9
|
+
--foreground-rgb: 0, 0, 0;
|
|
10
|
+
--background-rgb: 255, 255, 255;
|
|
11
|
+
--font-sans: ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
@media (prefers-color-scheme: dark) {
|
|
15
|
+
:root {
|
|
16
|
+
--foreground-rgb: 255, 255, 255;
|
|
17
|
+
--background-rgb: 0, 0, 0;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
* {
|
|
22
|
+
box-sizing: border-box;
|
|
23
|
+
margin: 0;
|
|
24
|
+
padding: 0;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
body,
|
|
28
|
+
html {
|
|
29
|
+
max-width: 100vw;
|
|
30
|
+
overflow-x: hidden;
|
|
31
|
+
font-size: 100%;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
body {
|
|
35
|
+
color: rgb(var(--foreground-rgb));
|
|
36
|
+
background: rgb(var(--background-rgb));
|
|
37
|
+
font-family: var(--font-sans);
|
|
38
|
+
font-style: normal;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
main {
|
|
42
|
+
display: flex;
|
|
43
|
+
flex-direction: column;
|
|
44
|
+
align-items: center;
|
|
45
|
+
justify-content: center;
|
|
46
|
+
height: 100vh;
|
|
47
|
+
padding: 0 4vw;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.message {
|
|
51
|
+
display: flex;
|
|
52
|
+
gap: 1rem;
|
|
53
|
+
flex-direction: column;
|
|
54
|
+
text-align: center;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.message h1 {
|
|
58
|
+
font-size: 2rem;
|
|
59
|
+
font-weight: 500;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
p {
|
|
63
|
+
line-height: 1.6;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
@media (prefers-color-scheme: dark) {
|
|
67
|
+
html {
|
|
68
|
+
color-scheme: dark;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
</style>
|
|
5
72
|
</head>
|
|
6
73
|
<body>
|
|
7
74
|
<!-- This file lives in public/404.html -->
|
|
8
|
-
<
|
|
9
|
-
|
|
75
|
+
<main>
|
|
76
|
+
<div class="message">
|
|
77
|
+
<h1>404</h1>
|
|
78
|
+
<p>The page you were looking for doesn’t exist.</p>
|
|
79
|
+
</div>
|
|
80
|
+
</main>
|
|
10
81
|
</body>
|
|
11
82
|
</html>
|
|
@@ -1,11 +1,82 @@
|
|
|
1
1
|
<!DOCTYPE html>
|
|
2
|
-
<html>
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>We’re sorry, but something went wrong (500)</title>
|
|
7
|
+
<style>
|
|
8
|
+
:root {
|
|
9
|
+
--foreground-rgb: 0, 0, 0;
|
|
10
|
+
--background-rgb: 255, 255, 255;
|
|
11
|
+
--font-sans: ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
@media (prefers-color-scheme: dark) {
|
|
15
|
+
:root {
|
|
16
|
+
--foreground-rgb: 255, 255, 255;
|
|
17
|
+
--background-rgb: 0, 0, 0;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
* {
|
|
22
|
+
box-sizing: border-box;
|
|
23
|
+
margin: 0;
|
|
24
|
+
padding: 0;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
body,
|
|
28
|
+
html {
|
|
29
|
+
max-width: 100vw;
|
|
30
|
+
overflow-x: hidden;
|
|
31
|
+
font-size: 100%;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
body {
|
|
35
|
+
color: rgb(var(--foreground-rgb));
|
|
36
|
+
background: rgb(var(--background-rgb));
|
|
37
|
+
font-family: var(--font-sans);
|
|
38
|
+
font-style: normal;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
main {
|
|
42
|
+
display: flex;
|
|
43
|
+
flex-direction: column;
|
|
44
|
+
align-items: center;
|
|
45
|
+
justify-content: center;
|
|
46
|
+
height: 100vh;
|
|
47
|
+
padding: 0 4vw;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.message {
|
|
51
|
+
display: flex;
|
|
52
|
+
gap: 1rem;
|
|
53
|
+
flex-direction: column;
|
|
54
|
+
text-align: center;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.message h1 {
|
|
58
|
+
font-size: 2rem;
|
|
59
|
+
font-weight: 500;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
p {
|
|
63
|
+
line-height: 1.6;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
@media (prefers-color-scheme: dark) {
|
|
67
|
+
html {
|
|
68
|
+
color-scheme: dark;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
</style>
|
|
5
72
|
</head>
|
|
6
73
|
<body>
|
|
7
74
|
<!-- This file lives in public/500.html -->
|
|
8
|
-
<
|
|
9
|
-
|
|
75
|
+
<main>
|
|
76
|
+
<div class="message">
|
|
77
|
+
<h1>500</h1>
|
|
78
|
+
<p>We’re sorry, but something went wrong.</p>
|
|
79
|
+
</div>
|
|
80
|
+
</main>
|
|
10
81
|
</body>
|
|
11
82
|
</html>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import "../css/app.css";
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title><%= humanized_app_name %></title>
|
|
7
|
+
<%- if generate_assets? -%>
|
|
8
|
+
<%%= favicon %>
|
|
9
|
+
<%%= css "app" %>
|
|
10
|
+
<%- end -%>
|
|
11
|
+
</head>
|
|
12
|
+
<body>
|
|
13
|
+
<%%= yield %>
|
|
14
|
+
<%- if generate_assets? -%>
|
|
15
|
+
<%%= js "app" %>
|
|
16
|
+
<%- end -%>
|
|
17
|
+
</body>
|
|
18
|
+
</html>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import * as assets from "hanami-assets";
|
|
2
|
+
|
|
3
|
+
await assets.run();
|
|
4
|
+
|
|
5
|
+
// To provide additional esbuild (https://esbuild.github.io) options, use the following:
|
|
6
|
+
//
|
|
7
|
+
// await assets.run({
|
|
8
|
+
// esbuildOptionsFn: (args, esbuildOptions) => {
|
|
9
|
+
// // Add to esbuildOptions here. Use `args.watch` as a condition for different options for
|
|
10
|
+
// // compile vs watch.
|
|
11
|
+
//
|
|
12
|
+
// return esbuildOptions;
|
|
13
|
+
// }
|
|
14
|
+
// });
|
|
Binary file
|
|
@@ -2,25 +2,31 @@
|
|
|
2
2
|
|
|
3
3
|
source "https://rubygems.org"
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
5
|
+
<%= hanami_gem("hanami") %>
|
|
6
|
+
<%= hanami_gem("router") %>
|
|
7
|
+
<%= hanami_gem("controller") %>
|
|
8
|
+
<%= hanami_gem("validations") %>
|
|
9
|
+
<%= hanami_gem("view") %>
|
|
10
|
+
<%- if generate_assets? -%>
|
|
11
|
+
<%= hanami_gem("assets") %>
|
|
12
|
+
<%- end -%>
|
|
11
13
|
|
|
12
14
|
gem "dry-types", "~> 1.0", ">= 1.6.1"
|
|
13
15
|
gem "puma"
|
|
14
16
|
gem "rake"
|
|
15
17
|
|
|
18
|
+
group :development do
|
|
19
|
+
<%= hanami_gem("webconsole") %>
|
|
20
|
+
end
|
|
21
|
+
|
|
16
22
|
group :development, :test do
|
|
17
23
|
gem "dotenv"
|
|
18
24
|
end
|
|
19
25
|
|
|
20
26
|
group :cli, :development do
|
|
21
|
-
|
|
27
|
+
<%= hanami_gem("reloader") %>
|
|
22
28
|
end
|
|
23
29
|
|
|
24
30
|
group :cli, :development, :test do
|
|
25
|
-
|
|
31
|
+
<%= hanami_gem("rspec") %>
|
|
26
32
|
end
|
|
@@ -1,17 +1,47 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
#
|
|
4
|
+
# Environment and port
|
|
5
|
+
#
|
|
6
|
+
port ENV.fetch("<%= Hanami::Port::ENV_VAR %>", <%= Hanami::Port::DEFAULT %>)
|
|
7
|
+
environment ENV.fetch("HANAMI_ENV", "development")
|
|
8
|
+
|
|
9
|
+
#
|
|
10
|
+
# Threads within each Puma/Ruby process (aka worker)
|
|
11
|
+
#
|
|
12
|
+
|
|
13
|
+
# Configure the minimum and maximum number of threads to use to answer requests.
|
|
3
14
|
max_threads_count = ENV.fetch("HANAMI_MAX_THREADS", 5)
|
|
4
15
|
min_threads_count = ENV.fetch("HANAMI_MIN_THREADS") { max_threads_count }
|
|
16
|
+
|
|
5
17
|
threads min_threads_count, max_threads_count
|
|
6
18
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
19
|
+
#
|
|
20
|
+
# Workers (aka Puma/Ruby processes)
|
|
21
|
+
#
|
|
10
22
|
|
|
11
|
-
|
|
12
|
-
|
|
23
|
+
puma_concurrency = Integer(ENV.fetch("HANAMI_WEB_CONCURRENCY", 0))
|
|
24
|
+
puma_cluster_mode = puma_concurrency > 1
|
|
25
|
+
|
|
26
|
+
# How many worker (Puma/Ruby) processes to run.
|
|
27
|
+
# Typically this is set to the number of available cores.
|
|
28
|
+
workers puma_concurrency
|
|
29
|
+
|
|
30
|
+
#
|
|
31
|
+
# Cluster mode (aka multiple workers)
|
|
32
|
+
#
|
|
33
|
+
|
|
34
|
+
if puma_cluster_mode
|
|
35
|
+
# Preload the application before starting the workers. Only in cluster mode.
|
|
36
|
+
preload_app!
|
|
37
|
+
|
|
38
|
+
# Code to run immediately before master process forks workers (once on boot).
|
|
39
|
+
#
|
|
40
|
+
# These hooks can block if necessary to wait for background operations unknown
|
|
41
|
+
# to puma to finish before the process terminates. This can be used to close
|
|
42
|
+
# any connections to remote servers (database, redis, …) that were opened when
|
|
43
|
+
# preloading the code.
|
|
44
|
+
before_fork do
|
|
13
45
|
Hanami.shutdown
|
|
14
46
|
end
|
|
15
47
|
end
|
|
16
|
-
|
|
17
|
-
preload_app!
|
|
@@ -40,8 +40,12 @@ module Hanami
|
|
|
40
40
|
fs.write("README.md", t("readme.erb", context))
|
|
41
41
|
fs.write("Gemfile", t("gemfile.erb", context))
|
|
42
42
|
fs.write("Rakefile", t("rakefile.erb", context))
|
|
43
|
+
fs.write("Procfile.dev", t("procfile.erb", context))
|
|
43
44
|
fs.write("config.ru", t("config_ru.erb", context))
|
|
44
45
|
|
|
46
|
+
fs.write("bin/dev", file("dev"))
|
|
47
|
+
fs.chmod("bin/dev", 0o755)
|
|
48
|
+
|
|
45
49
|
fs.write("config/app.rb", t("app.erb", context))
|
|
46
50
|
fs.write("config/settings.rb", t("settings.erb", context))
|
|
47
51
|
fs.write("config/routes.rb", t("routes.erb", context))
|
|
@@ -54,21 +58,34 @@ module Hanami
|
|
|
54
58
|
fs.write("app/action.rb", t("action.erb", context))
|
|
55
59
|
fs.write("app/view.rb", t("view.erb", context))
|
|
56
60
|
fs.write("app/views/helpers.rb", t("helpers.erb", context))
|
|
57
|
-
fs.write("app/templates/layouts/app.html.erb",
|
|
61
|
+
fs.write("app/templates/layouts/app.html.erb", t("app_layout.erb", context))
|
|
62
|
+
|
|
63
|
+
if context.generate_assets?
|
|
64
|
+
fs.write("package.json", t("package.json.erb", context))
|
|
65
|
+
fs.write("config/assets.mjs", file("assets.mjs"))
|
|
66
|
+
fs.write("app/assets/js/app.js", t("app_js.erb", context))
|
|
67
|
+
fs.write("app/assets/css/app.css", t("app_css.erb", context))
|
|
68
|
+
fs.write("app/assets/images/favicon.ico", file("favicon.ico"))
|
|
69
|
+
end
|
|
58
70
|
|
|
59
|
-
fs.write("public/404.html",
|
|
60
|
-
fs.write("public/500.html",
|
|
71
|
+
fs.write("public/404.html", file("404.html"))
|
|
72
|
+
fs.write("public/500.html", file("500.html"))
|
|
61
73
|
end
|
|
62
74
|
|
|
63
75
|
def template(path, context)
|
|
64
76
|
require "erb"
|
|
65
77
|
|
|
66
78
|
ERB.new(
|
|
67
|
-
File.read(File.join(__dir__, "app", path))
|
|
79
|
+
File.read(File.join(__dir__, "app", path)),
|
|
80
|
+
trim_mode: "-"
|
|
68
81
|
).result(context.ctx)
|
|
69
82
|
end
|
|
70
83
|
|
|
71
84
|
alias_method :t, :template
|
|
85
|
+
|
|
86
|
+
def file(path)
|
|
87
|
+
File.read(File.join(__dir__, "app", path))
|
|
88
|
+
end
|
|
72
89
|
end
|
|
73
90
|
end
|
|
74
91
|
end
|
|
@@ -26,6 +26,18 @@ module Hanami
|
|
|
26
26
|
"~> #{result}"
|
|
27
27
|
end
|
|
28
28
|
|
|
29
|
+
def self.npm_package_requirement
|
|
30
|
+
result = version
|
|
31
|
+
# Change "2.1.0.beta2.1" to "2.1.0-beta.2" (the only format tolerable by `npm install`)
|
|
32
|
+
if prerelease?
|
|
33
|
+
result = result
|
|
34
|
+
.sub(/\.(alpha|beta|rc)/, '-\1')
|
|
35
|
+
.sub(/(alpha|beta|rc)(.+)\.(.+)$/, '\1.\2')
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
"^#{result}"
|
|
39
|
+
end
|
|
40
|
+
|
|
29
41
|
# @since 2.0.0
|
|
30
42
|
# @api private
|
|
31
43
|
def self.prerelease?
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "open3"
|
|
4
|
+
|
|
5
|
+
module Hanami
|
|
6
|
+
module CLI
|
|
7
|
+
# @api private
|
|
8
|
+
# @since 2.1.0
|
|
9
|
+
class InteractiveSystemCall
|
|
10
|
+
# @api private
|
|
11
|
+
# @since 2.1.0
|
|
12
|
+
def initialize(out: $stdout, err: $stderr)
|
|
13
|
+
@out = out
|
|
14
|
+
@err = err
|
|
15
|
+
super()
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# @api private
|
|
19
|
+
# @since 2.1.0
|
|
20
|
+
def call(cmd, *args, env: {})
|
|
21
|
+
::Bundler.with_unbundled_env do
|
|
22
|
+
threads = []
|
|
23
|
+
exit_status = 0
|
|
24
|
+
|
|
25
|
+
# rubocop:disable Lint/SuppressedException
|
|
26
|
+
Open3.popen3(env, command(cmd, *args)) do |_stdin, stdout, stderr, wait_thr|
|
|
27
|
+
threads << Thread.new do
|
|
28
|
+
stdout.each_line do |line|
|
|
29
|
+
out.puts(line)
|
|
30
|
+
end
|
|
31
|
+
rescue IOError # FIXME: Check if this is legit
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
threads << Thread.new do
|
|
35
|
+
stderr.each_line do |line|
|
|
36
|
+
err.puts(line)
|
|
37
|
+
end
|
|
38
|
+
rescue IOError # FIXME: Check if this is legit
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
threads.each(&:join)
|
|
42
|
+
|
|
43
|
+
exit_status = wait_thr.value
|
|
44
|
+
end
|
|
45
|
+
# rubocop:enable Lint/SuppressedException
|
|
46
|
+
|
|
47
|
+
exit(exit_status.exitstatus)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
private
|
|
52
|
+
|
|
53
|
+
# @api private
|
|
54
|
+
# @since 2.1.0
|
|
55
|
+
attr_reader :out, :err
|
|
56
|
+
|
|
57
|
+
# @since 2.1.0
|
|
58
|
+
# @api public
|
|
59
|
+
def command(cmd, *args)
|
|
60
|
+
[cmd, args].flatten(1).compact.join(" ")
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -85,13 +85,13 @@ module Hanami
|
|
|
85
85
|
#
|
|
86
86
|
# @since 2.0.0
|
|
87
87
|
# @api public
|
|
88
|
-
def call(cmd, env: {})
|
|
88
|
+
def call(cmd, *args, env: {})
|
|
89
89
|
exitstatus = nil
|
|
90
90
|
out = nil
|
|
91
91
|
err = nil
|
|
92
92
|
|
|
93
93
|
::Bundler.with_unbundled_env do
|
|
94
|
-
Open3.popen3(env, cmd) do |stdin, stdout, stderr, wait_thr|
|
|
94
|
+
Open3.popen3(env, command(cmd, *args)) do |stdin, stdout, stderr, wait_thr|
|
|
95
95
|
yield stdin, stdout, stderr, wait_thr if block_given?
|
|
96
96
|
|
|
97
97
|
stdin.close
|
|
@@ -104,6 +104,12 @@ module Hanami
|
|
|
104
104
|
|
|
105
105
|
Result.new(exit_code: exitstatus, out: out, err: err)
|
|
106
106
|
end
|
|
107
|
+
|
|
108
|
+
# @since 2.1.0
|
|
109
|
+
# @api public
|
|
110
|
+
def command(cmd, *args)
|
|
111
|
+
[cmd, args].flatten(1).compact.join(" ")
|
|
112
|
+
end
|
|
107
113
|
end
|
|
108
114
|
end
|
|
109
115
|
end
|