hodler/src/cli.cr

145 lines
3.7 KiB
Crystal

require "./models"
require "./actions"
require "./models"
module Hodler
class Cli
alias Options = {
action: Action::Type,
verbose_enable: Bool,
config_file: String
}
property config : ConfigModel?
property options : Options?
def initialize
@config = nil
@options = nil
end
def self.parse_options(args) : Options
# default values
action = Action::Type::Report
config_file = XDGBasedir.full_path("hodler/wallet.yml", :config, :read).as(String)
verbose_enable = true
# parse
OptionParser.parse(args) do |parser|
parser.banner = "Usage: #{Version::PROGRAM} [options] [commands] [arguments]"
parser.separator
parser.separator "Options"
parser.on "-c CONFIG_FILE", "--config=CONFIG_FILE", "Use the following config file" do |file|
config_file = file
end
parser.on "-v", "--verbose", "Be verbose" do
verbose_enable = !verbose_enable
end
parser.on "--version", "Show version" do
puts "version #{Version::VERSION}"
exit 0
end
parser.on "-h", "--help", "Show this help" do
puts parser
exit 0
end
parser.on "--completion", "Provide autocompletion for bash" do
# nothing here
end
complete_with Version::PROGRAM, parser
parser.separator
parser.separator "Commands"
parser.on("report", "Compute report") do
parser.banner = "Usage: #{Version::PROGRAM} list [arguments]"
action = Action::Type::Report
end
parser.on("tui", "Run ncurses interactive UI") do
parser.banner = "Usage: #{Version::PROGRAM} tui [arguments]"
action = Action::Type::TextUi
end
parser.on("web", "Run web interactive UI") do
parser.banner = "Usage: #{Version::PROGRAM} web [arguments]"
action = Action::Type::WebUi
end
parser.separator
parser.missing_option do |flag|
STDERR.puts parser
STDERR.puts "ERROR: #{flag} requires an argument.".colorize(:red)
exit(1)
end
parser.invalid_option do |flag|
STDERR.puts parser
STDERR.puts "ERROR: #{flag} is not a valid option.".colorize(:red)
exit(1)
end
parser.unknown_args do |unknown_args|
unknown_args = unknown_args - %w(report web tui)
next if unknown_args.empty?
STDERR.puts parser
STDERR.puts "ERROR: \"#{unknown_args[0]}\" is not a valid command.".colorize(:red)
exit(1)
end
end
return {
verbose_enable: verbose_enable,
config_file: config_file,
action: action
}.as(Options)
end
def self.parse_config(options)
puts "Loading configuration...".colorize(:yellow) if options[:verbose_enable]
config_file = options[:config_file]
if ! File.exists? config_file
STDERR.puts "ERROR: Unable to read configuration file '#{config_file}'".colorize(:red)
exit 1
end
yaml_str = File.read(config_file)
config = ConfigModel.from_yaml(yaml_str)
if config.nil?
STDERR.puts "ERROR: Invalid YAML content in '#{config_file}'"
exit 1
end
return config
end
def self.run(args)
app = Cli.new
options = Cli.parse_options(args)
config = Cli.parse_config(options)
app.options = options
app.config = config
portfolio = PortfolioFactory.build(options, config)
action = ActionFactory.build(options, config)
action.perform
rescue ex : YAML::ParseException
STDERR.puts "ERROR: #{ex.message}".colorize(:red)
end
end
end