169 lines
4.1 KiB
Perl
Executable file
169 lines
4.1 KiB
Perl
Executable file
#!/usr/bin/env perl
|
|
# TODO:
|
|
# implement -s and -r flags
|
|
# implement --timeout flag in main loop
|
|
# create --help / -h flag and possibly a man page
|
|
#
|
|
# listen: a simple configurable build system
|
|
# created by Bryson Steck, @brysonsteck on GitHub
|
|
# free and open source under the GPL Version 3
|
|
#
|
|
# Usage
|
|
# listen [flags] [file(s) to watch] [command(s) to run on file changes]
|
|
#
|
|
# Flags
|
|
# -a if all of the files have changed, required if multiple files
|
|
# -o if any one of the files have changed, required if multiple files
|
|
# -s to use checksum on file change instead of when the file was modified
|
|
# -r immediately run exec command, then start listening
|
|
# --timeout=[time] change timeout time in whole seconds (DEFAULT 1 SECOND)
|
|
|
|
# GLOBALS
|
|
local $| = 1;
|
|
my $ARGC = scalar @ARGV;
|
|
my $TIMEOUT = 1;
|
|
my $START_LISTEN = 0;
|
|
my $EXEC_POSITION = $ARGC - 1;
|
|
my $EXEC_LISTEN = undef;
|
|
my $ALL_FLAG = undef;
|
|
my $ANY_FLAG = undef;
|
|
my $MULTI_FILES = undef;
|
|
my $CHECKSUM_FLAG = undef;
|
|
my $CHECKSUM_COMMAND = "sha1sum";
|
|
|
|
sub flags {
|
|
if ($ARGC == 0) {
|
|
print "listen: To what?\n";
|
|
exit 2;
|
|
}
|
|
|
|
my $current_arg = 0;
|
|
|
|
foreach $arg (@ARGV) {
|
|
if ($arg =~ m/-[aos]/) {
|
|
if ($arg =~ m/a/) {
|
|
$ALL_FLAG = "def";
|
|
}
|
|
if ($arg =~ m/o/) {
|
|
$ANY_FLAG = "def";
|
|
}
|
|
if ($arg =~ m/s/) {
|
|
$CHECKSUM_FLAG = "def";
|
|
}
|
|
} elsif ($arg =~ m/--timeout=/) {
|
|
my @timeout_split = split /\=/, $arg;
|
|
if (scalar @timeout_split == 1) {
|
|
print "timeout flag invalid\n";
|
|
exit 2;
|
|
} elsif (int($timeout_split[1]) > 0) {
|
|
$TIMEOUT = $timeout_split[1];
|
|
print "timeout is now $TIMEOUT seconds\n";
|
|
} else {
|
|
print "timeout flag invalid\n";
|
|
exit 2;
|
|
}
|
|
} else {
|
|
last;
|
|
}
|
|
$current_arg++;
|
|
}
|
|
|
|
$START_LISTEN = $current_arg;
|
|
}
|
|
|
|
sub get_exec {
|
|
if ($START_LISTEN + 1 == $ARGC) {
|
|
print "listen: Not enough arguments\n";
|
|
exit 3;
|
|
}
|
|
|
|
$EXEC_LISTEN = $ARGV[-1];
|
|
}
|
|
|
|
sub require_flags {
|
|
if ($EXEC_POSITION - $START_LISTEN != 1) {
|
|
if (!$ALL_FLAG and !$ANY_FLAG) {
|
|
print "listen: Either -a or -o must be specified with multiple files to watch\n";
|
|
exit 4;
|
|
} elsif ($ALL_FLAG and $ANY_FLAG) {
|
|
print "listen: You must specify either -a or -o for multiple files, not both\n";
|
|
exit 4;
|
|
}
|
|
|
|
$MULTI_FILES = "def";
|
|
}
|
|
}
|
|
|
|
sub check_files {
|
|
for (my $i = $START_LISTEN; $i < $EXEC_POSITION; $i++) {
|
|
if (not -e $ARGV[$i]) {
|
|
print "listen: $ARGV[$i]: No such file or directory\n";
|
|
exit 5;
|
|
}
|
|
if (not -r $ARGV[$i]) {
|
|
print "listen: $ARGV[$i]: Permission denied (warning)\n";
|
|
}
|
|
}
|
|
}
|
|
|
|
sub start {
|
|
print "This shell command will run:\n";
|
|
print " $EXEC_LISTEN\n";
|
|
|
|
if ($MULTI_FILES) {
|
|
if ($ALL_FLAG) {
|
|
print "When all the files below have been modified:\n";
|
|
for (my $i = $START_LISTEN; $i < $EXEC_POSITION; $i++) {
|
|
print " $ARGV[$i]\n";
|
|
}
|
|
} elsif ($ANY_FLAG) {
|
|
print "When any of the files below have been modified:\n";
|
|
for (my $i = $START_LISTEN; $i < $EXEC_POSITION; $i++) {
|
|
print " $ARGV[$i]\n";
|
|
}
|
|
}
|
|
} else {
|
|
print "When this file has been modified:\n";
|
|
print " $ARGV[$START_LISTEN]\n";
|
|
}
|
|
|
|
print "Starting now...\n";
|
|
|
|
my $previous_epoch = (stat($ARGV[$START_LISTEN]))[9];
|
|
my $current_epoch = (stat($ARGV[$START_LISTEN]))[9];
|
|
while (1) {
|
|
$current_epoch = (stat($ARGV[$START_LISTEN]))[9];
|
|
if ($current_epoch > $previous_epoch) {
|
|
print "--- File \"$ARGV[$START_LISTEN]\" modified. Running command... ---\n";
|
|
system $EXEC_LISTEN;
|
|
my $status = $? >> 8;
|
|
if (int($status) != 0) {
|
|
print "--- WARNING: Exit code is $status. Returned to listen... ---\n";
|
|
} else {
|
|
print "--- Returned to listen... ---\n";
|
|
}
|
|
|
|
$previous_epoch = $current_epoch;
|
|
}
|
|
|
|
sleep(1);
|
|
}
|
|
}
|
|
|
|
# ---- START OF SCRIPT ----
|
|
# start by checking flags
|
|
flags();
|
|
|
|
# get executable to run on trigger
|
|
get_exec();
|
|
|
|
# check if additional flags are needed
|
|
# because multiple files are being listened to
|
|
require_flags();
|
|
|
|
# check if file(s) exist
|
|
check_files();
|
|
|
|
# start listen
|
|
start();
|
|
|