117 lines
3.8 KiB
Ruby
117 lines
3.8 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
module FeatherCaseWizard
|
|
class CLI
|
|
def initialize(ui: HighLine.new, cases_root: CASES_ROOT,
|
|
model_source: MODEL_SOURCE, renderer_source: RENDERER_SOURCE,
|
|
toolchain: Toolchain.new)
|
|
@ui = ui
|
|
@cases_root = Pathname(cases_root)
|
|
@model_source = Pathname(model_source)
|
|
@renderer_source = Pathname(renderer_source)
|
|
@toolchain = toolchain
|
|
@wizard = Wizard.new(ui: ui)
|
|
end
|
|
|
|
def run
|
|
@ui.say(@ui.color("Feather Case Wizard", :bold))
|
|
loop do
|
|
action = @ui.choose("\nWhat would you like to do?") do |menu|
|
|
menu.choice("Create a new case") { :create }
|
|
menu.choice("Edit an existing case") { :edit }
|
|
menu.choice("Rebuild an existing case") { :rebuild }
|
|
menu.choice("Exit") { :exit }
|
|
end
|
|
return 0 if action == :exit
|
|
|
|
case action
|
|
when :create then create_case
|
|
when :edit then edit_case
|
|
when :rebuild then rebuild_case
|
|
end
|
|
rescue ConfigError, ToolError, Errno::EACCES => e
|
|
@ui.say(@ui.color("\n#{e.message}", :red))
|
|
rescue Interrupt
|
|
@ui.say("\nCancelled.")
|
|
return 130
|
|
end
|
|
end
|
|
|
|
private
|
|
|
|
def create_case
|
|
config = @wizard.create
|
|
destination = config.package_dir(@cases_root)
|
|
if destination.exist? &&
|
|
!@ui.agree("#{destination} already exists. Replace it? (y/n) ") { |q| q.default = "no" }
|
|
return
|
|
end
|
|
build(config, @model_source, @renderer_source) if @wizard.confirm_build(config)
|
|
end
|
|
|
|
def edit_case
|
|
path = choose_case
|
|
return unless path
|
|
|
|
config = Config.load(path)
|
|
package = path.dirname
|
|
source = package.join("source/feather_case.scad")
|
|
renderer = package.join("source/render_stl_previews.py")
|
|
source, renderer = choose_generator(config, source, renderer)
|
|
config = @wizard.edit(config)
|
|
build(config, source, renderer) if @wizard.confirm_build(config)
|
|
end
|
|
|
|
def rebuild_case
|
|
path = choose_case
|
|
return unless path
|
|
|
|
config = Config.load(path)
|
|
return unless @wizard.confirm_build(config)
|
|
|
|
package = path.dirname
|
|
build(config, package.join("source/feather_case.scad"),
|
|
package.join("source/render_stl_previews.py"))
|
|
end
|
|
|
|
def choose_case
|
|
paths = Dir.glob(@cases_root.join("*/case.yml")).sort.map { |item| Pathname(item) }
|
|
if paths.empty?
|
|
@ui.say("No saved cases found under #{@cases_root}.")
|
|
return nil
|
|
end
|
|
@ui.choose("Choose a saved case") do |menu|
|
|
paths.each do |path|
|
|
label = Config.load(path).name
|
|
menu.choice("#{label} (#{path.dirname.basename})") { path }
|
|
rescue ConfigError
|
|
menu.choice("Invalid configuration (#{path.dirname.basename})") { path }
|
|
end
|
|
end
|
|
end
|
|
|
|
def choose_generator(config, snapshot, renderer)
|
|
return [@model_source, @renderer_source] unless snapshot.file?
|
|
|
|
snapshot_sha = Digest::SHA256.file(snapshot).hexdigest
|
|
current_sha = Digest::SHA256.file(@model_source).hexdigest
|
|
return [snapshot, renderer] if snapshot_sha == current_sha
|
|
|
|
@ui.say("This case uses a different generator snapshot.")
|
|
upgrade = @ui.agree("Upgrade it to the current generator? (y/n) ") do |question|
|
|
question.default = "no"
|
|
end
|
|
upgrade ? [@model_source, @renderer_source] : [snapshot, renderer]
|
|
end
|
|
|
|
def build(config, source, renderer)
|
|
destination = PackageBuilder.new(
|
|
config, root: @cases_root, toolchain: @toolchain,
|
|
model_source: source, renderer_source: renderer,
|
|
reporter: ->(message) { @ui.say(" #{message}…") }
|
|
).build!
|
|
@ui.say(@ui.color("\nGenerated #{destination}", :green))
|
|
end
|
|
end
|
|
end
|