Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 24 additions & 35 deletions filesystem/src/fs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,8 @@ extern "C" {
#include <string>
#include <spdlog/spdlog.h>

#include "query_lang/parser.hpp"
#include "fs.hpp"
#include "db.hpp"
#include "fs.hpp"
#include "command_interface.h"
#include "utilities.hpp"

Expand All @@ -41,15 +40,20 @@ int lake_getattr(const char *path, struct stat *stbuf)

auto file = reverse_query(path);

if (file.empty()) {
if (!file.has_value())
{
return file.error();
}

if (file.value().empty()) {
spdlog::error("No file found!");

return -ENOENT;
}

spdlog::debug("stat'ing file at {0}", file);
spdlog::debug("stat'ing file at {0}", file.value());

if (stat(file.c_str(), stbuf) < 0)
if (stat(file.value().c_str(), stbuf) < 0)
{
spdlog::error("Error stat'ing: {0}", strerror(errno));

Expand Down Expand Up @@ -82,36 +86,14 @@ int lake_readdir(
filler(buf, "..", nullptr, 0);
#endif

std::vector<std::string> files;

// TODO: very nested, smelly

// Check if path is a query
if (path[strlen(path) - 1] == ')') {
std::string query = extract_query(path);

try {
const auto query_ast = parse(query);

if (query_ast.has_value()) {
files = db_run_query(query_ast.value());

} else {
spdlog::error("Error while parsing, invalid query");
const auto files = get_files(path);

return -EINVAL;
}
} catch (std::exception err) {
spdlog::error("Error while parsing: {0}", err.what());

return -EINVAL;
}

} else {
files = db_run_default_query();
if (!files.has_value())
{
return files.error();
}

for (const auto& file : files) {
for (const auto& file : files.value()) {
const std::string file_name = file.substr(file.find_last_of("/") + 1);

spdlog::trace("Will show file {0} as {1}", file, file_name);
Expand All @@ -136,12 +118,19 @@ int lake_open(const char *path, struct fuse_file_info *fi) {

auto file_path = reverse_query(path);

if (file_path.empty())
if (!file_path.has_value())
{
return file_path.error();
}

if (file_path.value().empty())
{
return -ENOENT;
}

spdlog::trace("Found file {0} to open", file_path);
spdlog::trace("Found file {0} to open", file_path.value());

fi->fh = open(file_path.c_str(), fi->flags);
fi->fh = open(file_path.value().c_str(), fi->flags);

if (fi->fh == -1) {
spdlog::error("Could not open file err: {0}", strerror(errno));
Expand Down
177 changes: 142 additions & 35 deletions filesystem/src/utilities.cpp
Original file line number Diff line number Diff line change
@@ -1,64 +1,141 @@
// SPDX-FileCopyrightText: 2025 Caleb Depatie
//
// SPDX-License-Identifier: BSD-3-Clause
#include <algorithm>
#include <spdlog/spdlog.h>
#include <vector>
#include <filesystem>

#include "query_lang/parser.hpp"
#include "db.hpp"
#include "utilities.hpp"

std::string reverse_query(const char* path) {
auto path_s = std::string(path);
std::expected<std::vector<std::string>, int> get_files(const char* path) {
spdlog::trace("Entering get_files(path={0})", path);

spdlog::trace("Entering reverse_query(path={0})", path_s);
std::vector<std::string> files;

// Get path segments from query
const auto path_segments = split(path, "/");

const bool path_has_query = path_segments.size() != 0 && path_segments[0].contains('(');

if (path_has_query)
{
const auto query = extract_query(path);
const auto query_ast = parse(query);

if (query_ast.has_value()) {
files = db_run_query(query_ast.value());

} else {
spdlog::error("Error while parsing, invalid query");

return std::unexpected(-EINVAL);
}
}
else
{
files = db_run_default_query();
}

std::vector<std::string> query_files;
if (path_segments.size() > 1)
{

if (path_s.find_first_of('(') == std::string::npos) {
query_files = db_run_default_query();
// Get the file path by comparing the file name to the query results
std::string file_path;
std::string looking_for_file;

} else {
std::string query = extract_query(path);
if (path_has_query)
{
looking_for_file = path_segments[1];
}
else
{
looking_for_file = path_segments[0];
}

try {
const auto query_ast = parse(query);

if (query_ast.has_value()) {
query_files = db_run_query(query_ast.value());
for (const auto& query_file : files) {

} else {
spdlog::error("Error while parsing, no value returned");
const std::string query_file_name =
query_file.substr(query_file.find_last_of("/") + 1);

return "";
if (query_file_name == looking_for_file) {
file_path = query_file;
break;
}

} catch (std::exception err) {
spdlog::error("Error while parsing: {0}", err.what());

return "";
}
}

// Get the file path by comparing the file name to the query results
std::string file_path;
// Have to drill down arbitry path lengths
// Take current real path, get dir entries
// look for next folder, get that real path
// repeat
for (int i = 1 + path_has_query; i < path_segments.size(); i++)
{
auto finding_dir = path_segments[i];

const auto dir_iter = std::filesystem::directory_iterator(file_path);

for (const auto& dir_entry : dir_iter)
{
if (dir_entry.path().filename() == finding_dir)
{
file_path = dir_entry.path();
break;
}
}
}

const std::string looking_for_file =
std::string(path_s).substr(std::string(path_s).find_last_of("/") + 1);
if (std::filesystem::is_directory(file_path))
{
// Query is for a folder
spdlog::debug("Found real dir path: {0}", file_path.c_str());

for (const auto& query_file : query_files) {

const std::string query_file_name =
query_file.substr(query_file.find_last_of("/") + 1);
// Get files of our actual destination folder
files.clear();

if (query_file_name == looking_for_file) {
file_path = query_file;
break;
for (auto const& dir_entry : std::filesystem::directory_iterator{file_path})
{
files.push_back(dir_entry.path());
}
}
}

spdlog::trace("Exiting reverse_query() -> {0}", file_path);
return file_path;
spdlog::trace("Exiting get_files() -> vec.size()={0}", files.size());
return files;
}

std::expected<std::string, int> reverse_query(const char* path) {
auto path_s = std::string(path);

spdlog::trace("Entering reverse_query(path={0})", path_s);

const auto path_segments = split(path, "/");

std::string looking_for_file = path_segments[path_segments.size()-1];

std::string reconstructed_path;

for (int i = 0; i < path_segments.size()-1; i++)
{
reconstructed_path += "/" + path_segments[i];
}

const auto files = get_files(reconstructed_path.c_str());

if (!files.has_value())
{
return std::unexpected(files.error());
}

const auto file_path = std::find_if(files->begin(), files->end(),
[looking_for_file] (const std::string& file_name) -> bool {
return std::filesystem::path(file_name).filename() == looking_for_file;
});

spdlog::trace("Exiting reverse_query() -> {0}", *file_path);
return *file_path;
}

std::string extract_query(const char* path) {
Expand All @@ -70,6 +147,36 @@ std::string extract_query(const char* path) {
const auto extracted_query =
path_s.substr(path_s.find_first_of('('), path_s.find_last_of(')') - path_s.find_first_of('(') + 1);

spdlog::trace("Exiting parse() -> {0}", extracted_query);
spdlog::trace("Exiting extract_query() -> {0}", extracted_query);
return extracted_query;
}

std::vector<std::string> split(const std::string str, const std::string delim) {
spdlog::trace("Entering split(str={0}, delim={1})", str, delim);

std::vector<std::string> parts;

int part_start = 0;
for (int i = 0; i < str.size(); i++)
{
const std::string delim_match = str.substr(i, delim.size());

if (delim_match == delim)
{
if (part_start != i)
{
parts.push_back(str.substr(part_start, i-part_start));
}

part_start = i + delim.size();
}
}

if (part_start < str.size())
{
parts.push_back(str.substr(part_start, str.size() - part_start));
}

spdlog::trace("Exiting split() -> vec.size()={0}", parts.size());
return parts;
}
12 changes: 10 additions & 2 deletions filesystem/src/utilities.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,17 @@
#pragma once

#include <string>
#include <vector>
#include <expected>

// Runs a query normally. Handles special logic to pull out folders
std::expected<std::vector<std::string>, int> get_files(const char* path);

// Takes a query path that involves a tag query and returns the real FS path
std::string reverse_query(const char* path);
std::expected<std::string, int> reverse_query(const char* path);

// Takes a path and returns the query segment
std::string extract_query(const char* path);
std::string extract_query(const char* path);

// Split a string based on a delimeter
std::vector<std::string> split(const std::string str, const std::string delim);
26 changes: 25 additions & 1 deletion filesystem/tests/utilities.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,28 @@ TEST_CASE("Query Extraction", "[utilities]") {

CHECK(res == "(tag1 & ((!place) | (tag2 & tag3)))");
}
}
}

TEST_CASE("String Splitting", "[utilities]") {
SECTION("Single char delim") {
const auto haystack = "wow/this/is/a/path/";
const auto needle = "/";

const auto found = split(haystack, needle);

CHECK(found.size() == 5);
CHECK(found[0] == "wow");
CHECK(found[4] == "path");
}

SECTION("Multi char delim") {
const auto haystack = "><i><love><testing";
const auto needle = "><";

const auto found = split(haystack, needle);

CHECK(found.size() == 3);
CHECK(found[0] == "i");
CHECK(found[2] == "testing");
}
}
2 changes: 1 addition & 1 deletion integration_tests/adv_query.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ source integration_tests/test_core.sh

# Issue #34 :: Exit gracefully with an incorrect query
# TODO: Seems to work but I only get 0 in $rc.
# /usr/bin/env ls $lake_dir/'((default | not_default) & )'
# ls $lake_dir/'((default | not_default) & )' && echo 'not ok!!'
# rc=$?

# if [ $rc != 1 ]; then
Expand Down
Loading
Loading