Skip to content

Commit

Permalink
Prevent generators from overwriting files (#274)
Browse files Browse the repository at this point in the history
  • Loading branch information
maxemitchell authored Dec 8, 2024
1 parent bfdf41f commit 04ec18a
Show file tree
Hide file tree
Showing 18 changed files with 580 additions and 359 deletions.
7 changes: 7 additions & 0 deletions lib/hanami/cli/errors.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,13 @@ def initialize(path)
end
end

# @api public
class FileAlreadyExistsError < Error
def initialize(path)
super("Cannot overwrite existing file: `#{path}`")
end
end

# @api public
class ForbiddenAppNameError < Error
def initialize(name)
Expand Down
15 changes: 11 additions & 4 deletions lib/hanami/cli/files.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@ def initialize(out: $stdout, **args)
@out = out
end

# @api private
def create(path, *content)
raise FileAlreadyExistsError.new(path) if exist?(path)

write(path, *content)
end

# @since 2.0.0
# @api private
def write(path, *content)
Expand All @@ -33,10 +40,10 @@ def write(path, *content)
# @since 2.0.0
# @api private
def mkdir(path)
unless exist?(path)
super
created(_path(path))
end
return if exist?(path)

super
created(_path(path))
end

# @since 2.0.0
Expand Down
16 changes: 8 additions & 8 deletions lib/hanami/cli/generators/app/action.rb
Original file line number Diff line number Diff line change
Expand Up @@ -85,15 +85,15 @@ def generate_for_slice(controller, action, url, http, format, skip_view, skip_ro
end

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

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

fs.mkdir(directory = fs.join(slice_directory, "templates", controller))
fs.write(fs.join(directory, "#{action}.#{format}.erb"),
t(template_with_format_ext("slice_template", format), context))
fs.create(fs.join(directory, "#{action}.#{format}.erb"),
t(template_with_format_ext("slice_template", format), context))
end
end

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

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

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

if generate_view?(skip_view, view, view_directory)
fs.mkdir(view_directory)
fs.write(fs.join(view_directory, "#{view}.rb"), t("view.erb", context))
fs.create(fs.join(view_directory, "#{view}.rb"), t("view.erb", context))

fs.mkdir(template_directory = fs.join("app", "templates", controller))
fs.write(fs.join(template_directory, "#{view}.#{format}.erb"),
t(template_with_format_ext("template", format), context))
fs.create(fs.join(template_directory, "#{view}.#{format}.erb"),
t(template_with_format_ext("template", format), context))
end
end
# rubocop:enable Metrics/AbcSize
Expand Down
2 changes: 1 addition & 1 deletion lib/hanami/cli/generators/app/migration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def call(key:, base_path:, gateway: nil, **_opts)

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

fs.write(path, FILE_CONTENTS)
fs.create(path, FILE_CONTENTS)
end

private
Expand Down
4 changes: 2 additions & 2 deletions lib/hanami/cli/generators/app/part.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ def generate_for_slice(context, slice)
generate_base_part_for_slice(context, slice)

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

# @since 2.1.0
Expand All @@ -59,7 +59,7 @@ def generate_for_app(context)
generate_base_part_for_app(context)

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

# @since 2.1.0
Expand Down
6 changes: 5 additions & 1 deletion lib/hanami/cli/generators/app/ruby_file_writer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def call(key:, namespace:, base_path:, relative_parent_class:, extra_namespace:
relative_parent_class: relative_parent_class,
extra_namespace: extra_namespace,
body: body,
).write
).create
end

private
Expand Down Expand Up @@ -62,6 +62,10 @@ def initialize(
@body = body
end

def create
fs.create(path, file_contents)
end

def write
fs.write(path, file_contents)
end
Expand Down
36 changes: 18 additions & 18 deletions lib/hanami/cli/generators/app/slice.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,33 +30,33 @@ def call(app, slice, url, context: nil, **opts)

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

fs.write(fs.join(directory, "action.rb"), t("action.erb", context))
fs.write(fs.join(directory, "view.rb"), t("view.erb", context))
fs.write(fs.join(directory, "views", "helpers.rb"), t("helpers.erb", context))
fs.write(fs.join(directory, "templates", "layouts", "app.html.erb"), t("app_layout.erb", context))
fs.write(fs.join(directory, "operation.rb"), t("operation.erb", context))
fs.create(fs.join(directory, "action.rb"), t("action.erb", context))
fs.create(fs.join(directory, "view.rb"), t("view.erb", context))
fs.create(fs.join(directory, "views", "helpers.rb"), t("helpers.erb", context))
fs.create(fs.join(directory, "templates", "layouts", "app.html.erb"), t("app_layout.erb", context))
fs.create(fs.join(directory, "operation.rb"), t("operation.erb", context))

if context.bundled_assets?
fs.write(fs.join(directory, "assets", "js", "app.js"), t("app_js.erb", context))
fs.write(fs.join(directory, "assets", "css", "app.css"), t("app_css.erb", context))
fs.write(fs.join(directory, "assets", "images", "favicon.ico"), file("favicon.ico"))
fs.create(fs.join(directory, "assets", "js", "app.js"), t("app_js.erb", context))
fs.create(fs.join(directory, "assets", "css", "app.css"), t("app_css.erb", context))
fs.create(fs.join(directory, "assets", "images", "favicon.ico"), file("favicon.ico"))
end

if context.generate_db?
fs.write(fs.join(directory, "db", "relation.rb"), t("relation.erb", context))
fs.write(fs.join(directory, "relations", ".keep"), t("keep.erb", context))
fs.create(fs.join(directory, "db", "relation.rb"), t("relation.erb", context))
fs.create(fs.join(directory, "relations", ".keep"), t("keep.erb", context))

fs.write(fs.join(directory, "db", "repo.rb"), t("repo.erb", context))
fs.write(fs.join(directory, "repos", ".keep"), t("keep.erb", context))
fs.create(fs.join(directory, "db", "repo.rb"), t("repo.erb", context))
fs.create(fs.join(directory, "repos", ".keep"), t("keep.erb", context))

fs.write(fs.join(directory, "db", "struct.rb"), t("struct.erb", context))
fs.write(fs.join(directory, "structs", ".keep"), t("keep.erb", context))
fs.create(fs.join(directory, "db", "struct.rb"), t("struct.erb", context))
fs.create(fs.join(directory, "structs", ".keep"), t("keep.erb", context))
end

fs.write(fs.join(directory, "actions/.keep"), t("keep.erb", context))
fs.write(fs.join(directory, "views/.keep"), t("keep.erb", context))
fs.write(fs.join(directory, "templates/.keep"), t("keep.erb", context))
fs.write(fs.join(directory, "templates/layouts/.keep"), t("keep.erb", context))
fs.create(fs.join(directory, "actions/.keep"), t("keep.erb", context))
fs.create(fs.join(directory, "views/.keep"), t("keep.erb", context))
fs.create(fs.join(directory, "templates/.keep"), t("keep.erb", context))
fs.create(fs.join(directory, "templates/layouts/.keep"), t("keep.erb", context))
end

private
Expand Down
12 changes: 6 additions & 6 deletions lib/hanami/cli/generators/app/view.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,20 +43,20 @@ def generate_for_slice(context, format, slice)
raise MissingSliceError.new(slice) unless fs.directory?(slice_directory)

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

fs.mkdir(directory = fs.join(slice_directory, "templates", context.namespaces))
fs.write(fs.join(directory, "#{context.name}.#{format}.erb"),
t(template_with_format_ext("slice_template", format), context))
fs.create(fs.join(directory, "#{context.name}.#{format}.erb"),
t(template_with_format_ext("slice_template", format), context))
end

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

fs.mkdir(directory = fs.join("app", "templates", context.namespaces))
fs.write(fs.join(directory, "#{context.name}.#{format}.erb"),
t(template_with_format_ext("app_template", format), context))
fs.create(fs.join(directory, "#{context.name}.#{format}.erb"),
t(template_with_format_ext("app_template", format), context))
end

# rubocop:enable Metrics/AbcSize
Expand Down
72 changes: 36 additions & 36 deletions lib/hanami/cli/generators/gem/app.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,62 +34,62 @@ def call(app, context: Context.new(inflector, app), &blk)
attr_reader :inflector

def generate_app(app, context) # rubocop:disable Metrics/AbcSize
fs.write(".gitignore", t("gitignore.erb", context))
fs.write(".env", t("env.erb", context))
fs.create(".gitignore", t("gitignore.erb", context))
fs.create(".env", t("env.erb", context))

fs.write("README.md", t("readme.erb", context))
fs.write("Gemfile", t("gemfile.erb", context))
fs.write("Rakefile", t("rakefile.erb", context))
fs.write("Procfile.dev", t("procfile.erb", context))
fs.write("config.ru", t("config_ru.erb", context))
fs.create("README.md", t("readme.erb", context))
fs.create("Gemfile", t("gemfile.erb", context))
fs.create("Rakefile", t("rakefile.erb", context))
fs.create("Procfile.dev", t("procfile.erb", context))
fs.create("config.ru", t("config_ru.erb", context))

fs.write("bin/dev", file("dev"))
fs.create("bin/dev", file("dev"))
fs.chmod("bin/dev", 0o755)

fs.write("config/app.rb", t("app.erb", context))
fs.write("config/settings.rb", t("settings.erb", context))
fs.write("config/routes.rb", t("routes.erb", context))
fs.write("config/puma.rb", t("puma.erb", context))
fs.create("config/app.rb", t("app.erb", context))
fs.create("config/settings.rb", t("settings.erb", context))
fs.create("config/routes.rb", t("routes.erb", context))
fs.create("config/puma.rb", t("puma.erb", context))

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

fs.write("app/actions/.keep", t("keep.erb", context))
fs.write("app/action.rb", t("action.erb", context))
fs.write("app/view.rb", t("view.erb", context))
fs.write("app/views/helpers.rb", t("helpers.erb", context))
fs.write("app/templates/layouts/app.html.erb", t("app_layout.erb", context))
fs.create("app/actions/.keep", t("keep.erb", context))
fs.create("app/action.rb", t("action.erb", context))
fs.create("app/view.rb", t("view.erb", context))
fs.create("app/views/helpers.rb", t("helpers.erb", context))
fs.create("app/templates/layouts/app.html.erb", t("app_layout.erb", context))

if context.generate_assets?
fs.write("package.json", t("package.json.erb", context))
fs.write("config/assets.js", file("assets.js"))
fs.write("app/assets/js/app.js", t("app_js.erb", context))
fs.write("app/assets/css/app.css", t("app_css.erb", context))
fs.write("app/assets/images/favicon.ico", file("favicon.ico"))
fs.create("package.json", t("package.json.erb", context))
fs.create("config/assets.js", file("assets.js"))
fs.create("app/assets/js/app.js", t("app_js.erb", context))
fs.create("app/assets/css/app.css", t("app_css.erb", context))
fs.create("app/assets/images/favicon.ico", file("favicon.ico"))
end

if context.generate_db?
fs.write("app/db/relation.rb", t("relation.erb", context))
fs.write("app/relations/.keep", t("keep.erb", context))
fs.create("app/db/relation.rb", t("relation.erb", context))
fs.create("app/relations/.keep", t("keep.erb", context))

fs.write("app/db/repo.rb", t("repo.erb", context))
fs.write("app/repos/.keep", t("keep.erb", context))
fs.create("app/db/repo.rb", t("repo.erb", context))
fs.create("app/repos/.keep", t("keep.erb", context))

fs.write("app/db/struct.rb", t("struct.erb", context))
fs.write("app/structs/.keep", t("keep.erb", context))
fs.create("app/db/struct.rb", t("struct.erb", context))
fs.create("app/structs/.keep", t("keep.erb", context))

fs.write("config/db/seeds.rb", t("seeds.erb", context))
fs.write("config/db/migrate/.keep", t("keep.erb", context))
fs.create("config/db/seeds.rb", t("seeds.erb", context))
fs.create("config/db/migrate/.keep", t("keep.erb", context))

if context.generate_sqlite?
fs.write("db/.keep", t("keep.erb", context))
fs.create("db/.keep", t("keep.erb", context))
end
end

fs.write("app/operation.rb", t("operation.erb", context))
fs.create("app/operation.rb", t("operation.erb", context))

fs.write("public/404.html", file("404.html"))
fs.write("public/500.html", file("500.html"))
fs.create("public/404.html", file("404.html"))
fs.create("public/500.html", file("500.html"))
end

def template(path, context)
Expand Down
Loading

0 comments on commit 04ec18a

Please sign in to comment.