Skip to content

Commit

Permalink
[api] Added pipy.mount()
Browse files Browse the repository at this point in the history
  • Loading branch information
pajama-coder committed Jun 17, 2024
1 parent 773ec5e commit a88123b
Show file tree
Hide file tree
Showing 4 changed files with 149 additions and 7 deletions.
19 changes: 16 additions & 3 deletions src/api/pipy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include "listener.hpp"
#include "outbound.hpp"
#include "file.hpp"
#include "fs.hpp"
#include "fstream.hpp"
#include "api/pipeline-api.hpp"
#include "os-platform.hpp"
Expand Down Expand Up @@ -655,11 +656,11 @@ template<> void ClassDef<Pipy>::init() {
ret.set(Thread::current());
});

method("now", [](Context &ctx, Object *obj, Value &ret) {
method("now", [](Context &ctx, Object*, Value &ret) {
ret.set(utils::now_since(Status::LocalInstance::since));
});

method("fork", [](Context &ctx, Object *obj, Value &ret) {
method("fork", [](Context &ctx, Object*, Value &ret) {
Function *func;
if (!ctx.arguments(1, &func)) return;
auto root = static_cast<pipy::Context*>(ctx.root());
Expand All @@ -669,6 +670,18 @@ template<> void ClassDef<Pipy>::init() {
if (!context->ok()) ctx.error(*context);
});

method("mount", [](Context &ctx, Object*, Value &ret) {
std::string path;
std::string dirname;
if (!ctx.arguments(2, &path, &dirname)) return;
if (!fs::is_dir(dirname)) return ctx.error("not a directory");
try {
Codebase::current()->mount(path, Codebase::from_fs(dirname));
} catch (std::runtime_error &err) {
ctx.error(err);
}
});

method("load", [](Context &ctx, Object*, Value &ret) {
std::string filename;
if (!ctx.arguments(1, &filename)) return;
Expand All @@ -688,7 +701,7 @@ template<> void ClassDef<Pipy>::init() {
for (const auto &name : codebase->list(path)) {
if (name.back() == '/') {
auto sub = name.substr(0, name.length() - 1);
auto str = path + '/' + sub;
auto str = utils::path_join(path, sub);
list_dir(str, base + sub + '/');
} else {
a->push(Str::make(base + name));
Expand Down
134 changes: 130 additions & 4 deletions src/codebase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,115 @@ static const pjs::Ref<pjs::Str> s_date(pjs::Str::make("last-modified"));

Codebase* Codebase::s_current = nullptr;

//
// CodebaseFromRoot
//

class CodebaseFromRoot : public Codebase {
public:
CodebaseFromRoot(Codebase *root);
~CodebaseFromRoot();


virtual auto version() const -> const std::string& override { return m_root->version(); }
virtual bool writable() const override { return m_root->writable(); }
virtual auto entry() const -> const std::string& override { return m_root->entry(); }
virtual void entry(const std::string &path) override { m_root->entry(path); }
virtual void mount(const std::string &path, Codebase *codebase) override;
virtual auto list(const std::string &path) -> std::list<std::string> override;
virtual auto get(const std::string &path) -> SharedData* override;
virtual void set(const std::string &path, SharedData *data) override;
virtual auto watch(const std::string &path, const std::function<void(bool)> &on_update) -> Watch* override;
virtual void sync(bool force, const std::function<void(bool)> &on_update) override { m_root->sync(force, on_update); }

private:
Codebase* m_root;
std::map<std::string, Codebase*> m_mounts;
std::mutex m_mutex;

auto find_mount(const std::string &path, std::string &local_path) -> Codebase*;
};

CodebaseFromRoot::CodebaseFromRoot(Codebase *root)
: m_root(root)
{
}

CodebaseFromRoot::~CodebaseFromRoot() {
for (const auto &p : m_mounts) delete p.second;
delete m_root;
}

void CodebaseFromRoot::mount(const std::string &name, Codebase *codebase) {
if (name.find('/') != std::string::npos) throw std::runtime_error("invalid mount name");
if (get(name)) throw std::runtime_error("mount path already exists");
if (list(name).size() > 0) throw std::runtime_error("mount path already exists");
std::lock_guard<std::mutex> lock(m_mutex);
for (const auto &p : m_mounts) {
if (p.first == name) {
throw std::runtime_error("mount path already exists");
}
}
m_mounts[name] = codebase;
}

auto CodebaseFromRoot::list(const std::string &path) -> std::list<std::string> {
std::lock_guard<std::mutex> lock(m_mutex);
std::string local_path;
if (auto codebase = find_mount(path, local_path)) {
return codebase->list(local_path);
}
auto list = m_root->list(path);
if (path == "/") for (const auto &p : m_mounts) list.push_back(p.first + '/');
return list;
}

auto CodebaseFromRoot::get(const std::string &path) -> SharedData* {
std::lock_guard<std::mutex> lock(m_mutex);
std::string local_path;
if (auto codebase = find_mount(path, local_path)) {
return codebase->get(local_path);
}
return m_root->get(path);
}

void CodebaseFromRoot::set(const std::string &path, SharedData *data) {
std::lock_guard<std::mutex> lock(m_mutex);
std::string local_path;
if (auto codebase = find_mount(path, local_path)) {
return codebase->set(local_path, data);
}
return m_root->set(path, data);
}

auto CodebaseFromRoot::watch(const std::string &path, const std::function<void(bool)> &on_update) -> Watch* {
std::lock_guard<std::mutex> lock(m_mutex);
std::string local_path;
if (auto codebase = find_mount(path, local_path)) {
return codebase->watch(local_path, on_update);
}
return m_root->watch(path, on_update);
}

auto CodebaseFromRoot::find_mount(const std::string &path, std::string &local_path) -> Codebase* {
std::string dirname = path;
if (dirname.front() != '/') dirname = '/' + dirname;
if (dirname.back() != '/') dirname += '/';
for (auto &p : m_mounts) {
auto &name = p.first;
auto n = name.length();
if (dirname.length() >= n + 2) {
if (dirname[n + 1] == '/') {
if (!std::strncmp(dirname.c_str() + 1, name.c_str(), n)) {
local_path = dirname.substr(n + 2);
return p.second;
}
}
}
}
return nullptr;
}

//
// CodebaseFromFS
//
Expand All @@ -60,6 +169,7 @@ class CodebaseFromFS : public Codebase {
virtual bool writable() const override { return true; }
virtual auto entry() const -> const std::string& override { return m_entry; }
virtual void entry(const std::string &path) override { m_entry = path; }
virtual void mount(const std::string &path, Codebase *codebase) override;
virtual auto list(const std::string &path) -> std::list<std::string> override;
virtual auto get(const std::string &path) -> SharedData* override;
virtual void set(const std::string &path, SharedData *data) override;
Expand Down Expand Up @@ -107,6 +217,10 @@ CodebaseFromFS::CodebaseFromFS(const std::string &path, const std::string &scrip
}
}

void CodebaseFromFS::mount(const std::string &, Codebase *) {
throw std::runtime_error("mounting unsupported");
}

auto CodebaseFromFS::list(const std::string &path) -> std::list<std::string> {
std::lock_guard<std::mutex> lock(m_mutex);
std::list<std::string> list;
Expand Down Expand Up @@ -217,6 +331,7 @@ class CodebaseFromStore : public Codebase {
virtual bool writable() const override { return false; }
virtual auto entry() const -> const std::string& override { return m_entry; }
virtual void entry(const std::string &path) override {}
virtual void mount(const std::string &path, Codebase *codebase) override;
virtual auto list(const std::string &path) -> std::list<std::string> override;
virtual auto get(const std::string &path) -> SharedData* override;
virtual void set(const std::string &path, SharedData *data) override {}
Expand Down Expand Up @@ -253,14 +368,17 @@ CodebaseFromStore::CodebaseFromStore(CodebaseStore *store, const std::string &na
}
}

void CodebaseFromStore::mount(const std::string &, Codebase *) {
throw std::runtime_error("mounting unsupported");
}

auto CodebaseFromStore::list(const std::string &path) -> std::list<std::string> {
std::lock_guard<std::mutex> lock(m_mutex);
std::set<std::string> names;
auto n = path.length();
for (const auto &i : m_files) {
const auto &name = i.first;
if (name.length() > path.length() &&
name[n] == '/' && !std::strncmp(name.c_str(), path.c_str(), n)) {
if (name.length() > n && name[n] == '/' && utils::starts_with(name, path)) {
auto i = name.find('/', n + 1);
if (i == std::string::npos) {
names.insert(name.substr(n + 1));
Expand Down Expand Up @@ -306,6 +424,7 @@ class CodebaseFromHTTP : public Codebase {
virtual bool writable() const override { return false; }
virtual auto entry() const -> const std::string& override { return m_entry; }
virtual void entry(const std::string &path) override {}
virtual void mount(const std::string &path, Codebase *codebase) override;
virtual auto list(const std::string &path) -> std::list<std::string> override;
virtual auto get(const std::string &path) -> SharedData* override;
virtual void set(const std::string &path, SharedData *data) override {}
Expand Down Expand Up @@ -359,14 +478,17 @@ CodebaseFromHTTP::CodebaseFromHTTP(const std::string &url, const Fetch::Options
m_request_header_post_status = headers;
}

void CodebaseFromHTTP::mount(const std::string &, Codebase *) {
throw std::runtime_error("mounting unsupported");
}

auto CodebaseFromHTTP::list(const std::string &path) -> std::list<std::string> {
std::lock_guard<std::mutex> lock(m_mutex);
std::set<std::string> names;
auto n = path.length();
for (const auto &i : m_files) {
const auto &name = i.first;
if (name.length() > path.length() &&
name[n] == '/' && !std::strncmp(name.c_str(), path.c_str(), n)) {
if (name.length() > n && name[n] == '/' && utils::starts_with(name, path)) {
auto i = name.find('/', n + 1);
if (i == std::string::npos) {
names.insert(name.substr(n + 1));
Expand Down Expand Up @@ -647,6 +769,10 @@ void CodebaseFromHTTP::response_error(const char *method, const char *path, http
// Codebase
//

Codebase* Codebase::from_root(Codebase *root) {
return new CodebaseFromRoot(root);
}

Codebase* Codebase::from_fs(const std::string &path) {
return new CodebaseFromFS(path);
}
Expand Down
2 changes: 2 additions & 0 deletions src/codebase.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ class Codebase {

static auto current() -> Codebase* { return s_current; }

static Codebase* from_root(Codebase *root);
static Codebase* from_fs(const std::string &path);
static Codebase* from_fs(const std::string &path, const std::string &script);
static Codebase* from_store(CodebaseStore *store, const std::string &name);
Expand All @@ -104,6 +105,7 @@ class Codebase {
virtual bool writable() const = 0;
virtual auto entry() const -> const std::string& = 0;
virtual void entry(const std::string &path) = 0;
virtual void mount(const std::string &path, Codebase *codebase) = 0;
virtual auto list(const std::string &path) -> std::list<std::string> = 0;
virtual auto get(const std::string &path) -> SharedData* = 0;
virtual void set(const std::string &path, SharedData *data) = 0;
Expand Down
1 change: 1 addition & 0 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -571,6 +571,7 @@ int pipy_main(int argc, char *argv[]) {
);
}

codebase = Codebase::from_root(codebase);
codebase->set_current();

bool started = false, start_error = false;
Expand Down

0 comments on commit a88123b

Please sign in to comment.