From bdeb23c2751d4163bcbac4f034002356ceaf1dfd Mon Sep 17 00:00:00 2001 From: Luka Vandervelden Date: Thu, 24 Oct 2019 20:31:38 +0200 Subject: [PATCH] Better handling of commands. --- src/service.cr | 308 +++++++++++++++++++++++++++---------------------- 1 file changed, 171 insertions(+), 137 deletions(-) diff --git a/src/service.cr b/src/service.cr index 006443c..1c2a568 100644 --- a/src/service.cr +++ b/src/service.cr @@ -13,17 +13,6 @@ args = [] of String parser = OptionParser.parse do |parser| parser.banner = "usage: service [options]\n" + - "\n" + - "commands:\n" + - " start Starts a stopped or dead service.\n" + - " stop Stops a running service.\n" + - " status Shows the current state of a service.\n" + - " show Describe a service in detail.\n" + - " add Add a service to an environment.\n" + - " del Remove a service from an environment.\n" + - " add-environment Creates a new, empty environment.\n" + - " list-environments Lists registered environments.\n" + - "\n" + "options:\n" parser.on "-h", "--help", "Prints this help message." do @@ -35,9 +24,177 @@ parser = OptionParser.parse do |parser| end end -command = args[0]? +alias Command = Proc(Array(String), Nil) +alias CommandTuple = Tuple(String, String, Command) +class CommandsList + def initialize + @commands = Array(CommandTuple).new + end + + def push(name : String, description : String, &proc : Command) + @commands << Tuple.new(name, description, proc) + end + + def find(&block : Proc(CommandTuple, Bool)) + @commands.find do |tuple| + if block.call tuple + next true + end + end + end + + def to_s + "commands:\n\n"+ @commands.map do |tuple| + " %-32s %s" % [tuple[0], tuple[1]] + end.join "\n" + end +end +commands = CommandsList.new + +commands.push "add", "Adds a service to an environment." do |args| + providers = Hash(String, String).new + + environment, service = Service.parse_id args[0] + + args.each_with_index do |arg, i| + next if i == 0 + + match = arg.match /(.*)=(.*)/ + + if match.nil? + raise ::Service::Exception.new "usage: service add " + next + end + + providers[match[1]] = match[2] + end + + Service.new(service, environment).tap do |service| + service.consumes.each do |token| + provider = providers[token.token]? + + if provider.nil? + provider = service.get_default_provider token.token + end + + if provider.nil? + STDERR.puts "This service consumes a “#{token.token}” token, but you have not specified what other service is supposed to provide it." + STDERR.puts "Use the `service add #{args[1]} #{token.token}=` syntax to specify it." + exit 1 + end + + service.providers[token.token] = provider + end + pp! service.providers + end.write RC_DIRECTORY +end + +commands.push "del", "Removes a service from an environment." do |args| + Service.new(args[0], args[1]?).remove RC_DIRECTORY +end + +commands.push "start", "Starts a service." do + services = args.map do |arg| + service = Service.get_by_id(arg) + + unless service + raise Service::Exception.new "Service '#{arg}' does not exist." + end + + service + end + + services.each do |service| + service.dependency_tree.flatten.reverse.each do |service| + next if service.running? PID_DIRECTORY + + puts "starting #{service.to_s}" + service.start PID_DIRECTORY, LOG_DIRECTORY + end + end +end + +commands.push "stop", "Stops a running service." do |args| + services = args.map do |arg| + service = Service.get_by_id(arg) + + unless service + raise Service::Exception.new "Service '#{arg}' does not exist." + end + + service + end + + services.each do |service| + # FIXME: Build revdep tree and stop services started as dependencies? + next if ! service.running? PID_DIRECTORY + # FIXME: Should we remove duplicate services from the + # tree once flattened? + service.reverse_dependency_tree.flatten.reverse.each do |service| + next if ! service.running? PID_DIRECTORY + + puts "stopping #{service.to_s}" + service.stop PID_DIRECTORY + end + end +end + +commands.push "status", "Prints the status of services." do |args| + child = Process.run "#{OWN_LIBEXEC_DIR}/status", args, + output: Process::Redirect::Inherit, + error: Process::Redirect::Inherit + return_value = (child.exit_status / 256).to_i + + # Errors not registered here should probably be verbose in `status`. + if return_value == 1 + STDERR << "No such service.\n" + end + + exit return_value +end + +commands.push "show", "Shows a service's configuration and state." do |args| + service = Service.all.find do |service| + unless service.name == args[0] + next false + end + + env = args[1]? || "root" + if service.environment.name != env + next false + end + + true + end + if service + puts service.summary + else + STDERR << "No such service is registered.\n" + exit 2 + end +end + +commands.push "add-environment", "Creates a new (empty) environment." do |arg| + Environment.new(args[9]).write ENVIRONMENTS_DIRECTORY +end + +commands.push "list-environments", "Lists all currently defined environments.s", do |arg| + Environment.all.map do |env| + puts env.to_s + end +end + +commands.push "help", "Prints this help message." do + puts parser + puts + puts commands.to_s +end + +command = commands.find &.[0].==(args[0]?) if command.nil? STDERR << parser << "\n" + STDERR << "\n" + STDERR << commands.to_s << "\n" exit 1 end @@ -46,131 +203,8 @@ Environment.load ENVIRONMENTS_DIRECTORY Service.load RC_DIRECTORY begin - if args[0] == "help" - puts parser - elsif args[0] == "add" - providers = Hash(String, String).new - - environment, service = Service.parse_id args[1] - - args.shift - args.each_with_index do |arg, i| - next if i == 0 - - match = arg.match /(.*)=(.*)/ - - if match.nil? - raise ::Service::Exception.new "usage: service add " - next - end - - providers[match[1]] = match[2] - end - - Service.new(service, environment).tap do |service| - service.consumes.each do |token| - provider = providers[token.token]? - - if provider.nil? - provider = service.get_default_provider token.token - end - - if provider.nil? - STDERR.puts "This service consumes a “#{token.token}” token, but you have not specified what other service is supposed to provide it." - STDERR.puts "Use the `service add #{args[1]} #{token.token}=` syntax to specify it." - exit 1 - end - - service.providers[token.token] = provider - end - pp! service.providers - end.write RC_DIRECTORY - elsif args[0] == "del" - Service.new(args[1], args[2]?).remove RC_DIRECTORY - elsif args[0] == "start" - services = args[1..args.size].map do |arg| - service = Service.get_by_id(arg) - - unless service - raise Service::Exception.new "Service '#{arg}' does not exist." - end - - service - end - - services.each do |service| - service.dependency_tree.flatten.reverse.each do |service| - next if service.running? PID_DIRECTORY - - puts "starting #{service.to_s}" - service.start PID_DIRECTORY, LOG_DIRECTORY - end - end - elsif args[0] == "stop" - services = args[1..args.size].map do |arg| - service = Service.get_by_id(arg) - - unless service - raise Service::Exception.new "Service '#{arg}' does not exist." - end - - service - end - - services.each do |service| - # FIXME: Build revdep tree and stop services started as dependencies? - next if ! service.running? PID_DIRECTORY - # FIXME: Should we remove duplicate services from the - # tree once flattened? - service.reverse_dependency_tree.flatten.reverse.each do |service| - next if ! service.running? PID_DIRECTORY - - puts "stopping #{service.to_s}" - service.stop PID_DIRECTORY - end - end - elsif args[0] == "status" - args.shift - child = Process.run "#{OWN_LIBEXEC_DIR}/status", args, - output: Process::Redirect::Inherit, - error: Process::Redirect::Inherit - return_value = (child.exit_status / 256).to_i - - # Errors not registered here should probably be verbose in `status`. - if return_value == 1 - STDERR << "No such service.\n" - end - - exit return_value - elsif args[0] == "show" - service = Service.all.find do |service| - unless service.name == args[1] - next false - end - - env = args[2]? || "root" - if service.environment.name != env - next false - end - - true - end - if service - puts service.summary - else - STDERR << "No such service is registered.\n" - exit 2 - end - elsif args[0] == "add-environment" - Environment.new(args[1]).write ENVIRONMENTS_DIRECTORY - elsif args[0] == "list-environments" - Environment.all.map do |env| - puts env.to_s - end - else - STDERR << parser << "\n" - exit 1 - end + args.shift + command.[2].call(args) rescue e : Service::Exception STDERR << e.message << "\n" exit 2