Skip to content

Commit 04ec18a

Browse files
authored
Prevent generators from overwriting files (#274)
1 parent bfdf41f commit 04ec18a

18 files changed

+580
-359
lines changed

lib/hanami/cli/errors.rb

+7
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,13 @@ def initialize(path)
4444
end
4545
end
4646

47+
# @api public
48+
class FileAlreadyExistsError < Error
49+
def initialize(path)
50+
super("Cannot overwrite existing file: `#{path}`")
51+
end
52+
end
53+
4754
# @api public
4855
class ForbiddenAppNameError < Error
4956
def initialize(name)

lib/hanami/cli/files.rb

+11-4
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,13 @@ def initialize(out: $stdout, **args)
1414
@out = out
1515
end
1616

17+
# @api private
18+
def create(path, *content)
19+
raise FileAlreadyExistsError.new(path) if exist?(path)
20+
21+
write(path, *content)
22+
end
23+
1724
# @since 2.0.0
1825
# @api private
1926
def write(path, *content)
@@ -33,10 +40,10 @@ def write(path, *content)
3340
# @since 2.0.0
3441
# @api private
3542
def mkdir(path)
36-
unless exist?(path)
37-
super
38-
created(_path(path))
39-
end
43+
return if exist?(path)
44+
45+
super
46+
created(_path(path))
4047
end
4148

4249
# @since 2.0.0

lib/hanami/cli/generators/app/action.rb

+8-8
Original file line numberDiff line numberDiff line change
@@ -85,15 +85,15 @@ def generate_for_slice(controller, action, url, http, format, skip_view, skip_ro
8585
end
8686

8787
fs.mkdir(directory = fs.join(slice_directory, "actions", controller))
88-
fs.write(fs.join(directory, "#{action}.rb"), t("slice_action.erb", context))
88+
fs.create(fs.join(directory, "#{action}.rb"), t("slice_action.erb", context))
8989

9090
if generate_view?(skip_view, action, directory)
9191
fs.mkdir(directory = fs.join(slice_directory, "views", controller))
92-
fs.write(fs.join(directory, "#{action}.rb"), t("slice_view.erb", context))
92+
fs.create(fs.join(directory, "#{action}.rb"), t("slice_view.erb", context))
9393

9494
fs.mkdir(directory = fs.join(slice_directory, "templates", controller))
95-
fs.write(fs.join(directory, "#{action}.#{format}.erb"),
96-
t(template_with_format_ext("slice_template", format), context))
95+
fs.create(fs.join(directory, "#{action}.#{format}.erb"),
96+
t(template_with_format_ext("slice_template", format), context))
9797
end
9898
end
9999

@@ -107,18 +107,18 @@ def generate_for_app(controller, action, url, http, format, skip_view, skip_rout
107107
end
108108

109109
fs.mkdir(directory = fs.join("app", "actions", controller))
110-
fs.write(fs.join(directory, "#{action}.rb"), t("action.erb", context))
110+
fs.create(fs.join(directory, "#{action}.rb"), t("action.erb", context))
111111

112112
view = action
113113
view_directory = fs.join("app", "views", controller)
114114

115115
if generate_view?(skip_view, view, view_directory)
116116
fs.mkdir(view_directory)
117-
fs.write(fs.join(view_directory, "#{view}.rb"), t("view.erb", context))
117+
fs.create(fs.join(view_directory, "#{view}.rb"), t("view.erb", context))
118118

119119
fs.mkdir(template_directory = fs.join("app", "templates", controller))
120-
fs.write(fs.join(template_directory, "#{view}.#{format}.erb"),
121-
t(template_with_format_ext("template", format), context))
120+
fs.create(fs.join(template_directory, "#{view}.#{format}.erb"),
121+
t(template_with_format_ext("template", format), context))
122122
end
123123
end
124124
# rubocop:enable Metrics/AbcSize

lib/hanami/cli/generators/app/migration.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ def call(key:, base_path:, gateway: nil, **_opts)
2626

2727
path = fs.join(*[base_path, "config", "db", migrate_dir, file_name(name)].compact)
2828

29-
fs.write(path, FILE_CONTENTS)
29+
fs.create(path, FILE_CONTENTS)
3030
end
3131

3232
private

lib/hanami/cli/generators/app/part.rb

+2-2
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ def generate_for_slice(context, slice)
5050
generate_base_part_for_slice(context, slice)
5151

5252
fs.mkdir(directory = fs.join(slice_directory, "views", "parts", *context.underscored_namespace))
53-
fs.write(fs.join(directory, "#{context.underscored_name}.rb"), t("slice_part.erb", context))
53+
fs.create(fs.join(directory, "#{context.underscored_name}.rb"), t("slice_part.erb", context))
5454
end
5555

5656
# @since 2.1.0
@@ -59,7 +59,7 @@ def generate_for_app(context)
5959
generate_base_part_for_app(context)
6060

6161
fs.mkdir(directory = fs.join("app", "views", "parts", *context.underscored_namespace))
62-
fs.write(fs.join(directory, "#{context.underscored_name}.rb"), t("app_part.erb", context))
62+
fs.create(fs.join(directory, "#{context.underscored_name}.rb"), t("app_part.erb", context))
6363
end
6464

6565
# @since 2.1.0

lib/hanami/cli/generators/app/ruby_file_writer.rb

+5-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ def call(key:, namespace:, base_path:, relative_parent_class:, extra_namespace:
3131
relative_parent_class: relative_parent_class,
3232
extra_namespace: extra_namespace,
3333
body: body,
34-
).write
34+
).create
3535
end
3636

3737
private
@@ -62,6 +62,10 @@ def initialize(
6262
@body = body
6363
end
6464

65+
def create
66+
fs.create(path, file_contents)
67+
end
68+
6569
def write
6670
fs.write(path, file_contents)
6771
end

lib/hanami/cli/generators/app/slice.rb

+18-18
Original file line numberDiff line numberDiff line change
@@ -30,33 +30,33 @@ def call(app, slice, url, context: nil, **opts)
3030

3131
fs.mkdir(directory = "slices/#{slice}")
3232

33-
fs.write(fs.join(directory, "action.rb"), t("action.erb", context))
34-
fs.write(fs.join(directory, "view.rb"), t("view.erb", context))
35-
fs.write(fs.join(directory, "views", "helpers.rb"), t("helpers.erb", context))
36-
fs.write(fs.join(directory, "templates", "layouts", "app.html.erb"), t("app_layout.erb", context))
37-
fs.write(fs.join(directory, "operation.rb"), t("operation.erb", context))
33+
fs.create(fs.join(directory, "action.rb"), t("action.erb", context))
34+
fs.create(fs.join(directory, "view.rb"), t("view.erb", context))
35+
fs.create(fs.join(directory, "views", "helpers.rb"), t("helpers.erb", context))
36+
fs.create(fs.join(directory, "templates", "layouts", "app.html.erb"), t("app_layout.erb", context))
37+
fs.create(fs.join(directory, "operation.rb"), t("operation.erb", context))
3838

3939
if context.bundled_assets?
40-
fs.write(fs.join(directory, "assets", "js", "app.js"), t("app_js.erb", context))
41-
fs.write(fs.join(directory, "assets", "css", "app.css"), t("app_css.erb", context))
42-
fs.write(fs.join(directory, "assets", "images", "favicon.ico"), file("favicon.ico"))
40+
fs.create(fs.join(directory, "assets", "js", "app.js"), t("app_js.erb", context))
41+
fs.create(fs.join(directory, "assets", "css", "app.css"), t("app_css.erb", context))
42+
fs.create(fs.join(directory, "assets", "images", "favicon.ico"), file("favicon.ico"))
4343
end
4444

4545
if context.generate_db?
46-
fs.write(fs.join(directory, "db", "relation.rb"), t("relation.erb", context))
47-
fs.write(fs.join(directory, "relations", ".keep"), t("keep.erb", context))
46+
fs.create(fs.join(directory, "db", "relation.rb"), t("relation.erb", context))
47+
fs.create(fs.join(directory, "relations", ".keep"), t("keep.erb", context))
4848

49-
fs.write(fs.join(directory, "db", "repo.rb"), t("repo.erb", context))
50-
fs.write(fs.join(directory, "repos", ".keep"), t("keep.erb", context))
49+
fs.create(fs.join(directory, "db", "repo.rb"), t("repo.erb", context))
50+
fs.create(fs.join(directory, "repos", ".keep"), t("keep.erb", context))
5151

52-
fs.write(fs.join(directory, "db", "struct.rb"), t("struct.erb", context))
53-
fs.write(fs.join(directory, "structs", ".keep"), t("keep.erb", context))
52+
fs.create(fs.join(directory, "db", "struct.rb"), t("struct.erb", context))
53+
fs.create(fs.join(directory, "structs", ".keep"), t("keep.erb", context))
5454
end
5555

56-
fs.write(fs.join(directory, "actions/.keep"), t("keep.erb", context))
57-
fs.write(fs.join(directory, "views/.keep"), t("keep.erb", context))
58-
fs.write(fs.join(directory, "templates/.keep"), t("keep.erb", context))
59-
fs.write(fs.join(directory, "templates/layouts/.keep"), t("keep.erb", context))
56+
fs.create(fs.join(directory, "actions/.keep"), t("keep.erb", context))
57+
fs.create(fs.join(directory, "views/.keep"), t("keep.erb", context))
58+
fs.create(fs.join(directory, "templates/.keep"), t("keep.erb", context))
59+
fs.create(fs.join(directory, "templates/layouts/.keep"), t("keep.erb", context))
6060
end
6161

6262
private

lib/hanami/cli/generators/app/view.rb

+6-6
Original file line numberDiff line numberDiff line change
@@ -43,20 +43,20 @@ def generate_for_slice(context, format, slice)
4343
raise MissingSliceError.new(slice) unless fs.directory?(slice_directory)
4444

4545
fs.mkdir(directory = fs.join(slice_directory, "views", context.namespaces))
46-
fs.write(fs.join(directory, "#{context.name}.rb"), t("slice_view.erb", context))
46+
fs.create(fs.join(directory, "#{context.name}.rb"), t("slice_view.erb", context))
4747

4848
fs.mkdir(directory = fs.join(slice_directory, "templates", context.namespaces))
49-
fs.write(fs.join(directory, "#{context.name}.#{format}.erb"),
50-
t(template_with_format_ext("slice_template", format), context))
49+
fs.create(fs.join(directory, "#{context.name}.#{format}.erb"),
50+
t(template_with_format_ext("slice_template", format), context))
5151
end
5252

5353
def generate_for_app(context, format, _slice)
5454
fs.mkdir(directory = fs.join("app", "views", context.namespaces))
55-
fs.write(fs.join(directory, "#{context.name}.rb"), t("app_view.erb", context))
55+
fs.create(fs.join(directory, "#{context.name}.rb"), t("app_view.erb", context))
5656

5757
fs.mkdir(directory = fs.join("app", "templates", context.namespaces))
58-
fs.write(fs.join(directory, "#{context.name}.#{format}.erb"),
59-
t(template_with_format_ext("app_template", format), context))
58+
fs.create(fs.join(directory, "#{context.name}.#{format}.erb"),
59+
t(template_with_format_ext("app_template", format), context))
6060
end
6161

6262
# rubocop:enable Metrics/AbcSize

lib/hanami/cli/generators/gem/app.rb

+36-36
Original file line numberDiff line numberDiff line change
@@ -34,62 +34,62 @@ def call(app, context: Context.new(inflector, app), &blk)
3434
attr_reader :inflector
3535

3636
def generate_app(app, context) # rubocop:disable Metrics/AbcSize
37-
fs.write(".gitignore", t("gitignore.erb", context))
38-
fs.write(".env", t("env.erb", context))
37+
fs.create(".gitignore", t("gitignore.erb", context))
38+
fs.create(".env", t("env.erb", context))
3939

40-
fs.write("README.md", t("readme.erb", context))
41-
fs.write("Gemfile", t("gemfile.erb", context))
42-
fs.write("Rakefile", t("rakefile.erb", context))
43-
fs.write("Procfile.dev", t("procfile.erb", context))
44-
fs.write("config.ru", t("config_ru.erb", context))
40+
fs.create("README.md", t("readme.erb", context))
41+
fs.create("Gemfile", t("gemfile.erb", context))
42+
fs.create("Rakefile", t("rakefile.erb", context))
43+
fs.create("Procfile.dev", t("procfile.erb", context))
44+
fs.create("config.ru", t("config_ru.erb", context))
4545

46-
fs.write("bin/dev", file("dev"))
46+
fs.create("bin/dev", file("dev"))
4747
fs.chmod("bin/dev", 0o755)
4848

49-
fs.write("config/app.rb", t("app.erb", context))
50-
fs.write("config/settings.rb", t("settings.erb", context))
51-
fs.write("config/routes.rb", t("routes.erb", context))
52-
fs.write("config/puma.rb", t("puma.erb", context))
49+
fs.create("config/app.rb", t("app.erb", context))
50+
fs.create("config/settings.rb", t("settings.erb", context))
51+
fs.create("config/routes.rb", t("routes.erb", context))
52+
fs.create("config/puma.rb", t("puma.erb", context))
5353

54-
fs.write("lib/tasks/.keep", t("keep.erb", context))
55-
fs.write("lib/#{app}/types.rb", t("types.erb", context))
54+
fs.create("lib/tasks/.keep", t("keep.erb", context))
55+
fs.create("lib/#{app}/types.rb", t("types.erb", context))
5656

57-
fs.write("app/actions/.keep", t("keep.erb", context))
58-
fs.write("app/action.rb", t("action.erb", context))
59-
fs.write("app/view.rb", t("view.erb", context))
60-
fs.write("app/views/helpers.rb", t("helpers.erb", context))
61-
fs.write("app/templates/layouts/app.html.erb", t("app_layout.erb", context))
57+
fs.create("app/actions/.keep", t("keep.erb", context))
58+
fs.create("app/action.rb", t("action.erb", context))
59+
fs.create("app/view.rb", t("view.erb", context))
60+
fs.create("app/views/helpers.rb", t("helpers.erb", context))
61+
fs.create("app/templates/layouts/app.html.erb", t("app_layout.erb", context))
6262

6363
if context.generate_assets?
64-
fs.write("package.json", t("package.json.erb", context))
65-
fs.write("config/assets.js", file("assets.js"))
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"))
64+
fs.create("package.json", t("package.json.erb", context))
65+
fs.create("config/assets.js", file("assets.js"))
66+
fs.create("app/assets/js/app.js", t("app_js.erb", context))
67+
fs.create("app/assets/css/app.css", t("app_css.erb", context))
68+
fs.create("app/assets/images/favicon.ico", file("favicon.ico"))
6969
end
7070

7171
if context.generate_db?
72-
fs.write("app/db/relation.rb", t("relation.erb", context))
73-
fs.write("app/relations/.keep", t("keep.erb", context))
72+
fs.create("app/db/relation.rb", t("relation.erb", context))
73+
fs.create("app/relations/.keep", t("keep.erb", context))
7474

75-
fs.write("app/db/repo.rb", t("repo.erb", context))
76-
fs.write("app/repos/.keep", t("keep.erb", context))
75+
fs.create("app/db/repo.rb", t("repo.erb", context))
76+
fs.create("app/repos/.keep", t("keep.erb", context))
7777

78-
fs.write("app/db/struct.rb", t("struct.erb", context))
79-
fs.write("app/structs/.keep", t("keep.erb", context))
78+
fs.create("app/db/struct.rb", t("struct.erb", context))
79+
fs.create("app/structs/.keep", t("keep.erb", context))
8080

81-
fs.write("config/db/seeds.rb", t("seeds.erb", context))
82-
fs.write("config/db/migrate/.keep", t("keep.erb", context))
81+
fs.create("config/db/seeds.rb", t("seeds.erb", context))
82+
fs.create("config/db/migrate/.keep", t("keep.erb", context))
8383

8484
if context.generate_sqlite?
85-
fs.write("db/.keep", t("keep.erb", context))
85+
fs.create("db/.keep", t("keep.erb", context))
8686
end
8787
end
8888

89-
fs.write("app/operation.rb", t("operation.erb", context))
89+
fs.create("app/operation.rb", t("operation.erb", context))
9090

91-
fs.write("public/404.html", file("404.html"))
92-
fs.write("public/500.html", file("500.html"))
91+
fs.create("public/404.html", file("404.html"))
92+
fs.create("public/500.html", file("500.html"))
9393
end
9494

9595
def template(path, context)

0 commit comments

Comments
 (0)