#! /usr/bin/perl
# VERSION 1.1
#
# ______________________________________   P Fan -  2/2017, 3/2017, 11/2019
#
# NAME
#
#    appversion <app bundle1> <app bundle2> ...
#
# SYNOPSIS
#    This prints out the version number of the given Apple app(s).
#    It is the value of the key CFBundleShortVersionString  or
#    in some rogue case  CFBundleVersion  in the file
#    <app>/Contents/Info.plist.  It is pretty standard.  We search
#    for the CFBundleShortVersionString key first.
#
#    Presently Info.plist is mostly a text file, but if it happens to be
#    in a binary format, it will be converted to text in /tmp and
#    we search the text version for the relevant key value.  The conversion
#    will require this apple binary plutil.
#
#    One could run this on any unix box as well, but won't be able to get
#    version from binary Info.plist.
#
#  EXAMPLE
#    From inside /Applications, we could do
#    appversion Safari.app,  appversion Utilities/*.app or appversion *.app
#
# ________________________________________________________________


@ARGV > 0 || die "Usage: appversion <app bundle1> <app bundle2> ...\n\n";

print "\n";

foreach $app (@ARGV) {
    # some sanity check first.

    if (!-d "$app") {
	print "I do not see $app\n";
	next;
    }

    $info =    "$app/Contents/Info.plist";
    $infover = "$app/Contents/version.plist";     # old apps may use this

    if (!-e "$info") {
	$info = $infover;    # use version.plist
    }

    if (!-e "$info") {
	print "WARNING: could not see Info.plist nor version.plist - ".
 	     "no version found\n".
	    "Make sure you specify the app bundle and not a parent folder.\n".
	   "  Usage: appversion <app bundle1> <app bundle2> ...\n";
	next;
    }

    $tmpf = "";
    $binary = `file "$info" | grep binary`;
    if ($binary ne "") {		# convert plist to text file if not
#    if (!-T $info) {		       # convert plist to text file if not
	if (-e "/usr/bin/plutil") {
	    chomp ($bapp = `basename "$app"`);    # just the app.
	    $tmpf = "/tmp/$bapp.info.plist";
	    `cp "$info" "$tmpf"`;
	    `plutil -convert xml1 "$tmpf"`;
	    $info = $tmpf;
	    if (!-T $info) {
	 	print "Could not convert plist for $app into text - ".
		     "no version found\n";
		`rm "$tmpf"`;
		next;
	    }
	}
	else {
	    print "Could not convert plist for $app into text - ".
	          "no version found\n";
	    next;
	}
    }


    # Now parse the Info.plist file and look for CFBundleShortVersionString

    open (F, "$info");
   
    $key = "";
    while ($v = <F>) {
	if ($v =~ /\<key\>CFBundleShortVersionString\<\/key\>/) {
	    $key = "yes";
  	    next;
	}
	elsif ($key eq "yes") {
	    $v =~ s/\s*\<string\>//;
	    $v =~ s/\<\/string\>\s*//;
	    print "   $app has version = $v\n";
	    last;
	}
    }
  	
    close (F);

    if ($key eq "") {
	open (G, "$info");
    }
   
    $key2 = "";
    while ($v = <G>) {
	if ($v =~ /\<key\>CFBundleVersion\<\/key\>/) {
	    $key2 = "yes";
  	    next;
	}
	elsif ($key2 eq "yes") {
	    $v =~ s/\s*\<string\>//;
	    $v =~ s/\<\/string\>\s*//;
	    print "   $app has version = $v\n";
	    last;
	}
    }
  	
    close (G);

    if ($key eq "" && $key2 eq "") {
        print "Sorry, could not find the app version for $app\n";
    }

    if ($tmpf ne "") {       # clean up possible scratch
	`rm "$tmpf"`;
    }
}

print "\n";




