Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove the crystal lib generator code. #800

Merged
merged 2 commits into from
Jun 10, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
174 changes: 38 additions & 136 deletions src/generators/web.cr
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
require "option_parser"

class LuckyCli::Generators::Web
include LuckyCli::GeneratorHelpers

Expand Down Expand Up @@ -45,13 +43,9 @@ class LuckyCli::Generators::Web

def run : Nil
ensure_directory_does_not_exist
generate_default_crystal_project
rename_shard_target_to_app
add_deps_to_shard_file
add_dev_deps_to_shard_file
remove_generated_src_files
remove_generated_spec_files
remove_default_readme
generate_default_project
generate_shard_yml

add_default_lucky_structure_to_src

if browser?
Expand All @@ -72,7 +66,6 @@ class LuckyCli::Generators::Web
end

setup_gitignore
remove_default_license

puts <<-TEXT
#{"Done generating your Lucky project".colorize.bold}
Expand All @@ -89,171 +82,80 @@ class LuckyCli::Generators::Web
if default_directory?
project_dir
else
[full_project_directory.chomp('/'), project_dir].join('/')
File.join(full_project_directory.chomp('/'), project_dir)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure how this looks on Windows, by we may need to see if there's some sort of Crystal::System::FileSeparator or whatever. I'm assuming on Windows we'd need to chomp('\')...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While you can use File methods for dealing with Paths, because they are just wrappers around Path, I'd recommend to just use Path directly instead. It makes it more clear what you're doing (e.g. path manipulation), and use File for actual filesystem operations (e.g. read/write a file).

You don't actually need #chomp here:

Suggested change
File.join(full_project_directory.chomp('/'), project_dir)
File.join(full_project_directory, project_dir)

