开发者

is there a way to automate changing filenames in <link> , <script> tags

when we use Expires header for text files like js, css, contents are cached in the browser, to get new content we need to change in the html file the new names in the link and script tag. When we add changes. How can we automate it.

In a Windows Box, I may have some bunch of html files in multiple folders also in subdirectories.

There would be a text file

filelist.txt

OldName                 NewName
oldfile1-ver-1.0.js      oldfile1-ver-2.0.js  
oldfile2-ver-1.0.js      oldfile2-ver-2.0.js  
oldfile3-ver-1.0.js      oldfile3-ver-2.0.js  
oldfile4-ver-1.0.js      oldfile4-ver-2.0.js 开发者_如何学运维 

The script should change all the oldfile1-ver-1.0.js into oldfile1-ver-2.0.js in the html, php files

I would run this script before i start uploading.

Finally the script could create a list of files and line number where it made the update.

The solution can be in Perl/PHP/BATCH or anything thats nice and elegant


There are almost certainly more elegant solutions, but this command line hack gets the job done.

$ perl -i~ -pe 's/ver-1.0.js/ver-2.0.js/g' *.html

That will make the change in all of the html files in the current directory. And you'll have a set of back-up files with the extension .html~.


The code below uses Perl's in-place editing feature to modify only those files that need changing and leaves backups of the originals. For example, if it updates foo.php, the original will be in foo.php.bak.

We begin with typical front matter. We'll use the File::Find module to search for HTML and PHP files at any depth, starting by default in the current directory or in all directories named on the command line.

#! /usr/bin/perl

use warnings;
use strict;

use File::Find;

sub usage { "Usage: $0 [ directory .. ]\n" }

In read_filelist, we get the list of transformations use them to generate two bits of code:

  1. a compiled regex that matches any line containing at least one old filename, and
  2. a compiled sub that replaces old names with new.

Note the use of \b which matches only at word boundaries and quotemeta, which escapes any regex metacharacters. These constrain the replacements to only literal occurrences of the old filenames.

It's a bit lengthy, so pardon the scrollbar.

sub read_filelist {
  my $path = "filelist.txt";
  open my $fh, "<", $path
    or die "$0: open $path: $!";

  my $code = q[
    sub {
      while (<>) {
  ];

  my @old;
  my $errors;
  while (<$fh>) {
    next if $. == 1 && /OldName.*NewName/;

    my($old,$new) = split;
    unless (defined($old) && defined($new)) {
      warn "$0: $path:$.: missing filename\n";
      ++$errors;
    }

    my($qmold,$qmnew) = map quotemeta($_) => $old, $new;
    $code .= "        s/\\b$qmold\\b/$qmnew/gi;\n";

    push @old, $old;
  }

  die "$0: will not continue\n" if $errors;

  $code .= q[        print; 
      }
    }];

  local $@;
  print $code, "\n";
  my $sub = eval $code;
  die "$0: should not happen: $@" if $@;

  my $pattern = '\b(' .
                join("|", map quotemeta, @old) .
                ')\b';

  #print $pattern, "\n";
  my $regex = eval { qr/$pattern/oi };
  die "$0: should not happen: $@" if $@;

  ($regex, $sub);
}

Here we remember the root directories to begin searching and read filelist.txt. Perl's in-place editing requires the files to be updated to be in the special @ARGV array.

my @dirs = @ARGV ? @ARGV : ".";
my($has_old,$replace) = read_filelist;

The sub needs_update is the worker that File::Find::find uses to check whether a given file should be modified. We could place all PHP and HTML files in @ARGV, but in cases when the code modifies nothing, you'd still get backup files for everything.

sub needs_update {
  return unless /\.(?:php|html)$/i;

  open my $fh, "<", $_
    or warn("$0: open $_: $!"), return;

  while (<$fh>) {
    if (/$has_old/) {
      push @ARGV, $File::Find::name;
      return;
    }
  }
}, 

For the main event, we clear @ARGV, use needs_update to add the appropriate PHP and HTML files, and unleash the compiled sub on them.

# set up in-place editing
@ARGV = ();
find \&needs_update, @dirs;

die "$0: nothing to do!\n" unless @ARGV;
$^I = ".bak";
$replace->();

__END__

A couple of notes:

  • The code above attempts to make all replacements in the order given in filelist.txt.
  • It makes no attempt to limit scope to <link> and <script> elements. Doing this correctly requires an HTML parser. If names of Javascript sources in filelist.txt should not be replaced sometimes, I can update this answer with the extra machinery, but doing would add even more code.

On Windows, paste the code (minus my running commentary) into a file with an extension of .pl, and then run it as

C:\> fixjs.pl

to patch HTML and PHP files beneath the current directory. To process one or more directories elsewhere, run

C:\> fixjs.pl D:\some\dir E:\another


Why not modify your system so that your files are templates, and then use a library like Template Toolkit to select your files at build time. You can also manage deployment specific information the same way.

It would be a simple thing to have a make target that copies your raw files and applies template processing based on configuration data stored in a file or pulled from the environment.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