WIP: feat: add scaffold for operations (command design pattern) #31

Closed
glenux wants to merge 17 commits from feature/1-add-support-for-fs-crud into develop
20 changed files with 142 additions and 51 deletions

View file

@ -8,15 +8,20 @@
# List of patterns to ignore during preloading # List of patterns to ignore during preloading
ignore_list: ignore_list:
- ^\.git/
- ^lib.*
- ^doc/
- ^bin/ - ^bin/
- ^\.code_preloader.yml
- ^doc/
- ^\.drone.yml
- ^\.git/
- ^\.gitattributes
- ^\.gitignore
- ^lib.*
- ^LICENSES/
- ^_prompts/ - ^_prompts/
- ^\.reuse/ - ^\.reuse/
- ^LICENSES/
- ^\.vagrant/
- ^scripts/ - ^scripts/
- ^\.tool-versions
- ^\.vagrant/
# Path to the output file (if null, output to STDOUT) # Path to the output file (if null, output to STDOUT)
output_path: null output_path: null

View file

@ -6,6 +6,9 @@ module GX::Commands
end end
def execute def execute
puts "FIXME: detect if config is present"
puts "FIXME: compute config path (either default, or from command line)"
puts "FIXME: create config file from default if needed"
end end
def self.handles_mode def self.handles_mode

View file

@ -6,10 +6,12 @@ module GX::Commands
end end
def execute def execute
puts "FIXME: detect option (either zsh or bash)"
puts "FIXME: output the right file from embedded data"
end end
def self.handles_mode def self.handles_mode
GX::Types::Mode::GlobalConfig GX::Types::Mode::GlobalCompletion
end end
end end
end end

View file

@ -2,7 +2,7 @@ require "./abstract_command"
module GX::Commands module GX::Commands
class GlobalConfig < AbstractCommand class GlobalConfig < AbstractCommand
def initialize(config : GX::Config) # FIXME def initialize(config : GX::Config)
end end
def execute def execute

View file

@ -2,7 +2,7 @@ require "./abstract_command"
module GX::Commands module GX::Commands
class GlobalHelp < AbstractCommand class GlobalHelp < AbstractCommand
def initialize(@config : GX::Config) # FIXME def initialize(@config : GX::Config)
end end
def execute def execute

View file

@ -5,7 +5,7 @@ module GX::Commands
class MappingMount < AbstractCommand class MappingMount < AbstractCommand
@file_system_manager : FileSystemManager @file_system_manager : FileSystemManager
def initialize(@config : GX::Config) # FIXME def initialize(@config : GX::Config)
@config.load_from_env @config.load_from_env
@config.load_from_file @config.load_from_file
@file_system_manager = FileSystemManager.new(@config) @file_system_manager = FileSystemManager.new(@config)

View file

@ -5,7 +5,7 @@ module GX::Commands
class MappingUmount < AbstractCommand class MappingUmount < AbstractCommand
@file_system_manager : FileSystemManager @file_system_manager : FileSystemManager
def initialize(@config : GX::Config) # FIXME def initialize(@config : GX::Config)
@config.load_from_env @config.load_from_env
@config.load_from_file @config.load_from_file
@file_system_manager = FileSystemManager.new(@config) @file_system_manager = FileSystemManager.new(@config)

View file

@ -89,7 +89,9 @@ module GX
end end
def choose_filesystem def choose_filesystem
names_display = {} of String => NamedTuple(filesystem: Models::AbstractFilesystemConfig, ansi_name: String) names_display = {} of String => NamedTuple(
filesystem: Models::AbstractFilesystemConfig,
ansi_name: String)
config_root = @config.root config_root = @config.root
return if config_root.nil? return if config_root.nil?
@ -114,16 +116,16 @@ module GX
end end
# # FIXME: feat: allow to sort by name or by filesystem # # FIXME: feat: allow to sort by name or by filesystem
sorted_values = names_display.values.sort_by { |item| item[:filesystem].name } sorted_values = names_display.values.sort_by!(&.[:filesystem].name)
result_filesystem_name = Utils::Fzf.run(sorted_values.map(&.[:ansi_name])).strip result_filesystem_name = Utils::Fzf.run(sorted_values.map(&.[:ansi_name])).strip
selected_filesystem = names_display[result_filesystem_name][:filesystem] selected_filesystem = names_display[result_filesystem_name][:filesystem]
puts ">> #{selected_filesystem.name}".colorize(:yellow) puts ">> #{selected_filesystem.name}".colorize(:yellow)
if !selected_filesystem if !selected_filesystem
STDERR.puts "Vault not found: #{selected_filesystem}.".colorize(:red) STDERR.puts "Mapping not found: #{selected_filesystem}.".colorize(:red)
return return
end end
return selected_filesystem selected_filesystem
end end
private def generate_display_name(filesystem : Models::AbstractFilesystemConfig) : String private def generate_display_name(filesystem : Models::AbstractFilesystemConfig) : String
@ -136,7 +138,7 @@ module GX
if ENV["DISPLAY"]? || ENV["WAYLAND_DISPLAY"]? if ENV["DISPLAY"]? || ENV["WAYLAND_DISPLAY"]?
return true return true
end end
return false false
end end
end end
end end

