2013-01-18 4 views
0

У меня есть существующий проект, который требует, чтобы заголовки лицензий использовались в начале каждого исходного файла. Проблема заключается в том, что заголовок лицензии не является статичным:Как продлить синтаксический анализатор заголовков исходного файла perl, чтобы сохранить существующую информацию?

#+====================================================================== 
# \$HeadURL [filled in by svn] \$ 
# \$Id [filled in by svn] \$ 
# 
# Project  : Project blah blah - only one line 
# 
# Description : A longer description 
#     which may or may not span multiple lines 
# 
# Author(s)  : some author text 
#     but there may be a few more authors, too! 
# 
# Copyright (c) : 2010-YYYY Some company, 
#     and a few fixed lines of 
#     address 
# 
# and a few more lines of fixed license code 
# that does not change 
# 
#-====================================================================== 

У меня есть существующий скрипт на Perl, который сканирует список файлов, чтобы определить тип файла (C, Java, Баш и т.д.) и делает элементарную проверку, см., существует ли преамбула лицензии.

Если нет, он может вставить пустой заголовок лицензии, который необходимо обновить вручную.

Но я хотел бы знать, как я могу:

  1. обнаружить существующую лицензию с нестатической информацией и
  2. Расширение существующего Perl ProcessFile ($ FileName, $ типа) функция (ниже) для сохранения существующих данных «Проект», «Описание» и «Автор (ы)»?

Я подозреваю, что мне может потребоваться разместить маркеры в шаблонах лицензий, чтобы указать динамический текст, который следует сохранить в регенерированном заголовке ..?

Не могли бы вы дать мне указания о том, как использовать регулярные выражения или шаблоны соответствия perl для захвата текущей информации о переменных, чтобы я мог снова вставить ее в заголовок и обновить год?

я могу видеть, что все волшебство должно произойти в "для ($ I = 0; $ я < 5; ++ $ я)" петля ...

sub processFile { 
    my $i; 
    my $lineno = 0; 
    my $filename = $_[0]; 
    my $type = $_[1]; 
    my @license = split(/\n/, $licenses{$type}); 
    my @contents; 

    #print "$filename is a $type file\n"; 
    tie @contents, 'Tie::File', $filename or die $!; 

    if ($prolog{$type}) { # should not insert license at line 0 
     my $len = scalar(@contents); 
     while ($lineno < $len) { 
      if ($contents[$lineno] =~ /^$prolog{$type}$/) { 
       last; 
      } else { 
       $lineno++; 
      } 
     } 
     if ($lineno >= $len) { 
      # no prolog, so let's just insert it into the start 
      $lineno = 0; 
     } else { 
      $lineno = $lineno + 1; 
     } 
    } else { 
     $lineno = 0; 
    } 

    # Compare the first 5 lines excluding prolog with the license 
    # header. If they match, the license header won't be inserted. 
    for ($i = 0; $i < 5; ++$i) { 
     my $line = $contents[$i + $lineno]; 
     $line =~ s/\$(\w+)\:.*\$/\$$1\$/; 
     if ($line ne $license[$i]) { 
      splice @contents, $lineno, 0, @license; 
      push @processedFiles, $filename; 
      last 
     } 
    } 

    untie @contents; 
} 
+1

То, что вы показали может быть заголовком для Баша или Perl. Java и C * могут * делиться другим. Я думаю, вам нужно будет использовать подход «обработчик языка», разделенный - * возможно * - на расширение файла. – Axeman

+0

Много предварительная обработка уже состоялась. Эта предварительная обработка определила тип файла (например, bash или Java) и выбрала текст лицензии по умолчанию для вставки. Поэтому к моменту появления «processFile» я уже знаю язык файла и имеет соответствующий заголовок (в массиве @licenses). – KevinM

ответ

1

Для того, чтобы ответить ваш вопрос более подробно, мне нужно было бы увидеть, как выглядят более крупные заголовки. Как я писал в своем комментарии, тот, который вы показываете здесь, может быть использован для bash или Perl - возможно, Python или Ruby (но вы не упомянули об этом).

Как я уже указывал, вы можете использовать подход обработчика. Вы устанавливаете массив обработчиков, и каждый обработчик сообщает основной части процессора, обрабатывает ли он файл с таким именем.

package CommentFileHandler; 

sub _unimpl { 
    local $Carp::CarpLevel = $Carp::CarpLevel + 1; 
    Carp::croak($_[0] . 'needs to implement ' . (caller 1)[3]); 
} 

