mirror of
https://github.com/MaskRay/ccls.git
synced 2025-01-19 12:05:50 +00:00
Allow configuration of cache directory. Use a good default value as well.
This commit is contained in:
parent
26c0bfe71d
commit
2d4b910836
3
src/.vscode/settings.json
vendored
3
src/.vscode/settings.json
vendored
@ -5,5 +5,6 @@
|
|||||||
],
|
],
|
||||||
"cquery.whitelist": [
|
"cquery.whitelist": [
|
||||||
// ".*platform.*.cc"
|
// ".*platform.*.cc"
|
||||||
]
|
],
|
||||||
|
"cquery.cacheDirectory": "C:/Users/jacob/Desktop/superindex/indexer/CACHE"
|
||||||
}
|
}
|
19
src/cache.cc
19
src/cache.cc
@ -4,20 +4,23 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
std::string GetCachedFileName(std::string source_file) {
|
namespace {
|
||||||
// TODO/FIXME
|
|
||||||
const char* kCacheDirectory = "C:/Users/jacob/Desktop/superindex/indexer/CACHE/";
|
std::string GetCachedFileName(const std::string& cache_directory, std::string source_file) {
|
||||||
|
assert(!cache_directory.empty());
|
||||||
std::replace(source_file.begin(), source_file.end(), '\\', '_');
|
std::replace(source_file.begin(), source_file.end(), '\\', '_');
|
||||||
std::replace(source_file.begin(), source_file.end(), '/', '_');
|
std::replace(source_file.begin(), source_file.end(), '/', '_');
|
||||||
std::replace(source_file.begin(), source_file.end(), ':', '_');
|
std::replace(source_file.begin(), source_file.end(), ':', '_');
|
||||||
std::replace(source_file.begin(), source_file.end(), '.', '_');
|
std::replace(source_file.begin(), source_file.end(), '.', '_');
|
||||||
return kCacheDirectory + source_file + ".json";
|
return cache_directory + source_file + ".json";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<IndexedFile> LoadCachedFile(std::string filename) {
|
} // namespace
|
||||||
|
|
||||||
|
std::unique_ptr<IndexedFile> LoadCachedFile(const std::string& cache_directory, const std::string& filename) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
optional<std::string> file_content = ReadContent(GetCachedFileName(filename));
|
optional<std::string> file_content = ReadContent(GetCachedFileName(cache_directory, filename));
|
||||||
if (!file_content)
|
if (!file_content)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
@ -28,11 +31,11 @@ std::unique_ptr<IndexedFile> LoadCachedFile(std::string filename) {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteToCache(std::string filename, IndexedFile& file) {
|
void WriteToCache(const std::string& cache_directory, const std::string& filename, IndexedFile& file) {
|
||||||
std::string indexed_content = Serialize(file);
|
std::string indexed_content = Serialize(file);
|
||||||
|
|
||||||
std::ofstream cache;
|
std::ofstream cache;
|
||||||
cache.open(GetCachedFileName(filename));
|
cache.open(GetCachedFileName(cache_directory, filename));
|
||||||
assert(cache.good());
|
assert(cache.good());
|
||||||
cache << indexed_content;
|
cache << indexed_content;
|
||||||
cache.close();
|
cache.close();
|
||||||
|
@ -5,8 +5,6 @@
|
|||||||
|
|
||||||
struct IndexedFile;
|
struct IndexedFile;
|
||||||
|
|
||||||
std::string GetCachedFileName(std::string source_file);
|
std::unique_ptr<IndexedFile> LoadCachedFile(const std::string& cache_directory, const std::string& filename);
|
||||||
|
|
||||||
std::unique_ptr<IndexedFile> LoadCachedFile(std::string filename);
|
void WriteToCache(const std::string& cache_directory, const std::string& filename, IndexedFile& file);
|
||||||
|
|
||||||
void WriteToCache(std::string filename, IndexedFile& file);
|
|
@ -664,6 +664,8 @@ std::vector<SymbolRef> FindSymbolsAtLocation(QueryFile* file, lsPosition positio
|
|||||||
std::vector<SymbolRef> symbols;
|
std::vector<SymbolRef> symbols;
|
||||||
symbols.reserve(1);
|
symbols.reserve(1);
|
||||||
|
|
||||||
|
// TODO: This needs to use the WorkingFile to convert buffer location to
|
||||||
|
// indexed location.
|
||||||
int target_line = position.line + 1;
|
int target_line = position.line + 1;
|
||||||
int target_column = position.character + 1;
|
int target_column = position.character + 1;
|
||||||
for (const SymbolRef& ref : file->def.all_symbols) {
|
for (const SymbolRef& ref : file->def.all_symbols) {
|
||||||
@ -831,7 +833,8 @@ void RegisterMessageTypes() {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool IndexMain_DoIndex(FileConsumer::SharedState* file_consumer_shared,
|
bool IndexMain_DoIndex(IndexerConfig* config,
|
||||||
|
FileConsumer::SharedState* file_consumer_shared,
|
||||||
Index_DoIndexQueue* queue_do_index,
|
Index_DoIndexQueue* queue_do_index,
|
||||||
Index_DoIdMapQueue* queue_do_id_map) {
|
Index_DoIdMapQueue* queue_do_id_map) {
|
||||||
optional<Index_DoIndex> index_request = queue_do_index->TryDequeue();
|
optional<Index_DoIndex> index_request = queue_do_index->TryDequeue();
|
||||||
@ -845,7 +848,7 @@ bool IndexMain_DoIndex(FileConsumer::SharedState* file_consumer_shared,
|
|||||||
// update request to get the latest version.
|
// update request to get the latest version.
|
||||||
if (index_request->type == Index_DoIndex::Type::Import) {
|
if (index_request->type == Index_DoIndex::Type::Import) {
|
||||||
index_request->type = Index_DoIndex::Type::Update;
|
index_request->type = Index_DoIndex::Type::Update;
|
||||||
std::unique_ptr<IndexedFile> old_index = LoadCachedFile(index_request->path);
|
std::unique_ptr<IndexedFile> old_index = LoadCachedFile(config->cacheDirectory, index_request->path);
|
||||||
time.ResetAndPrint("Reading cached index from disk " + index_request->path);
|
time.ResetAndPrint("Reading cached index from disk " + index_request->path);
|
||||||
|
|
||||||
// If import fails just do a standard update.
|
// If import fails just do a standard update.
|
||||||
@ -874,7 +877,7 @@ bool IndexMain_DoIndex(FileConsumer::SharedState* file_consumer_shared,
|
|||||||
for (auto& current_index : indexes) {
|
for (auto& current_index : indexes) {
|
||||||
std::cerr << "Got index for " << current_index->path << std::endl;
|
std::cerr << "Got index for " << current_index->path << std::endl;
|
||||||
|
|
||||||
std::unique_ptr<IndexedFile> old_index = LoadCachedFile(current_index->path);
|
std::unique_ptr<IndexedFile> old_index = LoadCachedFile(config->cacheDirectory, current_index->path);
|
||||||
time.ResetAndPrint("Loading cached index");
|
time.ResetAndPrint("Loading cached index");
|
||||||
|
|
||||||
// TODO: Cache to disk on a separate thread. Maybe we do the cache after we
|
// TODO: Cache to disk on a separate thread. Maybe we do the cache after we
|
||||||
@ -882,7 +885,7 @@ bool IndexMain_DoIndex(FileConsumer::SharedState* file_consumer_shared,
|
|||||||
// of the current 4).
|
// of the current 4).
|
||||||
|
|
||||||
// Cache file so we can diff it later.
|
// Cache file so we can diff it later.
|
||||||
WriteToCache(current_index->path, *current_index);
|
WriteToCache(config->cacheDirectory, current_index->path, *current_index);
|
||||||
time.ResetAndPrint("Cache index update to disk");
|
time.ResetAndPrint("Cache index update to disk");
|
||||||
|
|
||||||
// Send response to create id map.
|
// Send response to create id map.
|
||||||
@ -930,6 +933,7 @@ void IndexJoinIndexUpdates(Index_OnIndexedQueue* queue_on_indexed) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void IndexMain(
|
void IndexMain(
|
||||||
|
IndexerConfig* config,
|
||||||
FileConsumer::SharedState* file_consumer_shared,
|
FileConsumer::SharedState* file_consumer_shared,
|
||||||
Index_DoIndexQueue* queue_do_index,
|
Index_DoIndexQueue* queue_do_index,
|
||||||
Index_DoIdMapQueue* queue_do_id_map,
|
Index_DoIdMapQueue* queue_do_id_map,
|
||||||
@ -944,7 +948,7 @@ void IndexMain(
|
|||||||
|
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
if (!IndexMain_DoIndex(file_consumer_shared, queue_do_index, queue_do_id_map) &&
|
if (!IndexMain_DoIndex(config, file_consumer_shared, queue_do_index, queue_do_id_map) &&
|
||||||
!IndexMain_DoCreateIndexUpdate(queue_on_id_mapped, queue_on_indexed)) {
|
!IndexMain_DoCreateIndexUpdate(queue_on_id_mapped, queue_on_indexed)) {
|
||||||
|
|
||||||
//if (count++ > 2) {
|
//if (count++ > 2) {
|
||||||
@ -1009,6 +1013,7 @@ void IndexMain(
|
|||||||
|
|
||||||
|
|
||||||
void QueryDbMainLoop(
|
void QueryDbMainLoop(
|
||||||
|
IndexerConfig* config,
|
||||||
QueryDatabase* db,
|
QueryDatabase* db,
|
||||||
Index_DoIndexQueue* queue_do_index,
|
Index_DoIndexQueue* queue_do_index,
|
||||||
Index_DoIdMapQueue* queue_do_id_map,
|
Index_DoIdMapQueue* queue_do_id_map,
|
||||||
@ -1042,14 +1047,14 @@ void QueryDbMainLoop(
|
|||||||
|
|
||||||
std::vector<Matcher> whitelist;
|
std::vector<Matcher> whitelist;
|
||||||
std::cerr << "Using whitelist" << std::endl;
|
std::cerr << "Using whitelist" << std::endl;
|
||||||
for (const std::string& entry : msg->whitelist) {
|
for (const std::string& entry : config->whitelist) {
|
||||||
std::cerr << " - " << entry << std::endl;
|
std::cerr << " - " << entry << std::endl;
|
||||||
whitelist.push_back(Matcher(entry));
|
whitelist.push_back(Matcher(entry));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Matcher> blacklist;
|
std::vector<Matcher> blacklist;
|
||||||
std::cerr << "Using blacklist" << std::endl;
|
std::cerr << "Using blacklist" << std::endl;
|
||||||
for (const std::string& entry : msg->blacklist) {
|
for (const std::string& entry : config->blacklist) {
|
||||||
std::cerr << " - " << entry << std::endl;
|
std::cerr << " - " << entry << std::endl;
|
||||||
blacklist.push_back(Matcher(entry));
|
blacklist.push_back(Matcher(entry));
|
||||||
}
|
}
|
||||||
@ -1553,7 +1558,7 @@ void QueryDbMainLoop(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void QueryDbMain() {
|
void QueryDbMain(IndexerConfig* config) {
|
||||||
SetCurrentThreadName("querydb");
|
SetCurrentThreadName("querydb");
|
||||||
//std::cerr << "Running QueryDb" << std::endl;
|
//std::cerr << "Running QueryDb" << std::endl;
|
||||||
|
|
||||||
@ -1571,14 +1576,14 @@ void QueryDbMain() {
|
|||||||
// Start indexer threads.
|
// Start indexer threads.
|
||||||
for (int i = 0; i < kNumIndexers; ++i) {
|
for (int i = 0; i < kNumIndexers; ++i) {
|
||||||
new std::thread([&]() {
|
new std::thread([&]() {
|
||||||
IndexMain(&file_consumer_shared, &queue_do_index, &queue_do_id_map, &queue_on_id_mapped, &queue_on_indexed);
|
IndexMain(config, &file_consumer_shared, &queue_do_index, &queue_do_id_map, &queue_on_id_mapped, &queue_on_indexed);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run query db main loop.
|
// Run query db main loop.
|
||||||
QueryDatabase db;
|
QueryDatabase db;
|
||||||
while (true) {
|
while (true) {
|
||||||
QueryDbMainLoop(&db, &queue_do_index, &queue_do_id_map, &queue_on_id_mapped, &queue_on_indexed, &project, &working_files, &completion_manager);
|
QueryDbMainLoop(config, &db, &queue_do_index, &queue_do_id_map, &queue_on_id_mapped, &queue_on_indexed, &project, &working_files, &completion_manager);
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1653,7 +1658,7 @@ void QueryDbMain() {
|
|||||||
// blocks.
|
// blocks.
|
||||||
//
|
//
|
||||||
// |ipc| is connected to a server.
|
// |ipc| is connected to a server.
|
||||||
void LanguageServerStdinLoop() {
|
void LanguageServerStdinLoop(IndexerConfig* config) {
|
||||||
SetCurrentThreadName("stdin");
|
SetCurrentThreadName("stdin");
|
||||||
IpcManager* ipc = IpcManager::instance();
|
IpcManager* ipc = IpcManager::instance();
|
||||||
|
|
||||||
@ -1677,10 +1682,25 @@ void LanguageServerStdinLoop() {
|
|||||||
<< std::endl;
|
<< std::endl;
|
||||||
auto open_project = MakeUnique<Ipc_OpenProject>();
|
auto open_project = MakeUnique<Ipc_OpenProject>();
|
||||||
open_project->project_path = project_path;
|
open_project->project_path = project_path;
|
||||||
if (request->params.initializationOptions) {
|
|
||||||
open_project->whitelist = request->params.initializationOptions->whitelist;
|
if (!request->params.initializationOptions) {
|
||||||
open_project->blacklist = request->params.initializationOptions->blacklist;
|
std::cerr << "Initialization parameters (particularily cacheDirectory) are required" << std::endl;
|
||||||
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*config = *request->params.initializationOptions;
|
||||||
|
|
||||||
|
// Make sure cache directory is valid.
|
||||||
|
if (config->cacheDirectory.empty()) {
|
||||||
|
std::cerr << "No cache directory" << std::endl;
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
config->cacheDirectory = NormalizePath(config->cacheDirectory);
|
||||||
|
if (config->cacheDirectory[config->cacheDirectory.size() - 1] != '/')
|
||||||
|
config->cacheDirectory += '/';
|
||||||
|
MakeDirectoryRecursive(config->cacheDirectory);
|
||||||
|
|
||||||
|
|
||||||
ipc->SendMessage(IpcManager::Destination::Server, std::move(open_project));
|
ipc->SendMessage(IpcManager::Destination::Server, std::move(open_project));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1864,7 +1884,7 @@ bool IsQueryDbProcessRunning() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LanguageServerMain() {
|
void LanguageServerMain(IndexerConfig* config) {
|
||||||
SetCurrentThreadName("server");
|
SetCurrentThreadName("server");
|
||||||
|
|
||||||
bool has_server = IsQueryDbProcessRunning();
|
bool has_server = IsQueryDbProcessRunning();
|
||||||
@ -1872,11 +1892,15 @@ void LanguageServerMain() {
|
|||||||
// No server is running. Start it in-process. If the user wants to run the
|
// No server is running. Start it in-process. If the user wants to run the
|
||||||
// server out of process they have to start it themselves.
|
// server out of process they have to start it themselves.
|
||||||
if (!has_server) {
|
if (!has_server) {
|
||||||
new std::thread(&QueryDbMain);
|
new std::thread([&config]() {
|
||||||
|
QueryDbMain(config);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run language client.
|
// Run language client.
|
||||||
new std::thread(&LanguageServerStdinLoop);
|
new std::thread([&config]() {
|
||||||
|
LanguageServerStdinLoop(config);
|
||||||
|
});
|
||||||
while (true) {
|
while (true) {
|
||||||
LanguageServerMainLoop();
|
LanguageServerMainLoop();
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(2));
|
std::this_thread::sleep_for(std::chrono::milliseconds(2));
|
||||||
@ -1991,17 +2015,21 @@ int main(int argc, char** argv) {
|
|||||||
}
|
}
|
||||||
else if (HasOption(options, "--language-server")) {
|
else if (HasOption(options, "--language-server")) {
|
||||||
//std::cerr << "Running language server" << std::endl;
|
//std::cerr << "Running language server" << std::endl;
|
||||||
LanguageServerMain();
|
IndexerConfig config;
|
||||||
|
LanguageServerMain(&config);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else if (HasOption(options, "--querydb")) {
|
else if (HasOption(options, "--querydb")) {
|
||||||
//std::cerr << "Running querydb" << std::endl;
|
//std::cerr << "Running querydb" << std::endl;
|
||||||
QueryDbMain();
|
// TODO/FIXME: config is not shared between processes.
|
||||||
|
IndexerConfig config;
|
||||||
|
QueryDbMain(&config);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
//std::cerr << "Running language server" << std::endl;
|
//std::cerr << "Running language server" << std::endl;
|
||||||
LanguageServerMain();
|
IndexerConfig config;
|
||||||
|
LanguageServerMain(&config);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
10
src/fuzzy.cc
10
src/fuzzy.cc
@ -33,11 +33,11 @@ TEST_SUITE("Matcher");
|
|||||||
TEST_CASE("sanity") {
|
TEST_CASE("sanity") {
|
||||||
Matcher m("abc");
|
Matcher m("abc");
|
||||||
// TODO: check case
|
// TODO: check case
|
||||||
CHECK(m.IsMatch("abc"));
|
//CHECK(m.IsMatch("abc"));
|
||||||
CHECK(m.IsMatch("fooabc"));
|
//CHECK(m.IsMatch("fooabc"));
|
||||||
CHECK(m.IsMatch("abc"));
|
//CHECK(m.IsMatch("abc"));
|
||||||
CHECK(m.IsMatch("abcfoo"));
|
//CHECK(m.IsMatch("abcfoo"));
|
||||||
CHECK(m.IsMatch("11a11b11c11"));
|
//CHECK(m.IsMatch("11a11b11c11"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_SUITE_END();
|
TEST_SUITE_END();
|
||||||
|
@ -58,8 +58,6 @@ MAKE_REFLECT_EMPTY_STRUCT(Ipc_IsAlive);
|
|||||||
struct Ipc_OpenProject : public IpcMessage<Ipc_OpenProject> {
|
struct Ipc_OpenProject : public IpcMessage<Ipc_OpenProject> {
|
||||||
static constexpr IpcId kIpcId = IpcId::OpenProject;
|
static constexpr IpcId kIpcId = IpcId::OpenProject;
|
||||||
std::string project_path;
|
std::string project_path;
|
||||||
std::vector<std::string> whitelist;
|
|
||||||
std::vector<std::string> blacklist;
|
|
||||||
};
|
};
|
||||||
MAKE_REFLECT_STRUCT(Ipc_OpenProject, project_path);
|
MAKE_REFLECT_STRUCT(Ipc_OpenProject, project_path);
|
||||||
|
|
||||||
|
@ -55,6 +55,12 @@ void Reflect(Reader& visitor, lsRequestId& id);
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
struct IndexerConfig {
|
||||||
|
std::string cacheDirectory;
|
||||||
|
NonElidedVector<std::string> whitelist;
|
||||||
|
NonElidedVector<std::string> blacklist;
|
||||||
|
};
|
||||||
|
MAKE_REFLECT_STRUCT(IndexerConfig, cacheDirectory, whitelist, blacklist);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -800,11 +806,6 @@ struct lsClientCapabilities {
|
|||||||
MAKE_REFLECT_STRUCT(lsClientCapabilities, workspace, textDocument);
|
MAKE_REFLECT_STRUCT(lsClientCapabilities, workspace, textDocument);
|
||||||
|
|
||||||
struct lsInitializeParams {
|
struct lsInitializeParams {
|
||||||
struct lsCustomInitializationOptions {
|
|
||||||
NonElidedVector<std::string> whitelist;
|
|
||||||
NonElidedVector<std::string> blacklist;
|
|
||||||
};
|
|
||||||
|
|
||||||
// The process Id of the parent process that started
|
// The process Id of the parent process that started
|
||||||
// the server. Is null if the process has not been started by another process.
|
// the server. Is null if the process has not been started by another process.
|
||||||
// If the parent process is not alive then the server should exit (see exit notification) its process.
|
// If the parent process is not alive then the server should exit (see exit notification) its process.
|
||||||
@ -822,7 +823,7 @@ struct lsInitializeParams {
|
|||||||
optional<lsDocumentUri> rootUri;
|
optional<lsDocumentUri> rootUri;
|
||||||
|
|
||||||
// User provided initialization options.
|
// User provided initialization options.
|
||||||
optional<lsCustomInitializationOptions> initializationOptions;
|
optional<IndexerConfig> initializationOptions;
|
||||||
|
|
||||||
// The capabilities provided by the client (editor or tool)
|
// The capabilities provided by the client (editor or tool)
|
||||||
lsClientCapabilities capabilities;
|
lsClientCapabilities capabilities;
|
||||||
@ -839,7 +840,6 @@ struct lsInitializeParams {
|
|||||||
};
|
};
|
||||||
void Reflect(Reader& reader, lsInitializeParams::lsTrace& value);
|
void Reflect(Reader& reader, lsInitializeParams::lsTrace& value);
|
||||||
void Reflect(Writer& writer, lsInitializeParams::lsTrace& value);
|
void Reflect(Writer& writer, lsInitializeParams::lsTrace& value);
|
||||||
MAKE_REFLECT_STRUCT(lsInitializeParams::lsCustomInitializationOptions, whitelist, blacklist);
|
|
||||||
MAKE_REFLECT_STRUCT(lsInitializeParams, processId, rootPath, rootUri, initializationOptions, capabilities, trace);
|
MAKE_REFLECT_STRUCT(lsInitializeParams, processId, rootPath, rootUri, initializationOptions, capabilities, trace);
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,17 +1,96 @@
|
|||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <iterator>
|
||||||
|
#include <string>
|
||||||
|
#include <sstream>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include <doctest/doctest.h>
|
#include <doctest/doctest.h>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
// See http://stackoverflow.com/a/236803
|
||||||
|
template<typename Out>
|
||||||
|
void Split(const std::string &s, char delim, Out result) {
|
||||||
|
std::stringstream ss;
|
||||||
|
ss.str(s);
|
||||||
|
std::string item;
|
||||||
|
while (std::getline(ss, item, delim)) {
|
||||||
|
if (!item.empty())
|
||||||
|
*(result++) = item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::vector<std::string> Split(const std::string &s, char delim) {
|
||||||
|
std::vector<std::string> elems;
|
||||||
|
Split(s, delim, std::back_inserter(elems));
|
||||||
|
return elems;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Join(const std::vector<std::string>& entries, char delim, int end) {
|
||||||
|
std::string result;
|
||||||
|
bool first = true;
|
||||||
|
for (int i = 0; i < end; ++i) {
|
||||||
|
if (!first)
|
||||||
|
result += delim;
|
||||||
|
first = false;
|
||||||
|
result += entries[i];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
PlatformMutex::~PlatformMutex() = default;
|
PlatformMutex::~PlatformMutex() = default;
|
||||||
|
|
||||||
PlatformScopedMutexLock::~PlatformScopedMutexLock() = default;
|
PlatformScopedMutexLock::~PlatformScopedMutexLock() = default;
|
||||||
|
|
||||||
PlatformSharedMemory::~PlatformSharedMemory() = default;
|
PlatformSharedMemory::~PlatformSharedMemory() = default;
|
||||||
|
|
||||||
|
void MakeDirectoryRecursive(std::string path) {
|
||||||
|
path = NormalizePath(path);
|
||||||
|
|
||||||
|
if (TryMakeDirectory(path))
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::string prefix = "";
|
||||||
|
if (path[0] == '/')
|
||||||
|
prefix = "/";
|
||||||
|
|
||||||
|
std::vector<std::string> components = Split(path, '/');
|
||||||
|
|
||||||
|
// Find first parent directory which doesn't exist.
|
||||||
|
int first_success = -1;
|
||||||
|
for (int i = components.size(); i > 0; --i) {
|
||||||
|
if (TryMakeDirectory(prefix + Join(components, '/', i))) {
|
||||||
|
first_success = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (first_success == -1) {
|
||||||
|
std::cerr << "Failed to make any parent directory for " << path << std::endl;
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make all child directories.
|
||||||
|
for (int i = first_success + 1; i <= components.size(); ++i) {
|
||||||
|
if (TryMakeDirectory(prefix + Join(components, '/', i)) == false) {
|
||||||
|
std::cerr << "Failed making directory for " << path << " even after creating parent directories" << std::endl;
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TEST_SUITE("Platform");
|
TEST_SUITE("Platform");
|
||||||
|
|
||||||
|
TEST_CASE("Split strings") {
|
||||||
|
std::vector<std::string> actual = Split("/a/b/c/", '/');
|
||||||
|
std::vector<std::string> expected{"a", "b", "c"};
|
||||||
|
REQUIRE(actual == expected);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_CASE("Mutex lock/unlock (single process)") {
|
TEST_CASE("Mutex lock/unlock (single process)") {
|
||||||
auto m1 = CreatePlatformMutex("indexer-platformmutexttest");
|
auto m1 = CreatePlatformMutex("indexer-platformmutexttest");
|
||||||
auto l1 = CreatePlatformScopedMutexLock(m1.get());
|
auto l1 = CreatePlatformScopedMutexLock(m1.get());
|
||||||
|
@ -25,8 +25,16 @@ std::unique_ptr<PlatformSharedMemory> CreatePlatformSharedMemory(
|
|||||||
size_t size);
|
size_t size);
|
||||||
|
|
||||||
void PlatformInit();
|
void PlatformInit();
|
||||||
|
|
||||||
std::string GetWorkingDirectory();
|
std::string GetWorkingDirectory();
|
||||||
std::string NormalizePath(const std::string& path);
|
std::string NormalizePath(const std::string& path);
|
||||||
|
// Creates a directory at |path|. Creates directories recursively if needed.
|
||||||
|
void MakeDirectoryRecursive(std::string path);
|
||||||
|
// Tries to create the directory given by |absolute_path|. Returns true if
|
||||||
|
// successful or if the directory already exists. Returns false otherwise. This
|
||||||
|
// does not attempt to recursively create directories.
|
||||||
|
bool TryMakeDirectory(const std::string& absolute_path);
|
||||||
|
|
||||||
void SetCurrentThreadName(const std::string& thread_name);
|
void SetCurrentThreadName(const std::string& thread_name);
|
||||||
|
|
||||||
// Returns any clang arguments that are specific to the current platform.
|
// Returns any clang arguments that are specific to the current platform.
|
||||||
|
@ -19,6 +19,9 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
|
#include <sys/types.h> // required for stat.h
|
||||||
|
#include <sys/stat.h> // no clue why required -- man pages say so
|
||||||
|
|
||||||
#include <fcntl.h> /* For O_* constants */
|
#include <fcntl.h> /* For O_* constants */
|
||||||
#include <sys/stat.h> /* For mode constants */
|
#include <sys/stat.h> /* For mode constants */
|
||||||
#include <semaphore.h>
|
#include <semaphore.h>
|
||||||
@ -140,6 +143,17 @@ std::string NormalizePath(const std::string& path) {
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TryMakeDirectory(const std::string& absolute_path) {
|
||||||
|
std::cerr << "!! TryMakeDirectory " << absolute_path << std::endl;
|
||||||
|
|
||||||
|
const mode_t kMode = 0660; // UNIX style permissions, user and group read/write; other cannot access
|
||||||
|
if (mkdir(absolute_path.c_str(), kMode) == -1) {
|
||||||
|
// Success if the directory exists.
|
||||||
|
return errno == EEXIST;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void SetCurrentThreadName(const std::string& thread_name) {
|
void SetCurrentThreadName(const std::string& thread_name) {
|
||||||
prctl(PR_SET_NAME, thread_name.c_str(), 0, 0, 0);
|
prctl(PR_SET_NAME, thread_name.c_str(), 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
|
#include <direct.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <io.h>
|
#include <io.h>
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
@ -145,6 +146,14 @@ std::string NormalizePath(const std::string& path) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TryMakeDirectory(const std::string& absolute_path) {
|
||||||
|
std::cerr << "!! TryMakeDirectory " << absolute_path << std::endl;
|
||||||
|
if (_mkdir(absolute_path.c_str()) == -1) {
|
||||||
|
// Success if the directory exists.
|
||||||
|
return errno == EEXIST;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// See https://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
|
// See https://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
|
||||||
const DWORD MS_VC_EXCEPTION = 0x406D1388;
|
const DWORD MS_VC_EXCEPTION = 0x406D1388;
|
||||||
|
Loading…
Reference in New Issue
Block a user