View file

@ -31,7 +31,7 @@ module GX::Models::Concerns
end end
end end
def _mount_wrapper(&block) : Nil def _mount_wrapper(&) : Nil
mount_point_safe = mount_point mount_point_safe = mount_point
return if mount_point_safe.nil? return if mount_point_safe.nil?
@ -46,7 +46,7 @@ module GX::Models::Concerns
if result_status.success? if result_status.success?
puts "Models #{name} is now available on #{mount_point_safe}".colorize(:green) puts "Models #{name} is now available on #{mount_point_safe}".colorize(:green)
else else
puts "Error mounting the vault".colorize(:red) puts "Error mounting the mapping".colorize(:red)
return return
end end
end end

View file

@ -32,7 +32,7 @@ module GX::Models
output: STDOUT, output: STDOUT,
error: STDERR error: STDERR
) )
return process.wait process.wait
end end
end end
end end

View file

@ -32,7 +32,7 @@ module GX::Models
output: STDOUT, output: STDOUT,
error: STDERR error: STDERR
) )
return process.wait process.wait
end end
end end
end end

View file

@ -39,7 +39,7 @@ module GX::Models
output: STDOUT, output: STDOUT,
error: STDERR error: STDERR
) )
return process.wait process.wait
end end
end end
end end

View file

@ -12,11 +12,11 @@ module GX::Parsers
) )
parser.separator("\nCompletion commands:") parser.separator("\nCompletion commands:")
parser.on("--bash", "Generate bash completion") do |flag| parser.on("--bash", "Generate bash completion") do |_|
Log.info { "Set bash completion" } Log.info { "Set bash completion" }
end end
parser.on("--zsh", "Generate zsh completion") do |flag| parser.on("--zsh", "Generate zsh completion") do |_|
Log.info { "Set zsh completion" } Log.info { "Set zsh completion" }
end end

View file

@ -23,7 +23,7 @@ module GX::Parsers
parser.banner = Utils.usage_line(breadcrumbs + "init", "Create initial mfm configuration") parser.banner = Utils.usage_line(breadcrumbs + "init", "Create initial mfm configuration")
parser.separator("\nInit options") parser.separator("\nInit options")
parser.on("-p", "--path", "Set vault encrypted path") do |path| parser.on("-p", "--path", "Set mapping encrypted path") do |path|
config.config_init_options.try do |opts| config.config_init_options.try do |opts|
opts.path = path opts.path = path
end end

View file