sub accept_file  { &_unimpl; } 
sub scan_for_header { &_unimpl; } 
sub has_header  { &_unimpl; } 
sub insert_header { &_unimpl; } 

package Perlish::CommentHandler; 
use strict; 
use warnings; 
use parent -norequire 'CommentFileHandler'; 

sub accept_file { 
    my ($self, $file_name, $h) = @_; 
    return 1 if $file_name =~ m/\.(?:cgi|(?:ba|[ck])sh|p[lmy]|rb)$/; 
    # might need to scan for shbang. 
    while (<$h>) { 
     if (m/^#!/) { # we're locked in... 
      return m/\b(python|perl|ruby|(?:ba|k)?sh) /; 
     } 
    } 
    return; 
} 

sub scan_for_header { 
    # might be as simple as this: 
    my ($self, $h) = @_; 
    my $text = <$h> . <$h>; 
    return $text =~ m{ 
     \A  # Start of all text 
     [#]  # literal hash 
     [+]  # literal '+' 
     ={70}  # 70 '=' 
     \s*?  # any number of spaces (wide accepter pattern) -- non-greedy 
     $   # end of one line 
     \s*?  # possible other control character 
     ^  # start of the next 
     [#]  # literal '#' 
     \W+  # At least one "Non-word" word=[_0-9A-Za-z] 
     HeadURL\b # The word 'HeadURL' 
    }msx; # x - means that we can expand it as above. 
} 

sub insert_header { 
    my ($self, $h) = @_; 
    # expect $h to be rewound back to top of file: seek($h, 0, 0) 
    print $h <<'END_COMMENT_HEADER'; 
#+====================================================================== 
# \$HeadURL [filled in by svn] \$ 
# \$Id [filled in by svn] \$ 
# 
# Project  : Project blah blah - only one line 
# 
# Description : A longer description 
#     which may or may not span multiple lines 
# 
# Author(s)  : some author text 
#     but there may be a few more authors, too! 
# 
# Copyright (c) : 2010-YYYY Some company, 
#     and a few fixed lines of 
#     address 
# 
# and a few more lines of fixed license code 
# that does not change 
# 
#-====================================================================== 
END_COMMENT_HEADER 
    } 

Вы бы затем отслеживать каждый файл, который был изменен таким образом, вы бы список вручную редактировать файлы, если изменены.

Вы можете загрузить свои обработчики, например, так:

my @file_handlers = qw<Perlish::CommentHandler CStyle::CommentHandler ...>; 

use List::Util qw<first>; 
File::Find::find(sub { 
     # sorry, I'm an "early return" guy. 
     unless (-r $File::Find::name and -w $File::Find::name) { 
      say "File: $File::Find::name could not be processed."; 
      return; 
     } 

     return unless my $handler 
      = first { $_->accept_file($File::Find::name) } @file_handlers 
      ; 

     # We *have* a handler from here on out. 

     unless (open(my $fh, '<', $File::Find::name)) { 
      Carp::carp("Could not open $File::Find::name!"); 
      return; 
     } 

     # We *have* an open file from here on out... 

     return unless $handler->scan_for_header($File::Find::name, $fh); 

     seek($fh, 0, 0); # back to the start of the file. 
     my $tmp = File::Temp->new(UNLINK => 1, SUFFIX => '.dat'); 
     $handler->insert_header($tmp); 
     print $tmp, $_ while <$fh>; 
     $tmp->seek(0, 0); 
     $fh->close; 

     unless (open($fh, '>', $File::Find::name)) { 
      Carp::carp("Could not open $File::Find::name to write out header!"); 
      return; # You have to check on this 
     } 

     print $fh $_ while <$tmp>; 
     $tmp->close; 
     $fh->close; 
     # printing out is an easy enough way to "record" our changes. 
     say "File $File::Find::name was modified at " . localtime; 

    } => @selected_roots 
    ); 
+0

Спасибо, но мне не ясно, как, как только я знаю тип файла и выбрал текст лицензии по умолчанию, как я сканирую заголовок * * файла * (который имеет переменное содержимое: в некоторых файлах есть один автор, у некоторых есть два и т. д.) и сравнить их с лицензией по умолчанию, чтобы обеспечить существование всех разделов? Я добился определенного прогресса, выполнив поиск заголовков «Проект», «Описание» и т. Д. Теперь я могу определить, существуют ли все разделы *.Возможно, это достаточно хорошо на данный момент - расширение будет состоять в том, чтобы проверить, что отсутствует, и заполнить их по умолчанию, при копировании остальных. – KevinM