Uploading the main structure
هذا الالتزام موجود في:
302
node_modules/@parcel/watcher/src/watchman/BSER.cc
مولّد
مباع
Normal file
302
node_modules/@parcel/watcher/src/watchman/BSER.cc
مولّد
مباع
Normal file
@@ -0,0 +1,302 @@
|
||||
#include <stdint.h>
|
||||
#include "./BSER.hh"
|
||||
|
||||
BSERType decodeType(std::istream &iss) {
|
||||
int8_t type;
|
||||
iss.read(reinterpret_cast<char*>(&type), sizeof(type));
|
||||
return (BSERType) type;
|
||||
}
|
||||
|
||||
void expectType(std::istream &iss, BSERType expected) {
|
||||
BSERType got = decodeType(iss);
|
||||
if (got != expected) {
|
||||
throw std::runtime_error("Unexpected BSER type");
|
||||
}
|
||||
}
|
||||
|
||||
void encodeType(std::ostream &oss, BSERType type) {
|
||||
int8_t t = (int8_t)type;
|
||||
oss.write(reinterpret_cast<char*>(&t), sizeof(t));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
class Value : public BSERValue {
|
||||
public:
|
||||
T value;
|
||||
Value(T val) {
|
||||
value = val;
|
||||
}
|
||||
|
||||
Value() {}
|
||||
};
|
||||
|
||||
class BSERInteger : public Value<int64_t> {
|
||||
public:
|
||||
BSERInteger(int64_t value) : Value(value) {}
|
||||
BSERInteger(std::istream &iss) {
|
||||
int8_t int8;
|
||||
int16_t int16;
|
||||
int32_t int32;
|
||||
int64_t int64;
|
||||
|
||||
BSERType type = decodeType(iss);
|
||||
|
||||
switch (type) {
|
||||
case BSER_INT8:
|
||||
iss.read(reinterpret_cast<char*>(&int8), sizeof(int8));
|
||||
value = int8;
|
||||
break;
|
||||
case BSER_INT16:
|
||||
iss.read(reinterpret_cast<char*>(&int16), sizeof(int16));
|
||||
value = int16;
|
||||
break;
|
||||
case BSER_INT32:
|
||||
iss.read(reinterpret_cast<char*>(&int32), sizeof(int32));
|
||||
value = int32;
|
||||
break;
|
||||
case BSER_INT64:
|
||||
iss.read(reinterpret_cast<char*>(&int64), sizeof(int64));
|
||||
value = int64;
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("Invalid BSER int type");
|
||||
}
|
||||
}
|
||||
|
||||
int64_t intValue() override {
|
||||
return value;
|
||||
}
|
||||
|
||||
void encode(std::ostream &oss) override {
|
||||
if (value <= INT8_MAX) {
|
||||
encodeType(oss, BSER_INT8);
|
||||
int8_t v = (int8_t)value;
|
||||
oss.write(reinterpret_cast<char*>(&v), sizeof(v));
|
||||
} else if (value <= INT16_MAX) {
|
||||
encodeType(oss, BSER_INT16);
|
||||
int16_t v = (int16_t)value;
|
||||
oss.write(reinterpret_cast<char*>(&v), sizeof(v));
|
||||
} else if (value <= INT32_MAX) {
|
||||
encodeType(oss, BSER_INT32);
|
||||
int32_t v = (int32_t)value;
|
||||
oss.write(reinterpret_cast<char*>(&v), sizeof(v));
|
||||
} else {
|
||||
encodeType(oss, BSER_INT64);
|
||||
oss.write(reinterpret_cast<char*>(&value), sizeof(value));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class BSERArray : public Value<BSER::Array> {
|
||||
public:
|
||||
BSERArray() : Value() {}
|
||||
BSERArray(BSER::Array value) : Value(value) {}
|
||||
BSERArray(std::istream &iss) {
|
||||
expectType(iss, BSER_ARRAY);
|
||||
int64_t len = BSERInteger(iss).intValue();
|
||||
for (int64_t i = 0; i < len; i++) {
|
||||
value.push_back(BSER(iss));
|
||||
}
|
||||
}
|
||||
|
||||
BSER::Array arrayValue() override {
|
||||
return value;
|
||||
}
|
||||
|
||||
void encode(std::ostream &oss) override {
|
||||
encodeType(oss, BSER_ARRAY);
|
||||
BSERInteger(value.size()).encode(oss);
|
||||
for (auto it = value.begin(); it != value.end(); it++) {
|
||||
it->encode(oss);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class BSERString : public Value<std::string> {
|
||||
public:
|
||||
BSERString(std::string value) : Value(value) {}
|
||||
BSERString(std::istream &iss) {
|
||||
expectType(iss, BSER_STRING);
|
||||
int64_t len = BSERInteger(iss).intValue();
|
||||
value.resize(len);
|
||||
iss.read(&value[0], len);
|
||||
}
|
||||
|
||||
std::string stringValue() override {
|
||||
return value;
|
||||
}
|
||||
|
||||
void encode(std::ostream &oss) override {
|
||||
encodeType(oss, BSER_STRING);
|
||||
BSERInteger(value.size()).encode(oss);
|
||||
oss << value;
|
||||
}
|
||||
};
|
||||
|
||||
class BSERObject : public Value<BSER::Object> {
|
||||
public:
|
||||
BSERObject() : Value() {}
|
||||
BSERObject(BSER::Object value) : Value(value) {}
|
||||
BSERObject(std::istream &iss) {
|
||||
expectType(iss, BSER_OBJECT);
|
||||
int64_t len = BSERInteger(iss).intValue();
|
||||
for (int64_t i = 0; i < len; i++) {
|
||||
auto key = BSERString(iss).stringValue();
|
||||
auto val = BSER(iss);
|
||||
value.emplace(key, val);
|
||||
}
|
||||
}
|
||||
|
||||
BSER::Object objectValue() override {
|
||||
return value;
|
||||
}
|
||||
|
||||
void encode(std::ostream &oss) override {
|
||||
encodeType(oss, BSER_OBJECT);
|
||||
BSERInteger(value.size()).encode(oss);
|
||||
for (auto it = value.begin(); it != value.end(); it++) {
|
||||
BSERString(it->first).encode(oss);
|
||||
it->second.encode(oss);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class BSERDouble : public Value<double> {
|
||||
public:
|
||||
BSERDouble(double value) : Value(value) {}
|
||||
BSERDouble(std::istream &iss) {
|
||||
expectType(iss, BSER_REAL);
|
||||
iss.read(reinterpret_cast<char*>(&value), sizeof(value));
|
||||
}
|
||||
|
||||
double doubleValue() override {
|
||||
return value;
|
||||
}
|
||||
|
||||
void encode(std::ostream &oss) override {
|
||||
encodeType(oss, BSER_REAL);
|
||||
oss.write(reinterpret_cast<char*>(&value), sizeof(value));
|
||||
}
|
||||
};
|
||||
|
||||
class BSERBoolean : public Value<bool> {
|
||||
public:
|
||||
BSERBoolean(bool value) : Value(value) {}
|
||||
bool boolValue() override { return value; }
|
||||
void encode(std::ostream &oss) override {
|
||||
int8_t t = value == true ? BSER_BOOL_TRUE : BSER_BOOL_FALSE;
|
||||
oss.write(reinterpret_cast<char*>(&t), sizeof(t));
|
||||
}
|
||||
};
|
||||
|
||||
class BSERNull : public Value<bool> {
|
||||
public:
|
||||
BSERNull() : Value(false) {}
|
||||
void encode(std::ostream &oss) override {
|
||||
encodeType(oss, BSER_NULL);
|
||||
}
|
||||
};
|
||||
|
||||
std::shared_ptr<BSERArray> decodeTemplate(std::istream &iss) {
|
||||
expectType(iss, BSER_TEMPLATE);
|
||||
auto keys = BSERArray(iss).arrayValue();
|
||||
auto len = BSERInteger(iss).intValue();
|
||||
std::shared_ptr<BSERArray> arr = std::make_shared<BSERArray>();
|
||||
for (int64_t i = 0; i < len; i++) {
|
||||
BSER::Object obj;
|
||||
for (auto it = keys.begin(); it != keys.end(); it++) {
|
||||
if (iss.peek() == 0x0c) {
|
||||
iss.ignore(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
auto val = BSER(iss);
|
||||
obj.emplace(it->stringValue(), val);
|
||||
}
|
||||
arr->value.push_back(obj);
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
BSER::BSER(std::istream &iss) {
|
||||
BSERType type = decodeType(iss);
|
||||
iss.unget();
|
||||
|
||||
switch (type) {
|
||||
case BSER_ARRAY:
|
||||
m_ptr = std::make_shared<BSERArray>(iss);
|
||||
break;
|
||||
case BSER_OBJECT:
|
||||
m_ptr = std::make_shared<BSERObject>(iss);
|
||||
break;
|
||||
case BSER_STRING:
|
||||
m_ptr = std::make_shared<BSERString>(iss);
|
||||
break;
|
||||
case BSER_INT8:
|
||||
case BSER_INT16:
|
||||
case BSER_INT32:
|
||||
case BSER_INT64:
|
||||
m_ptr = std::make_shared<BSERInteger>(iss);
|
||||
break;
|
||||
case BSER_REAL:
|
||||
m_ptr = std::make_shared<BSERDouble>(iss);
|
||||
break;
|
||||
case BSER_BOOL_TRUE:
|
||||
iss.ignore(1);
|
||||
m_ptr = std::make_shared<BSERBoolean>(true);
|
||||
break;
|
||||
case BSER_BOOL_FALSE:
|
||||
iss.ignore(1);
|
||||
m_ptr = std::make_shared<BSERBoolean>(false);
|
||||
break;
|
||||
case BSER_NULL:
|
||||
iss.ignore(1);
|
||||
m_ptr = std::make_shared<BSERNull>();
|
||||
break;
|
||||
case BSER_TEMPLATE:
|
||||
m_ptr = decodeTemplate(iss);
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("unknown BSER type");
|
||||
}
|
||||
}
|
||||
|
||||
BSER::BSER() : m_ptr(std::make_shared<BSERNull>()) {}
|
||||
BSER::BSER(BSER::Array value) : m_ptr(std::make_shared<BSERArray>(value)) {}
|
||||
BSER::BSER(BSER::Object value) : m_ptr(std::make_shared<BSERObject>(value)) {}
|
||||
BSER::BSER(const char *value) : m_ptr(std::make_shared<BSERString>(value)) {}
|
||||
BSER::BSER(std::string value) : m_ptr(std::make_shared<BSERString>(value)) {}
|
||||
BSER::BSER(int64_t value) : m_ptr(std::make_shared<BSERInteger>(value)) {}
|
||||
BSER::BSER(double value) : m_ptr(std::make_shared<BSERDouble>(value)) {}
|
||||
BSER::BSER(bool value) : m_ptr(std::make_shared<BSERBoolean>(value)) {}
|
||||
|
||||
BSER::Array BSER::arrayValue() { return m_ptr->arrayValue(); }
|
||||
BSER::Object BSER::objectValue() { return m_ptr->objectValue(); }
|
||||
std::string BSER::stringValue() { return m_ptr->stringValue(); }
|
||||
int64_t BSER::intValue() { return m_ptr->intValue(); }
|
||||
double BSER::doubleValue() { return m_ptr->doubleValue(); }
|
||||
bool BSER::boolValue() { return m_ptr->boolValue(); }
|
||||
void BSER::encode(std::ostream &oss) {
|
||||
m_ptr->encode(oss);
|
||||
}
|
||||
|
||||
int64_t BSER::decodeLength(std::istream &iss) {
|
||||
char pdu[2];
|
||||
if (!iss.read(pdu, 2) || pdu[0] != 0 || pdu[1] != 1) {
|
||||
throw std::runtime_error("Invalid BSER");
|
||||
}
|
||||
|
||||
return BSERInteger(iss).intValue();
|
||||
}
|
||||
|
||||
std::string BSER::encode() {
|
||||
std::ostringstream oss(std::ios_base::binary);
|
||||
encode(oss);
|
||||
|
||||
std::ostringstream res(std::ios_base::binary);
|
||||
res.write("\x00\x01", 2);
|
||||
|
||||
BSERInteger(oss.str().size()).encode(res);
|
||||
res << oss.str();
|
||||
return res.str();
|
||||
}
|
69
node_modules/@parcel/watcher/src/watchman/BSER.hh
مولّد
مباع
Normal file
69
node_modules/@parcel/watcher/src/watchman/BSER.hh
مولّد
مباع
Normal file
@@ -0,0 +1,69 @@
|
||||
#ifndef BSER_H
|
||||
#define BSER_H
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <memory>
|
||||
|
||||
enum BSERType {
|
||||
BSER_ARRAY = 0x00,
|
||||
BSER_OBJECT = 0x01,
|
||||
BSER_STRING = 0x02,
|
||||
BSER_INT8 = 0x03,
|
||||
BSER_INT16 = 0x04,
|
||||
BSER_INT32 = 0x05,
|
||||
BSER_INT64 = 0x06,
|
||||
BSER_REAL = 0x07,
|
||||
BSER_BOOL_TRUE = 0x08,
|
||||
BSER_BOOL_FALSE = 0x09,
|
||||
BSER_NULL = 0x0a,
|
||||
BSER_TEMPLATE = 0x0b
|
||||
};
|
||||
|
||||
class BSERValue;
|
||||
|
||||
class BSER {
|
||||
public:
|
||||
typedef std::vector<BSER> Array;
|
||||
typedef std::unordered_map<std::string, BSER> Object;
|
||||
|
||||
BSER();
|
||||
BSER(BSER::Array value);
|
||||
BSER(BSER::Object value);
|
||||
BSER(std::string value);
|
||||
BSER(const char *value);
|
||||
BSER(int64_t value);
|
||||
BSER(double value);
|
||||
BSER(bool value);
|
||||
BSER(std::istream &iss);
|
||||
|
||||
BSER::Array arrayValue();
|
||||
BSER::Object objectValue();
|
||||
std::string stringValue();
|
||||
int64_t intValue();
|
||||
double doubleValue();
|
||||
bool boolValue();
|
||||
void encode(std::ostream &oss);
|
||||
|
||||
static int64_t decodeLength(std::istream &iss);
|
||||
std::string encode();
|
||||
private:
|
||||
std::shared_ptr<BSERValue> m_ptr;
|
||||
};
|
||||
|
||||
class BSERValue {
|
||||
protected:
|
||||
friend class BSER;
|
||||
virtual BSER::Array arrayValue() { return BSER::Array(); }
|
||||
virtual BSER::Object objectValue() { return BSER::Object(); }
|
||||
virtual std::string stringValue() { return std::string(); }
|
||||
virtual int64_t intValue() { return 0; }
|
||||
virtual double doubleValue() { return 0; }
|
||||
virtual bool boolValue() { return false; }
|
||||
virtual void encode(std::ostream &oss) {}
|
||||
virtual ~BSERValue() {}
|
||||
};
|
||||
|
||||
#endif
|
175
node_modules/@parcel/watcher/src/watchman/IPC.hh
مولّد
مباع
Normal file
175
node_modules/@parcel/watcher/src/watchman/IPC.hh
مولّد
مباع
Normal file
@@ -0,0 +1,175 @@
|
||||
#ifndef IPC_H
|
||||
#define IPC_H
|
||||
|
||||
#include <string>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#endif
|
||||
|
||||
class IPC {
|
||||
public:
|
||||
IPC(std::string path) {
|
||||
mStopped = false;
|
||||
#ifdef _WIN32
|
||||
while (true) {
|
||||
mPipe = CreateFile(
|
||||
path.data(), // pipe name
|
||||
GENERIC_READ | GENERIC_WRITE, // read and write access
|
||||
0, // no sharing
|
||||
NULL, // default security attributes
|
||||
OPEN_EXISTING, // opens existing pipe
|
||||
FILE_FLAG_OVERLAPPED, // attributes
|
||||
NULL // no template file
|
||||
);
|
||||
|
||||
if (mPipe != INVALID_HANDLE_VALUE) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (GetLastError() != ERROR_PIPE_BUSY) {
|
||||
throw std::runtime_error("Could not open pipe");
|
||||
}
|
||||
|
||||
// Wait for pipe to become available if it is busy
|
||||
if (!WaitNamedPipe(path.data(), 30000)) {
|
||||
throw std::runtime_error("Error waiting for pipe");
|
||||
}
|
||||
}
|
||||
|
||||
mReader = CreateEvent(NULL, true, false, NULL);
|
||||
mWriter = CreateEvent(NULL, true, false, NULL);
|
||||
#else
|
||||
struct sockaddr_un addr;
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sun_family = AF_UNIX;
|
||||
strncpy(addr.sun_path, path.c_str(), sizeof(addr.sun_path) - 1);
|
||||
|
||||
mSock = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (connect(mSock, (struct sockaddr *) &addr, sizeof(struct sockaddr_un))) {
|
||||
throw std::runtime_error("Error connecting to socket");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
~IPC() {
|
||||
mStopped = true;
|
||||
#ifdef _WIN32
|
||||
CancelIo(mPipe);
|
||||
CloseHandle(mPipe);
|
||||
CloseHandle(mReader);
|
||||
CloseHandle(mWriter);
|
||||
#else
|
||||
shutdown(mSock, SHUT_RDWR);
|
||||
#endif
|
||||
}
|
||||
|
||||
void write(std::string buf) {
|
||||
#ifdef _WIN32
|
||||
OVERLAPPED overlapped;
|
||||
overlapped.hEvent = mWriter;
|
||||
bool success = WriteFile(
|
||||
mPipe, // pipe handle
|
||||
buf.data(), // message
|
||||
buf.size(), // message length
|
||||
NULL, // bytes written
|
||||
&overlapped // overlapped
|
||||
);
|
||||
|
||||
if (mStopped) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
if (GetLastError() != ERROR_IO_PENDING) {
|
||||
throw std::runtime_error("Write error");
|
||||
}
|
||||
}
|
||||
|
||||
DWORD written;
|
||||
success = GetOverlappedResult(mPipe, &overlapped, &written, true);
|
||||
if (!success) {
|
||||
throw std::runtime_error("GetOverlappedResult failed");
|
||||
}
|
||||
|
||||
if (written != buf.size()) {
|
||||
throw std::runtime_error("Wrong number of bytes written");
|
||||
}
|
||||
#else
|
||||
int r = 0;
|
||||
for (unsigned int i = 0; i != buf.size(); i += r) {
|
||||
r = ::write(mSock, &buf[i], buf.size() - i);
|
||||
if (r == -1) {
|
||||
if (errno == EAGAIN) {
|
||||
r = 0;
|
||||
} else if (mStopped) {
|
||||
return;
|
||||
} else {
|
||||
throw std::runtime_error("Write error");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int read(char *buf, size_t len) {
|
||||
#ifdef _WIN32
|
||||
OVERLAPPED overlapped;
|
||||
overlapped.hEvent = mReader;
|
||||
bool success = ReadFile(
|
||||
mPipe, // pipe handle
|
||||
buf, // buffer to receive reply
|
||||
len, // size of buffer
|
||||
NULL, // number of bytes read
|
||||
&overlapped // overlapped
|
||||
);
|
||||
|
||||
if (!success && !mStopped) {
|
||||
if (GetLastError() != ERROR_IO_PENDING) {
|
||||
throw std::runtime_error("Read error");
|
||||
}
|
||||
}
|
||||
|
||||
DWORD read = 0;
|
||||
success = GetOverlappedResult(mPipe, &overlapped, &read, true);
|
||||
if (!success && !mStopped) {
|
||||
throw std::runtime_error("GetOverlappedResult failed");
|
||||
}
|
||||
|
||||
return read;
|
||||
#else
|
||||
int r = ::read(mSock, buf, len);
|
||||
if (r == 0 && !mStopped) {
|
||||
throw std::runtime_error("Socket ended unexpectedly");
|
||||
}
|
||||
|
||||
if (r < 0) {
|
||||
if (mStopped) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
throw std::runtime_error(strerror(errno));
|
||||
}
|
||||
|
||||
return r;
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
bool mStopped;
|
||||
#ifdef _WIN32
|
||||
HANDLE mPipe;
|
||||
HANDLE mReader;
|
||||
HANDLE mWriter;
|
||||
#else
|
||||
int mSock;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
338
node_modules/@parcel/watcher/src/watchman/WatchmanBackend.cc
مولّد
مباع
Normal file
338
node_modules/@parcel/watcher/src/watchman/WatchmanBackend.cc
مولّد
مباع
Normal file
@@ -0,0 +1,338 @@
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <stdlib.h>
|
||||
#include <algorithm>
|
||||
#include "../DirTree.hh"
|
||||
#include "../Event.hh"
|
||||
#include "./BSER.hh"
|
||||
#include "./WatchmanBackend.hh"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "../windows/win_utils.hh"
|
||||
#define S_ISDIR(mode) ((mode & _S_IFDIR) == _S_IFDIR)
|
||||
#define popen _popen
|
||||
#define pclose _pclose
|
||||
#else
|
||||
#include <sys/stat.h>
|
||||
#define normalizePath(dir) dir
|
||||
#endif
|
||||
|
||||
template<typename T>
|
||||
BSER readBSER(T &&do_read) {
|
||||
std::stringstream oss;
|
||||
char buffer[256];
|
||||
int r;
|
||||
int64_t len = -1;
|
||||
do {
|
||||
// Start by reading a minimal amount of data in order to decode the length.
|
||||
// After that, attempt to read the remaining length, up to the buffer size.
|
||||
r = do_read(buffer, len == -1 ? 20 : (len < 256 ? len : 256));
|
||||
oss << std::string(buffer, r);
|
||||
|
||||
if (len == -1) {
|
||||
uint64_t l = BSER::decodeLength(oss);
|
||||
len = l + oss.tellg();
|
||||
}
|
||||
|
||||
len -= r;
|
||||
} while (len > 0);
|
||||
|
||||
return BSER(oss);
|
||||
}
|
||||
|
||||
std::string getSockPath() {
|
||||
auto var = getenv("WATCHMAN_SOCK");
|
||||
if (var && *var) {
|
||||
return std::string(var);
|
||||
}
|
||||
|
||||
FILE *fp = popen("watchman --output-encoding=bser get-sockname", "r");
|
||||
if (fp == NULL || errno == ECHILD) {
|
||||
throw std::runtime_error("Failed to execute watchman");
|
||||
}
|
||||
|
||||
BSER b = readBSER([fp] (char *buf, size_t len) {
|
||||
return fread(buf, sizeof(char), len, fp);
|
||||
});
|
||||
|
||||
pclose(fp);
|
||||
|
||||
auto objValue = b.objectValue();
|
||||
auto foundSockname = objValue.find("sockname");
|
||||
if (foundSockname == objValue.end()) {
|
||||
throw std::runtime_error("sockname not found");
|
||||
}
|
||||
return foundSockname->second.stringValue();
|
||||
}
|
||||
|
||||
std::unique_ptr<IPC> watchmanConnect() {
|
||||
std::string path = getSockPath();
|
||||
return std::unique_ptr<IPC>(new IPC(path));
|
||||
}
|
||||
|
||||
BSER watchmanRead(IPC *ipc) {
|
||||
return readBSER([ipc] (char *buf, size_t len) {
|
||||
return ipc->read(buf, len);
|
||||
});
|
||||
}
|
||||
|
||||
BSER::Object WatchmanBackend::watchmanRequest(BSER b) {
|
||||
std::string cmd = b.encode();
|
||||
mIPC->write(cmd);
|
||||
mRequestSignal.notify();
|
||||
|
||||
mResponseSignal.wait();
|
||||
mResponseSignal.reset();
|
||||
|
||||
if (!mError.empty()) {
|
||||
std::runtime_error err = std::runtime_error(mError);
|
||||
mError = std::string();
|
||||
throw err;
|
||||
}
|
||||
|
||||
return mResponse;
|
||||
}
|
||||
|
||||
void WatchmanBackend::watchmanWatch(std::string dir) {
|
||||
std::vector<BSER> cmd;
|
||||
cmd.push_back("watch");
|
||||
cmd.push_back(normalizePath(dir));
|
||||
watchmanRequest(cmd);
|
||||
}
|
||||
|
||||
bool WatchmanBackend::checkAvailable() {
|
||||
try {
|
||||
watchmanConnect();
|
||||
return true;
|
||||
} catch (std::exception &err) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void handleFiles(WatcherRef watcher, BSER::Object obj) {
|
||||
auto found = obj.find("files");
|
||||
if (found == obj.end()) {
|
||||
throw WatcherError("Error reading changes from watchman", watcher);
|
||||
}
|
||||
|
||||
auto files = found->second.arrayValue();
|
||||
for (auto it = files.begin(); it != files.end(); it++) {
|
||||
auto file = it->objectValue();
|
||||
auto name = file.find("name")->second.stringValue();
|
||||
#ifdef _WIN32
|
||||
std::replace(name.begin(), name.end(), '/', '\\');
|
||||
#endif
|
||||
auto mode = file.find("mode")->second.intValue();
|
||||
auto isNew = file.find("new")->second.boolValue();
|
||||
auto exists = file.find("exists")->second.boolValue();
|
||||
auto path = watcher->mDir + DIR_SEP + name;
|
||||
if (watcher->isIgnored(path)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isNew && exists) {
|
||||
watcher->mEvents.create(path);
|
||||
} else if (exists && !S_ISDIR(mode)) {
|
||||
watcher->mEvents.update(path);
|
||||
} else if (!isNew && !exists) {
|
||||
watcher->mEvents.remove(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WatchmanBackend::handleSubscription(BSER::Object obj) {
|
||||
std::unique_lock<std::mutex> lock(mMutex);
|
||||
auto subscription = obj.find("subscription")->second.stringValue();
|
||||
auto it = mSubscriptions.find(subscription);
|
||||
if (it == mSubscriptions.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto watcher = it->second;
|
||||
try {
|
||||
handleFiles(watcher, obj);
|
||||
watcher->notify();
|
||||
} catch (WatcherError &err) {
|
||||
handleWatcherError(err);
|
||||
}
|
||||
}
|
||||
|
||||
void WatchmanBackend::start() {
|
||||
mIPC = watchmanConnect();
|
||||
notifyStarted();
|
||||
|
||||
while (true) {
|
||||
// If there are no subscriptions we are reading, wait for a request.
|
||||
if (mSubscriptions.size() == 0) {
|
||||
mRequestSignal.wait();
|
||||
mRequestSignal.reset();
|
||||
}
|
||||
|
||||
// Break out of loop if we are stopped.
|
||||
if (mStopped) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Attempt to read from the socket.
|
||||
// If there is an error and we are stopped, break.
|
||||
BSER b;
|
||||
try {
|
||||
b = watchmanRead(&*mIPC);
|
||||
} catch (std::exception &err) {
|
||||
if (mStopped) {
|
||||
break;
|
||||
} else if (mResponseSignal.isWaiting()) {
|
||||
mError = err.what();
|
||||
mResponseSignal.notify();
|
||||
} else {
|
||||
// Throwing causes the backend to be destroyed, but we never reach the code below to notify the signal
|
||||
mEndedSignal.notify();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
auto obj = b.objectValue();
|
||||
auto error = obj.find("error");
|
||||
if (error != obj.end()) {
|
||||
mError = error->second.stringValue();
|
||||
mResponseSignal.notify();
|
||||
continue;
|
||||
}
|
||||
|
||||
// If this message is for a subscription, handle it, otherwise notify the request.
|
||||
auto subscription = obj.find("subscription");
|
||||
if (subscription != obj.end()) {
|
||||
handleSubscription(obj);
|
||||
} else {
|
||||
mResponse = obj;
|
||||
mResponseSignal.notify();
|
||||
}
|
||||
}
|
||||
|
||||
mEndedSignal.notify();
|
||||
}
|
||||
|
||||
WatchmanBackend::~WatchmanBackend() {
|
||||
// Mark the watcher as stopped, close the socket, and trigger the lock.
|
||||
// This will cause the read loop to be broken and the thread to exit.
|
||||
mStopped = true;
|
||||
mIPC.reset();
|
||||
mRequestSignal.notify();
|
||||
|
||||
// If not ended yet, wait.
|
||||
mEndedSignal.wait();
|
||||
}
|
||||
|
||||
std::string WatchmanBackend::clock(WatcherRef watcher) {
|
||||
BSER::Array cmd;
|
||||
cmd.push_back("clock");
|
||||
cmd.push_back(normalizePath(watcher->mDir));
|
||||
|
||||
BSER::Object obj = watchmanRequest(cmd);
|
||||
auto found = obj.find("clock");
|
||||
if (found == obj.end()) {
|
||||
throw WatcherError("Error reading clock from watchman", watcher);
|
||||
}
|
||||
|
||||
return found->second.stringValue();
|
||||
}
|
||||
|
||||
void WatchmanBackend::writeSnapshot(WatcherRef watcher, std::string *snapshotPath) {
|
||||
std::unique_lock<std::mutex> lock(mMutex);
|
||||
watchmanWatch(watcher->mDir);
|
||||
|
||||
std::ofstream ofs(*snapshotPath);
|
||||
ofs << clock(watcher);
|
||||
}
|
||||
|
||||
void WatchmanBackend::getEventsSince(WatcherRef watcher, std::string *snapshotPath) {
|
||||
std::unique_lock<std::mutex> lock(mMutex);
|
||||
std::ifstream ifs(*snapshotPath);
|
||||
if (ifs.fail()) {
|
||||
return;
|
||||
}
|
||||
|
||||
watchmanWatch(watcher->mDir);
|
||||
|
||||
std::string clock;
|
||||
ifs >> clock;
|
||||
|
||||
BSER::Array cmd;
|
||||
cmd.push_back("since");
|
||||
cmd.push_back(normalizePath(watcher->mDir));
|
||||
cmd.push_back(clock);
|
||||
|
||||
BSER::Object obj = watchmanRequest(cmd);
|
||||
handleFiles(watcher, obj);
|
||||
}
|
||||
|
||||
std::string getId(WatcherRef watcher) {
|
||||
std::ostringstream id;
|
||||
id << "parcel-";
|
||||
id << static_cast<void*>(watcher.get());
|
||||
return id.str();
|
||||
}
|
||||
|
||||
// This function is called by Backend::watch which takes a lock on mMutex
|
||||
void WatchmanBackend::subscribe(WatcherRef watcher) {
|
||||
watchmanWatch(watcher->mDir);
|
||||
|
||||
std::string id = getId(watcher);
|
||||
BSER::Array cmd;
|
||||
cmd.push_back("subscribe");
|
||||
cmd.push_back(normalizePath(watcher->mDir));
|
||||
cmd.push_back(id);
|
||||
|
||||
BSER::Array fields;
|
||||
fields.push_back("name");
|
||||
fields.push_back("mode");
|
||||
fields.push_back("exists");
|
||||
fields.push_back("new");
|
||||
|
||||
BSER::Object opts;
|
||||
opts.emplace("fields", fields);
|
||||
opts.emplace("since", clock(watcher));
|
||||
|
||||
if (watcher->mIgnorePaths.size() > 0) {
|
||||
BSER::Array ignore;
|
||||
BSER::Array anyOf;
|
||||
anyOf.push_back("anyof");
|
||||
|
||||
for (auto it = watcher->mIgnorePaths.begin(); it != watcher->mIgnorePaths.end(); it++) {
|
||||
std::string pathStart = watcher->mDir + DIR_SEP;
|
||||
if (it->rfind(pathStart, 0) == 0) {
|
||||
auto relative = it->substr(pathStart.size());
|
||||
BSER::Array dirname;
|
||||
dirname.push_back("dirname");
|
||||
dirname.push_back(relative);
|
||||
anyOf.push_back(dirname);
|
||||
}
|
||||
}
|
||||
|
||||
ignore.push_back("not");
|
||||
ignore.push_back(anyOf);
|
||||
|
||||
opts.emplace("expression", ignore);
|
||||
}
|
||||
|
||||
cmd.push_back(opts);
|
||||
watchmanRequest(cmd);
|
||||
|
||||
mSubscriptions.emplace(id, watcher);
|
||||
mRequestSignal.notify();
|
||||
}
|
||||
|
||||
// This function is called by Backend::unwatch which takes a lock on mMutex
|
||||
void WatchmanBackend::unsubscribe(WatcherRef watcher) {
|
||||
std::string id = getId(watcher);
|
||||
auto erased = mSubscriptions.erase(id);
|
||||
|
||||
if (erased) {
|
||||
BSER::Array cmd;
|
||||
cmd.push_back("unsubscribe");
|
||||
cmd.push_back(normalizePath(watcher->mDir));
|
||||
cmd.push_back(id);
|
||||
|
||||
watchmanRequest(cmd);
|
||||
}
|
||||
}
|
35
node_modules/@parcel/watcher/src/watchman/WatchmanBackend.hh
مولّد
مباع
Normal file
35
node_modules/@parcel/watcher/src/watchman/WatchmanBackend.hh
مولّد
مباع
Normal file
@@ -0,0 +1,35 @@
|
||||
#ifndef WATCHMAN_H
|
||||
#define WATCHMAN_H
|
||||
|
||||
#include "../Backend.hh"
|
||||
#include "./BSER.hh"
|
||||
#include "../Signal.hh"
|
||||
#include "./IPC.hh"
|
||||
|
||||
class WatchmanBackend : public Backend {
|
||||
public:
|
||||
static bool checkAvailable();
|
||||
void start() override;
|
||||
WatchmanBackend() : mStopped(false) {};
|
||||
~WatchmanBackend();
|
||||
void writeSnapshot(WatcherRef watcher, std::string *snapshotPath) override;
|
||||
void getEventsSince(WatcherRef watcher, std::string *snapshotPath) override;
|
||||
void subscribe(WatcherRef watcher) override;
|
||||
void unsubscribe(WatcherRef watcher) override;
|
||||
private:
|
||||
std::unique_ptr<IPC> mIPC;
|
||||
Signal mRequestSignal;
|
||||
Signal mResponseSignal;
|
||||
BSER::Object mResponse;
|
||||
std::string mError;
|
||||
std::unordered_map<std::string, WatcherRef> mSubscriptions;
|
||||
bool mStopped;
|
||||
Signal mEndedSignal;
|
||||
|
||||
std::string clock(WatcherRef watcher);
|
||||
void watchmanWatch(std::string dir);
|
||||
BSER::Object watchmanRequest(BSER cmd);
|
||||
void handleSubscription(BSER::Object obj);
|
||||
};
|
||||
|
||||
#endif
|
المرجع في مشكلة جديدة
حظر مستخدم