Skip to content

Commit

Permalink
watcher-c: cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
Will committed Jul 23, 2024
1 parent c941f94 commit f36ad47
Show file tree
Hide file tree
Showing 18 changed files with 195 additions and 2,711 deletions.
25 changes: 25 additions & 0 deletions tool/portable-cp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#! /usr/bin/env python3

"""
A portable `cp` command that works on both Windows and Unix-like systems.
"""

import os
import sys
import shutil

def main():
if len(sys.argv) != 3:
print("Usage: {} SOURCE DEST".format(sys.argv[0]))
sys.exit(1)

src = sys.argv[1]
dst = sys.argv[2]

if os.path.isdir(src):
shutil.copytree(src, dst)
else:
shutil.copy2(src, dst)

if __name__ == "__main__":
main()
1 change: 1 addition & 0 deletions watcher-c/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
out
compile_commands.json
include/wtr/watcher.hpp
21 changes: 15 additions & 6 deletions watcher-c/include/wtr/watcher-c.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ extern "C" {
#endif

/* Represents "what happened" to a path. */
static const int8_t WTR_WATCHER_EVENT_RENAME = 0;
static const int8_t WTR_WATCHER_EVENT_MODIFY = 1;
static const int8_t WTR_WATCHER_EVENT_CREATE = 2;
static const int8_t WTR_WATCHER_EVENT_DESTROY = 3;
static const int8_t WTR_WATCHER_EVENT_OWNER = 4;
static const int8_t WTR_WATCHER_EVENT_OTHER = 5;
static const int8_t WTR_WATCHER_EFFECT_RENAME = 0;
static const int8_t WTR_WATCHER_EFFECT_MODIFY = 1;
static const int8_t WTR_WATCHER_EFFECT_CREATE = 2;
static const int8_t WTR_WATCHER_EFFECT_DESTROY = 3;
static const int8_t WTR_WATCHER_EFFECT_OWNER = 4;
static const int8_t WTR_WATCHER_EFFECT_OTHER = 5;

/* Represents "what kind" of path it is. */
static const int8_t WTR_WATCHER_PATH_DIR = 0;
Expand Down Expand Up @@ -62,6 +62,15 @@ void* wtr_watcher_open(char const* const path, wtr_watcher_callback callback, vo

bool wtr_watcher_close(void* watcher);

/* The user, or the language we're working with,
might not prefer a callback-style API.
We provide a pipe-based API for these cases.
Instead of forwarding events to a callback,
we write json-serialized events to a pipe. */
void* wtr_watcher_open_pipe(char const* const path, int* read_fd, int* write_fd);

bool wtr_watcher_close_pipe(void* watcher, int read_fd, int write_fd);

#ifdef __cplusplus
}
#endif
2,285 changes: 0 additions & 2,285 deletions watcher-c/include/wtr/watcher.hpp

This file was deleted.

14 changes: 14 additions & 0 deletions watcher-c/meson.build
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
# Libwatcher-c depends on ../include/wtr/watcher.hpp, but meson doesn't allow
# that kind of structure. We can just copy the header file around ourselves.
portable_cp = join_paths(meson.source_root(), 'tool', 'portable-cp')
watcher_hpp_src = join_paths(meson.source_root(), 'include', 'wtr', 'watcher.hpp')
watcher_hpp_dst = join_paths(meson.source_root(), 'watcher-c', 'include', 'wtr', 'watcher.hpp')
watcher_hpp = custom_target(
'watcher_hpp',
build_by_default : true,
command : [portable_cp, watcher_hpp_src, watcher_hpp_dst],
output : 'watcher.hpp',
install : false,
)

# I know it's not the convential way to version a library...
# But I'm not sure how to do it the "right" way in Meson.
libwatcher_c_name = 'watcher-c-' + meson.project_version()
Expand All @@ -8,6 +21,7 @@ else
libwatcher_c_deps = [dependency('threads')]
endif


libwatcher_c = library(
libwatcher_c_name,
['src/watcher-c.cpp'],
Expand Down
79 changes: 72 additions & 7 deletions watcher-c/src/test-watcher-c.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#include "wtr/watcher-c.h"
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <poll.h>

void callback(struct wtr_watcher_event event, void* data)
{
Expand Down Expand Up @@ -32,15 +34,78 @@ void callback(struct wtr_watcher_event event, void* data)
event.associated_path_name ? event.associated_path_name : "");
}

void do_poll_read_loop(int read_fd)
{
printf("Press enter to exit\n");
struct pollfd fds[2];
memset(fds, 0, sizeof(fds));
fds[0].fd = read_fd;
fds[0].events = POLLIN;
fds[0].revents = 0;
fds[1].fd = STDIN_FILENO;
fds[1].events = POLLIN;
fds[1].revents = 0;
while (true) {
int ret = poll(fds, 2, -1);
if (ret < 0) {
perror("poll");
break;
}
if (fds[0].revents & POLLIN) {
char buf[4096];
memset(buf, 0, sizeof(buf));
ssize_t n = read(read_fd, buf, sizeof(buf) - 1);
if (n < 0) {
perror("read");
break;
}
if (n == 0) {
fprintf(stderr, "EOF\n");
break;
}
printf("%s", buf);
}
if (fds[1].revents & POLLIN) {
break;
}
}
}

int main(int argc, char** argv)
{
char path[4096];
char op[32];
memset(path, 0, sizeof(path));
if (argc > 1) strncpy(path, argv[1], sizeof(path) - 1);
int count = 0;
void* watcher = wtr_watcher_open(path, callback, &count);
if (! watcher) return 1;
getchar();
if (! wtr_watcher_close(watcher)) return 1;
return 0;
memset(op, 0, sizeof(op));
bool badargs = argc != 2 && argc != 3;
bool ishelp = ! badargs && strcmp(argv[1], "-h") == 0;
if (badargs || ishelp) {
fprintf(stderr, "Usage: %s <op> [path]\n", argv[0]);
fprintf(stderr, " op: pipe, cb-with-ctx\n");
fprintf(stderr, " path: path to watch\n");
return 1;
}
if (argc >= 2) strncpy(op, argv[1], sizeof(op) - 1);
if (argc == 3) strncpy(path, argv[2], sizeof(path) - 1);
if (strcmp(op, "cb-with-ctx") == 0) {
int count = 0;
void* watcher = wtr_watcher_open(path, callback, &count);
if (! watcher) return 1;
getchar();
if (! wtr_watcher_close(watcher)) return 1;
return 0;
} else if (strcmp(op, "pipe") == 0) {
int read_fd = -1;
int write_fd = -1;
void* watcher = wtr_watcher_open_pipe(path, &read_fd, &write_fd);
if (! watcher) return 1;
if (read_fd < 0) return 1;
if (write_fd < 0) return 1;
do_poll_read_loop(read_fd);
if (! wtr_watcher_close_pipe(watcher, read_fd, write_fd)) return 1;
return 0;
} else {
fprintf(stderr, "Unknown op: %s\n", op);
return 1;
}
}
60 changes: 59 additions & 1 deletion watcher-c/src/watcher-c.cpp
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
#include <cstdint>
#include <cstdio>
#include "wtr/watcher-c.h"
#include "wtr/watcher.hpp"

#ifdef _WIN32
#define PATH_BUF_LEN 4096
#include <cstdio>
#include <windows.h>
#include <stringapiset.h>
#else
// We support a pipe-based API for non-Windows platforms.
#include <unistd.h>
#include <fcntl.h>
#include <string>
#endif

extern "C" {
Expand Down Expand Up @@ -72,4 +77,57 @@ bool wtr_watcher_close(void* watcher)
return true;
}

#ifdef _WIN32
void* wtr_watcher_open_pipe(char const* const path, int* read_fd)
{
return NULL;
}

bool wtr_watcher_close_pipe(void* watcher, int read_fd)
{
return false;
}
#else
void* wtr_watcher_open_pipe(char const* const path, int* read_fd, int* write_fd)
{
if (! path) { fprintf(stderr, "Path is null.\n"); return NULL; }
if (! read_fd) { fprintf(stderr, "Read fd is null.\n"); return NULL; }
if (! write_fd) { fprintf(stderr, "Write fd is null.\n"); return NULL; }
if (*read_fd > 0) { fprintf(stderr, "Read fd is already open.\n"); return NULL; }
if (*write_fd > 0) { fprintf(stderr, "Write fd is already open.\n"); return NULL; }
int pipe_fds[2];
memset(pipe_fds, 0, sizeof(pipe_fds));
if (pipe(pipe_fds) == -1) { perror("pipe"); return NULL; }
if (pipe_fds[0] <= 0) { fprintf(stderr, "Read fd is invalid.\n"); return NULL; }
if (pipe_fds[1] <= 0) { fprintf(stderr, "Write fd is invalid.\n"); return NULL; }
fcntl(pipe_fds[0], F_SETFL, O_NONBLOCK);
fcntl(pipe_fds[1], F_SETFL, O_NONBLOCK);
*read_fd = pipe_fds[0];
*write_fd = pipe_fds[1];
auto json_serialize_event_to_pipe = [pipe_fds](wtr::watcher::event event) {
auto json = wtr::to<std::string>(event) + "\n";
write(pipe_fds[1], json.c_str(), json.size());
};
auto w = new wtr::watcher::watch(path, json_serialize_event_to_pipe);
if (! w) {
perror("new wtr::watcher::watch");
close(pipe_fds[0]);
close(pipe_fds[1]);
return NULL;
}
*read_fd = pipe_fds[0];
return (void*)w;
}

bool wtr_watcher_close_pipe(void* watcher, int read_fd, int write_fd)
{
bool ok = false;
ok |= watcher && ((wtr::watcher::watch*)watcher)->close();
ok |= write_fd > 0 && close(write_fd);
ok |= read_fd > 0 && close(read_fd);
if (watcher) delete (wtr::watcher::watch*)watcher;
return ok;
}
#endif

} // extern "C"
12 changes: 6 additions & 6 deletions watcher-nodejs/lib/watcher-napi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@ static void effect_type_js_obj(napi_env env, napi_value* effect_obj)
{
napi_create_object(env, effect_obj);
napi_value rename, modify, create, destroy, owner, other;
napi_create_int32(env, WTR_WATCHER_EVENT_RENAME, &rename);
napi_create_int32(env, WTR_WATCHER_EVENT_MODIFY, &modify);
napi_create_int32(env, WTR_WATCHER_EVENT_CREATE, &create);
napi_create_int32(env, WTR_WATCHER_EVENT_DESTROY, &destroy);
napi_create_int32(env, WTR_WATCHER_EVENT_OWNER, &owner);
napi_create_int32(env, WTR_WATCHER_EVENT_OTHER, &other);
napi_create_int32(env, WTR_WATCHER_EFFECT_RENAME, &rename);
napi_create_int32(env, WTR_WATCHER_EFFECT_MODIFY, &modify);
napi_create_int32(env, WTR_WATCHER_EFFECT_CREATE, &create);
napi_create_int32(env, WTR_WATCHER_EFFECT_DESTROY, &destroy);
napi_create_int32(env, WTR_WATCHER_EFFECT_OWNER, &owner);
napi_create_int32(env, WTR_WATCHER_EFFECT_OTHER, &other);
napi_set_named_property(env, *effect_obj, "rename", rename);
napi_set_named_property(env, *effect_obj, "modify", modify);
napi_set_named_property(env, *effect_obj, "create", create);
Expand Down
6 changes: 3 additions & 3 deletions watcher-py/watcher/watcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,11 +126,11 @@ class Watch:
"""
Filesystem watcher.
Begins watching when constructed.
Stops when the context manager exits (preferred to use this way).
Stops when the context manager exits (preferred to use it this way).
Or when `close`, del or deinit happens, but you don't need to do that.
Example usage:
```python
with watcher.Watch(os.path.expanduser("~"), print) as _:
with watcher.Watch(os.path.expanduser("~"), print):
input()
```
"""
Expand Down Expand Up @@ -176,5 +176,5 @@ def __exit__(self, *_):

if __name__ == "__main__":
events_at = sys.argv[1] if len(sys.argv) > 1 else "."
with Watch(events_at, print) as _:
with Watch(events_at, print):
input()
2 changes: 0 additions & 2 deletions watcher-rb/.bundle/config

This file was deleted.

7 changes: 0 additions & 7 deletions watcher-rb/.gitignore

This file was deleted.

12 changes: 0 additions & 12 deletions watcher-rb/Gemfile

This file was deleted.

Loading

0 comments on commit f36ad47

Please sign in to comment.