I've been building a number of websites where it has been necessary to write code into locally hosted files, and to then test on remote servers. After performing literally hundreds of drag-and-drop ssh transfers, I finally decided to search out an app that would simply monitor and sync the remote directories to my local folders.
However, the only minimalist app I could locate was lsyncd, which, while a perfect match for my needs, has not been supported on OS X for years. Given the minimalist functionality that I required, I decided I would quickly write my own, but then I remembered...
I have been looking for an opportunity to experience for myself just how capable and convenient ChatGPT is as a coding tool, and also to gauge my comfort level with using AI in this way. I decided to turn my need for a folder syncing exercise into a two-birds-with-one-stone opportunity.
The primary incompatibility between lsyncd and OS X is caused by lsync's dependence on inotify for monitoring directory changes. However, iontify is not OSX compatible, and so I selected fswatch as an OS X-friendly monitoring alternative. Combined with the all powerful rsync, there was little the app would need to do on its own.
Without any reference to best practices, I asked ChatGTPT 3.5 to:
"Write a linux application in the C language that syncs the contents of a target folder to a source folder, whenever the content of the source folder changes. Use fswatch instead of inotify to monitor the source folder. Make the application capable of syncing to the target folder over ssh. Exclude Apple OSes hidden .DS_Store files."
ChatGPT not only provided simple, functional C, but also documented its work and provided basic implementation steps.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char *argv[]) {
if ((argc != 3 && argc != 6) || (argc == 6 && strcmp(argv[3], "-ssh") != 0)) {
fprintf(stderr, "Usage: %s <source_folder> <target_folder> [-ssh <ssh_username> <ssh_hostname>]\n", argv[0]);
return EXIT_FAILURE;
}
const char *source_folder = argv[1];
const char *target_folder = argv[2];
char command[1024]; // Adjust buffer size accordingly
if (argc == 6) {
// Sync to a remote target folder over SSH
const char *ssh_username = argv[4];
const char *ssh_hostname = argv[5];
// Build the fswatch command
snprintf(command, sizeof(command), "fswatch --exclude='.DS_Store' -r \"%s\" | while read -r; do rsync -av --delete --exclude='.DS_Store' -e 'ssh' \"%s/\" \"%s@%s:%s\"; done", source_folder, source_folder, ssh_username, ssh_hostname, target_folder);
} else {
// Sync to a local target folder
// Build the fswatch command
snprintf(command, sizeof(command), "fswatch --exclude='.DS_Store' -r \"%s\" | while read -r; do rsync -av --delete --exclude='.DS_Store' \"%s/\" \"%s\"; done", source_folder, source_folder, target_folder);
}
// Execute the fswatch command
FILE *fp = popen(command, "r");
if (fp == NULL) {
perror("popen");
return EXIT_FAILURE;
}
// Keep the program running
while (1) {
sleep(1); // Or do other processing here if needed
}
// Close the file pointer
pclose(fp);
return EXIT_SUCCESS;
}
There were small errors, though. The positions of arguments the AI engine had chosen to store in an array were incorrectly referenced, so that even correctly formatted calls to execute failed the application's own rudimentary syntax validation. For anyone who understands array basics, this would be easy to recognize and correct, but for a non-programmer using ChatGPT for similar purposes, this would result in a fail. Likewise, usage instructions were sparse, with the chatbot assuming that the user would not flinch at being instructed to use "gcc to compile the code."
On a second, more refined query, I asked for the application to additionally ignore hidden files located within the monitored directories. ChatGPT did as asked, but the resulting exclude clauses were incorrectly written, causing all files to be excluded, instead of only hidden ones. (Note: the code posted above is fully functional, with errors corrected.)
As has been noted by practitioners from many fields, ChatGPT is supremely confident, even when it is wrong. I find myself wishing ChatGPT had been designed to humbly gauge its confidence in its responses. I guess we want chatbots to exist beyond the limits of our self-doubt.
I may be a bit old-fashioned. I may be a bit stubborn. Or, I may be right to feel uncomfortable sharing, or worse, selling code that I did not write. Wanting to better understand the various arguments, I descended into a rabbit hole of discussion forums covering the stances held by programmers and non-programmers arguing the cases for and against the use of AI to produce code. It took some time to establish a framework that I could comfortably work within.
A common argument in support of using AI is that programmers have been borrowing, referencing, including and reusing code for as long as code has existed. This is obviously true. However, the provenance of shared code libraries is well-established. Code imported from libraries or copied from internet sources typically represent individual pieces in very large puzzles. It remains the programmer's role to fit these pieces together into a unique product. By comparison, AI chatbots are able to produce and return entire, completed applications in seconds. There is simply no analogy, unless programmers were to limit AI assistance to querying for examples of how to accomplish particular coding tasks.
A related argument is that AI is simply the newest layer of technological convenience. When we write HTML or CSS, our work sits atop — and depends upon — a multitude of code layers that we currently take for granted. It can be argued that, in the near future, we will be working closely with our AI assistants to produce code as immediately as we recognize the need. Proponents argue that once past the psychological barriers, developers will as likely worry about using chatbots to complete work as they currently worry about using browsers, servers or operating systems that they hadn't scratch-coded themselves. This may eventually become the case, but we're not there, yet. Operating systems, servers and browsers are, in fact, extremely unique examples of software whose use is vigorously monitored and protected by owners and creators.
From my current position, the only honest way to publish AI-produced software is to label it as such. My stance may shift as industry norms become established, or as intellectual property law supersedes individual ethics. For the moment, I intend to comment AI-generated code with honest and accurate attribution. I am further considering using the relevant AI tool's logo, in conjunction with the phrase "Created with [AI_tool_name]" on all related visual materials. I will first need to research the permitted use of logos and trademarks of the AI tools I find myself using. After all, if AIs are only tools, then it should be no more embarassing to acknowledge one's use of AI to create software than to acknowledge one's use of a specific hammer to complete a repair.
Source and compiled versions are available for download here: source, compiled.
Once downloaded, just move the compiled file to a valid $PATH directory, such as '/usr/bin' or '/usr/local/bin'
Then, if syncing over ssh, configure your local machine to log into the remote host with automatic password handling. Hy hosting company, Dreamhost, offers a very succinct set of instructions, for those who are not familiar with creating and sharing key pairs.
matchdir can then be executed from the command line, as follows:
Usage: matchdir <source_folder> <target_folder> [-ssh <ssh_username> <ssh_hostname>]
<ssh_username> <ssh_hostname> are optional, but must be proceeded by the '-ssh' switch to inform matchdir that syncing is to occur between local and remote hosts
Sample for local syncing:
matchdir ~/folder1 ~/folder2
Sample for local to remote syncing:
matchdir ~/folder1 /folder2 -ssh my_username my.webhost.com
WARNING matchdir precisely and recursively syncs the target to the source. This means that any file or folder, new or previously existing, will be promptly and permanently deleted, unless the exact same file or folder is also located in the source directory. Until you have bacome completely comfortable using matchdir, keep copies and backups of your files and directories.
DISCLAIMER This is to specifically emphasize that neither the author, nor any organization associated with the author, can or will be held responsible for data-loss caused by possible malfunctions of matchdir. Use at your own risk.