@ -5,8 +5,10 @@ module GX::Parsers
class MappingParser < AbstractParser class MappingParser < AbstractParser
def build(parser, ancestors, config) def build(parser, ancestors, config)
breadcrumbs = ancestors + "mapping" breadcrumbs = ancestors + "mapping"
add_args = {name: "", path: ""} create_args = {name: "", path: ""}
delete_args = {name: ""} delete_args = {name: ""}
mount_args = {name: ""}
umount_args = {name: ""}
parser.banner = Utils.usage_line( parser.banner = Utils.usage_line(
breadcrumbs, breadcrumbs,
@ -23,45 +25,90 @@ module GX::Parsers
parser.on("create", "Create mapping") do parser.on("create", "Create mapping") do
config.mode = Types::Mode::MappingCreate config.mode = Types::Mode::MappingCreate
# pp parser
pp parser
parser.banner = Utils.usage_line(breadcrumbs + "create", "Create mapping", true) parser.banner = Utils.usage_line(breadcrumbs + "create", "Create mapping", true)
parser.separator("\nCreate options") parser.separator("\nCreate options")
parser.on("-n", "--name", "Set vault name") do |name| parser.on("-t", "--type TYPE", "Set filesystem type") do |type|
add_args = add_args.merge({name: name}) create_args = create_args.merge({type: type})
end end
parser.on("-p", "--path", "Set vault encrypted path") do |path| parser.on("-n", "--name", "Set mapping name") do |name|
add_args = add_args.merge({path: path}) create_args = create_args.merge({name: name})
end end
# Filesystem specific
parser.on("--encrypted-path PATH", "Set encrypted path (for gocryptfs)") do |path|
encrypted_path = path
end
parser.on("--remote-user USER", "Set SSH user (for sshfs)") do |user|
create_args = create_args.merge({remote_user: user})
end
parser.on("--remote-host HOST", "Set SSH host (for sshfs)") do |host|
create_args = create_args.merge({remote_host: host})
end
parser.on("--source-path PATH", "Set remote path (for sshfs)") do |path|
create_args = create_args.merge({remote_path: path})
end
parser.on("--remote-port PORT", "Set SSH port (for sshfs)") do |port|
create_args = create_args.merge({remote_port: port})
end
parser.on("--url URL", "Set URL (for httpdirfs)") do |url|
create_args = create_args.merge({url: url})
end
parser.separator(Utils.help_line(breadcrumbs + "create")) parser.separator(Utils.help_line(breadcrumbs + "create"))
end end
parser.on("edit", "Edit configuration") do |flag| parser.on("edit", "Edit configuration") do |_|
config.mode = Types::Mode::MappingEdit config.mode = Types::Mode::MappingEdit
parser.on("--remote-user USER", "Set SSH user") do |user|
create_args = create_args.merge({remote_user: user})
end
parser.on("--remote-host HOST", "Set SSH host") do |host|
create_args = create_args.merge({remote_host: host})
end
parser.on("--source-path PATH", "Set remote path") do |path|
create_args = create_args.merge({remote_path: path})
end
parser.separator(Utils.help_line(breadcrumbs + "edit")) parser.separator(Utils.help_line(breadcrumbs + "edit"))
# abort("FIXME: Not implemented") # abort("FIXME: Not implemented")
end end
parser.on("mount", "Mount mapping") do |flag| parser.on("mount", "Mount mapping") do |_|
config.mode = Types::Mode::MappingMount config.mode = Types::Mode::MappingMount
parser.banner = Utils.usage_line(breadcrumbs + "mount", "mount mapping", true)
parser.separator("\nMount options")
parser.on("-n", "--name", "Set mapping name") do |name|
mount_args = mount_args.merge({name: name})
end
parser.separator(Utils.help_line(breadcrumbs + "mount")) parser.separator(Utils.help_line(breadcrumbs + "mount"))
# abort("FIXME: Not implemented")
end end
parser.on("umount", "Umount mapping") do |flag| parser.on("umount", "Umount mapping") do |_|
config.mode = Types::Mode::MappingUmount config.mode = Types::Mode::MappingUmount
parser.banner = Utils.usage_line(breadcrumbs + "umount", "umount mapping", true)
parser.separator("\nUmount options")
parser.on("-n", "--name", "Set mapping name") do |name|
umount_args = umount_args.merge({name: name})
end
parser.separator(Utils.help_line(breadcrumbs + "umount")) parser.separator(Utils.help_line(breadcrumbs + "umount"))
# abort("FIXME: Not implemented")
end end
parser.on("delete", "Delete mapping") do parser.on("delete", "Delete mapping") do
config.mode = Types::Mode::MappingDelete config.mode = Types::Mode::MappingDelete
parser.banner = Utils.usage_line(breadcrumbs + "delete", "Delete mapping", true) parser.banner = Utils.usage_line(breadcrumbs + "delete", "delete mapping", true)
parser.separator("\nDelete options") parser.separator("\ndelete options")
parser.on("-n", "--name", "Set vault name") do |name| parser.on("-n", "--name", "Set mapping name") do |name|
delete_args = delete_args.merge({name: name}) delete_args = delete_args.merge({name: name})
end end
parser.separator(Utils.help_line(breadcrumbs + "delete")) parser.separator(Utils.help_line(breadcrumbs + "delete"))

View file

@ -21,24 +21,24 @@ module GX::Parsers
config.path = path config.path = path
end end
parser.on("-v", "--verbose", "Set more verbosity") do |flag| parser.on("-v", "--verbose", "Set more verbosity") do |_|
Log.info { "Verbosity enabled" } Log.info { "Verbosity enabled" }
config.verbose = true config.verbose = true
end end
parser.on("-o", "--open", "Automatically open directory after mount") do |flag| parser.on("-o", "--open", "Automatically open directory after mount") do |_|
Log.info { "Auto-open enabled" } Log.info { "Auto-open enabled" }
config.auto_open = true config.auto_open = true
end end
parser.on("--version", "Show version") do |flag| parser.on("--version", "Show version") do |_|
config.mode = Types::Mode::GlobalVersion config.mode = Types::Mode::GlobalVersion
end end
parser.on("-h", "--help", "Show this help") do |flag| parser.on("-h", "--help", "Show this help") do |_|
config.mode = Types::Mode::GlobalHelp config.mode = Types::Mode::GlobalHelp
config.help_options = Parsers::Options::HelpOptions.new config.help_options = Parsers::Options::HelpOptions.new
config.help_options.try { |opts| opts.parser_snapshot = parser.dup } config.help_options.try(&.parser_snapshot=(parser.dup))
end end
parser.separator("\nGlobal commands:") parser.separator("\nGlobal commands:")
@ -46,7 +46,7 @@ module GX::Parsers
parser.on("config", "Manage configuration file") do parser.on("config", "Manage configuration file") do
config.mode = Types::Mode::GlobalHelp config.mode = Types::Mode::GlobalHelp
config.help_options = Parsers::Options::HelpOptions.new config.help_options = Parsers::Options::HelpOptions.new
config.help_options.try { |opts| opts.parser_snapshot = parser.dup } config.help_options.try(&.parser_snapshot=(parser.dup))
# config.command = Commands::Config.new(config) # config.command = Commands::Config.new(config)
Parsers::ConfigParser.new.build(parser, breadcrumbs, config) Parsers::ConfigParser.new.build(parser, breadcrumbs, config)
@ -59,7 +59,7 @@ module GX::Parsers
parser.on("mapping", "Manage mappings") do parser.on("mapping", "Manage mappings") do
config.mode = Types::Mode::GlobalHelp config.mode = Types::Mode::GlobalHelp
config.help_options = Parsers::Options::HelpOptions.new config.help_options = Parsers::Options::HelpOptions.new
config.help_options.try { |opts| opts.parser_snapshot = parser.dup } config.help_options.try(&.parser_snapshot=(parser.dup))
Parsers::MappingParser.new.build(parser, breadcrumbs, config) Parsers::MappingParser.new.build(parser, breadcrumbs, config)
end end

View file

@ -4,12 +4,12 @@ module GX::Utils
@ancestors = base @ancestors = base
end end
def +(elem : String) def +(other : String)
b = BreadCrumbs.new(@ancestors + [elem]) BreadCrumbs.new(@ancestors + [other])
end end
def to_s def to_s(io : IO)
@ancestors.join(" ") io << @ancestors.join(" ")
end end
def to_a def to_a

View file

@ -3,7 +3,7 @@ require "./breadcrumbs"
module GX::Utils module GX::Utils
def self.usage_line(breadcrumbs : BreadCrumbs, description : String, has_commands : Bool = false) def self.usage_line(breadcrumbs : BreadCrumbs, description : String, has_commands : Bool = false)
[ [
"Usage: #{breadcrumbs.to_s}#{has_commands ? " [commands]" : ""} [options]", "Usage: #{breadcrumbs}#{has_commands ? " [commands]" : ""} [options]",
"", "",
description, description,
"", "",
@ -12,6 +12,6 @@ module GX::Utils
end end
def self.help_line(breadcrumbs : BreadCrumbs) def self.help_line(breadcrumbs : BreadCrumbs)
"\nRun '#{breadcrumbs.to_s} COMMAND --help' for more information on a command." "\nRun '#{breadcrumbs} COMMAND --help' for more information on a command."
end end
end end

0
static/completion.zsh Normal file
View file

32
static/sample.mfm.yaml Normal file
View file

@ -0,0 +1,32 @@
---
version: 1
global:
mount_point_base: "{{env.HOME}}/mnt"
filesystems:
##
## Sample configuration for encrypted vault (gocryptfs)
##
# - type: gocryptfs
# name: "Credential Vault"
# encrypted_path: "{{env.HOME}}/Documents/Credential.Vault"
#
##
## Sample configuration remote SSH directory (sshfs)
##
# - type: sshfs
# name: "Remote SSH server"
# remote_host: ssh.example.com
# remote_user: "{{env.USER}}"
# remote_path: "/home/{{env.USER}}"
# remote_port: 443
#
##
## Sample configuration for remote HTTP directory (httpdirfs)
##
- type: httpdirfs
name: "Debian Repository"
url: "http://ftp.debian.org/debian/"
# mount_point: "{{env.HOME}}/another.dir"
#