diff options
-rw-r--r-- | Makefile | 2 | ||||
-rwxr-xr-x | sbofixinfo | 209 |
2 files changed, 210 insertions, 1 deletions
@@ -14,7 +14,7 @@ MAN1DIR=$(MANDIR)/man1 DOCDIR=$(PREFIX)/doc/$(PROJ)-$(VERSION) DOCS=README QUICKSTART TODO pre-commit-sbolint -SCRIPTS=sbopkglint sbolint +SCRIPTS=sbopkglint sbolint sbofixinfo all: @echo "Use 'make install PREFIX=<path>' to install $(PROJ)." diff --git a/sbofixinfo b/sbofixinfo new file mode 100755 index 0000000..2515989 --- /dev/null +++ b/sbofixinfo @@ -0,0 +1,209 @@ +#!/usr/bin/perl -w + +# reorder the keys in a SBo .info file. +# assumes the file is otherwise valid. +# companion piece to sbolint. + +$VERSION="0.1"; + +# generate man page with: +# pod2man --stderr -r0.1 -s1 -c"SBo Maintainer Tools" sbofixinfo > sbofixinfo.1 + +=pod + +=head1 NAME + +sbofixinfo - fix common errors in a SlackBuilds.org .info file + +=head1 SYNOPSIS + +sbofixinfo [-b] infofile [infofile ...] + +=head1 DESCRIPTION + +B<sbofixinfo> attempts to fix the following errors in SBo .info files: + +=over 4 + +=item - + +Out-of-order keys will be reordered to match order in the template. + +=item - + +Extraneous keys will be removed. + +=item - + +Blank lines will be removed. + +=item - + +Extra whitespace will be removed. This doesn't include indentation for +the 2nd and further lines of a multi-line value. + +=item - + +Missing \ (backslash) continuation characters will be added. + +=item - + +Missing " (double-quote) characters around key values will be added. + +=item - + +Values quoted with single-quotes will be quoted with double-quotes. + +=item - + +Multi-valued keys (e.g. DOWNLOAD with two URLs) will be split up into +multiple lines, if they're not already. Any missing line-continuation +backslashes will be added. + +=back + +B<sbofixinfo> doesn't attempt to detect any other errors or dubious +constructs. Use B<sbolint> before and after running B<sbofixinfo> for +comprehensive checking. + +The file is modified 'in-place', in the same way as the B<-i> option +to B<sed>(1). + +=head1 OPTIONS + +B<-b> causes B<sbofixinfo> to keep a backup of the original file with the +extension I<.bak> appended to the filename. If the backup file already +exists, it will be silently overwritten. After the new file is generated, +B<diff>(1) (with its B<-u> option) is run on the backup and modified +files, and the backup is deleted if the new file is identical. The diff +output also goes to stdout, so the user can see what changes were made. + +=head1 EXIT STATUS + +Will be 0 for success. If any errors reading or writing any of the .info +files occur, the exit status will be the error count. + +=head1 BUGS + +Misspelled key names (e.g. MD5USM or DOWNLAOD) will have their values +discarded. Not a true bug (it's by design), but it violates the principle +of least surprise a bit. + +B<sbofixinfo> can't automatically fix every issue B<sbolint> reports. +In particular, missing or extra values (for valid keys) can't +automatically be fixed. This isn't really a bug, as B<sbofixinfo> +can't know what to do in these situations. In other words, B<sbofixinfo> +operates only at the syntactic level, and knows nothing of semantics. + +=head1 AUTHOR + +B. Watson (yalhcru at slackware.uk, or Urchlay on Libera IRC) + +=head1 SEE ALSO + +B<sbolint>(1), B<sbopkglint>(1) + +=cut + +($SELF = $0) =~ s,.*/,,; + +@keyorder = qw/ +PRGNAM VERSION HOMEPAGE DOWNLOAD MD5SUM DOWNLOAD_x86_64 MD5SUM_x86_64 REQUIRES MAINTAINER EMAIL +/; + +die "$SELF v$VERSION\nUsage: $SELF [--help] [-b] infofile <infofile ...>\n" unless @ARGV; + +if($ARGV[0] eq '--help') { + no warnings; + require FindBin; + system("perldoc $FindBin::RealScript"); + exit 0; +} + +if($ARGV[0] eq '-b') { + $backup = 1; + shift; +} + +$errcnt = 0; +fix_info($_) for @ARGV; +exit $errcnt; + +sub fix_info { + my $file = shift; + open my $fh, "<$file" or do { + warn "$SELF: can't read $file: $!\n"; + $errcnt++; + return; + }; + + my $key = 'INVALID_STUFF'; + my %info; + + # read through the whole file, extracting the values of all the + # keys, stash them in a hashtable. Multi-valued keys will be stored + # with carriage returns as a delimiter (they're otherwise not allowed). + # Quotes, backslashes, etc aren't stored (only the actual values). + while(<$fh>) { + chomp; + s/\r//g; # no DOS line endings + next if /^\s*$/; # ignore blank lines entirely + + s/(?:^\s+|\s+$)//g; # remove leading/trailing spaces + s/^(\w+)\s+=\s+/$1=/; # remove spaces around = + + if(/^(\w+)=(.*)$/) { + $key = $1; + $val = $2; + $val =~ s,(?:^['"]|['"]$),,g; # remove quotes around value + $val =~ s,[\s\\]*$,,; # remove any line-continuation backslash + + # multiple valued keys all on the same line get split up into + # multi-line values. This only applies to download and md5sum + # URLs (which can't contain spaces anyway). + if($key =~ /^(?:DOWNLOAD|MD5SUM)/) { + $val =~ s/\s+/\r/g; + } + + $info{$key} = $val; + } else { + s,[\s\\\"]*$,,; + $info{$key} .= "\r$_"; + } + } + close $fh; + + system("mv $file $file.bak") if $backup; + + open $fh, ">$file" or do { + warn "$SELF: can't write $file: $!\n"; + $errcnt++; + return; + }; + + # Reconstitute info file from the values, with correct indentation and + # quoting, backslashes, etc. + for $key (@keyorder) { + $info{$key} ||= ""; # avoid unitialized value on missing key + my @values = split /\r/, $info{$key}; + if(@values == 0) { + print $fh "$key=\"\"\n"; + } elsif(@values == 1) { + print $fh "$key=\"$values[0]\"\n"; + } else { + my $indent = " " x (length($key) + 2); + my $first = shift @values; + my $last = pop @values; + print $fh "$key=\"$first \\\n"; + print $fh "$indent$_ \\\n" for @values; + print $fh "$indent$last\"\n"; + } + } + + if($backup) { + my $result = system("diff $file.bak $file"); + if($result == 0) { + system("rm $file.bak"); + } + } +} |