2016-04-19 04:35:53 +00:00
|
|
|
// The classes responsible for autoloading functions and completions.
|
2012-01-25 19:47:45 +00:00
|
|
|
#ifndef FISH_AUTOLOAD_H
|
|
|
|
#define FISH_AUTOLOAD_H
|
2012-01-25 08:36:55 +00:00
|
|
|
|
2015-07-25 15:14:25 +00:00
|
|
|
#include <pthread.h>
|
|
|
|
#include <time.h>
|
2017-02-14 04:37:27 +00:00
|
|
|
|
2012-01-25 08:36:55 +00:00
|
|
|
#include <set>
|
2017-08-19 20:29:52 +00:00
|
|
|
#include <unordered_set>
|
2016-04-21 06:00:54 +00:00
|
|
|
|
2012-01-25 08:36:55 +00:00
|
|
|
#include "common.h"
|
2017-08-06 01:22:49 +00:00
|
|
|
#include "env.h"
|
2012-02-06 04:54:41 +00:00
|
|
|
#include "lru.h"
|
2019-04-20 01:26:29 +00:00
|
|
|
#include "wutil.h"
|
2012-01-25 08:36:55 +00:00
|
|
|
|
2019-04-27 18:00:36 +00:00
|
|
|
class autoload_file_cache_t;
|
|
|
|
class environment_t;
|
|
|
|
|
|
|
|
/// autoloader_t is a class that knows how to autoload .fish files from a list of directories. This
|
|
|
|
/// is used by autoloading functions and completions. It maintains a file cache, which is
|
|
|
|
/// responsible for potentially cached accesses of files, and then a list of files that have
|
|
|
|
/// actually been autoloaded. A client may request a file to autoload given a command name, and may
|
|
|
|
/// be returned a path which it is expected to source.
|
|
|
|
/// autoloader_t does not have any internal locks; it is the responsibility of the caller to lock
|
|
|
|
/// it.
|
|
|
|
class autoloader_t {
|
|
|
|
/// The environment variable whose paths we observe.
|
|
|
|
const wcstring env_var_name_;
|
|
|
|
|
|
|
|
/// A map from command to the files we have autoloaded.
|
|
|
|
std::unordered_map<wcstring, file_id_t> autoloaded_files_;
|
|
|
|
|
|
|
|
/// The list of commands that we are currently autoloading.
|
|
|
|
std::unordered_set<wcstring> current_autoloading_;
|
|
|
|
|
|
|
|
/// The autoload cache.
|
|
|
|
/// This is a unique_ptr because want to change it if the value of our environment variable
|
|
|
|
/// changes. This is never null (but it may be a cache with no paths).
|
|
|
|
std::unique_ptr<autoload_file_cache_t> cache_;
|
|
|
|
|
|
|
|
public:
|
|
|
|
/// Construct an autoloader that loads from the paths given by \p env_var_name.
|
|
|
|
explicit autoloader_t(wcstring env_var_name);
|
|
|
|
|
|
|
|
~autoloader_t();
|
|
|
|
|
|
|
|
/// Given a command, get a path to autoload.
|
|
|
|
/// For example, if the environment variable is 'fish_function_path' and the command is 'foo',
|
|
|
|
/// this will look for a file 'foo.fish' in one of the directories given by fish_function_path.
|
|
|
|
/// If there is no such file, OR if the file has been previously resolved and is now unchanged,
|
|
|
|
/// this will return none. But if the file is either new or changed, this will return the path.
|
|
|
|
/// After returning a path, the command is marked in-progress until the caller calls
|
|
|
|
/// mark_autoload_finished() with the same command. Note this does not actually execute any
|
|
|
|
/// code; it is the caller's responsibility to load the file.
|
|
|
|
maybe_t<wcstring> resolve_command(const wcstring &cmd, const environment_t &env);
|
|
|
|
|
2019-04-26 22:03:41 +00:00
|
|
|
/// Helper to actually perform an autoload.
|
|
|
|
/// This is a static function because it executes fish script, and so must be called without
|
|
|
|
/// holding any particular locks.
|
|
|
|
static void perform_autoload(const wcstring &path);
|
|
|
|
|
2019-04-27 18:00:36 +00:00
|
|
|
/// Mark that a command previously returned from path_to_autoload is finished autoloading.
|
|
|
|
void mark_autoload_finished(const wcstring &cmd) {
|
|
|
|
size_t amt = current_autoloading_.erase(cmd);
|
|
|
|
assert(amt > 0 && "cmd was not being autoloaded");
|
|
|
|
(void)amt;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \return whether a command is currently being autoloaded.
|
|
|
|
bool autoload_in_progress(const wcstring &cmd) const {
|
|
|
|
return current_autoloading_.count(cmd) > 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \return whether a command could potentially be autoloaded.
|
|
|
|
/// This does not actually mark the command as being autoloaded.
|
|
|
|
bool can_autoload(const wcstring &cmd);
|
|
|
|
|
|
|
|
/// Mark that all autoloaded files have been forgotten.
|
|
|
|
/// Future calls to path_to_autoload() will return previously-returned paths.
|
|
|
|
void clear() {
|
|
|
|
// Note there is no reason to invalidate the cache here.
|
|
|
|
autoloaded_files_.clear();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-06-06 04:30:24 +00:00
|
|
|
/// Record of an attempt to access a file.
|
2016-04-19 04:35:53 +00:00
|
|
|
struct file_access_attempt_t {
|
2019-04-20 01:47:07 +00:00
|
|
|
/// If filled, the file ID of the checked file.
|
|
|
|
/// Otherwise the file did not exist or was otherwise inaccessible.
|
|
|
|
/// Note that this will never contain kInvalidFileID.
|
|
|
|
maybe_t<file_id_t> file_id;
|
|
|
|
|
|
|
|
/// When we last checked the file.
|
2016-06-06 02:24:23 +00:00
|
|
|
time_t last_checked;
|
2019-04-20 01:47:07 +00:00
|
|
|
|
|
|
|
/// Whether or not we believe we can access this file.
|
|
|
|
bool accessible() const { return file_id.has_value(); }
|
2012-01-25 08:36:55 +00:00
|
|
|
};
|
2012-01-25 19:47:45 +00:00
|
|
|
file_access_attempt_t access_file(const wcstring &path, int mode);
|
2012-01-25 08:36:55 +00:00
|
|
|
|
2017-01-27 20:18:16 +00:00
|
|
|
struct autoload_function_t {
|
|
|
|
explicit autoload_function_t(bool placeholder)
|
2017-08-19 14:46:51 +00:00
|
|
|
: access(), is_loaded(false), is_placeholder(placeholder) {}
|
2016-06-06 04:30:24 +00:00
|
|
|
|
|
|
|
/// The last access attempt recorded
|
2016-06-06 02:24:23 +00:00
|
|
|
file_access_attempt_t access;
|
2016-06-06 04:30:24 +00:00
|
|
|
/// Have we actually loaded this function?
|
2016-06-06 02:24:23 +00:00
|
|
|
bool is_loaded;
|
|
|
|
/// Whether we are a placeholder that stands in for "no such function". If this is true, then
|
|
|
|
/// is_loaded must be false.
|
2016-04-19 04:35:53 +00:00
|
|
|
bool is_placeholder;
|
2012-01-26 02:59:35 +00:00
|
|
|
};
|
|
|
|
|
2016-06-06 04:30:24 +00:00
|
|
|
/// Class representing a path from which we can autoload and the autoloaded contents.
|
2017-01-27 20:18:16 +00:00
|
|
|
class autoload_t : public lru_cache_t<autoload_t, autoload_function_t> {
|
2016-04-19 04:35:53 +00:00
|
|
|
private:
|
2016-06-06 04:30:24 +00:00
|
|
|
/// Lock for thread safety.
|
2018-12-31 02:15:49 +00:00
|
|
|
std::mutex lock;
|
2016-06-06 04:30:24 +00:00
|
|
|
/// The environment variable name.
|
2012-01-26 02:59:35 +00:00
|
|
|
const wcstring env_var_name;
|
2018-02-16 05:58:02 +00:00
|
|
|
/// The paths from which to autoload, or missing if none.
|
|
|
|
maybe_t<wcstring_list_t> paths;
|
2016-06-06 04:30:24 +00:00
|
|
|
/// A table containing all the files that are currently being loaded.
|
|
|
|
/// This is here to help prevent recursion.
|
2017-08-19 23:27:24 +00:00
|
|
|
std::unordered_set<wcstring> is_loading_set;
|
2012-01-26 02:59:35 +00:00
|
|
|
|
2017-01-27 20:18:16 +00:00
|
|
|
void remove_all_functions() { this->evict_all_nodes(); }
|
2012-11-18 10:23:22 +00:00
|
|
|
|
2016-04-19 04:35:53 +00:00
|
|
|
bool locate_file_and_maybe_load_it(const wcstring &cmd, bool really_load, bool reload,
|
|
|
|
const wcstring_list_t &path_list);
|
2012-11-18 10:23:22 +00:00
|
|
|
|
2016-04-19 04:35:53 +00:00
|
|
|
autoload_function_t *get_autoloaded_function_with_creation(const wcstring &cmd,
|
|
|
|
bool allow_eviction);
|
|
|
|
|
|
|
|
public:
|
2017-01-27 20:18:16 +00:00
|
|
|
// CRTP override
|
|
|
|
void entry_was_evicted(wcstring key, autoload_function_t node);
|
|
|
|
|
|
|
|
// Create an autoload_t for the given environment variable name.
|
2019-04-22 03:32:21 +00:00
|
|
|
explicit autoload_t(wcstring env_var_name_var);
|
2016-04-19 04:35:53 +00:00
|
|
|
|
2016-06-06 04:30:24 +00:00
|
|
|
/// Autoload the specified file, if it exists in the specified path. Do not load it multiple
|
|
|
|
/// times unless its timestamp changes or parse_util_unload is called.
|
|
|
|
/// @param cmd the filename to search for. The suffix '.fish' is always added to this name
|
|
|
|
/// @param reload wheter to recheck file timestamps on already loaded files
|
2012-11-19 00:30:30 +00:00
|
|
|
int load(const wcstring &cmd, bool reload);
|
2012-11-18 10:23:22 +00:00
|
|
|
|
2016-06-06 04:30:24 +00:00
|
|
|
/// Check whether we have tried loading the given command. Does not do any I/O.
|
2012-11-19 00:30:30 +00:00
|
|
|
bool has_tried_loading(const wcstring &cmd);
|
2012-01-26 02:59:35 +00:00
|
|
|
|
2016-06-06 04:30:24 +00:00
|
|
|
/// Tell the autoloader that the specified file, in the specified path, is no longer loaded.
|
|
|
|
/// Returns non-zero if the file was removed, zero if the file had not yet been loaded
|
2012-11-19 00:30:30 +00:00
|
|
|
int unload(const wcstring &cmd);
|
2012-11-18 10:23:22 +00:00
|
|
|
|
2016-06-06 04:30:24 +00:00
|
|
|
/// Check whether the given command could be loaded, but do not load it.
|
2018-09-09 09:25:51 +00:00
|
|
|
bool can_load(const wcstring &cmd, const environment_t &vars);
|
2018-02-16 05:58:02 +00:00
|
|
|
|
|
|
|
/// Invalidates all entries. Uesd when the underlying path variable changes.
|
|
|
|
void invalidate();
|
2012-01-26 02:59:35 +00:00
|
|
|
};
|
2012-01-25 08:36:55 +00:00
|
|
|
#endif
|