Last active
November 27, 2020 18:05
-
-
Save s1037989/2623f65e85557f1dc5525b57fdf5263c to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
FILE=`which file 2>/dev/null` || exit 1 | |
finish_writing() { | |
local file=$1; shift | |
if [ $still_growing_timeout -gt 0 ]; then | |
printf "waiting for $file to finish\n" >$stderr | |
wait_file $file | |
! file "$file" "$mime_type" && return | |
! validate "$file" "$test" && return | |
fi | |
local _file="$tmpl" | |
[[ "$_file" =~ %f ]] && _file="${_file/\%f/${file##*/}}" | |
[[ "$_file" =~ %w ]] && _file="${_file/\%w/${file%/*}/}" | |
[[ "$_file" =~ %T ]] && _file="${_file/\%T/$(date +%FT%T.%N)}" | |
[[ "$_file" =~ %s ]] && _file="${_file/\%s/$(stat -c%s $file)}" | |
echo "$_file" | |
} | |
file() { | |
local file=$1; shift | |
[ -z "$file" -o ! -f "$file" ] && return 1 | |
local mime_type=$1; shift | |
[ -z "$mime_type" ] && return 0 | |
[ $($FILE -bp -m ${magic:-/etc/magic} -- mime_type $file) == "$mime_type" ] | |
} | |
still_growing() { | |
local file=$1; shift | |
[ -z "$file" ] && return 1 | |
test ! -e $file -o ! -s $file && return 0 | |
test $(echo "scale=9; $(date +%s.%N)-$(test -e $file && date -r $file +%s.%N || echo 0) < ${still_growing_timeout:-1}" | bc) -eq 1 | |
} | |
usage() { | |
cat <<EOF; | |
Usage: $0 [OPTIONS] | |
Wait for a file to finish growing, and optionally detect the file type based on | |
its contents and pass a test. Each file is tested in a subprocess so files are | |
reported finished as they finish and not in the order they are created. | |
Options: | |
-f tmpl Output template, defaults to "%w%f" | |
%f Basename | |
%s Size | |
%T Current time (%FT%T.%N) | |
%w Dirname with trailing slash | |
-h Usage | |
-M type Mime Type | |
-m magic Magic file | |
-q Quiet | |
-T test Test to pass to validate file | |
-t sec Timeout to assume no longer growing | |
Examples: | |
After 1 second of no growth, assume file is finished writing. | |
$ inotifywait -m `pwd` | finish_writing | |
EOF | |
exit 1 | |
} | |
validate() { | |
local file=$1; shift | |
[ -z "$file" -o ! -f "$file" ] && return 1 | |
local test=$1; shift | |
[ -z "$test" ] && return 0 | |
eval ${test/\%f/$file} &>/dev/null | |
} | |
wait_file() { | |
local file=$1; shift | |
[ -z "$file" ] && return 1 | |
while still_growing $file; do sleep $still_growing_pause; done | |
} | |
while getopts "f:hM:m:p:qT:t:" o; do | |
case "$o" in | |
f) tmpl=$OPTARG;; | |
h) usage;; | |
M) mime_type=$OPTARG;; | |
m) magic=$OPTARG;; | |
t) still_growing_pause=$OPTARG;; | |
q) stderr=/dev/null;; | |
T) test=$OPTARG;; | |
t) still_growing_timeout=$OPTARG;; | |
esac | |
done | |
shift $(($OPTIND-1)) | |
: ${tmpl:="%f"} | |
: ${stderr:=/dev/stderr} | |
: ${still_growing_timeout:=1} | |
: ${still_growing_pause:=.1} | |
while read file; do finish_writing "$file" & done | |
pause() { | |
local IFS | |
[[ -n "${_pause_fd:-}" ]] || exec {_pause_fd}<> <(:) | |
read ${1:+-t "$1"} -u $_pause_fd || : | |
} | |
slow() { | |
local pid=$1; shift | |
local run=${1:-.001}; shift | |
local wait=${1:-.001}; shift | |
local i=1 | |
local sp="/-\|" | |
printf " " >&2 | |
pause $run | |
while kill -0 $pid &>/dev/null; do | |
kill -19 $pid &>/dev/null | |
printf "\b${sp:i++%${#sp}:1}" >&2 | |
pause $wait | |
kill -18 $pid &>/dev/null | |
pause $run | |
done | |
printf "\b$i\n" >&2 | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env perl | |
use 5.010; | |
use strict; | |
use warnings; | |
use File::LibMagic; | |
use IO::Select; | |
use Mojo::EventEmitter; | |
use Mojo::File qw(path); | |
use Mojo::IOLoop; | |
use Time::HiRes qw(stat time); | |
my $files = {}; | |
my $s = IO::Select->new; | |
$s->add(\*STDIN); | |
my $magic = File::LibMagic->new; | |
my $e = Mojo::EventEmitter->new; | |
$e->on(create => sub { | |
my ($e, $file) = @_; | |
warn "$file"; | |
$files->{"$file"} = $file; | |
}); | |
$e->on(finish => sub { | |
my ($e, $file) = @_; | |
delete $files->{"$file"}; | |
my $info = $magic->info_from_filename("$file"); | |
return if $ENV{MIME_TYPE} && !mime_type($info->{mime_type}); | |
return if $ENV{TEST} && !test($file); | |
my $_file = $ENV{TEMPLATE}||'%w%f'; | |
$_file =~ s/%w/$file->dirname.'\/'/eg; | |
$_file =~ s/%f/$file->basename/eg; | |
$_file =~ s/%T/mtime($file)/eg; | |
$_file =~ s/%s/-s $file/eg; | |
printf "%s\n", $_file; | |
}); | |
Mojo::IOLoop->recurring(0 => sub { | |
my $loop = shift; | |
foreach my $file (values %$files) { | |
$e->emit(finish => $file) if time - $file->stat->mtime > ($ENV{TIMEOUT}||1); | |
} | |
}); | |
Mojo::IOLoop->recurring(0 => sub { | |
my $loop = shift; | |
my ($stdin) = $s->can_read(0) or return; | |
chomp(my $file = <$stdin>); | |
$e->emit(create => path($file)); | |
}); | |
Mojo::IOLoop->start unless Mojo::IOLoop->is_running; | |
sub mime_type { shift != $ENV{MIME_TYPE} } | |
sub mtime { ((stat(shift))[9]) } | |
sub test { | |
my $file = shift; | |
my $test = $ENV{TEST}; | |
$test =~ s/%f/$file/g; | |
qx($test); | |
return $? ? 0 : 1; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment