Switched to docopt because all CLI things suck
This commit is contained in:
parent
bef6ded369
commit
11d7cf1f9f
@ -4,10 +4,6 @@ shards:
|
||||
git: https://github.com/sija/backtracer.cr.git
|
||||
version: 1.2.2
|
||||
|
||||
commander:
|
||||
git: https://github.com/mrrooijen/commander.git
|
||||
version: 0.4.0
|
||||
|
||||
crest:
|
||||
git: https://github.com/mamantoha/crest.git
|
||||
version: 1.3.13
|
||||
@ -20,6 +16,10 @@ shards:
|
||||
git: https://github.com/naqvis/crystar.git
|
||||
version: 0.4.0
|
||||
|
||||
docopt:
|
||||
git: https://github.com/chenkovsky/docopt.cr.git
|
||||
version: 0.2.0+git.commit.620fce4f334ff15d7321e5ecb6665ad258fe9297
|
||||
|
||||
docr:
|
||||
git: https://github.com/ralsina/docr.git
|
||||
version: 0.1.1+git.commit.18f15cc7111b1d0c63347c7cca07aee9ec87a7a8
|
||||
|
22
shard.yml
22
shard.yml
@ -15,18 +15,18 @@ crystal: ">= 1.12.2"
|
||||
license: MIT
|
||||
|
||||
dependencies:
|
||||
docr:
|
||||
github: ralsina/docr
|
||||
branch: add_exposed_ports
|
||||
commander:
|
||||
github: mrrooijen/commander
|
||||
kemal:
|
||||
github: kemalcr/kemal
|
||||
kemal-basic-auth:
|
||||
github: kemalcr/kemal-basic-auth
|
||||
crest:
|
||||
github: mamantoha/crest
|
||||
crinja:
|
||||
github: straight-shoota/crinja
|
||||
crystar:
|
||||
github: naqvis/crystar
|
||||
crest:
|
||||
github: mamantoha/crest
|
||||
docopt:
|
||||
github: chenkovsky/docopt.cr
|
||||
docr:
|
||||
github: ralsina/docr
|
||||
branch: add_exposed_ports
|
||||
kemal:
|
||||
github: kemalcr/kemal
|
||||
kemal-basic-auth:
|
||||
github: kemalcr/kemal-basic-auth
|
||||
|
85
src/faaso.cr
85
src/faaso.cr
@ -1,5 +1,4 @@
|
||||
require "./funko.cr"
|
||||
require "commander"
|
||||
require "crest"
|
||||
require "docr"
|
||||
require "docr/utils.cr"
|
||||
@ -29,19 +28,10 @@ module Faaso
|
||||
module Commands
|
||||
# Build images for one or more funkos
|
||||
class Build
|
||||
@arguments : Array(String) = [] of String
|
||||
@options : Commander::Options
|
||||
def run(options, folders : Array(String))
|
||||
funkos = Funko::Funko.from_paths(folders)
|
||||
|
||||
def initialize(options, arguments)
|
||||
@options = options
|
||||
@arguments = arguments
|
||||
end
|
||||
|
||||
def run
|
||||
funkos = Funko::Funko.from_paths(@arguments)
|
||||
local = @options.@bool["local"]
|
||||
|
||||
if local
|
||||
if options["--local"]
|
||||
funkos.each do |funko|
|
||||
# Create temporary build location
|
||||
tmp_dir = Path.new("tmp", UUID.random.to_s)
|
||||
@ -112,7 +102,7 @@ module Faaso
|
||||
# If there are no images for the funko, it will fail to bring it up.
|
||||
class Up
|
||||
@arguments : Array(String) = [] of String
|
||||
@options : Commander::Options
|
||||
@options : Hash(String, Bool)
|
||||
|
||||
def initialize(options, arguments)
|
||||
@options = options
|
||||
@ -179,64 +169,17 @@ module Faaso
|
||||
end
|
||||
|
||||
class Export
|
||||
@arguments : Array(String) = [] of String
|
||||
@options : Commander::Options
|
||||
|
||||
def initialize(options, arguments)
|
||||
@options = options
|
||||
@arguments = arguments
|
||||
end
|
||||
|
||||
def run
|
||||
funkos = Funko::Funko.from_paths(@arguments)
|
||||
funkos.each do |funko|
|
||||
# Create temporary build location
|
||||
dst_path = Path.new("export", funko.name)
|
||||
if File.exists? dst_path
|
||||
Log.error { "#{dst_path} already exists, not exporting #{funko.path}" }
|
||||
next
|
||||
end
|
||||
Log.info { "Exporting #{funko.path} to #{dst_path}" }
|
||||
Dir.mkdir_p(dst_path)
|
||||
funko.prepare_build dst_path
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class Down
|
||||
@arguments : Array(String) = [] of String
|
||||
@options : Commander::Options
|
||||
|
||||
def initialize(options, arguments)
|
||||
@options = options
|
||||
@arguments = arguments
|
||||
end
|
||||
|
||||
def run
|
||||
@arguments.each do |arg|
|
||||
Log.info { "Stopping funko... #{arg}" }
|
||||
# TODO: check if funko is running
|
||||
# TODO: stop funko container
|
||||
# TODO: delete funko container
|
||||
# TODO: remove route from reverse proxy
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class Deploy
|
||||
@arguments : Array(String) = [] of String
|
||||
@options : Commander::Options
|
||||
|
||||
def initialize(options, arguments)
|
||||
@options = options
|
||||
@arguments = arguments
|
||||
end
|
||||
|
||||
def run
|
||||
@arguments.each do |arg|
|
||||
Log.info { "Deploying funko... #{arg}" }
|
||||
# TODO: Everything
|
||||
def run(options, source : String, destination : String)
|
||||
funko = Funko::Funko.from_paths([source])[0]
|
||||
# Create temporary build location
|
||||
dst_path = destination
|
||||
if File.exists? dst_path
|
||||
Log.error { "#{dst_path} already exists, not exporting #{funko.path}" }
|
||||
return 1
|
||||
end
|
||||
Log.info { "Exporting #{funko.path} to #{dst_path}" }
|
||||
Dir.mkdir_p(dst_path)
|
||||
funko.prepare_build Path[dst_path]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
81
src/funko.cr
81
src/funko.cr
@ -25,6 +25,10 @@ module Funko
|
||||
@[YAML::Field(ignore: true)]
|
||||
property path : String = ""
|
||||
|
||||
# Scale: how many instances of this funko should be running
|
||||
@[YAML::Field(ignore: true)]
|
||||
property scale = 0
|
||||
|
||||
# Healthcheck properties
|
||||
property healthcheck_options : String = "--interval=1m --timeout=2s --start-period=2s --retries=3"
|
||||
property healthcheck_command : String = "curl --fail http://localhost:3000/ping || exit 1"
|
||||
@ -60,37 +64,31 @@ module Funko
|
||||
}
|
||||
end
|
||||
|
||||
# Create an array of funkos just from names. These are limited in function
|
||||
# and can't call `prepare_build` or some other functionality
|
||||
def self.from_names(names : Array(String)) : Array(Funko)
|
||||
names.map { |name|
|
||||
Funko.from_yaml("name: #{name}")
|
||||
# Get the number of running instances of this funko
|
||||
def scale
|
||||
docker_api = Docr::API.new(Docr::Client.new)
|
||||
docker_api.containers.list.count { |container|
|
||||
container.@name.starts_with? "faaso-#{name}-" && container.@state == "running"
|
||||
}
|
||||
end
|
||||
|
||||
# Get all the funkos docker knows about.
|
||||
def self.from_docker : Array(Funko)
|
||||
# Set the number of running instances of this funko
|
||||
def scale(new_scale : Int)
|
||||
docker_api = Docr::API.new(Docr::Client.new)
|
||||
names = [] of String
|
||||
current_scale = self.scale
|
||||
return if current_scale == new_scale
|
||||
|
||||
# Get all containers that look like funkos
|
||||
docker_api.containers.list(
|
||||
all: true,
|
||||
).each { |container|
|
||||
container.@names.each { |name|
|
||||
names << name.split("-", 2)[1].lstrip("/") if name.starts_with?("/faaso-")
|
||||
if new_scale > current_scale
|
||||
(current_scale...new_scale).each { start(create_container) }
|
||||
else
|
||||
containers.select { |contatiner| container.@state == "running" }.sort! { |i, j|
|
||||
i.@created <=> j.@created
|
||||
}.each { |container|
|
||||
docker_api.containers.stop(container.@id)
|
||||
current_scale -= 1
|
||||
break if current_scale == new_scale
|
||||
}
|
||||
}
|
||||
|
||||
# Now get all images that look like funkos, since
|
||||
# we can start them just fine.
|
||||
docker_api.images.list.each { |image|
|
||||
next if image.@repo_tags.nil?
|
||||
image.@repo_tags.as(Array(String)).each { |tag|
|
||||
names << tag.split("-", 2)[1].split(":", 2)[0] if tag.starts_with?("faaso-")
|
||||
}
|
||||
}
|
||||
from_names(names.to_set.to_a.sort!)
|
||||
end
|
||||
end
|
||||
|
||||
# Setup the target directory `path` with all the files needed
|
||||
@ -280,5 +278,38 @@ module Funko
|
||||
docker_api.containers.start(response.@id) if autostart
|
||||
response.@id
|
||||
end
|
||||
|
||||
# Create an array of funkos just from names. These are limited in function
|
||||
# and can't call `prepare_build` or some other functionality
|
||||
def self.from_names(names : Array(String)) : Array(Funko)
|
||||
names.map { |name|
|
||||
Funko.from_yaml("name: #{name}")
|
||||
}
|
||||
end
|
||||
|
||||
# Get all the funkos docker knows about.
|
||||
def self.from_docker : Array(Funko)
|
||||
docker_api = Docr::API.new(Docr::Client.new)
|
||||
names = [] of String
|
||||
|
||||
# Get all containers that look like funkos
|
||||
docker_api.containers.list(
|
||||
all: true,
|
||||
).each { |container|
|
||||
container.@names.each { |name|
|
||||
names << name.split("-", 2)[1].lstrip("/") if name.starts_with?("/faaso-")
|
||||
}
|
||||
}
|
||||
|
||||
# Now get all images that look like funkos, since
|
||||
# we can start them just fine.
|
||||
docker_api.images.list.each { |image|
|
||||
next if image.@repo_tags.nil?
|
||||
image.@repo_tags.as(Array(String)).each { |tag|
|
||||
names << tag.split("-", 2)[1].split(":", 2)[0] if tag.starts_with?("faaso-")
|
||||
}
|
||||
}
|
||||
from_names(names.to_set.to_a.sort!)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
127
src/main.cr
127
src/main.cr
@ -1,6 +1,21 @@
|
||||
require "./faaso.cr"
|
||||
require "colorize"
|
||||
require "commander"
|
||||
require "docopt"
|
||||
|
||||
doc = <<-DOC
|
||||
FaaSO CLI tool.
|
||||
|
||||
Usage:
|
||||
faaso build FOLDER ... [-l] [-v=<level>]
|
||||
faaso scale FUNKO_NAME SCALE [-l] [-v=<level>]
|
||||
faaso export SOURCE DESTINATION [-v=<level>]
|
||||
|
||||
Options:
|
||||
-h --help Show this screen.
|
||||
--version Show version.
|
||||
-l --local Run commands locally instead of against a FaaSO server.
|
||||
-v=level Control the logging verbosity, 0 to 5 [default: 3]
|
||||
DOC
|
||||
|
||||
# Log formatter for
|
||||
struct LogFormat < Log::StaticFormatter
|
||||
@ -17,19 +32,15 @@ struct LogFormat < Log::StaticFormatter
|
||||
string "[#{Time.local}] #{@entry.severity.label}: #{@entry.message}".colorize(@@colors[@entry.severity.label])
|
||||
end
|
||||
|
||||
def self.setup(quiet : Bool, verbosity)
|
||||
if quiet
|
||||
_verbosity = Log::Severity::Fatal
|
||||
else
|
||||
_verbosity = [
|
||||
Log::Severity::Fatal,
|
||||
Log::Severity::Error,
|
||||
Log::Severity::Warn,
|
||||
Log::Severity::Info,
|
||||
Log::Severity::Debug,
|
||||
Log::Severity::Trace,
|
||||
][[verbosity, 5].min]
|
||||
end
|
||||
def self.setup(verbosity)
|
||||
_verbosity = [
|
||||
Log::Severity::Fatal,
|
||||
Log::Severity::Error,
|
||||
Log::Severity::Warn,
|
||||
Log::Severity::Info,
|
||||
Log::Severity::Debug,
|
||||
Log::Severity::Trace,
|
||||
][[verbosity, 5].min]
|
||||
Log.setup(
|
||||
_verbosity,
|
||||
Log::IOBackend.new(io: STDERR, formatter: LogFormat)
|
||||
@ -37,86 +48,12 @@ struct LogFormat < Log::StaticFormatter
|
||||
end
|
||||
end
|
||||
|
||||
cli = Commander::Command.new do |cmd|
|
||||
cmd.use = "faaso"
|
||||
cmd.long = "Functions as a Service, Open"
|
||||
ans = Docopt.docopt(doc, ARGV)
|
||||
LogFormat.setup(ans["-v"].to_s.to_i)
|
||||
|
||||
cmd.flags.add do |flag|
|
||||
flag.name = "local"
|
||||
flag.short = "-l"
|
||||
flag.long = "--local"
|
||||
flag.description = "Run commands locally instead of against a FaaSO server."
|
||||
flag.default = false
|
||||
flag.persistent = true
|
||||
end
|
||||
|
||||
cmd.flags.add do |flag|
|
||||
flag.name = "quiet"
|
||||
flag.short = "-q"
|
||||
flag.long = "--quiet"
|
||||
flag.description = "Don't log anything"
|
||||
flag.default = false
|
||||
flag.persistent = true
|
||||
end
|
||||
|
||||
cmd.flags.add do |flag|
|
||||
flag.name = "verbosity"
|
||||
flag.short = "-v"
|
||||
flag.long = "--verbosity"
|
||||
flag.description = "Control the logging verbosity, 0 to 5 "
|
||||
flag.default = 3
|
||||
flag.persistent = true
|
||||
end
|
||||
|
||||
cmd.commands.add do |command|
|
||||
command.use = "build"
|
||||
command.short = "Build a funko"
|
||||
command.long = "Build a funko's Docker image and upload it to registry"
|
||||
command.run do |options, arguments|
|
||||
LogFormat.setup(options.@bool["quiet"], options.@int["verbosity"])
|
||||
Faaso::Commands::Build.new(options, arguments).run
|
||||
end
|
||||
end
|
||||
|
||||
cmd.commands.add do |command|
|
||||
command.use = "up"
|
||||
command.short = "Ensure funkos are running"
|
||||
command.long = "Start/unpause/create containers for requested funkos and ensure they are up."
|
||||
command.run do |options, arguments|
|
||||
LogFormat.setup(options.@bool["quiet"], options.@int["verbosity"])
|
||||
Faaso::Commands::Up.new(options, arguments).run
|
||||
end
|
||||
end
|
||||
|
||||
cmd.commands.add do |command|
|
||||
command.use = "deploy"
|
||||
command.short = "Deploy latest images"
|
||||
command.long = "Update containers for all funkos to latest image."
|
||||
command.run do |options, arguments|
|
||||
LogFormat.setup(options.@bool["quiet"], options.@int["verbosity"])
|
||||
Faaso::Commands::Deploy.new(options, arguments).run
|
||||
end
|
||||
end
|
||||
|
||||
cmd.commands.add do |command|
|
||||
command.use = "down"
|
||||
command.short = "Stop a funko"
|
||||
command.long = "Stop a funko in a container"
|
||||
command.run do |options, arguments|
|
||||
LogFormat.setup(options.@bool["quiet"], options.@int["verbosity"])
|
||||
Faaso::Commands::Down.new(options, arguments).run
|
||||
end
|
||||
end
|
||||
|
||||
cmd.commands.add do |command|
|
||||
command.use = "export"
|
||||
command.short = "Export a funko to a directory"
|
||||
command.long = "Exports a funko as a self-contained directory."
|
||||
command.run do |options, arguments|
|
||||
LogFormat.setup(options.@bool["quiet"], options.@int["verbosity"])
|
||||
Faaso::Commands::Export.new(options, arguments).run
|
||||
end
|
||||
end
|
||||
case ans
|
||||
when .fetch("build", false)
|
||||
Faaso::Commands::Build.new.run(ans, ans["FOLDER"].as(Array(String)))
|
||||
when .fetch("export", false)
|
||||
Faaso::Commands::Export.new.run(ans, ans["SOURCE"].as(String), ans["DESTINATION"].as(String))
|
||||
end
|
||||
|
||||
Commander.run(cli, ARGV)
|
||||
|
Loading…
Reference in New Issue
Block a user