Compare commits
28 commits
develop
...
feature/43
Author | SHA1 | Date | |
---|---|---|---|
d48b585bda | |||
cc90d09fae | |||
c912f480b7 | |||
093c9d2fa1 | |||
b1567a1aa0 | |||
a51ce2e98f | |||
26510531e7 | |||
0e2ddde081 | |||
6ec7ae0ec7 | |||
92aaf5f0b5 | |||
59ab4ce272 | |||
1f5a2f33ec | |||
cb99019be5 | |||
91f2e7a554 | |||
bb5941a86a | |||
1a5c2cd223 | |||
be8980b74c | |||
8f145189c0 | |||
dbb0a42e91 | |||
ed2cf5227f | |||
b59f1011ac | |||
f5d28671a2 | |||
531cba0dc7 | |||
16bb660fc2 | |||
275f66d19d | |||
8f1862eb43 | |||
29ab85a61f | |||
aec45eebd4 |
31 changed files with 270 additions and 95 deletions
|
@ -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
|
||||||
|
|
2
Makefile
2
Makefile
|
@ -24,7 +24,7 @@ test:
|
||||||
install:
|
install:
|
||||||
install \
|
install \
|
||||||
-m 755 \
|
-m 755 \
|
||||||
bin/code-preloader \
|
bin/mfm \
|
||||||
$(PREFIX)/bin
|
$(PREFIX)/bin
|
||||||
|
|
||||||
.PHONY: spec test build all prepare install
|
.PHONY: spec test build all prepare install
|
||||||
|
|
19
README.md
19
README.md
|
@ -14,6 +14,8 @@
|
||||||
> version of our project, please visit our primary repository at:
|
> version of our project, please visit our primary repository at:
|
||||||
> <https://code.apps.glenux.net/glenux/mfm>.
|
> <https://code.apps.glenux.net/glenux/mfm>.
|
||||||
|
|
||||||
|
<!-- hello -->
|
||||||
|
|
||||||
# Minimalist Fuse Manager (MFM)
|
# Minimalist Fuse Manager (MFM)
|
||||||
|
|
||||||
MFM is a Crystal-lang CLI designed to streamline the management of various FUSE filesystems, such as sshfs, gocryptfs, httpdirfs, and more. Through its user-friendly interface, users can effortlessly mount and unmount filesystems, get real-time filesystem status, and handle errors proficiently.
|
MFM is a Crystal-lang CLI designed to streamline the management of various FUSE filesystems, such as sshfs, gocryptfs, httpdirfs, and more. Through its user-friendly interface, users can effortlessly mount and unmount filesystems, get real-time filesystem status, and handle errors proficiently.
|
||||||
|
@ -44,18 +46,23 @@ To build from source, you'll also need:
|
||||||
For Debian/Ubuntu you can use the following command:
|
For Debian/Ubuntu you can use the following command:
|
||||||
|
|
||||||
```shell-session
|
```shell-session
|
||||||
$ sudo apt-get update && sudo apt-get install libpcre3-dev libevent-2.1-dev
|
$ sudo apt-get update && sudo apt-get install libpcre3-dev libevent-2.1-dev make
|
||||||
```
|
```
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
### 1. From Source
|
### 1. From Source
|
||||||
|
|
||||||
1. Clone or download the source code.
|
To get started with MFM, ensure that you have the prerequisites installed on your system (see above).
|
||||||
2. Navigate to the source directory.
|
|
||||||
3. Run `shards install` to fetch dependencies.
|
Then follow these steps to install:
|
||||||
4. Compile using `shards build`.
|
|
||||||
5. The compiled binary will be in the `bin` directory.
|
git clone https://code.apps.glenux.net/glenux/mfm
|
||||||
|
cd mfm
|
||||||
|
make prepare
|
||||||
|
make build
|
||||||
|
sudo make install # either to install system-wide
|
||||||
|
make install PREFIX=$HOME/.local # or to install as a user
|
||||||
|
|
||||||
### 2. Binary Download
|
### 2. Binary Download
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,10 @@ shards:
|
||||||
git: https://github.com/crystal-ameba/ameba.git
|
git: https://github.com/crystal-ameba/ameba.git
|
||||||
version: 1.6.1
|
version: 1.6.1
|
||||||
|
|
||||||
|
baked_file_system:
|
||||||
|
git: https://github.com/schovi/baked_file_system.git
|
||||||
|
version: 0.10.0
|
||||||
|
|
||||||
crinja:
|
crinja:
|
||||||
git: https://github.com/straight-shoota/crinja.git
|
git: https://github.com/straight-shoota/crinja.git
|
||||||
version: 0.8.1
|
version: 0.8.1
|
||||||
|
|
|
@ -26,6 +26,9 @@ dependencies:
|
||||||
github: hugopl/version_from_shard
|
github: hugopl/version_from_shard
|
||||||
tablo:
|
tablo:
|
||||||
github: hutou/tablo
|
github: hutou/tablo
|
||||||
|
baked_file_system:
|
||||||
|
github: schovi/baked_file_system
|
||||||
|
version: 0.10.0
|
||||||
|
|
||||||
development_dependencies:
|
development_dependencies:
|
||||||
ameba:
|
ameba:
|
||||||
|
|
|
@ -16,7 +16,7 @@ module GX
|
||||||
class Cli
|
class Cli
|
||||||
Log = ::Log.for("cli")
|
Log = ::Log.for("cli")
|
||||||
|
|
||||||
@config : GX::Config
|
@config : GX::Config
|
||||||
|
|
||||||
def initialize
|
def initialize
|
||||||
# Main execution starts here
|
# Main execution starts here
|
||||||
|
|
17
src/commands/completion_autodetect.cr
Normal file
17
src/commands/completion_autodetect.cr
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
require "./abstract_command"
|
||||||
|
|
||||||
|
module GX::Commands
|
||||||
|
class CompletionAutodetect < AbstractCommand
|
||||||
|
def initialize(@config : GX::Config)
|
||||||
|
end
|
||||||
|
|
||||||
|
def execute
|
||||||
|
STDERR.puts "FIXME: Completion auto-detection isn't implemented yet. Please select one of the following: --bash or --zsh"
|
||||||
|
exit(0)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.handles_mode
|
||||||
|
GX::Types::Mode::CompletionAutodetect
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
17
src/commands/completion_bash.cr
Normal file
17
src/commands/completion_bash.cr
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
require "./abstract_command"
|
||||||
|
|
||||||
|
module GX::Commands
|
||||||
|
class CompletionBash < AbstractCommand
|
||||||
|
def initialize(@config : GX::Config)
|
||||||
|
end
|
||||||
|
|
||||||
|
def execute
|
||||||
|
completion_bash = FileStorage.get("completion.bash")
|
||||||
|
STDOUT.puts completion_bash.gets_to_end
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.handles_mode
|
||||||
|
GX::Types::Mode::CompletionBash
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
17
src/commands/completion_zsh.cr
Normal file
17
src/commands/completion_zsh.cr
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
require "./abstract_command"
|
||||||
|
|
||||||
|
module GX::Commands
|
||||||
|
class CompletionZsh < AbstractCommand
|
||||||
|
def initialize(@config : GX::Config)
|
||||||
|
end
|
||||||
|
|
||||||
|
def execute
|
||||||
|
completion_bash = FileStorage.get("completion.zsh")
|
||||||
|
STDOUT.puts completion_bash.gets_to_end
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.handles_mode
|
||||||
|
GX::Types::Mode::CompletionZsh
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,11 +1,36 @@
|
||||||
require "./abstract_command"
|
require "./abstract_command"
|
||||||
|
require "../file_storage"
|
||||||
|
|
||||||
module GX::Commands
|
module GX::Commands
|
||||||
class ConfigInit < AbstractCommand
|
class ConfigInit < AbstractCommand
|
||||||
def initialize(config : GX::Config) # FIXME
|
def initialize(@config : GX::Config)
|
||||||
end
|
end
|
||||||
|
|
||||||
def execute
|
def execute
|
||||||
|
config_dir = File.join(@config.home_dir, ".config", "mfm")
|
||||||
|
config_file_path = File.join(config_dir, "config.yml")
|
||||||
|
|
||||||
|
# Guard condition to exit if the configuration file already exists
|
||||||
|
if File.exists?(config_file_path)
|
||||||
|
puts "Configuration file already exists at #{config_file_path}. No action taken."
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
puts "Creating initial configuration file at #{config_file_path}"
|
||||||
|
|
||||||
|
# Ensure the configuration directory exists
|
||||||
|
FileUtils.mkdir_p(config_dir)
|
||||||
|
|
||||||
|
# Read the default configuration content from the baked file storage
|
||||||
|
default_config_content = FileStorage.get("sample.mfm.yaml")
|
||||||
|
|
||||||
|
# Write the default configuration to the target path
|
||||||
|
File.write(config_file_path, default_config_content)
|
||||||
|
|
||||||
|
puts "Configuration file created successfully."
|
||||||
|
rescue ex
|
||||||
|
STDERR.puts "Error creating the configuration file: #{ex.message}"
|
||||||
|
exit(1)
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.handles_mode
|
def self.handles_mode
|
||||||
|
|
|
@ -1,15 +0,0 @@
|
||||||
require "./abstract_command"
|
|
||||||
|
|
||||||
module GX::Commands
|
|
||||||
class GlobalCompletion < AbstractCommand
|
|
||||||
def initialize(@config : GX::Config)
|
|
||||||
end
|
|
||||||
|
|
||||||
def execute
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.handles_mode
|
|
||||||
GX::Types::Mode::GlobalConfig
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
8
src/file_storage.cr
Normal file
8
src/file_storage.cr
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
require "baked_file_system"
|
||||||
|
|
||||||
|
class FileStorage
|
||||||
|
extend BakedFileSystem
|
||||||
|
|
||||||
|
bake_folder "../static"
|
||||||
|
end
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -22,7 +22,7 @@ struct BaseFormat < Log::StaticFormatter
|
||||||
end
|
end
|
||||||
|
|
||||||
Log.setup do |config|
|
Log.setup do |config|
|
||||||
backend = Log::IOBackend.new(formatter: BaseFormat)
|
backend = Log::IOBackend.new(io: STDERR, formatter: BaseFormat)
|
||||||
config.bind "*", Log::Severity::Info, backend
|
config.bind "*", Log::Severity::Info, backend
|
||||||
|
|
||||||
if ENV["LOG_LEVEL"]?
|
if ENV["LOG_LEVEL"]?
|
||||||
|
@ -31,6 +31,6 @@ Log.setup do |config|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
cli = GX::Cli.new
|
app = GX::Cli.new
|
||||||
cli.parse_command_line(ARGV)
|
app.parse_command_line(ARGV)
|
||||||
cli.run
|
app.run
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -13,7 +13,6 @@ module GX::Models
|
||||||
getter remote_user : String = ""
|
getter remote_user : String = ""
|
||||||
getter remote_host : String = ""
|
getter remote_host : String = ""
|
||||||
getter remote_port : String = "22"
|
getter remote_port : String = "22"
|
||||||
getter options : Array(String) = [] of String
|
|
||||||
|
|
||||||
include Concerns::Base
|
include Concerns::Base
|
||||||
|
|
||||||
|
@ -29,25 +28,18 @@ module GX::Models
|
||||||
mount_point_safe = @mount_point
|
mount_point_safe = @mount_point
|
||||||
raise InvalidMountpointError.new("Invalid mount point") if mount_point_safe.nil?
|
raise InvalidMountpointError.new("Invalid mount point") if mount_point_safe.nil?
|
||||||
|
|
||||||
options = [] of String
|
|
||||||
# merge sshfs options
|
|
||||||
@options.each do |option|
|
|
||||||
options.push("-o", option)
|
|
||||||
end
|
|
||||||
options.push("-p", remote_port)
|
|
||||||
options.push(
|
|
||||||
"#{@remote_user}@#{@remote_host}:#{@remote_path}",
|
|
||||||
mount_point_safe
|
|
||||||
)
|
|
||||||
process = Process.new(
|
process = Process.new(
|
||||||
"sshfs",
|
"sshfs",
|
||||||
options,
|
[
|
||||||
|
"-p", remote_port,
|
||||||
|
"#{@remote_user}@#{@remote_host}:#{@remote_path}",
|
||||||
|
mount_point_safe,
|
||||||
|
],
|
||||||
input: STDIN,
|
input: STDIN,
|
||||||
output: STDOUT,
|
output: STDOUT,
|
||||||
error: STDERR
|
error: STDERR
|
||||||
)
|
)
|
||||||
return process.wait
|
process.wait
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ module GX::Parsers
|
||||||
class CompletionParser < AbstractParser
|
class CompletionParser < AbstractParser
|
||||||
def build(parser, ancestors, config)
|
def build(parser, ancestors, config)
|
||||||
breadcrumbs = ancestors + "completion"
|
breadcrumbs = ancestors + "completion"
|
||||||
|
# config.mode = Types::Mode::CompletionAutodetect
|
||||||
|
|
||||||
parser.banner = Utils.usage_line(
|
parser.banner = Utils.usage_line(
|
||||||
breadcrumbs,
|
breadcrumbs,
|
||||||
|
@ -12,11 +13,13 @@ 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 |_|
|
||||||
|
config.mode = Types::Mode::CompletionBash
|
||||||
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 |_|
|
||||||
|
config.mode = Types::Mode::CompletionZsh
|
||||||
Log.info { "Set zsh completion" }
|
Log.info { "Set zsh completion" }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
@ -18,50 +20,94 @@ module GX::Parsers
|
||||||
parser.on("list", "List mappings") do
|
parser.on("list", "List mappings") do
|
||||||
config.mode = Types::Mode::MappingList
|
config.mode = Types::Mode::MappingList
|
||||||
parser.separator(Utils.help_line(breadcrumbs + "list"))
|
parser.separator(Utils.help_line(breadcrumbs + "list"))
|
||||||
# abort("FIXME: Not implemented")
|
|
||||||
end
|
end
|
||||||
|
|
||||||
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"))
|
||||||
|
|
|
@ -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
|
||||||
|
@ -69,7 +69,10 @@ module GX::Parsers
|
||||||
# end
|
# end
|
||||||
|
|
||||||
parser.on("completion", "Manage completion") do
|
parser.on("completion", "Manage completion") do
|
||||||
config.mode = Types::Mode::GlobalCompletion
|
config.mode = Types::Mode::GlobalHelp
|
||||||
|
config.help_options = Parsers::Options::HelpOptions.new
|
||||||
|
config.help_options.try(&.parser_snapshot=(parser.dup))
|
||||||
|
|
||||||
Parsers::CompletionParser.new.build(parser, breadcrumbs, config)
|
Parsers::CompletionParser.new.build(parser, breadcrumbs, config)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -4,11 +4,15 @@ module GX::Types
|
||||||
|
|
||||||
GlobalVersion
|
GlobalVersion
|
||||||
GlobalHelp
|
GlobalHelp
|
||||||
GlobalCompletion
|
# GlobalCompletion
|
||||||
GlobalTui
|
GlobalTui
|
||||||
GlobalConfig
|
GlobalConfig
|
||||||
GlobalMapping
|
GlobalMapping
|
||||||
|
|
||||||
|
CompletionBash
|
||||||
|
CompletionZsh
|
||||||
|
CompletionAutodetect
|
||||||
|
|
||||||
ConfigInit
|
ConfigInit
|
||||||
|
|
||||||
MappingCreate
|
MappingCreate
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
5
static/completion.zsh
Normal file
5
static/completion.zsh
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
#!/bin/zsh
|
||||||
|
|
||||||
|
# mfm Zsh completion script
|
||||||
|
|
||||||
|
|
32
static/sample.mfm.yaml
Normal file
32
static/sample.mfm.yaml
Normal 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"
|
||||||
|
#
|
Loading…
Reference in a new issue