0

すべてのソースファイルの先頭でライセンスヘッダーを使用する必要がある既存のプロジェクトがあります。問題は、ライセンスヘッダーが静的ではないことです。

#+======================================================================
# \$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
#
#-======================================================================

ファイルのリストをスキャンしてファイルタイプ(C、Java、bashなど)を判別し、ライセンスのプリアンブルが存在するかどうかを確認するための基本的なチェックを行う既存のperlスクリプトがあります。

そうでない場合は、手動で更新する必要がある空白のライセンスヘッダーを挿入できます。

しかし、私はどのように私ができるか知りたいです:

  1. 非静的情報を使用して既存のライセンスを検出し、
  2. 既存のperlprocessFile($ fileName、$ type)関数(下記)を拡張して、既存の「プロジェクト」、「説明」、および「作成者」情報を保持しますか?

動的テキストを示すためにライセンステンプレートにマーカーを配置する必要があるのではないかと思います。動的テキストは、再生成されたヘッダーに保存する必要があります。

perl正規表現またはパターンマッチャーを使用して現在の変数情報を取得し、ヘッダーに再挿入して年を更新する方法についての指針を教えてください。

すべての魔法は「for($ i = 0; $ i <5; ++ $ i)」ループで発生する必要があることがわかります。

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;
}
4

1 に答える 1

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 
    ); 
于 2013-01-18T13:38:23.563 に答える