From 1c6758009e82c47b5b341d418be2be401ef31482 Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Fri, 6 Sep 2019 22:20:46 +0300 Subject: Add builtins support --- libbutl/builtin.mxx | 174 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 174 insertions(+) create mode 100644 libbutl/builtin.mxx (limited to 'libbutl/builtin.mxx') diff --git a/libbutl/builtin.mxx b/libbutl/builtin.mxx new file mode 100644 index 0000000..8c9d295 --- /dev/null +++ b/libbutl/builtin.mxx @@ -0,0 +1,174 @@ +// file : libbutl/builtin.mxx -*- C++ -*- +// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd +// license : MIT; see accompanying LICENSE file + +#ifndef __cpp_modules_ts +#pragma once +#endif + +// C includes. + +#ifndef __cpp_lib_modules_ts +#include +#include +#include +#include +#include // size_t +#include // move() +#include // uint8_t +#include +#endif + +// Other includes. + +#ifdef __cpp_modules_ts +export module butl.builtin; +#ifdef __cpp_lib_modules_ts +import std.core; +import std.threading; +#endif +import butl.path; +import butl.fdstream; +import butl.timestamp; +#else +#include +#include +#include +#endif + +#include + +LIBBUTL_MODEXPORT namespace butl +{ + // A process/thread-like object representing a running builtin. + // + // For now, instead of allocating the result storage dynamically, we + // expect it to be provided by the caller. + // + class builtin + { + public: + std::uint8_t + wait () {if (t_.joinable ()) t_.join (); return r_;} + + ~builtin () {wait ();} + + public: + builtin (std::uint8_t& r, std::thread&& t = std::thread ()) + : r_ (r), t_ (move (t)) {} + + builtin (builtin&&) = default; + + private: + std::uint8_t& r_; + std::thread t_; + }; + + // Builtin execution callbacks that can be used for checking/handling the + // filesystem entries being acted upon (enforcing that they are sub-entries + // of some "working" directory, registering cleanups for new entries, etc) + // and for providing custom implementations for some functions used by + // builtins. + // + // Note that the filesystem paths passed to the callbacks are absolute and + // normalized with directories distinguished from non-directories based on + // the lexical representation (presence of the trailing directory separator; + // use path::to_directory() to check). + // + // Also note that builtins catch any exceptions that may be thrown by the + // callbacks and, if that's the case, issue diagnostics and exit with the + // non-zero status. + // + struct builtin_callbacks + { + // If specified, called before (pre is true) and after (pre is false) a + // new filesystem entry is created or an existing one is re-created or + // updated. + // + using create_hook = void (const path&, bool pre); + + std::function create; + + // If specified, called before (pre is true) and after (pre is false) a + // filesystem entry is moved. The force argument is true if the builtin is + // executed with the --force option. + // + using move_hook = void (const path& from, + const path& to, + bool force, + bool pre); + + std::function move; + + // If specified, called before (pre is true) and after (pre is false) a + // filesystem entry is removed. The force argument is true if the builtin + // is executed with the --force option. + // + using remove_hook = void (const path&, bool force, bool pre); + + std::function remove; + + // If specified, called on encountering an unknown option passing the + // argument list and the position of the option in question. Return the + // number of parsed arguments. + // + using parse_option_function = + std::size_t (const std::vector&, std::size_t); + + std::function parse_option; + + // If specified, called by the sleep builtin instead of the default + // implementation. + // + using sleep_function = void (const duration&); + + std::function sleep; + + explicit + builtin_callbacks (std::function c = {}, + std::function m = {}, + std::function r = {}, + std::function p = {}, + std::function s = {}) + : create (std::move (c)), + move (std::move (m)), + remove (std::move (r)), + parse_option (std::move (p)), + sleep (std::move (s)) {} + + explicit + builtin_callbacks (std::function sl) + : sleep (std::move (sl)) {} + }; + + // Start a builtin command. Use the current process' standard streams for + // the unopened in, out, and err file descriptors. Use the process' current + // working directory unless an alternative is specified. Throw + // std::system_error on failure. + // + // Note that unlike argc/argv, args don't include the program name. + // + using builtin_function = builtin (std::uint8_t& result, + const std::vector& args, + auto_fd in, auto_fd out, auto_fd err, + const dir_path& cwd, + const builtin_callbacks&); + + class builtin_map: public std::map + { + public: + using base = std::map; + using base::base; + + // Return NULL if not a builtin. + // + builtin_function* + find (const std::string& n) const + { + auto i (base::find (n)); + return i != end () ? i->second : nullptr; + } + }; + + LIBBUTL_SYMEXPORT extern const builtin_map builtins; +} -- cgit v1.1