Skip to content

Instantly share code, notes, and snippets.

@augustine-tran
Created September 21, 2024 04:45
Show Gist options
  • Save augustine-tran/5f049940a9478620eb351125b21931f5 to your computer and use it in GitHub Desktop.
Save augustine-tran/5f049940a9478620eb351125b21931f5 to your computer and use it in GitHub Desktop.
#!/usr/bin/env ruby
require 'fileutils'
require 'optparse'
# Helper function to prompt for user confirmation
def ask_override(message)
puts "#{message} (y/n):"
answer = gets.chomp.downcase
answer == 'y'
end
# Function to get input for project name and port
def get_project_details(options)
project_name = options[:project_name]
port = options[:port]
if project_name.nil? || project_name.strip.empty?
puts "Enter project name (e.g. shelob):"
project_name = gets.chomp
end
if port.nil? || port.strip.empty?
puts "Enter port number (e.g. 3000):"
port = gets.chomp
end
{ project_name: project_name, port: port }
end
# Function to update /etc/hosts idempotently, with option to override
def update_hosts_file(project_name, dry_run)
hosts_entry = "127.0.0.1 #{project_name}.test"
hosts_file = "/etc/hosts"
if File.read(hosts_file).include?(hosts_entry)
puts "/etc/hosts already contains entry for #{project_name}.test"
if ask_override("Do you want to override the /etc/hosts entry?")
unless dry_run
system("sudo sed -i '' '/#{project_name}.test/d' #{hosts_file}")
system("sudo sh -c 'echo \"#{hosts_entry}\" >> /etc/hosts'")
puts "Overwritten /etc/hosts entry with #{hosts_entry}"
else
puts "[Dry-run] Would overwrite /etc/hosts entry with #{hosts_entry}"
end
else
puts "Skipping /etc/hosts update."
end
else
if dry_run
puts "[Dry-run] Would append '#{hosts_entry}' to /etc/hosts"
else
system("sudo sh -c 'echo \"#{hosts_entry}\" >> /etc/hosts'")
puts "Updated /etc/hosts with #{hosts_entry}"
end
end
end
# Function to generate SSL certificates idempotently, with option to override
def generate_ssl_certificates(project_name, dry_run)
cert_dir = "/opt/caddy/certs"
cert_file = "#{cert_dir}/#{project_name}.test+1.pem"
key_file = "#{cert_dir}/#{project_name}.test+1-key.pem"
if File.exist?(cert_file) && File.exist?(key_file)
puts "SSL certificates for #{project_name}.test already exist."
if ask_override("Do you want to regenerate the SSL certificates?")
unless dry_run
system("rm -f #{cert_file} #{key_file}")
system("mkcert -cert-file #{cert_file} -key-file #{key_file} #{project_name}.test")
puts "Overwritten SSL certificates for #{project_name}.test"
else
puts "[Dry-run] Would overwrite SSL certificates for #{project_name}.test"
end
else
puts "Skipping SSL certificate generation."
end
else
if dry_run
puts "[Dry-run] Would generate SSL certificates for #{project_name}.test"
else
FileUtils.mkdir_p(cert_dir) unless File.directory?(cert_dir)
system("mkcert -cert-file #{cert_file} -key-file #{key_file} #{project_name}.test")
puts "Generated SSL certificates for #{project_name}.test and stored in #{cert_dir}"
end
end
end
# Function to update Caddyfile idempotently, with option to override
def update_caddyfile(project_name, port, dry_run)
caddyfile = "/opt/homebrew/etc/Caddyfile"
caddy_block = <<-CADDY
#{project_name}.test {
tls /opt/caddy/certs/#{project_name}.test+1.pem /opt/caddy/certs/#{project_name}.test+1-key.pem
reverse_proxy 127.0.0.1:#{port} {
header_up Host {host}
header_up Origin {scheme}://{host}
header_up X-Real-IP {remote}
header_up X-Forwarded-Host {host}
header_up X-Forwarded-Server {host}
header_up X-Forwarded-Port {port}
header_up X-Forwarded-For {remote}
header_up X-Forwarded-Proto {scheme}
}
}
CADDY
if File.exist?(caddyfile) && File.read(caddyfile).include?("#{project_name}.test")
puts "Caddyfile already contains entry for #{project_name}.test."
if ask_override("Do you want to overwrite the Caddy configuration for #{project_name}.test?")
unless dry_run
system("sed -i '' '/#{project_name}.test/,+12d' #{caddyfile}")
File.open(caddyfile, "a") { |f| f.puts caddy_block }
puts "Overwritten Caddy configuration for #{project_name}.test on port #{port}."
else
puts "[Dry-run] Would overwrite Caddy configuration for #{project_name}.test on port #{port}."
end
else
puts "Skipping Caddyfile update."
end
else
if dry_run
puts "[Dry-run] Would append Caddy configuration for #{project_name}.test on port #{port}"
else
File.open(caddyfile, "a") { |f| f.puts caddy_block }
puts "Appended Caddy configuration for #{project_name}.test on port #{port}."
end
end
end
# Main script logic
def main
# Parse options for project name, port, and dry-run mode
options = {}
OptionParser.new do |opts|
opts.banner = "Usage: setup_local_domain.rb [options]"
opts.on("--project-name NAME", "Project name (e.g., shelob)") do |name|
options[:project_name] = name
end
opts.on("--port PORT", "Port number (e.g., 3000)") do |port|
options[:port] = port
end
opts.on("--dry-run", "Run script in dry-run mode (no changes will be made)") do
options[:dry_run] = true
end
end.parse!
# Get project details from command line or prompt for them
project_details = get_project_details(options)
project_name = project_details[:project_name]
port = project_details[:port]
dry_run = options[:dry_run] || false
# Run the script with or without dry-run
update_hosts_file(project_name, dry_run)
generate_ssl_certificates(project_name, dry_run)
update_caddyfile(project_name, port, dry_run)
if dry_run
puts "Dry-run complete for #{project_name}.test on port #{port}. No changes were made."
else
puts "Setup complete for #{project_name}.test on port #{port}."
end
end
main if __FILE__ == $PROGRAM_NAME
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment