#!/usr/bin/perl ###################################################### # find_unused_graphics.pl # ======================= # # Purpose # ======= # - Scans a text listing of graphics used in a FrameMaker book or file, and # compares it with a graphics directory. # - Reports on files that appear to be unused. Also creates a batch file, 'mover.bat'. The commands # in 'mover.bat' will move those unused files to an 'unused_graphics' directory. So, # after running this Perl script, run 'mover.bat'. (Optionally, you may wish to open 'mover.bat' in # a text editor to see what it going to do before you run it.) In Windows, you can run a batch file # just by double-clicking it. # # To use # ====== # 1) Update the used graphics list (see "Usage" below). # 2) Run this Perl script (see "Usage" below). # For convenience, you can use the accompanying batch file 'run_it.bat' to run this Perl script. Before # running 'run_it.bat', you will have to open it in a text editor and change the parameters. # See the comments in 'run_it.bat' for details. # # Notes # ===== # - The batch file 'mover.bat' is created when you run this Perl script. # - This Perl script scans the graphics subdirectory recursively, so the directory can contain subdirectories # containing more graphics. # - This script assumes that _everything_ in the graphics directory (and any subdirectories) is a graphic, # so anything in there that is not in the graphics listing is considered unused and will be moved # by 'mover.bat'. If that is not the case, you may need to edit 'mover.bat' (open it in a text editor) # before running it. # - When you run 'mover.bat', it creates the 'unused_graphics' directory if it does not already exist. # It creates it as a sibling directory to the graphics directory. It assumes you have the necessary # access rights to create that directory. # - For safety, 'mover.bat' will not overwrite files that already exist in 'unused_graphics'. # - Do not run 'mover.bat' without updating it (via this Perl script or via 'run_it.bat') first. # - After using 'mover.bat', it is wise to open all the files in the FrameMaker book just to make sure you # don't get any "can't find the graphic" ERRORs. # - Note that conditional text can hide graphics. If you have a graphic hidden through conditional text, # this script may move it to the 'unused graphics' directory. So, be careful about deleting things in # that directory! They may be needed after all when you change conditions. # - In the list of graphics, there must be a TAB after the graphic name (ie, before the page number # if there is one). (If necessary, set this up on the list's Reference page in FrameMaker.) # - This script assumes there are no "@"s in the graphic names. # - This script only deals with graphic files that are imported by reference into FrameMaker, not copied in. # - Some of the directory parsing parts of this script are Windows-specific. If you are porting to another # platform you may have to twiddle a bit. # - The latest versions of these files can be found on . # # Usage # ===== # perl -w find_unused_graphics.pl # where # is the full path of the graphics directory # is a text file produced by copying the text out of FrameMaker's # list of imported graphics. # It has lines like: # graphics/ops_3a.gif @ 300 dpi 4-6 # graphics/more graphics/What a boy.gif @ 72 dpi 1 # graphics/icons/i_relv.gif 2-6 # NOTE: This script assumes there is always a TAB between the graphic name and page number. IE: # graphics/ops_3a.gif @ 300 dpi 4-6 # graphics/more graphics/What a boy.gif @ 72 dpi 1 # graphics/icons/i_relv.gif 2-6 # If this list is not in the same directory as the Perl script, you'll have # to give its full path. # # (To add such a list to a FrameMaker v 5.5 book: # a) Choose File:Add File. # b) Select 'Generated List' --> 'List of References' # c) Select 'Include References' --> 'Imported Graphics'.) # EG # perl -w find_unused_graphics.pl "D:\Docs\Wonderful Manual\graphics" pix.txt # or # perl -w find_unused_graphics.pl "D:\Docs\Wonderful Manual\graphics" "C:\new\pix.txt" # # # # Freeware written by Philip Sharman . Placed in the public domain. # No rights reserved. Use at your own risk. No warranties expressed or implied. Please report any # bugs you encounter. # # Version: # v 2.0 - Extensively rewritten. 2000/March/06 # v 2.1 - Sigh. Not all lines in the list of graphics contain "@"s. Fixed. # v 2.2 - Now handles the case where 'mover.bat' is on a different drive than the graphics directory. # v 2.3 - Clarified the comments. # v 2.4 - Added comments about conditional text and graphics. 2000/May/30 # v 2.5 - Clarified the comments. 2000/August/02 # v 2.6 - Web site and email address changed. 2001/January/02 # v 2.7 - Fixed a potential bug where the script would not distinguish between two graphics # with the same name but in different locations. # - Now ignores graphics in higher-level directories (e.g., "../common/thing.gif"). ####################################################### use strict; use File::Find; # Declare variables my @files_used; my @files_in_directory; my $item; my $nargs = @ARGV; if ($nargs != 2) {die "ERROR. Number of arguments is $nargs. Expected two.\n";} my $graphics_path = $ARGV[0]; my $graphics_path2 = quotemeta($graphics_path); my $used_graphics_list = $ARGV[1]; # Get the last part of the graphics path (e.g "graphics"). my $graphics_directory = $ARGV[0]; $graphics_directory =~ s%.*\\%% ; ####################################################### # Extract the file names from the 'used_graphics' list open (INPUT, "<$used_graphics_list" ) || die "ERROR: Could not open '$used_graphics_list' for input. ($!) \n"; while () { # Skip blank lines if ( /^\s*$/) {next;} # Find everything before the first TAB. if ( /^(.*?)\t/) { my $temp = $1; # Ignore graphics that live in directories higher up (e.g. ../Common Graphics/HTML/ArrowDown.gif) if ( $temp =~ /^\.\./) { print "Ignoring what appears to be a graphic in a higher-level directory: '$temp' \n"; next; } # Strip off any size information such as "@ 300 dpi" $temp =~ s/\s*@.*$//; # Here it gets tricky. We know the full path to our graphics directory, # e.g "C:\docs\project Acme\graphics" # but the FrameMaker file only records the path relative to the FrameMaker file, # e.g. "graphics/more graphics/banana.gif". # We want to extract the "more graphics/banana.gif" part. # Get the part of the name that is relative to our graphics directory. if ($temp =~ /$graphics_directory\/(.*)/) { my $filename = $1; # Strip any trailing whitespace $filename =~ s/\s*$//; # Add the file to the array. push @files_used, $filename; ### print "used: '$filename' \n"; } else { print "ERROR: Could not parse directory information from '$temp'. \n"; } } else { print "ERROR: COULD NOT PARSE: '$_' (Make sure there is a tab between the file name and the page number.)\n"; } } close INPUT; ####################################################### # Find the names of files in the graphics directory (and any subdirectories) # This subroutine fills in @files_in_directory &get_directory_listing; ####################################################### # Find elements in @files_in_directory that aren't in @files_used. # (See _The Perl Cookbook_, section 4.7) my %seen = (); my @files_to_move = (); foreach $item (@files_used) { $seen{$item} = 1; ### print "seen: '$item' \n"; } foreach $item (@files_in_directory) { ### print "in directory: '$item' \n"; unless ($seen{$item}) { # It's not in %seen, so add to @files_to_move push(@files_to_move, $item); } } ####################################################### # Report, and make batch file if necessary my $n = scalar(@files_to_move); if ($n == 0) { print "No files appear to be unused.\n"; # Overwrite any previous 'mover.bat' for safety. open (OUTPUT, ">mover.bat" ) || die "Could not open 'mover.bat' for output. ($!) \n"; print OUTPUT "\@echo off \n"; print OUTPUT "echo There are no files to be moved. \n"; print OUTPUT "pause \n"; close OUTPUT; } else { print "The following $n files appear to be unused: \n"; foreach $item (@files_to_move) { print "\t'$item'\n"; } &create_batch_file; } print "Done.\n"; ####################################################### # SUBROUTINES ####################################################### # Create the batch file. sub create_batch_file { open (OUTPUT, ">mover.bat" ) || die "Could not open 'mover.bat' for output. ($!) \n"; # Handle the case where 'mover.bat' is on a different drive from the graphics directory. my $drive = ""; if ( $graphics_path =~ /(.*?):/ ) { $drive = $1; } else { print "ERROR. Could not figure out the drive letter. 'mover.bat' may fail if it is run from a different drive than the graphics directory.\n"; } my $quote_char = "\""; print OUTPUT "\@echo off \n"; print OUTPUT "$drive:\n"; print OUTPUT "cd $quote_char$graphics_path$quote_char \n"; print OUTPUT "if exist $quote_char..\\unused graphics\\$quote_char goto MORE \n"; print OUTPUT "mkdir $quote_char..\\unused graphics$quote_char \n"; print OUTPUT "\n"; print OUTPUT ":MORE\n"; foreach (@files_to_move) { print OUTPUT "echo Moving $quote_char$_$quote_char ... \n"; print OUTPUT "if exist $quote_char$_$quote_char move $quote_char$_$quote_char $quote_char..\\unused graphics\\$quote_char \n"; } print OUTPUT "pause \n"; close OUTPUT; print "\n'Mover.bat' now contains commands for moving these files to 'unused graphics'. \n"; } ####################################################### # Get the directory listing # Fills in the (global) @files_in_directory array sub get_directory_listing { # Check the directory is readable. if (! -e $graphics_path) { die "ERORR: Cannot find graphics directory '$graphics_path'. (Check the spelling is exactly correct.) \n"; } my $file; # Fill in the @files_in_directory array find(\&process_file, $graphics_path); # Strip off the leading "/" foreach $file (@files_in_directory) { $file =~ s/^\///; } } ##### sub process_file { # Do files, not directories if (! -d $File::Find::name ) { ### print "File = '$File::Find::name' \n"; # Get the part of the name that is relative to our base directory. if ($File::Find::name =~ /$graphics_path2(.*)/) { push @files_in_directory, $1; ### print "added '$1' \n"; } else { print "ERROR: Could not parse '$File::Find::name'. \n"; } } } #######################################################