From 7cb86b6fe72c38fde3bcf82a2238a6aca1b48ee3 Mon Sep 17 00:00:00 2001 From: Max Fierke Date: Mon, 12 Feb 2024 16:19:17 -0600 Subject: [PATCH] Extract class on Project#bootstrap --- src/mstrap.cr | 3 +- src/mstrap/bootstrapper.cr | 28 ++++++++ .../bootstrappers/default_bootstrapper.cr | 35 ++++++++++ .../bootstrappers/script_bootstrapper.cr | 38 +++++++++++ src/mstrap/bootstrappers/web_bootstrapper.cr | 33 +++++++++ src/mstrap/cli.cr | 2 +- src/mstrap/project.cr | 68 ------------------- src/mstrap/steps/projects_step.cr | 4 +- src/mstrap/web_bootstrapper.cr | 31 --------- 9 files changed, 139 insertions(+), 103 deletions(-) create mode 100644 src/mstrap/bootstrapper.cr create mode 100644 src/mstrap/bootstrappers/default_bootstrapper.cr create mode 100644 src/mstrap/bootstrappers/script_bootstrapper.cr create mode 100644 src/mstrap/bootstrappers/web_bootstrapper.cr delete mode 100644 src/mstrap/web_bootstrapper.cr diff --git a/src/mstrap.cr b/src/mstrap.cr index 2b256e8..19dab49 100644 --- a/src/mstrap.cr +++ b/src/mstrap.cr @@ -25,7 +25,8 @@ require "./mstrap/profile_fetcher" require "./mstrap/user" require "./mstrap/configuration" require "./mstrap/supports/**" -require "./mstrap/web_bootstrapper" +require "./mstrap/bootstrapper" +require "./mstrap/bootstrappers/**" require "./mstrap/runtime_manager" require "./mstrap/runtime_managers/**" require "./mstrap/runtime" diff --git a/src/mstrap/bootstrapper.cr b/src/mstrap/bootstrapper.cr new file mode 100644 index 0000000..89dc76e --- /dev/null +++ b/src/mstrap/bootstrapper.cr @@ -0,0 +1,28 @@ +module MStrap + abstract class Bootstrapper + include DSL + + def initialize(@config : Configuration) + end + + def self.for(config : Configuration, project : Project) : Array(Bootstrapper) + bootstrappers = Array(Bootstrapper).new + + if project.run_scripts? && Bootstrappers::ScriptBootstrapper.has_scripts?(project) + bootstrappers << Bootstrappers::ScriptBootstrapper.new(config) + else + bootstrappers << Bootstrappers::DefaultBootstrapper.new(config) + + if project.web? + bootstrappers << Bootstrappers::WebBootstrapper.new(config) + end + end + + bootstrappers + end + + abstract def bootstrap(project : Project) : Bool + + protected getter :config + end +end diff --git a/src/mstrap/bootstrappers/default_bootstrapper.cr b/src/mstrap/bootstrappers/default_bootstrapper.cr new file mode 100644 index 0000000..62e0e80 --- /dev/null +++ b/src/mstrap/bootstrappers/default_bootstrapper.cr @@ -0,0 +1,35 @@ +module MStrap + module Bootstrappers + class DefaultBootstrapper < Bootstrapper + # Conventional bootstrapping from mstrap. This will auto-detect the runtimes + # used by the project and run the standard bootstrapping for each runtime. + # This **does not** run any bootstrapping scripts, and is used mainly for + # calling into conventional bootstrapping within a project's + # `script/bootstrap` or `script/setup` from `mstrap project`. + def bootstrap(project : Project) : Bool + logd "Bootstrapping '#{project.name}' with runtime defaults." + + runtime_impls(project).each do |runtime| + Dir.cd(project.path) do + if runtime.matches? + logd "Detected #{runtime.language_name}. Installing #{runtime.language_name}, project #{runtime.language_name} packages, and other relevant dependencies" + runtime.setup + end + end + end + + true + end + + def runtime_impls(project) + if project.runtimes.empty? + config.runtime_manager.runtimes + else + config.runtime_manager.runtimes.select do |runtime| + project.runtimes.includes?(runtime.language_name) + end + end + end + end + end +end diff --git a/src/mstrap/bootstrappers/script_bootstrapper.cr b/src/mstrap/bootstrappers/script_bootstrapper.cr new file mode 100644 index 0000000..b999a57 --- /dev/null +++ b/src/mstrap/bootstrappers/script_bootstrapper.cr @@ -0,0 +1,38 @@ +module MStrap + module Bootstrappers + class ScriptBootstrapper < Bootstrapper + # :nodoc: + BOOTSTRAP_SCRIPT = File.join("script", "bootstrap") + + # :nodoc: + SETUP_SCRIPT = File.join("script", "setup") + + # Executes `script/bootstrap` and `script/setup` (if either exists and are + # configured to run) + def bootstrap(project : Project) : Bool + logd "Found bootstrapping scripts, executing instead of using defaults." + + begin + ENV["__MSTRAP_EXEC_SCRIPTS"] = "true" + + Dir.cd(project.path) do + cmd BOOTSTRAP_SCRIPT if File.exists?(BOOTSTRAP_SCRIPT) + cmd SETUP_SCRIPT if File.exists?(SETUP_SCRIPT) + end + ensure + ENV.delete("__MSTRAP_EXEC_SCRIPTS") + end + + true + end + + # Whether project has any bootstrapping/setup scripts a-la + # [`scripts-to-rule-them-all`](https://github.com/github/scripts-to-rule-them-all) + def self.has_scripts?(project) + [BOOTSTRAP_SCRIPT, SETUP_SCRIPT].any? do |script_path| + File.exists?(File.join(project.path, script_path)) + end + end + end + end +end diff --git a/src/mstrap/bootstrappers/web_bootstrapper.cr b/src/mstrap/bootstrappers/web_bootstrapper.cr new file mode 100644 index 0000000..77e703b --- /dev/null +++ b/src/mstrap/bootstrappers/web_bootstrapper.cr @@ -0,0 +1,33 @@ +module MStrap + module Bootstrappers + # The `WebBootstrapper` is responsible for bootstrapping web-based projects. + # Currently, this is just setting up an NGINX configuration for the project. + class WebBootstrapper < Bootstrapper + include DSL + + def initialize(@config : Configuration) + super + @mkcert = Mkcert.new + end + + # Executes the bootstrapper + def bootstrap(project : Project) : Bool + logd "'#{project.name}' is a web project. Running web bootstrapper." + + if mkcert.installed? + Dir.cd(Paths::PROJECT_CERTS) do + mkcert.install! + mkcert.install_cert!(project.hostname) + end + else + logw "mkcert not found. Skipping cert setup." + end + + Templates::NginxConf.new(project).write_to_config! + true + end + + private getter :mkcert + end + end +end diff --git a/src/mstrap/cli.cr b/src/mstrap/cli.cr index 7430e13..96fb574 100644 --- a/src/mstrap/cli.cr +++ b/src/mstrap/cli.cr @@ -200,7 +200,7 @@ DESC project_def.runtimes = options.string["runtimes"].split(',') if options.string.has_key?("runtimes") project = MStrap::Project.for(project_def) - project.bootstrap(config.runtime_manager) + Bootstrapper.for(config, project).each { |bs| bs.bootstrap(project) } end end diff --git a/src/mstrap/project.cr b/src/mstrap/project.cr index 5f11b66..218387d 100644 --- a/src/mstrap/project.cr +++ b/src/mstrap/project.cr @@ -8,12 +8,6 @@ module MStrap # :nodoc: SCP_REPO_REGEX = /\A(.+@)?[\w\d\.\-_]+:/ - # :nodoc: - BOOTSTRAP_SCRIPT = File.join("script", "bootstrap") - - # :nodoc: - SETUP_SCRIPT = File.join("script", "setup") - @cname : String @hostname : String @name : String @@ -117,14 +111,6 @@ module MStrap end end - # Whether project has any bootstrapping/setup scripts a-la - # [`scripts-to-rule-them-all`](https://github.com/github/scripts-to-rule-them-all) - def has_scripts? - [BOOTSTRAP_SCRIPT, SETUP_SCRIPT].any? do |script_path| - File.exists?(File.join(path, script_path)) - end - end - # Clones the project from Git def clone success = cmd("git", "clone", git_uri, path, quiet: true) @@ -165,60 +151,6 @@ module MStrap end end - # Executes `script/bootstrap` and `script/setup` (if either exists and are - # configured to run) or executes conventional runtime bootstrapping as - # determined by mstrap. - def bootstrap(runtime_manager : RuntimeManager) - if has_scripts? && run_scripts? - logd "Found bootstrapping scripts, executing instead of using defaults." - begin - ENV["__MSTRAP_EXEC_SCRIPTS"] = "true" - - Dir.cd(path) do - cmd BOOTSTRAP_SCRIPT if File.exists?(BOOTSTRAP_SCRIPT) - cmd SETUP_SCRIPT if File.exists?(SETUP_SCRIPT) - end - ensure - ENV.delete("__MSTRAP_EXEC_SCRIPTS") - end - else - logd "Bootstrapping '#{name}' with runtime defaults." - default_bootstrap(runtime_manager) - end - end - - # Conventional bootstrapping from mstrap. This will auto-detect the runtimes - # used by the project and run the standard bootstrapping for each runtime. - # This **does not** run any bootstrapping scripts, and is used mainly for - # calling into conventional bootstrapping within a project's - # `script/bootstrap` or `script/setup` from `mstrap project`. - # - # TODO: Move this somewhere more appropriate - protected def default_bootstrap(runtime_manager : RuntimeManager) - runtime_impls = - if runtimes.empty? - runtime_manager.runtimes - else - runtime_manager.runtimes.select do |runtime| - runtimes.includes?(runtime.language_name) - end - end - - runtime_impls.each do |runtime| - Dir.cd(path) do - if runtime.matches? - logd "Detected #{runtime.language_name}. Installing #{runtime.language_name}, project #{runtime.language_name} packages, and other relevant dependencies" - runtime.setup - end - end - end - - if web? - logd "'#{name}' is a web project. Running web bootstrapper." - WebBootstrapper.new(self).bootstrap - end - end - private def current_branch `git rev-parse --abbrev-ref HEAD`.chomp end diff --git a/src/mstrap/steps/projects_step.cr b/src/mstrap/steps/projects_step.cr index 2611fbc..f2fa04e 100644 --- a/src/mstrap/steps/projects_step.cr +++ b/src/mstrap/steps/projects_step.cr @@ -4,7 +4,7 @@ module MStrap # updating, and bootstrapping all configured projects. class ProjectsStep < Step @has_web_projects = false - @projects : Array(Project) | Nil + @projects : Array(Project)? def self.description "Bootstraps configured projects" @@ -38,7 +38,7 @@ module MStrap end logn "--> Bootstrapping: " - project.bootstrap(runtime_manager) + Bootstrapper.for(config, project).each { |bs| bs.bootstrap(project) } success "Finished bootstrapping #{project.name}" end diff --git a/src/mstrap/web_bootstrapper.cr b/src/mstrap/web_bootstrapper.cr deleted file mode 100644 index 8351f7f..0000000 --- a/src/mstrap/web_bootstrapper.cr +++ /dev/null @@ -1,31 +0,0 @@ -module MStrap - # The `WebBootstrapper` is responsible for bootstrapping web-based projects. - # Currently, this is just setting up an NGINX configuration for the project. - class WebBootstrapper - include DSL - - # Project to run bootstrapper on - getter :project - - def initialize(project : Project) - @project = project - @mkcert = Mkcert.new - end - - # Executes the bootstrapper - def bootstrap - if mkcert.installed? - Dir.cd(Paths::PROJECT_CERTS) do - mkcert.install! - mkcert.install_cert!(project.hostname) - end - else - logw "mkcert not found. Skipping cert setup." - end - - Templates::NginxConf.new(project).write_to_config! - end - - private getter :mkcert - end -end