aboutsummaryrefslogtreecommitdiff
path: root/libbutl/builtin.mxx
diff options
context:
space:
mode:
Diffstat (limited to 'libbutl/builtin.mxx')
-rw-r--r--libbutl/builtin.mxx174
1 files changed, 174 insertions, 0 deletions
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 <map>
+#include <string>
+#include <vector>
+#include <thread>
+#include <cstddef> // size_t
+#include <utility> // move()
+#include <cstdint> // uint8_t
+#include <functional>
+#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 <libbutl/path.mxx>
+#include <libbutl/fdstream.mxx>
+#include <libbutl/timestamp.mxx>
+#endif
+
+#include <libbutl/export.hxx>
+
+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_hook> 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_hook> 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_hook> 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::string>&, std::size_t);
+
+ std::function<parse_option_function> parse_option;
+
+ // If specified, called by the sleep builtin instead of the default
+ // implementation.
+ //
+ using sleep_function = void (const duration&);
+
+ std::function<sleep_function> sleep;
+
+ explicit
+ builtin_callbacks (std::function<create_hook> c = {},
+ std::function<move_hook> m = {},
+ std::function<remove_hook> r = {},
+ std::function<parse_option_function> p = {},
+ std::function<sleep_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<sleep_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<std::string>& args,
+ auto_fd in, auto_fd out, auto_fd err,
+ const dir_path& cwd,
+ const builtin_callbacks&);
+
+ class builtin_map: public std::map<std::string, builtin_function*>
+ {
+ public:
+ using base = std::map<std::string, builtin_function*>;
+ 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;
+}