2023-10-25 14:01:46 +02:00
|
|
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
#
|
|
|
|
# SPDX-FileCopyrightText: 2023 Glenn Y. Rolland <glenux@glenux.net>
|
|
|
|
# Copyright © 2023 Glenn Y. Rolland <glenux@glenux.net>
|
2023-10-22 23:23:56 +02:00
|
|
|
|
2023-10-23 23:11:12 +02:00
|
|
|
require "option_parser"
|
2023-10-22 23:23:56 +02:00
|
|
|
require "./config"
|
|
|
|
require "./fzf"
|
2023-11-18 23:55:13 +01:00
|
|
|
require "./version"
|
2023-10-22 23:23:56 +02:00
|
|
|
|
|
|
|
module GX
|
|
|
|
class Cli
|
2023-11-18 19:32:12 +01:00
|
|
|
Log = ::Log.for("cli")
|
2023-10-23 23:11:12 +02:00
|
|
|
|
2023-10-22 23:23:56 +02:00
|
|
|
@config : Config
|
|
|
|
|
|
|
|
def initialize()
|
|
|
|
# Main execution starts here
|
2023-10-23 23:11:12 +02:00
|
|
|
@config = Config.new
|
2023-10-22 23:23:56 +02:00
|
|
|
|
|
|
|
## FIXME: check that FZF is installed
|
|
|
|
end
|
|
|
|
|
2023-10-23 23:11:12 +02:00
|
|
|
def parse_command_line(args)
|
|
|
|
# update
|
|
|
|
add_args = { name: "", path: "" }
|
|
|
|
delete_args = { name: "" }
|
|
|
|
pparser = OptionParser.new do |parser|
|
2023-10-24 14:49:46 +02:00
|
|
|
parser.banner = "Usage: #{PROGRAM_NAME} [options]\n\nGlobal options"
|
2023-10-23 23:11:12 +02:00
|
|
|
|
|
|
|
parser.on("-c", "--config FILE", "Set configuration file") do |path|
|
2023-11-18 19:32:12 +01:00
|
|
|
Log.info { "Configuration set to #{path}" }
|
2023-10-23 23:11:12 +02:00
|
|
|
@config.path = path
|
|
|
|
end
|
2023-11-02 12:44:37 +01:00
|
|
|
|
|
|
|
parser.on("-v", "--verbose", "Set more verbosity") do |flag|
|
2023-11-18 19:32:12 +01:00
|
|
|
Log.info { "Verbosity enabled" }
|
2023-11-02 12:44:37 +01:00
|
|
|
@config.verbose = true
|
|
|
|
end
|
|
|
|
|
2023-11-24 10:25:30 +01:00
|
|
|
parser.on("-o", "--open", "Automatically open directory after mount") do |flag|
|
|
|
|
Log.info { "Auto-open enabled" }
|
|
|
|
@config.auto_open = true
|
|
|
|
end
|
|
|
|
|
2023-11-02 12:44:37 +01:00
|
|
|
parser.on("--version", "Show version") do |flag|
|
|
|
|
@config.mode = Config::Mode::ShowVersion
|
|
|
|
end
|
|
|
|
|
2023-10-23 23:11:12 +02:00
|
|
|
parser.on("-h", "--help", "Show this help") do |flag|
|
|
|
|
STDOUT.puts parser
|
|
|
|
exit(0)
|
|
|
|
end
|
|
|
|
|
|
|
|
parser.separator("\nCommands")
|
2023-11-02 12:44:37 +01:00
|
|
|
parser.on("config", "Manage configuration") do
|
|
|
|
parser.banner = "Usage: #{PROGRAM_NAME} config [commands] [options]\n\nGlobal options"
|
|
|
|
parser.separator("\nCommands")
|
|
|
|
|
|
|
|
parser.on("create", "Create vault") do
|
|
|
|
@config.mode = Config::Mode::ConfigAdd
|
|
|
|
|
|
|
|
parser.banner = "Usage: #{PROGRAM_NAME} config create [commands] [options]\n\nGlobal options"
|
|
|
|
parser.separator("\nCommand options")
|
|
|
|
|
|
|
|
parser.on("-n", "--name", "Set vault name") do |name|
|
|
|
|
add_args = add_args.merge({ name: name })
|
|
|
|
end
|
|
|
|
parser.on("-p", "--path", "Set vault encrypted path") do |path|
|
|
|
|
add_args = add_args.merge({ path: path })
|
|
|
|
end
|
2023-10-23 23:11:12 +02:00
|
|
|
end
|
|
|
|
|
2023-11-02 12:44:37 +01:00
|
|
|
parser.on("delete", "Delete vault") do
|
|
|
|
@config.mode = Config::Mode::ConfigAdd
|
2023-10-23 23:11:12 +02:00
|
|
|
|
2023-11-02 12:44:37 +01:00
|
|
|
parser.banner = "Usage: #{PROGRAM_NAME} delete [options]\n\nGlobal options"
|
|
|
|
parser.separator("\nCommand options")
|
2023-10-23 23:11:12 +02:00
|
|
|
|
2023-11-02 12:44:37 +01:00
|
|
|
parser.on("-n", "--name", "Set vault name") do |name|
|
|
|
|
delete_args = delete_args.merge({ name: name })
|
|
|
|
end
|
2023-10-23 23:11:12 +02:00
|
|
|
end
|
|
|
|
|
2023-11-02 12:44:37 +01:00
|
|
|
parser.on("edit", "Edit configuration") do |flag|
|
|
|
|
@config.mode = Config::Mode::ConfigEdit
|
|
|
|
end
|
2023-10-23 23:11:12 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
end
|
|
|
|
pparser.parse(args)
|
|
|
|
end
|
|
|
|
|
2023-10-22 23:23:56 +02:00
|
|
|
def run()
|
2023-11-02 12:44:37 +01:00
|
|
|
case @config.mode
|
|
|
|
when Config::Mode::ShowVersion
|
|
|
|
STDOUT.puts "#{PROGRAM_NAME} #{VERSION}"
|
|
|
|
when Config::Mode::Mount
|
2023-11-18 23:35:54 +01:00
|
|
|
@config.load_from_file
|
2023-11-24 00:20:16 +01:00
|
|
|
filesystem = choose_filesystem
|
2023-11-24 10:25:30 +01:00
|
|
|
raise Models::InvalidFilesystemError.new("Invalid filesystem") if filesystem.nil?
|
|
|
|
|
|
|
|
mount_or_umount(filesystem)
|
2023-11-24 19:25:50 +01:00
|
|
|
auto_open(filesystem) if filesystem.mounted? && @config.auto_open
|
2023-11-02 12:44:37 +01:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2023-11-24 10:25:30 +01:00
|
|
|
def auto_open(filesystem)
|
|
|
|
# FIXME: support xdg-open
|
|
|
|
# FIXME: support mailcap
|
|
|
|
# FIXME: support user-defined command
|
|
|
|
# FIXME: detect graphical environment
|
|
|
|
|
|
|
|
mount_point_safe = filesystem.mount_point
|
|
|
|
raise Models::InvalidMountpointError.new("Invalid filesystem") if mount_point_safe.nil?
|
|
|
|
|
|
|
|
if graphical_environment?
|
|
|
|
process = Process.new(
|
|
|
|
"xdg-open", ## FIXME: make configurable
|
|
|
|
[mount_point_safe],
|
|
|
|
input: STDIN,
|
|
|
|
output: STDOUT,
|
|
|
|
error: STDERR
|
|
|
|
)
|
|
|
|
unless process.wait.success?
|
|
|
|
puts "Error opening filesystem".colorize(:red)
|
|
|
|
return
|
|
|
|
end
|
|
|
|
else
|
|
|
|
process = Process.new(
|
|
|
|
"vifm", ## FIXME: make configurable
|
|
|
|
[mount_point_safe],
|
|
|
|
input: STDIN,
|
|
|
|
output: STDOUT,
|
|
|
|
error: STDERR
|
|
|
|
)
|
|
|
|
unless process.wait.success?
|
|
|
|
puts "Error opening filesystem".colorize(:red)
|
|
|
|
return
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def graphical_environment?
|
|
|
|
if ENV["DISPLAY"]? || ENV["WAYLAND_DISPLAY"]?
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
|
2023-11-24 00:20:16 +01:00
|
|
|
def choose_filesystem()
|
|
|
|
names_display = {} of String => NamedTuple(filesystem: Models::AbstractFilesystemConfig, ansi_name: String)
|
|
|
|
|
|
|
|
config_root = @config.root
|
|
|
|
return if config_root.nil?
|
|
|
|
|
|
|
|
config_root.filesystems.each do |filesystem|
|
2023-10-24 17:04:15 +02:00
|
|
|
fs_str = filesystem.type.ljust(12,' ')
|
2023-11-02 12:44:37 +01:00
|
|
|
|
|
|
|
suffix = ""
|
|
|
|
suffix_ansi = ""
|
|
|
|
if filesystem.mounted?
|
|
|
|
suffix = "[open]"
|
|
|
|
suffix_ansi = "[#{ "open".colorize(:green) }]"
|
|
|
|
end
|
|
|
|
|
|
|
|
result_name = "#{fs_str} #{filesystem.name} #{suffix}".strip
|
|
|
|
ansi_name = "#{fs_str.colorize(:dark_gray)} #{filesystem.name} #{suffix_ansi}".strip
|
2023-10-24 12:50:01 +02:00
|
|
|
|
|
|
|
names_display[result_name] = {
|
2023-10-24 14:49:46 +02:00
|
|
|
filesystem: filesystem,
|
2023-10-24 12:50:01 +02:00
|
|
|
ansi_name: ansi_name
|
|
|
|
}
|
2023-10-22 23:23:56 +02:00
|
|
|
end
|
|
|
|
|
2023-11-24 10:49:32 +01:00
|
|
|
## FIXME: feat: allow to sort by name or by filesystem
|
|
|
|
sorted_values = names_display.values.sort_by { |item| item[:filesystem].name }
|
|
|
|
result_filesystem_name = Fzf.run(sorted_values.map(&.[:ansi_name])).strip
|
2023-10-24 14:49:46 +02:00
|
|
|
selected_filesystem = names_display[result_filesystem_name][:filesystem]
|
|
|
|
puts ">> #{selected_filesystem.name}".colorize(:yellow)
|
2023-10-22 23:23:56 +02:00
|
|
|
|
2023-11-24 00:20:16 +01:00
|
|
|
if !selected_filesystem
|
2023-10-24 14:49:46 +02:00
|
|
|
STDERR.puts "Vault not found: #{selected_filesystem}.".colorize(:red)
|
2023-11-24 00:20:16 +01:00
|
|
|
return
|
2023-10-22 23:23:56 +02:00
|
|
|
end
|
2023-11-24 00:20:16 +01:00
|
|
|
return selected_filesystem
|
|
|
|
end
|
2023-10-22 23:23:56 +02:00
|
|
|
|
2023-11-24 00:20:16 +01:00
|
|
|
def mount_or_umount(selected_filesystem)
|
|
|
|
if !selected_filesystem.mounted?
|
|
|
|
selected_filesystem.mount()
|
|
|
|
else
|
|
|
|
selected_filesystem.umount()
|
|
|
|
end
|
2023-10-22 23:23:56 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|