libos+cp: Add prompt functionality
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
6d9ba8deb4
commit
5c9503ac71
23
apps/cp.cpp
23
apps/cp.cpp
@ -1,11 +1,13 @@
|
|||||||
#include <luna/PathParser.h>
|
#include <luna/PathParser.h>
|
||||||
|
#include <luna/String.h>
|
||||||
#include <os/ArgumentParser.h>
|
#include <os/ArgumentParser.h>
|
||||||
#include <os/File.h>
|
#include <os/File.h>
|
||||||
#include <os/FileSystem.h>
|
#include <os/FileSystem.h>
|
||||||
|
#include <os/Prompt.h>
|
||||||
|
|
||||||
using os::File;
|
using os::File;
|
||||||
|
|
||||||
Result<void> copy_file(StringView source, StringView destination, bool verbose)
|
Result<void> copy_file(StringView source, StringView destination, bool verbose, bool interactive)
|
||||||
{
|
{
|
||||||
SharedPtr<File> source_file = TRY(os::File::open(source, File::ReadOnly));
|
SharedPtr<File> source_file = TRY(os::File::open(source, File::ReadOnly));
|
||||||
SharedPtr<File> destination_file;
|
SharedPtr<File> destination_file;
|
||||||
@ -19,10 +21,23 @@ Result<void> copy_file(StringView source, StringView destination, bool verbose)
|
|||||||
auto basename = TRY(PathParser::basename(source));
|
auto basename = TRY(PathParser::basename(source));
|
||||||
auto path = TRY(PathParser::join_paths(destination, basename.view()));
|
auto path = TRY(PathParser::join_paths(destination, basename.view()));
|
||||||
|
|
||||||
|
if (interactive && os::FileSystem::exists(path.view(), false))
|
||||||
|
{
|
||||||
|
auto prompt = TRY(String::format("cp: Overwrite %s with %s?"_sv, path.chars(), source.chars()));
|
||||||
|
if (!os::conditional_prompt(prompt.view(), os::DefaultNo)) return {};
|
||||||
|
}
|
||||||
|
|
||||||
destination_file = TRY(File::open_or_create(path.view(), File::ReadWrite, st.st_mode & ~S_IFMT));
|
destination_file = TRY(File::open_or_create(path.view(), File::ReadWrite, st.st_mode & ~S_IFMT));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
if (interactive && os::FileSystem::exists(destination, false))
|
||||||
|
{
|
||||||
|
auto prompt = TRY(String::format("cp: Overwrite %s with %s?"_sv, destination.chars(), source.chars()));
|
||||||
|
if (!os::conditional_prompt(prompt.view(), os::DefaultNo)) return {};
|
||||||
|
}
|
||||||
destination_file = TRY(File::open_or_create(destination, File::ReadWrite, st.st_mode & ~S_IFMT));
|
destination_file = TRY(File::open_or_create(destination, File::ReadWrite, st.st_mode & ~S_IFMT));
|
||||||
|
}
|
||||||
|
|
||||||
if (verbose) os::eprintln("copying %s to %s", source.chars(), destination.chars());
|
if (verbose) os::eprintln("copying %s to %s", source.chars(), destination.chars());
|
||||||
|
|
||||||
@ -42,6 +57,7 @@ Result<int> luna_main(int argc, char** argv)
|
|||||||
Vector<StringView> files;
|
Vector<StringView> files;
|
||||||
StringView destination;
|
StringView destination;
|
||||||
bool verbose { false };
|
bool verbose { false };
|
||||||
|
bool interactive { false };
|
||||||
|
|
||||||
os::ArgumentParser parser;
|
os::ArgumentParser parser;
|
||||||
parser.add_description("Copy files or directories."_sv);
|
parser.add_description("Copy files or directories."_sv);
|
||||||
@ -49,9 +65,10 @@ Result<int> luna_main(int argc, char** argv)
|
|||||||
parser.set_vector_argument(files, "files"_sv, true);
|
parser.set_vector_argument(files, "files"_sv, true);
|
||||||
parser.add_positional_argument(destination, "destination"_sv, true);
|
parser.add_positional_argument(destination, "destination"_sv, true);
|
||||||
parser.add_switch_argument(verbose, 'v', "verbose"_sv, "show more information"_sv);
|
parser.add_switch_argument(verbose, 'v', "verbose"_sv, "show more information"_sv);
|
||||||
parser.parse(argc, argv);
|
parser.add_switch_argument(interactive, 'i', "interactive"_sv, "prompt before overwriting existing files"_sv);
|
||||||
|
TRY(parser.parse(argc, argv));
|
||||||
|
|
||||||
for (const auto& file : files) { TRY(copy_file(file, destination, verbose)); }
|
for (const auto& file : files) { TRY(copy_file(file, destination, verbose, interactive)); }
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ set(SOURCES
|
|||||||
src/Main.cpp
|
src/Main.cpp
|
||||||
src/Path.cpp
|
src/Path.cpp
|
||||||
src/Mode.cpp
|
src/Mode.cpp
|
||||||
|
src/Prompt.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
add_library(os ${SOURCES})
|
add_library(os ${SOURCES})
|
||||||
|
35
libos/include/os/Prompt.h
Normal file
35
libos/include/os/Prompt.h
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
/**
|
||||||
|
* @file Prompt.h
|
||||||
|
* @author apio (cloudapio.eu)
|
||||||
|
* @brief A few functions to get input from the user.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2023, the Luna authors.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <luna/StringView.h>
|
||||||
|
|
||||||
|
namespace os
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @brief The default value for a conditional prompt.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
enum DefaultValue
|
||||||
|
{
|
||||||
|
DefaultNo = 0,
|
||||||
|
DefaultYes = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Show a prompt asking a yes or no question to the user.
|
||||||
|
*
|
||||||
|
* @param prompt The prompt that will be shown, without the "[y/N]" part. This will be added automatically by the
|
||||||
|
* function.
|
||||||
|
* @param fallback The value to return if the user's input was not a valid yes or no answer.
|
||||||
|
* @return true If the user entered 'y', 'Y', or the default value was yes and the input was invalid.
|
||||||
|
* @return false If the user entered 'n', 'N', or the default value was no and the input was invalid.
|
||||||
|
*/
|
||||||
|
bool conditional_prompt(StringView prompt, DefaultValue fallback);
|
||||||
|
}
|
24
libos/src/Prompt.cpp
Normal file
24
libos/src/Prompt.cpp
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#include <luna/String.h>
|
||||||
|
#include <os/File.h>
|
||||||
|
#include <os/Prompt.h>
|
||||||
|
|
||||||
|
namespace os
|
||||||
|
{
|
||||||
|
bool conditional_prompt(StringView prompt, DefaultValue fallback)
|
||||||
|
{
|
||||||
|
bool default_yes = fallback == DefaultYes;
|
||||||
|
|
||||||
|
os::print("%s [%s] ", prompt.chars(), default_yes ? "Y/n" : "y/N");
|
||||||
|
|
||||||
|
auto line_or_error = os::File::standard_input()->read_line();
|
||||||
|
if (line_or_error.has_error()) return default_yes;
|
||||||
|
|
||||||
|
auto line = line_or_error.release_value();
|
||||||
|
line.trim("\n");
|
||||||
|
|
||||||
|
if (line.view() == "y" || line.view() == "Y") return true;
|
||||||
|
if (line.view() == "n" || line.view() == "N") return false;
|
||||||
|
|
||||||
|
return default_yes;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user