3 #=======================================================================
5 # File ID: 3d0e23bc-400e-11e4-a184-c80aa9e67bbd
7 # Check that some necessary programs are installed.
10 # ©opyleft 2014– Øyvind A. Holm <sunny@sunbase.org>
11 # License: GNU General Public License version 2 or later, see end of
12 # file for legal stuff.
13 #=======================================================================
20 plan skip_all
=> "We're not on GNU/Linux";
30 our $CMD = "../$CMDB";
46 $progname =~ s/^.*\/(.*?)$/$1/;
47 our $VERSION = '0.0.0';
49 my %descriptions = ();
51 Getopt
::Long
::Configure
('bundling');
54 'all|a' => \
$Opt{'all'},
55 'gui|g' => \
$Opt{'gui'},
56 'help|h' => \
$Opt{'help'},
57 'other|o' => \
$Opt{'other'},
58 'quiet|q+' => \
$Opt{'quiet'},
59 'todo|t' => \
$Opt{'todo'},
60 'verbose|v+' => \
$Opt{'verbose'},
61 'version' => \
$Opt{'version'},
63 ) || die("$progname: Option error. Use -h for help.\n");
65 $Opt{'verbose'} -= $Opt{'quiet'};
66 $Opt{'help'} && usage
(0);
67 if ($Opt{'version'}) {
78 my $Lh = "[0-9a-fA-F]";
79 my $Templ = "$Lh\{8}-$Lh\{4}-$Lh\{4}-$Lh\{4}-$Lh\{12}";
80 my $v1_templ = "$Lh\{8}-$Lh\{4}-1$Lh\{3}-$Lh\{4}-$Lh\{12}";
81 my $v1rand_templ = "$Lh\{8}-$Lh\{4}-1$Lh\{3}-$Lh\{4}-$Lh\[37bf]$Lh\{10}";
82 my $v4_templ = "$Lh\{8}-$Lh\{4}-4$Lh\{3}-[89ab]$Lh\{3}-$Lh\{12}";
84 diag
(sprintf('========== Executing %s v%s ==========',
85 $progname, $VERSION));
87 if ($Opt{'todo'} && !$Opt{'all'}) {
93 testcmd("$CMD command", # {{{
106 diag
("Checking coreutils...");
108 arch base32 base64 basename cat chcon chgrp
chmod chown chroot cksum
109 comm cp csplit cut date dd df dir dircolors dirname du echo env expand
110 expr factor false fmt fold groups head hostid id install
join link ln
111 logname ls md5sum
mkdir mkfifo mknod mktemp mv nice nl nohup nproc
112 numfmt od paste pathchk pinky pr printenv
printf ptx pwd
readlink
113 realpath rm
rmdir runcon seq sha1sum sha224sum sha256sum sha384sum
114 sha512sum shred shuf
sleep sort split stat stdbuf stty sum sync tac
115 tail tee timeout touch tr true
truncate tsort tty uname unexpand uniq
116 unlink uptime users vdir wc who whoami yes
119 diag
("Checking important software...");
120 installed
('autoconf --version', '/GNU Autoconf/', 'stdout');
121 installed
('bash --version', '/^GNU bash/', 'stdout');
122 installed
('bc --version', '/^bc \d.*Free Software Foundation/s', 'stdout');
123 installed
('cmake --version', '/^cmake version \d/', 'stdout');
124 installed
('cmark --version', '/^cmark \d+\.\d+\.\d+/', 'stdout');
125 installed
('cronolog --version', '/^cronolog version \d/', 'stderr');
126 installed
('ctags --version', '/^(Exuberant|Universal) Ctags \d/', 'stdout');
127 installed
('curl --version', '/^curl /', 'stdout');
128 installed
('dict --version', '/^dict \d/', 'stdout');
129 installed
('echo ABC ZZZ aabel abbel abc bbbe © Å Æ Ø å æ ø → 🤘 | fmt -1 | sort', '/^ABC\nZZZ\naabel\nabbel\nabc\nbbbe\n©\nÅ\nÆ\nØ\nå\næ\nø\n→\n🤘\n$/', 'stdout', 'Use C sorting order');
130 installed
('find --version', '/GNU findutils/', 'stdout');
131 installed
('gadu --version', '/git-annex-utils \d/', 'stdout');
132 installed
('gcc --version', '/^gcc /', 'stdout');
133 installed
('git --version', '/^git version 2\./', 'stdout');
134 installed
('git-annex version', '/^git-annex version: /', 'stdout');
135 installed
('gnuplot --version', '/^gnuplot /', 'stdout');
136 installed
('gpg --version', '/^gpg.+GnuPG\b/', 'stdout');
137 installed
('grep --version', '/GNU grep/', 'stdout');
138 installed
('gzip --version', '/^gzip \d/', 'stdout');
139 installed
('indent --version', '/GNU indent 2\.2\./', 'stdout');
140 installed
('lilypond --version', '/^GNU LilyPond 2/', 'stdout');
141 installed
('make --version', '/GNU Make/', 'stdout');
142 installed
('mc --version', '/GNU Midnight Commander/', 'stdout');
143 installed
('mysql --version', '/^$/', 'stdout', 'MySQL is not installed');
144 installed
('ncdu -v', '/^ncdu \d/', 'stdout');
145 installed
('perl --version', '/This is perl( |, v)5/', 'stdout');
146 installed
('pinfo --version', '/^Przemek\'s Info Viewer /', 'stdout');
147 installed
('pv --version', '/^pv \d/', 'stdout');
148 installed
('python --version', '/Python (2|3)/', 'both');
149 installed
('python3 --version', '/^Python 3/', 'both');
150 installed
('recode --version', '/^Free recode \d/', 'stdout');
151 installed
('rsync --version', '/^rsync\s+version \d/', 'stdout');
152 installed
('screen --version', '/^Screen version \d/', 'stdout');
153 installed
('script --version', '/^script .+\butil-linux\b/', 'stdout');
154 installed
('sqlite3 --version', '/^3\.[2-4]/', 'stdout');
155 installed
('ssh -V', '/OpenSSH/', 'stderr');
156 installed
('sshfs --version', '/SSHFS version \d/', 'stdout');
157 installed
('tar --version', '/GNU tar\b/', 'stdout');
158 installed
('tree --version', '/^tree v\d\./', 'stdout');
159 installed
('unzip -v', '/^UnZip \d.*Info-ZIP/', 'stdout');
160 installed
('uprecords -v', '/^uprecords \d/', 'stdout');
161 installed
('uuid -d ac89d100-5809-11e0-b3ff-00023faf1383', '/2011-03-27 00:32:19\.377792\.0 UTC/', 'stdout', 'OSSP uuid');
162 installed
('vim --version', '/VIM - Vi IMproved [89]\../', 'stdout');
163 installed
('wget --version', '/GNU Wget/', 'stdout');
164 installed
('zip -v', '/This is Zip \d.*Info-ZIP/', 'stdout');
165 repeat_test
('uuidgen -r', 100, "^$v4_templ\$");
166 repeat_test
('uuidgen -t', 100, "^$v1_templ\$");
168 is
(`echo "SELECT json('[\\"a\\", 4, true, { \\"abc\\" :\\"def\\"}]');" | sqlite3 2>/dev/null`,
169 "[\"a\",4,true,{\"abc\":\"def\"}]\n",
170 "sqlite3 has json support",
173 if ($Opt{'other'} || $Opt{'all'}) {
175 diag
("Checking other software...");
176 installed
('archivemount --version', '/^archivemount version \d/', 'stderr');
177 installed
('arj', '/^ARJ\S*? v \d/', 'stdout');
178 installed
('asciidoc --version', '/^asciidoc \d/', 'stdout');
179 installed
('bison --version', '/^bison\b.+GNU Bison\b/', 'stdout');
180 installed
('cdparanoia --version', '/^cdparanoia III/', 'stderr');
181 installed
('cpio --version', '/GNU cpio/', 'stdout');
182 installed
('dblatex --version', '/^dblatex version \d/', 'stdout');
183 installed
('dot -V', '/graphviz version \d/', 'stderr');
184 installed
('echo "[{ }]" | json_reformat -m', '/^\[{}+]$/', 'stdout', 'json_reformat');
185 installed
('exifprobe -V', '/Program: \'exifprobe\' version \d/', 'stdout');
186 installed
('exiftool -ver', '/^\d+\.\d/', 'stdout');
187 installed
('fdupes --version', '/^fdupes \d\./', 'stdout');
188 installed
('flac --version', '/^flac /', 'stdout');
189 installed
('flex --version', '/^flex \d/', 'stdout');
190 installed
('fontforge --version', '/^fontforge 20/', 'stdout');
191 installed
('fossil version', '/^This is fossil version 2\.3 /', 'stdout');
192 installed
('gettext --version', '/GNU gettext/', 'stdout');
193 installed
('gpsbabel --version', '/GPSBabel Version \d/', 'stdout');
194 installed
('groff --version', '/^GNU groff version \d/', 'stdout');
195 installed
('htop --version', '/^htop \d/', 'stdout');
196 installed
('iotop --version', '/^iotop \d/', 'stdout');
197 installed
('lame --version', '/LAME .* version /', 'stdout');
198 installed
('lftp --version', '/^LFTP .+Version \d/', 'stdout');
199 installed
('lynx --version', '/^Lynx Version \d/', 'stdout');
200 installed
('lzip --version', '/^Lzip \d/i', 'stdout');
201 installed
('mftrace --version', '/^mftrace \d\./', 'stdout');
202 installed
('mosh --version', '/^mosh \d/', 'stdout');
203 installed
('mutt -h', '/^Mutt \d/', 'stdout');
204 installed
('ncftp -v', '/Program version:\s+NcFTP /', 'stderr');
205 installed
('nmap --version', '/Nmap version /', 'stdout');
206 installed
('nodejs --version', '/^v\d+\.\d+\.\d+$/', 'stdout');
207 installed
('npm --version', '/^\d+\.\d+\.\d+$/', 'stdout');
208 installed
('pandoc --version', '/^pandoc \d\./', 'stdout');
209 installed
('pip --version', '/^pip \d/', 'stdout');
210 installed
('pip3 --version', '/^pip \d/', 'stdout');
211 installed
('psql --version', '/psql \(PostgreSQL\)/', 'stdout');
212 installed
('pylint --version', '/^pylint \d/', 'stdout');
213 installed
('quilt --version', '/^\d\./', 'stdout');
214 installed
('rtorrent -h', '/BitTorrent client version /', 'stdout');
215 installed
('rzip --version', '/^rzip version \d/', 'stdout');
216 installed
('scriptreplay --help', '/-m, --maxdelay/', 'stdout', 'scriptreplay has -m/--maxdelay');
217 installed
('strace -V', '/^strace -- version (\d+|UNKNOWN)/', 'stdout');
218 installed
('svn --version', '/svn, version /', 'stdout');
219 installed
('task --version', '/^2\.6\.0$/', 'stdout');
220 installed
('texi2html --version', '/^\d\./', 'stdout');
221 installed
('tig --version', '/^tig version /', 'stdout');
222 installed
('tmux -V', '/^tmux \d\./', 'stdout');
223 installed
('top -v', '/procps(-ng)?( version)? \d/', 'stdout');
224 installed
('trickle -V', '/^trickle: version \d/', 'stderr');
225 installed
('unrar --version', '/UNRAR \d/', 'stdout');
226 installed
('uuencode --version', '/^uuencode \(GNU sharutils\)/', 'stdout');
227 installed
('whois --version', '/^Version \d/', 'stdout');
228 installed
('wiggle --version', '/^wiggle v?1\.0/', 'stderr');
229 installed
('xmllint --version', '/^xmllint: using libxml version /', 'stderr');
230 installed
('xmlto --version', '/^xmlto version \d/', 'stdout');
231 installed
('xz --version', '/^xz \(XZ Utils\) \d/s', 'stdout');
232 installed
('youtube-dl --version', '/^20\d\d\.\d\d\.\d\d/', 'stdout');
236 if ($Opt{'gui'} || $Opt{'all'}) {
238 diag
("Checking graphical software...");
239 installed
('abiword --version', '/^\d\.\d+\.\d+/', 'stdout');
240 installed
('bash -c "type -p gnome-system-monitor"', '/bin\/gnome-system-monitor$/', 'stdout');
241 installed
('celestia --help', '/Usage:.*\bcelestia\b.+OPTION/s', 'stdout');
242 installed
('firefox --version', '/Mozilla Firefox \d+\.\d+/', 'stdout');
243 installed
('geeqie --version', '/^Geeqie \d\./', 'stderr');
244 installed
('gnucash --version', '/GnuCash \d\./', 'stdout');
245 installed
('gnumeric --version', '/^gnumeric version /', 'stdout');
246 installed
('gource --help', '/Gource v\d/', 'stdout');
247 installed
('inkscape -V', '/^Inkscape \d/', 'stdout');
248 installed
('mplayer -V', '/^MPlayer2 /', 'stdout');
249 installed
('okular --version', '/okular:? \d/i', 'stdout');
250 installed
('qemu-system-i386 --version', '/QEMU emulator version \d/', 'stdout');
251 installed
('shutter -v', '/^\d+\.\d+(\.\d+)? Rev\.\d+/', 'stdout');
252 installed
('ufraw --version', '/^ufraw \d/', 'stderr');
253 installed
('vlc --version', '/^VLC version \d/', 'stdout');
254 installed
('wireshark --version', '/^wireshark \d/i', 'stdout');
255 installed
('x264 --version', '/^x264 \d/', 'stdout');
256 installed
('xdot --help', '/Usage:.*\bxdot\b/si', 'stdout');
257 installed
('xtightvncviewer -h', '/^TightVNC Viewer /', 'stderr');
264 if ($Opt{'all'} || $Opt{'todo'}) {
265 diag
('Running TODO tests...'); # {{{
270 # Insert TODO tests here.
276 diag
('Testing finished.');
283 my ($Cmd, $Exp, $Std, $Desc) = @_;
284 $Std =~ /^(both|stderr|stdout)$/ ||
285 BAIL_OUT
("installed(): $Cmd: Invalid stream: '$Std'");
293 if ($Std eq 'stdout') {
294 like
(`$Cmd 2>/dev/null`, $Exp, $Txt);
295 } elsif ($Std eq 'stderr') {
296 like
(`$Cmd 2>&1 >/dev/null`, $Exp, $Txt);
298 like
(`$Cmd 2>&1`, $Exp, $Txt);
308 for my $curr (@progs) {
310 if ($curr =~ /^(echo|false|kill|pwd|true|printf)$/) {
311 for my $d (qw{ /usr/local/bin /usr
/bin /bin
}) {
318 installed
("$cmd --version",
319 "/^$curr .*?\\b(coreutils|procps-ng)\\b/",
320 'stdout') || ($retval = 1);
328 my ($cmd, $count, $regexp) = @_;
332 for (my $t = $count; $t && ($retval < 10); $t--) {
334 $uuid =~ /$regexp/s || ($retval++, $erruuid .= $uuid);
337 is
($erruuid, '', "$cmd: Repeat test $count times");
344 my ($Cmd, $Exp_stdout, $Exp_stderr, $Exp_retval, $Desc) = @_;
345 defined($descriptions{$Desc}) &&
346 BAIL_OUT
("testcmd(): '$Desc' description is used twice");
347 $descriptions{$Desc} = 1;
349 my $cmd_outp_str = $Opt{'verbose'} >= 1 ?
"\"$Cmd\" - " : '';
350 my $Txt = join('', $cmd_outp_str, defined($Desc) ?
$Desc : '');
351 my $TMP_STDERR = "$CMDB-stderr.tmp";
354 if (defined($Exp_stderr)) {
355 $stderr_cmd = " 2>$TMP_STDERR";
357 $retval &= is
(`$Cmd$stderr_cmd`, $Exp_stdout, "$Txt (stdout)");
359 if (defined($Exp_stderr)) {
360 $retval &= is
(file_data
($TMP_STDERR), $Exp_stderr, "$Txt (stderr)");
363 diag
("Warning: stderr not defined for '$Txt'");
365 $retval &= is
($ret_val >> 8, $Exp_retval, "$Txt (retval)");
373 my ($Cmd, $Exp_stdout, $Exp_stderr, $Exp_retval, $Desc) = @_;
374 defined($descriptions{$Desc}) &&
375 BAIL_OUT
("likecmd(): '$Desc' description is used twice");
376 $descriptions{$Desc} = 1;
378 my $cmd_outp_str = $Opt{'verbose'} >= 1 ?
"\"$Cmd\" - " : '';
379 my $Txt = join('', $cmd_outp_str, defined($Desc) ?
$Desc : '');
380 my $TMP_STDERR = "$CMDB-stderr.tmp";
383 if (defined($Exp_stderr)) {
384 $stderr_cmd = " 2>$TMP_STDERR";
386 $retval &= like
(`$Cmd$stderr_cmd`, $Exp_stdout, "$Txt (stdout)");
388 if (defined($Exp_stderr)) {
389 $retval &= like
(file_data
($TMP_STDERR), $Exp_stderr, "$Txt (stderr)");
392 diag
("Warning: stderr not defined for '$Txt'");
394 $retval &= is
($ret_val >> 8, $Exp_retval, "$Txt (retval)");
401 # Return file content as a string {{{
405 open(my $fp, '<', $File) or return undef;
414 # Print program version {{{
415 print("$progname $VERSION\n");
421 # Send the help message to stdout {{{
424 if ($Opt{'verbose'}) {
430 Usage: $progname [options]
432 Check for missing necessary programs needed by some scripts.
437 Run all tests, also TODOs.
439 Also check for programs that need a graphical environment.
443 Check for other software, programs that aren't essential for a
446 Be more quiet. Can be repeated to increase silence.
448 Run only the TODO tests.
450 Increase level of verbosity. Can be repeated.
452 Print version information.
460 # Print a status message to stderr based on verbosity level {{{
461 my ($verbose_level, $Txt) = @_;
463 $verbose_level > $Opt{'verbose'} && return;
464 print(STDERR
"$progname: $Txt\n");
471 # This program is free software; you can redistribute it and/or modify
472 # it under the terms of the GNU General Public License as published by
473 # the Free Software Foundation; either version 2 of the License, or (at
474 # your option) any later version.
476 # This program is distributed in the hope that it will be useful, but
477 # WITHOUT ANY WARRANTY; without even the implied warranty of
478 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
479 # See the GNU General Public License for more details.
481 # You should have received a copy of the GNU General Public License
482 # along with this program.
483 # If not, see L<http://www.gnu.org/licenses/>.
485 # vim: set fenc=UTF-8 ft=perl fdm=marker ts=4 sw=4 sts=4 et fo+=w :