But this is my suggestion (which is the same as File#join, just prefer using Path):

Suggested change
File.join(full_project_directory.chomp('/'), project_dir)
Path.new(full_project_directory).join(project_dir).to_s

However, my above suggestion would be better suited in a separate PR to change all other places using File instead of Path (I might add this to my lucky_template work).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I never thought about using Path until I started seeing your code. I think that makes more sense. Maybe I'll just merge this PR in as-is, then in another one we can go through it all and really start cleaning stuff up.

end
end

private def setup_gitignore
append_text to: ".gitignore", text: <<-TEXT
start_server
*.dwarf
*.local.cr
.env
/tmp
TEXT
if browser?
append_text to: ".gitignore", text: <<-TEXT
/public/js
/public/css
/public/mix-manifest.json
/node_modules
yarn-error.log
File.open(File.join(project_dir, ".gitignore"), "w") do |io|
io << <<-TEXT
/docs/
/lib/
/bin/
/.shards/
*.dwarf
start_server
*.dwarf
*.local.cr
.env
/tmp
TEXT

if browser?
io << <<-TEXT
/public/js
/public/css
/public/mix-manifest.json
/node_modules
yarn-error.log
TEXT
end
end
end

private def add_default_lucky_structure_to_src
SrcTemplate.new(project_name, generate_auth: generate_auth?, api_only: api_only?, with_sec_tester: with_sec_tester?)
.render("./#{project_dir}", force: true)
.render(project_dir, force: true)
end

private def add_browser_app_structure_to_src
BrowserSrcTemplate.new(generate_auth: generate_auth?)
.render("./#{project_dir}", force: true)
.render(project_dir, force: true)
end

private def add_base_auth_to_src
BaseAuthenticationSrcTemplate.new.render("./#{project_dir}", force: true)
BaseAuthenticationSrcTemplate.new.render(project_dir, force: true)
end

private def add_api_authentication_to_src
ApiAuthenticationTemplate.new.render("./#{project_dir}", force: true)
ApiAuthenticationTemplate.new.render(project_dir, force: true)
end

private def add_browser_authentication_to_src
BrowserAuthenticationSrcTemplate.new.render("./#{project_dir}", force: true)
BrowserAuthenticationSrcTemplate.new.render(project_dir, force: true)
end

private def add_sec_tester_to_src
AppWithSecTesterTemplate.new(generate_auth: generate_auth?, browser: browser?)
.render("./#{project_dir}", force: true)
end

private def remove_generated_src_files
remove_default_generated_if_exists("src")
end

private def remove_generated_spec_files
remove_default_generated_if_exists("spec")
end

private def remove_default_readme
remove_default_generated_if_exists("README.md")
end

private def remove_default_license
remove_license_from_shard
remove_default_generated_if_exists("LICENSE")
end

private def remove_default_generated_if_exists(file_or_directory : String)
to_delete = "#{project_dir}/#{file_or_directory}"
if File.exists?(to_delete)
FileUtils.rm_rf(to_delete)
end
end

private def remove_license_from_shard
shard_path = "#{project_dir}/shard.yml"
lines = [] of String
File.each_line shard_path do |line|
lines << line unless line.includes?("license")
end
File.write shard_path, lines.join("\n")
.render(project_dir, force: true)
end

private def install_shards
puts "Installing shards"
run_command "shards install"
end

private def generate_default_crystal_project
io = IO::Memory.new
Process.run "crystal init app #{project_name} #{project_dir}",
shell: true,
output: io,
error: STDERR
end

private def rename_shard_target_to_app
replace_text "shard.yml", from: "#{project_name}:", to: "app:"
end

private def add_deps_to_shard_file
append_text to: "shard.yml", text: <<-DEPS_LIST
dependencies:
lucky:
github: luckyframework/lucky
version: ~> 1.0.0
avram:
github: luckyframework/avram
version: ~> 1.0.0
carbon:
github: luckyframework/carbon
version: ~> 0.3.0
carbon_sendgrid_adapter:
github: luckyframework/carbon_sendgrid_adapter
version: ~> 0.3.0
lucky_env:
github: luckyframework/lucky_env
version: ~> 0.1.4
lucky_task:
github: luckyframework/lucky_task
version: ~> 0.1.1
DEPS_LIST

if generate_auth?
append_text to: "shard.yml", text: <<-DEPS_LIST
authentic:
github: luckyframework/authentic
version: ~> 1.0.0
jwt:
github: crystal-community/jwt
version: ~> 1.6.0
DEPS_LIST
end
end

private def needs_development_dependencies?
browser? || with_sec_tester?
private def generate_default_project : Nil
Dir.mkdir_p(project_dir)
end

private def add_dev_deps_to_shard_file
if needs_development_dependencies?
append_text to: "shard.yml", text: <<-DEPS_LIST
development_dependencies:
DEPS_LIST

if browser?
append_text to: "shard.yml", text: <<-DEPS_LIST
lucky_flow:
github: luckyframework/lucky_flow
version: ~> 0.9.0
DEPS_LIST
end

if with_sec_tester?
append_text to: "shard.yml", text: <<-DEPS_LIST
lucky_sec_tester:
github: luckyframework/lucky_sec_tester
version: ~> 0.2.0
DEPS_LIST
end
end
private def generate_shard_yml : Nil
ShardFileGenerator.new(project_name, generate_auth: generate_auth?, browser: browser?, with_sec_tester: with_sec_tester?)
.render(project_dir)
end

private def ensure_directory_does_not_exist
if Dir.exists?("./#{project_dir}")
if Dir.exists?(project_dir)
puts "Folder named #{project_dir} already exists, please use a different name".colorize.red.bold
exit
end
Expand Down
104 changes: 104 additions & 0 deletions src/lucky_cli/shard_file_generator.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
require "yaml"

class ShardFileGenerator
getter project_name : String
getter? generate_auth : Bool
getter? browser : Bool
getter? with_sec_tester : Bool

def initialize(
@project_name : String,
@generate_auth : Bool,
@browser : Bool,
@with_sec_tester : Bool
)
end

private def project_base_dependencies
{
lucky: {github: "luckyframework/lucky", version: "~> 1.0.0"},
avram: {github: "luckyframework/avram", version: "~> 1.0.0"},
carbon: {github: "luckyframework/carbon", version: "~> 0.3.0"},
carbon_sendgrid_adapter: {github: "luckyframework/carbon_sendgrid_adapter", version: "~> 0.3.0"},
lucky_env: {github: "luckyframework/lucky_env", version: "~> 0.1.4"},
lucky_task: {github: "luckyframework/lucky_task", version: "~> 0.1.1"},
}
end

private def project_auth_dependencies
{
authentic: {github: "luckyframework/authentic", version: "~> 1.0.0"},
jwt: {github: "crystal-community/jwt", version: "~> 1.6.0"},
}
end

private def project_browser_dev_dependencies
{
lucky_flow: {github: "luckyframework/lucky_flow", version: "~> 0.9.0"},
}
end

private def project_additional_dev_dependencies
{
lucky_sec_tester: {github: "luckyframework/lucky_sec_tester", version: "~> 0.2.0"},
}
end

private def add_dependency(yaml, dep_name, details)
yaml.scalar dep_name.to_s
yaml.mapping do
details.each do |key, value|
yaml.scalar key.to_s
yaml.scalar value.to_s
end
end
end

def render(project_directory : String)
File.open(File.join(project_directory, "shard.yml"), "w") do |f|
YAML.build(f) do |yaml|
yaml.mapping do
yaml.scalar "name"
yaml.scalar project_name
yaml.scalar "version"
yaml.scalar "0.1.0"
yaml.scalar "crystal"
yaml.scalar ">= #{Crystal::VERSION}"
yaml.scalar "targets"
yaml.mapping do
yaml.scalar project_name
yaml.mapping do
yaml.scalar "main"
yaml.scalar File.join("src", "#{project_name}.cr")
end
end
yaml.scalar "dependencies"
yaml.mapping do
project_base_dependencies.each do |dep_name, details|
add_dependency(yaml, dep_name, details)
end

if generate_auth?
project_auth_dependencies.each do |dep_name, details|
add_dependency(yaml, dep_name, details)
end
end
end
yaml.scalar "development_dependencies"
yaml.mapping do
if browser?
project_browser_dev_dependencies.each do |dep_name, details|
add_dependency(yaml, dep_name, details)
end
end
if with_sec_tester?
project_additional_dev_dependencies.each do |dep_name, details|
add_dependency(yaml, dep_name, details)
end
end
end
end
end
end
end
end