diff options
Diffstat (limited to 'rt/devel/tools')
-rw-r--r-- | rt/devel/tools/apache.conf | 173 | ||||
-rw-r--r-- | rt/devel/tools/change-loc-msgstr | 92 | ||||
-rw-r--r-- | rt/devel/tools/extract-message-catalog | 385 | ||||
-rw-r--r-- | rt/devel/tools/factory | 372 | ||||
-rw-r--r-- | rt/devel/tools/license_tag | 262 | ||||
-rw-r--r-- | rt/devel/tools/merge-rosetta.pl | 49 | ||||
-rw-r--r-- | rt/devel/tools/rt-attributes-editor | 130 | ||||
-rw-r--r-- | rt/devel/tools/tweak-template-locstring | 55 |
8 files changed, 1518 insertions, 0 deletions
diff --git a/rt/devel/tools/apache.conf b/rt/devel/tools/apache.conf new file mode 100644 index 000000000..2ae67c651 --- /dev/null +++ b/rt/devel/tools/apache.conf @@ -0,0 +1,173 @@ +# Single-process Apache testing with mod_perl, mod_fcgi, or mod_fastcgi +# +# Start this via: +# apache2 -f `pwd`/devel/tools/apache.conf -DPERL -k start +# +# The full path to the configuration file is needed, or Apache assumes +# it is under the ServerRoot. Since the deployment strategies differ +# between RT 3 and 4, you must either supply -DRT3 if you are attempting +# to deploy an rt3 instance. You must also supply one of -DPERL, +# -DFASTCGI, or -DFCGID. +# +# The /opt/rt4/etc/apache_local.conf file should contain: +# User chmrr +# Group chmrr +# Listen 8080 +# ...or the equivilent. +# +# Apache access and error logs will be written to /opt/rt4/var/log/. +# +<IfDefine !RT3> +Include /opt/rt4/etc/apache_local.conf +</IfDefine> +<IfDefine RT3> +Include /opt/rt3/etc/apache_local.conf +</IfDefine> + +<IfModule mpm_prefork_module> + StartServers 1 + MinSpareServers 1 + MaxSpareServers 1 + MaxClients 1 + MaxRequestsPerChild 0 +</IfModule> + +<IfModule mpm_worker_module> + StartServers 1 + MinSpareThreads 1 + MaxSpareThreads 1 + ThreadLimit 1 + ThreadsPerChild 1 + MaxClients 1 + MaxRequestsPerChild 0 +</IfModule> + +ServerRoot /etc/apache2 +PidFile /opt/rt4/var/apache2.pid +LockFile /opt/rt4/var/apache2.lock +ServerAdmin root@localhost + +LoadModule authz_host_module /usr/lib/apache2/modules/mod_authz_host.so +LoadModule env_module /usr/lib/apache2/modules/mod_env.so +LoadModule alias_module /usr/lib/apache2/modules/mod_alias.so +LoadModule mime_module /usr/lib/apache2/modules/mod_mime.so +<IfDefine PERL> + LoadModule perl_module /usr/lib/apache2/modules/mod_perl.so +</IfDefine> +<IfDefine FASTCGI> + LoadModule fastcgi_module /usr/lib/apache2/modules/mod_fastcgi.so +</IfDefine> +<IfDefine FCGID> + LoadModule fcgid_module /usr/lib/apache2/modules/mod_fcgid.so +</IfDefine> + +ErrorLog "/opt/rt4/var/log/apache-error.log" +TransferLog "/opt/rt4/var/log/apache-access.log" +LogLevel debug + +<Directory /> + Options FollowSymLinks + AllowOverride None + Order deny,allow + Deny from all +</Directory> + +AddDefaultCharset UTF-8 + +DocumentRoot /var/www +<Directory /var/www> + Order allow,deny + Allow from all +</Directory> + +Alias /NoAuth/images/ /opt/rt4/share/html/NoAuth/images/ +<Directory /opt/rt4/share/html/NoAuth/images> + Order allow,deny + Allow from all +</Directory> + +<IfDefine !RT3> +########## 4.0 mod_perl +<IfDefine PERL> + PerlSetEnv RT_SITE_CONFIG /opt/rt4/etc/RT_SiteConfig.pm + <Location /> + Order allow,deny + Allow from all + SetHandler modperl + PerlResponseHandler Plack::Handler::Apache2 + PerlSetVar psgi_app /opt/rt4/sbin/rt-server + </Location> + <Perl> + use Plack::Handler::Apache2; + Plack::Handler::Apache2->preload("/opt/rt4/sbin/rt-server"); + </Perl> +</IfDefine> + +########## 4.0 mod_fastcgi +<IfDefine FASTCGI> + FastCgiIpcDir /opt/rt4/var + FastCgiServer /opt/rt4/sbin/rt-server.fcgi -processes 1 -idle-timeout 300 + ScriptAlias / /opt/rt4/sbin/rt-server.fcgi/ + <Location /> + Order allow,deny + Allow from all + Options +ExecCGI + AddHandler fastcgi-script fcgi + </Location> +</IfDefine> + +########## 4.0 mod_fcgid +<IfDefine FCGID> + FcgidProcessTableFile /opt/rt4/var/fcgid_shm + FcgidIPCDir /opt/rt4/var + ScriptAlias / /opt/rt4/sbin/rt-server.fcgi/ + <Location /> + Order allow,deny + Allow from all + Options +ExecCGI + AddHandler fcgid-script fcgi + </Location> +</IfDefine> +</IfDefine> + + +<IfDefine RT3> +########## 3.8 mod_perl +<IfDefine PERL> + PerlSetEnv RT_SITE_CONFIG /opt/rt3/etc/RT_SiteConfig.pm + PerlRequire "/opt/rt3/bin/webmux.pl" + <Location /NoAuth/images> + SetHandler default + </Location> + <Location /> + SetHandler perl-script + PerlResponseHandler RT::Mason + </Location> +</IfDefine> + +########## 3.8 mod_fastcgi +<IfDefine FASTCGI> + FastCgiIpcDir /opt/rt3/var + FastCgiServer /opt/rt3/bin/mason_handler.fcgi -processes 1 -idle-timeout 300 + ScriptAlias / /opt/rt3/bin/mason_handler.fcgi/ + <Location /> + Order allow,deny + Allow from all + Options +ExecCGI + AddHandler fastcgi-script fcgi + </Location> +</IfDefine> + +########## 3.8 mod_fcgid +<IfDefine FCGID> + FcgidProcessTableFile /opt/rt3/var/fcgid_shm + FcgidIPCDir /opt/rt3/var + ScriptAlias / /opt/rt3/bin/mason_handler.fcgi/ + <Location /> + Order allow,deny + Allow from all + Options +ExecCGI + AddHandler fcgid-script fcgi + </Location> +</IfDefine> +</IfDefine> diff --git a/rt/devel/tools/change-loc-msgstr b/rt/devel/tools/change-loc-msgstr new file mode 100644 index 000000000..75fc72df7 --- /dev/null +++ b/rt/devel/tools/change-loc-msgstr @@ -0,0 +1,92 @@ +#!/usr/bin/env perl +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC +# <sales@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# +# This work is made available to you under the terms of Version 2 of +# the GNU General Public License. A copy of that license should have +# been provided with this software, but in any event can be snarfed +# from www.gnu.org. +# +# This work is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} +use strict; +use warnings; + +use File::Copy; + +die "Usage: $0 'pattern to match msgid' 'code that changes \$_ for the msgstr' [files]" if @ARGV < 2; + +my $msgid_pattern = shift; +my $msgid_regex = qr#$msgid_pattern#o; + +my $code_str = shift; + +@ARGV = ( + <share/po/*.po>, + <share/po/*.pot>, + <po/*.po>, + <po/*.pot> +) unless @ARGV; + +my @files = @ARGV; + +for my $file (@files) { + my ($src, $dest) = ($file, "$file.new"); + open(my $fh_in, '<', $src) or die $!; + open(my $fh_out, '>', $dest) or die $!; + my $mark_to_change = 0; + while (<$fh_in>) { + if (/^msgid\s+"(.+?)"$/ and $1 =~ $msgid_regex) { + # we're at the msgid in question + $mark_to_change = 1; + } + elsif ($mark_to_change) { + # we're at the line after the msgid in question + eval $code_str; + $mark_to_change = 0; + } + print $fh_out $_; + } + close $_ for $fh_in, $fh_out; + + # copy back to source + move($dest => $src); +} + diff --git a/rt/devel/tools/extract-message-catalog b/rt/devel/tools/extract-message-catalog new file mode 100644 index 000000000..1533cfa61 --- /dev/null +++ b/rt/devel/tools/extract-message-catalog @@ -0,0 +1,385 @@ +#!/usr/bin/env perl +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC +# <sales@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# +# This work is made available to you under the terms of Version 2 of +# the GNU General Public License. A copy of that license should have +# been provided with this software, but in any event can be snarfed +# from www.gnu.org. +# +# This work is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} +# Portions Copyright 2002 Autrijus Tang <autrijus@autrijus.org> + +use strict; +use warnings; + +use File::Find; +use File::Copy; +use Regexp::Common; +use Carp; + +# po dir is for extensions +@ARGV = (<share/po/*.po>, <share/po/*.pot>, <po/*.po>, <po/*.pot>) unless @ARGV; + +our %FILECAT; + +# extract all strings and stuff them into %FILECAT +# scan html dir for extensions +File::Find::find( { wanted => \&extract_strings_from_code, follow => 1 }, qw(bin sbin lib share html etc) ); + +# ensure proper escaping and [_1] => %1 transformation +foreach my $str ( sort keys %FILECAT ) { + my $entry = $FILECAT{$str}; + my $oldstr = $str; + + $str =~ s/\\/\\\\/g; + $str =~ s/\"/\\"/g; + $str =~ s/((?<!~)(?:~~)*)\[_(\d+)\]/$1%$2/g; + $str =~ s/((?<!~)(?:~~)*)\[([A-Za-z#*]\w*),([^\]]+)\]/"$1%$2(".escape($3).")"/eg; + $str =~ s/~([\[\]])/$1/g; + + delete $FILECAT{$oldstr}; + $FILECAT{$str} = $entry; +} + +# update all language dictionaries +foreach my $dict (@ARGV) { + $dict = "share/po/$dict.pot" if ( $dict eq 'rt' ); + $dict = "share/po/$dict.po" unless -f $dict or $dict =~ m!/!; + + my $lang = $dict; + $lang =~ s|.*/||; + $lang =~ s|\.po$||; + $lang =~ s|\.pot$||; + + update($lang, $dict); +} + +# warn about various red flags in loc strings +foreach my $str ( sort keys %FILECAT ) { + my $entry = $FILECAT{$str}; + my $entry_count = @$entry; + + # doesn't exist in the current codebase, ignore for now + next if $entry_count == 0; + + my ($filename, $line) = @{ $entry->[0] }; + + my $location = "$filename line $line" . ($entry_count > 1 ? " (and ".($entry_count-1)." other places)" : ""); + + if ($str =~ /^\s/m || $str =~ /\s$/m || $str =~ /\\n$/m) { + warn "Extraneous whitespace in '$str' at $location\n"; + } + + if ($str =~ /([\$\@]\w+)/) { + warn "Interpolated variable '$1' in '$str' at $location\n"; + } +} + + +sub extract_strings_from_code { + my $file = $_; + + local $/; + return if ( -d $_ || !-e _ ); + return + if ( $File::Find::dir =~ + qr!lib/blib|lib/t/autogen|var|m4|local|share/fonts! ); + return if ( /\.(?:pot|po|bak|gif|png|psd|jpe?g|svg|css|js)$/ ); + return if ( /~|,D|,B$|extract-message-catalog$|tweak-template-locstring$/ ); + return if ( /StyleGuide.pod/ ); + return if ( /^[\.#]/ ); + return if ( -f "$_.in" ); + + print "Looking at $File::Find::name\n"; + my $filename = $File::Find::name; + $filename =~ s'^\./''; + $filename =~ s'\.in$''; + + unless (open _, '<', $file) { + print "Cannot open $file for reading ($!), skipping.\n"; + return; + } + + my $re_space_wo_nl = qr{(?!\n)\s}; + my $re_loc_suffix = qr{$re_space_wo_nl* \# $re_space_wo_nl* loc $re_space_wo_nl* $}mx; + my $re_loc_qw_suffix = qr{$re_space_wo_nl* \# $re_space_wo_nl* loc_qw $re_space_wo_nl* $}mx; + my $re_loc_pair_suffix = qr{$re_space_wo_nl* \# $re_space_wo_nl* loc_pair $re_space_wo_nl* $}mx; + my $re_loc_left_pair_suffix = qr{$re_space_wo_nl* \# $re_space_wo_nl* loc_left_pair $re_space_wo_nl* $}mx; + my $re_delim = $RE{delimited}{-delim=>q{'"}}{-keep}; + + $_ = <_>; + + # Mason filter: <&|/l>...</&> + my $line = 1; + while (m!\G(.*?<&\|/l(.*?)&>(.*?)</&>)!sg) { + my ( $all, $vars, $str ) = ( $1, $2, $3 ); + $vars =~ s/[\n\r]//g; + $line += ( $all =~ tr/\n/\n/ ); + $str =~ s/\\'/\'/g; + #print "STR IS $str\n"; + push @{ $FILECAT{$str} }, [ $filename, $line, $vars ]; + } + + # Localization function: loc(...) + $line = 1; + pos($_) = 0; + while (m/\G(.*?\bloc$RE{balanced}{-parens=>'()'}{-keep})/sg) { + my ( $all, $match ) = ( $1, $2 ); + $line += ( $all =~ tr/\n/\n/ ); + + my ( $vars, $str ); + if ( $match =~ + /\(\s*($re_delim)(.*?)\s*\)$/so ) { + + $str = substr( $1, 1, -1 ); # $str comes before $vars now + $vars = $9; + } + else { + next; + } + + $vars =~ s/[\n\r]//g; + $str =~ s/\\'/\'/g; + + push @{ $FILECAT{$str} }, [ $filename, $line, $vars ]; + } + + # Comment-based mark: "..." # loc + $line = 1; + pos($_) = 0; + while (m/\G(.*?($re_delim)[\}\)\],;]*$re_loc_suffix)/smgo) { + my ( $all, $str ) = ( $1, $2 ); + $line += ( $all =~ tr/\n/\n/ ); + unless ( defined $str ) { + warn "Couldn't process loc at $filename:$line"; + next; + } + $str = substr($str, 1, -1); + $str =~ s/\\'/\'/g; + push @{ $FILECAT{$str} }, [ $filename, $line, '' ]; + } + + # Comment-based qw mark: "qw(...)" # loc_qw + $line = 1; + pos($_) = 0; + while (m/\G(.*?(?:qw\(([^)]+)\)[\}\)\],;]*)?$re_loc_qw_suffix)/smgo) { + my ( $all, $str ) = ( $1, $2 ); + $line += ( $all =~ tr/\n/\n/ ); + unless ( defined $str ) { + warn "Couldn't process loc_qw at $filename:$line"; + next; + } + foreach my $value (split ' ', $str) { + push @{ $FILECAT{$value} }, [ $filename, $line, '' ]; + } + } + + # Comment-based left pair mark: "..." => ... # loc_left_pair + $line = 1; + pos($_) = 0; + while (m/\G(.*?(?:(\w+|$re_delim)\s*=>[^#\n]+?)?$re_loc_left_pair_suffix)/smgo) { + my ( $all, $key ) = ( $1, $2 ); + $line += ( $all =~ tr/\n/\n/ ); + unless ( defined $key ) { + warn "Couldn't process loc_left_pair at $filename:$line"; + next; + } + $key =~ s/\\'/\'/g; + push @{ $FILECAT{$key} }, [ $filename, $line, '' ]; + } + + # Comment-based pair mark: "..." => "..." # loc_pair + $line = 1; + pos($_) = 0; + while (m/\G(.*?(?:(\w+)\s*=>\s*($re_delim)[\}\)\],;]*)?$re_loc_pair_suffix)/smgo) { + my ( $all, $key, $val ) = ( $1, $2, $3 ); + $line += ( $all =~ tr/\n/\n/ ); + unless ( defined $key && defined $val ) { + warn "Couldn't process loc_pair at $filename:$line"; + next; + } + $val = substr($val, 1, -1); + $key =~ s/\\'/\'/g; + $val =~ s/\\'/\'/g; + push @{ $FILECAT{$key} }, [ $filename, $line, '' ]; + push @{ $FILECAT{$val} }, [ $filename, $line, '' ]; + } + + close (_); +} + +sub update { + my $lang = shift; + my $file = shift; + my ( %Lexicon, %Header); + my $out = ''; + + unless (!-e $file or -w $file) { + warn "Can't write to $lang, skipping...\n"; + return; + } + + print "Updating $lang...\n"; + + my @lines; + @lines = (<LEXICON>) if open LEXICON, '<', $file; + @lines = grep { !/^(#(:|\.)\s*|$)/ } @lines; + while (@lines) { + my $msghdr = ""; + $msghdr .= shift @lines while ( $lines[0] && $lines[0] !~ /^(#~ )?msgid/ ); + + my $msgid = ""; + +# '#~ ' is the prefix of launchpad for msg that's not found the the source +# we'll remove the prefix later so we can still show them with our own mark + + $msgid .= shift @lines while ( $lines[0] && $lines[0] =~ /^(#~ )?(msgid|")/ ); + my $msgstr = ""; + $msgstr .= shift @lines while ( $lines[0] && $lines[0] =~ /^(#~ )?(msgstr|")/ ); + + last unless $msgid; + + chomp $msgid; + chomp $msgstr; + + $msgid =~ s/^#~ //mg; + $msgstr =~ s/^#~ //mg; + + $msgid =~ s/^msgid "(.*)"\s*?$/$1/m or warn "$msgid in $file"; + + if ( $msgid eq '' ) { + # null msgid, msgstr will have head info + $msgstr =~ s/^msgstr "(.*)"\s*?$/$1/ms or warn "$msgstr in $file"; + } + else { + $msgstr =~ s/^msgstr "(.*)"\s*?$/$1/m or warn "$msgstr in $file"; + } + + if ( $msgid ne '' ) { + for my $msg ( \$msgid, \$msgstr ) { + if ( $$msg =~ /\n/ ) { + my @lines = split /\n/, $$msg; + $$msg = + shift @lines; # first line don't need to handle any more + for (@lines) { + if (/^"(.*)"\s*$/) { + $$msg .= $1; + } + } + } + + # convert \\n back to \n + $$msg =~ s/(?!\\)\\n/\n/g; + } + } + + $Lexicon{$msgid} = $msgstr; + $Header{$msgid} = $msghdr; + } + + my $is_english = ( $lang =~ /^en(?:[^A-Za-z]|$)/ ); + + foreach my $str ( keys %FILECAT ) { + $Lexicon{$str} ||= ''; + } + foreach ( sort keys %Lexicon ) { + my $f = join ( ' ', sort map $_->[0].":".$_->[1], @{ $FILECAT{$_} } ); + my $nospace = $_; + $nospace =~ s/ +$//; + + if ( !$Lexicon{$_} and $Lexicon{$nospace} ) { + $Lexicon{$_} = + $Lexicon{$nospace} . ( ' ' x ( length($_) - length($nospace) ) ); + } + + next if !length( $Lexicon{$_} ) and $is_english; + + my %seen; + $out .= $Header{$_} if exists $Header{$_}; + + + + next if (!$f && $_ && !$Lexicon{$_}); + if ( $f && $f !~ /^\s+$/ ) { + + $out .= "#: $f\n"; + } + elsif ($_) { + $out .= "#: NOT FOUND IN SOURCE\n"; + } + foreach my $entry ( sort { $a->[2] cmp $b->[2] } grep { $_->[2] } @{ $FILECAT{$_} } ) { + my ( $file, $line, $var ) = @{$entry}; + $var =~ s/^\s*,\s*//; + $var =~ s/\s*$//; + $out .= "#. ($var)\n" unless $seen{$var}++; + } + $out .= 'msgid ' . fmt($_) . "msgstr \"$Lexicon{$_}\"\n\n"; + } + + open PO, '>', $file or die "Couldn't open '$file' for writing: $!"; + print PO $out; + close PO; + + return 1; +} + +sub escape { + my $text = shift; + $text =~ s/\b_(\d+)/%$1/; + return $text; +} + +sub fmt { + my $str = shift; + return "\"$str\"\n" unless $str =~ /\n/; + + my $multi_line = ($str =~ /\n(?!\z)/); + $str =~ s/\n/\\n"\n"/g; + + if ($str =~ /\n"$/) { + chop $str; + } + else { + $str .= "\"\n"; + } + return $multi_line ? qq(""\n"$str) : qq("$str); +} diff --git a/rt/devel/tools/factory b/rt/devel/tools/factory new file mode 100644 index 000000000..099d2db8c --- /dev/null +++ b/rt/devel/tools/factory @@ -0,0 +1,372 @@ +#!/usr/bin/env perl +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC +# <sales@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# +# This work is made available to you under the terms of Version 2 of +# the GNU General Public License. A copy of that license should have +# been provided with this software, but in any event can be snarfed +# from www.gnu.org. +# +# This work is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} +use strict; +use DBI; + +die "Usage: $0 database namespace" if @ARGV != 2; + +my $database = shift; +my $namespace = shift; + +my $CollectionBaseclass = 'RT::SearchBuilder'; +my $RecordBaseclass = 'RT::Record'; + +my $driver = 'mysql'; +my $hostname = 'localhost'; +my $user = 'root'; +my $password = ''; + + +my $LicenseBlock = ''; +my $Attribution = ''; + +my $dsn = "DBI:$driver:database=$database;host=$hostname"; + +my $dbh = DBI->connect( $dsn, $user, $password ); + +#get all tables out of database +my @tables = map { s/^\`\Q$database\E\`\.//; $_ } $dbh->tables(); + +my ( %tablemap, $typemap, %modulemap ); + +foreach my $table (@tables) { + $table =~ s/\`//g; + next if ($table eq 'sessions'); + $table = ucfirst($table); + $table =~ s/field/Field/; + $table =~ s/group/Group/; + $table =~ s/custom/Custom/; + $table =~ s/member/Member/; + $table =~ s/Scripaction/ScripAction/g; + $table =~ s/condition/Condition/g; + $table =~ s/value/Value/; + $table =~ s/Acl/ACL/g; + $tablemap{$table} = $table; + $modulemap{$table} = $table; + if ( $table =~ /^(.*)s$/ ) { + $tablemap{$1} = $table; + $modulemap{$1} = $1; + } +} +$tablemap{'CreatedBy'} = 'User'; +$tablemap{'UpdatedBy'} = 'User'; + +my %typemap; +$typemap{'id'} = 'ro'; +$typemap{'Creator'} = 'auto'; +$typemap{'Created'} = 'auto'; +$typemap{'Updated'} = 'auto'; +$typemap{'UpdatedBy'} = 'auto'; +$typemap{'LastUpdated'} = 'auto'; +$typemap{'LastUpdatedBy'} = 'auto'; + +foreach my $table (@tables) { + next if ($table eq 'sessions'); + my $tablesingle = $table; + $tablesingle =~ s/s$//; + my $tableplural = $tablesingle . "s"; + + if ( $tablesingle eq 'ACL' ) { + $tablesingle = "ACE"; + $tableplural = "ACL"; + } + + my %requirements; + + my $CollectionClassName = $namespace . "::" . $tableplural; + my $RecordClassName = $namespace . "::" . $tablesingle; + + my $path = $namespace; + $path =~ s/::/\//g; + + my $RecordClassPath = $path . "/" . $tablesingle . ".pm"; + my $CollectionClassPath = $path . "/" . $tableplural . ".pm"; + + #create a collection class + my $CreateInParams; + my $CreateOutParams; + my $ClassAccessible = ""; + my $FieldsPod = ""; + my $CreatePod = ""; + my $RecordInit = ""; + my %fields; + + + my $introspection = $dbh->prepare("SELECT * from $table where id is null"); + $introspection->execute(); + my @names =@{ $introspection->{'NAME'}}; + my @types = @{$introspection->{'TYPE'}}; + my @is_blob = @{$introspection->{'mysql_is_blob'}}; + my @is_num = @{$introspection->{'mysql_is_num'}}; + + my %blobness = (); + my %sqltypes = (); + my %numeric = (); + foreach my $name (@names) { + $sqltypes{$name} = shift @types; + $blobness{$name} = (shift @is_blob || "0"); + $numeric{$name} = (shift @is_num || "0"); + } + + + my $sth = $dbh->prepare("DESCRIBE $table"); + $sth->execute; + + while ( my $row = $sth->fetchrow_hashref() ) { + my $field = $row->{'Field'}; + my $type = $row->{'Type'}; + my $default = $row->{'Default'}; + my $length = 0; + if ($type =~ /^(?:.*?)\((\d+)\)$/) { + $length = $1; + } + $fields{$field} = 1; + + #generate the 'accessible' datastructure + + no warnings 'uninitialized'; + + if ( $typemap{$field} eq 'auto' ) { + $ClassAccessible .= " $field => + {read => 1, auto => 1,"; + } + elsif ( $typemap{$field} eq 'ro' ) { + $ClassAccessible .= " $field => + {read => 1,"; + } + else { + $ClassAccessible .= " $field => + {read => 1, write => 1,"; + + } + $ClassAccessible .= " sql_type => $sqltypes{$field}, length => $length, is_blob => $blobness{$field}, is_numeric => $numeric{$field}, "; + $ClassAccessible .= " type => '$type', default => '$default'},\n"; + + #generate pod for the accessible fields + $FieldsPod .= " +=head2 $field + +Returns the current value of $field. +(In the database, $field is stored as $type.) + +"; + + unless ( exists $typemap{$field} && ( $typemap{$field} eq 'auto' || $typemap{$field} eq 'ro' )) { + $FieldsPod .= " + +=head2 Set$field VALUE + + +Set $field to VALUE. +Returns (1, 'Status message') on success and (0, 'Error Message') on failure. +(In the database, $field will be stored as a $type.) + +"; + } + + $FieldsPod .= " +=cut + +"; + + if ( $modulemap{$field} ) { + $FieldsPod .= " +=head2 ${field}Obj + +Returns the $modulemap{$field} Object which has the id returned by $field + + +=cut + +sub ${field}Obj { + my \$self = shift; + my \$$field = ${namespace}::$modulemap{$field}->new(\$self->CurrentUser); + \$$field->Load(\$self->__Value('$field')); + return(\$$field); +} +"; + $requirements{ $tablemap{$field} } = + "use ${namespace}::$modulemap{$field};"; + + } + + unless ( $typemap{$field} eq 'auto' || $field eq 'id' ) { + + #generate create statement + $CreateInParams .= " $field => '$default',\n"; + $CreateOutParams .= + " $field => \$args{'$field'},\n"; + + #gerenate pod for the create statement + $CreatePod .= " $type '$field'"; + $CreatePod .= " defaults to '$default'" if ($default); + $CreatePod .= ".\n"; + + } + + } + + my $Create = ""; + $CreatePod .= "\n=cut\n\n"; + + my $CollectionClass = $LicenseBlock . $Attribution . + + " +use $RecordClassName; + +use base '$CollectionBaseclass'; + +sub Table { '$table'} + +sub _Init { +"; + + if ( $fields{'SortOrder'} && $fields{'Name'} ) { + $CollectionClass .= " + + # By default, order by SortOrder + \$self->OrderByCols( + { ALIAS => 'main', + FIELD => 'SortOrder', + ORDER => 'ASC' }, + { ALIAS => 'main', + FIELD => 'Name', + ORDER => 'ASC' }, + { ALIAS => 'main', + FIELD => 'id', + ORDER => 'ASC' }, + ); +"; + } + elsif ( $fields{'SortOrder'} ) { + + $CollectionClass .= " + + # By default, order by SortOrder + \$self->OrderByCols( + { ALIAS => 'main', + FIELD => 'SortOrder', + ORDER => 'ASC' }, + { ALIAS => 'main', + FIELD => 'id', + ORDER => 'ASC' }, + ); +"; + } + $CollectionClass .= " + return ( \$self->SUPER::_Init(\@_) ); +} + + +=head2 NewItem + +Returns an empty new $RecordClassName item + +=cut + +sub NewItem { + my \$self = shift; + return($RecordClassName->new(\$self->CurrentUser)); +} +" . MagicImport($CollectionClassName); + + my $RecordClassHeader = $Attribution . " +"; + + foreach my $key ( keys %requirements ) { + $RecordClassHeader .= $requirements{$key} . "\n"; + } + $RecordClassHeader .= "use base '$RecordBaseclass'; + +sub Table {'$table'} + +"; + + my $RecordClass = $LicenseBlock . $RecordClassHeader . " + +$RecordInit + +$FieldsPod + +sub _CoreAccessible { + { + +$ClassAccessible + } +}; + +" . MagicImport($RecordClassName); + + print "About to make $RecordClassPath, $CollectionClassPath\n"; + `mkdir -p $path`; + + open( RECORD, '>>', $RecordClassPath ) or die $!; + print RECORD $RecordClass; + close(RECORD); + + open( COL, '>>', $CollectionClassPath ) or die $!; + print COL $CollectionClass; + close(COL); + +} + +sub MagicImport { + my $class = shift; + + #if (exists \$warnings::{unimport}) { + # no warnings qw(redefine); + + my $content = "RT::Base->_ImportOverlays(); + +1; +"; + return $content; +} + + diff --git a/rt/devel/tools/license_tag b/rt/devel/tools/license_tag new file mode 100644 index 000000000..de3bd3bc3 --- /dev/null +++ b/rt/devel/tools/license_tag @@ -0,0 +1,262 @@ +#!/usr/bin/env perl + + +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC +# <sales@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# +# This work is made available to you under the terms of Version 2 of +# the GNU General Public License. A copy of that license should have +# been provided with this software, but in any event can be snarfed +# from www.gnu.org. +# +# This work is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} +my $LICENSE = <<'EOL'; + +COPYRIGHT: + +This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC + <sales@bestpractical.com> + +(Except where explicitly superseded by other copyright notices) + + +LICENSE: + +This work is made available to you under the terms of Version 2 of +the GNU General Public License. A copy of that license should have +been provided with this software, but in any event can be snarfed +from www.gnu.org. + +This work is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 or visit their web page on the internet at +http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. + + +CONTRIBUTION SUBMISSION POLICY: + +(The following paragraph is not intended to limit the rights granted +to you to modify and distribute this software under the terms of +the GNU General Public License and is only of importance to you if +you choose to contribute your changes and enhancements to the +community by submitting them to Best Practical Solutions, LLC.) + +By intentionally submitting any modifications, corrections or +derivatives to this work, or any other work intended for use with +Request Tracker, to Best Practical Solutions, LLC, you confirm that +you are the copyright holder for those contributions and you grant +Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +royalty-free, perpetual, license to use, copy, create derivative +works based on those contributions, and sublicense and distribute +those contributions and any derivatives thereof. + +EOL + +use File::Find; + +my @MAKE = qw(Makefile); + +File::Find::find({ no_chdir => 1, wanted => \&tag_pm}, 'lib'); +File::Find::find({ no_chdir => 1, wanted => \&tag_mason}, 'share/html'); +File::Find::find({ no_chdir => 1, wanted => \&tag_script}, 'sbin'); +File::Find::find({ no_chdir => 1, wanted => \&tag_script}, 'bin'); +File::Find::find({ no_chdir => 1, wanted => \&tag_script}, 'etc/upgrade'); +File::Find::find({ no_chdir => 1, wanted => \&tag_script}, 'devel/tools'); +tag_makefile ('Makefile.in'); +tag_makefile ('README'); + + +sub tag_mason { + my $pm = $_; + return unless (-f $pm); + return if $pm =~ /images/ || $pm =~ /\.(?:png|jpe?g|gif)$/; + open( FILE, '<', $pm ) or die "Failed to open $pm"; + my $file = (join "", <FILE>); + close (FILE); + print "$pm - "; + return if another_license($pm => $file) && print "has different license\n"; + + my $pmlic = $LICENSE; + $pmlic =~ s/^/%# /mg; + $pmlic =~ s/\s*$//mg; + if ($file =~ /^%# BEGIN BPS TAGGED BLOCK {{{/ms) { + print "has license section"; + $file =~ s/^%# BEGIN BPS TAGGED BLOCK {{{(.*?)%# END BPS TAGGED BLOCK }}}/%# BEGIN BPS TAGGED BLOCK {{{\n$pmlic\n%# END BPS TAGGED BLOCK }}}/ms; + + + } else { + print "no license section"; + $file ="%# BEGIN BPS TAGGED BLOCK {{{\n$pmlic\n%# END BPS TAGGED BLOCK }}}\n". $file; + } + $file =~ s/%# END BPS TAGGED BLOCK }}}(\n+)/%# END BPS TAGGED BLOCK }}}\n/mg; + print "\n"; + + + + + open( FILE, '>', $pm ) or die "couldn't write new file"; + print FILE $file; + close FILE; + +} + + +sub tag_makefile { + my $pm = shift; + open( FILE, '<', $pm ) or die "Failed to open $pm"; + my $file = (join "", <FILE>); + close (FILE); + print "$pm - "; + return if another_license($pm => $file) && print "has different license\n"; + + my $pmlic = $LICENSE; + $pmlic =~ s/^/# /mg; + $pmlic =~ s/\s*$//mg; + if ($file =~ /^# BEGIN BPS TAGGED BLOCK {{{/ms) { + print "has license section"; + $file =~ s/^# BEGIN BPS TAGGED BLOCK {{{(.*?)# END BPS TAGGED BLOCK }}}/# BEGIN BPS TAGGED BLOCK {{{\n$pmlic\n# END BPS TAGGED BLOCK }}}/ms; + + + } else { + print "no license section"; + $file ="# BEGIN BPS TAGGED BLOCK {{{\n$pmlic\n# END BPS TAGGED BLOCK }}}\n". $file; + } + $file =~ s/# END BPS TAGGED BLOCK }}}(\n+)/# END BPS TAGGED BLOCK }}}\n/mg; + print "\n"; + + + + + open( FILE, '>', $pm ) or die "couldn't write new file"; + print FILE $file; + close FILE; + +} + + +sub tag_pm { + my $pm = $_; + next unless $pm =~ /\.pm/s; + open( FILE, '<', $pm ) or die "Failed to open $pm"; + my $file = (join "", <FILE>); + close (FILE); + print "$pm - "; + return if another_license($pm => $file) && print "has different license\n"; + + my $pmlic = $LICENSE; + $pmlic =~ s/^/# /mg; + $pmlic =~ s/\s*$//mg; + if ($file =~ /^# BEGIN BPS TAGGED BLOCK {{{/ms) { + print "has license section"; + $file =~ s/^# BEGIN BPS TAGGED BLOCK {{{(.*?)# END BPS TAGGED BLOCK }}}/# BEGIN BPS TAGGED BLOCK {{{\n$pmlic\n# END BPS TAGGED BLOCK }}}/ms; + + + } else { + print "no license section"; + $file ="# BEGIN BPS TAGGED BLOCK {{{\n$pmlic\n# END BPS TAGGED BLOCK }}}\n". $file; + } + $file =~ s/# END BPS TAGGED BLOCK }}}(\n+)/# END BPS TAGGED BLOCK }}}\n\n/mg; + print "\n"; + + + + + open( FILE, '>', $pm ) or die "couldn't write new file $pm"; + print FILE $file; + close FILE; + +} + + +sub tag_script { + my $pm = $_; + return unless (-f $pm); + open( FILE, '<', $pm ) or die "Failed to open $pm"; + my $file = (join "", <FILE>); + close (FILE); + print "$pm - "; + return if another_license($pm => $file) && print "has different license\n"; + + my $pmlic = $LICENSE; + $pmlic =~ s/^/# /msg; + $pmlic =~ s/\s*$//mg; + if ($file =~ /^# BEGIN BPS TAGGED BLOCK {{{/ms) { + print "has license section"; + $file =~ s/^# BEGIN BPS TAGGED BLOCK {{{(.*?)# END BPS TAGGED BLOCK }}}/# BEGIN BPS TAGGED BLOCK {{{\n$pmlic\n# END BPS TAGGED BLOCK }}}/ms; + + + } else { + print "no license section"; + if ($file =~ /^(#!.*?)\n/) { + + my $lic ="# BEGIN BPS TAGGED BLOCK {{{\n$pmlic\n# END BPS TAGGED BLOCK }}}\n"; + $file =~ s/^(#!.*?)\n/$1\n$lic/; + + } + } + $file =~ s/# END BPS TAGGED BLOCK }}}(\n+)/# END BPS TAGGED BLOCK }}}\n/mg; + print "\n"; + + + open( FILE, '>', $pm ) or die "couldn't write new file"; + print FILE $file; + close FILE; + +} + +sub another_license { + my $name = shift; + my $file = shift; + + return 1 if ($name =~ /(?:FCKEditor|scriptaculous|superfish|tablesorter|farbtastic)/i); + + return 0 if $file =~ /Copyright\s+\(c\)\s+\d\d\d\d-\d\d\d\d Best Practical Solutions/i; + return 1 if $file =~ /\b(copyright|GPL|Public Domain)\b/i; # common + return 1 if $file =~ /\(c\)\s+\d\d\d\d(?:-\d\d\d\d)?/i; # prototype + return 0; +} + diff --git a/rt/devel/tools/merge-rosetta.pl b/rt/devel/tools/merge-rosetta.pl new file mode 100644 index 000000000..e3b45a1ac --- /dev/null +++ b/rt/devel/tools/merge-rosetta.pl @@ -0,0 +1,49 @@ +#!/usr/bin/env perl +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC +# <sales@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# +# This work is made available to you under the terms of Version 2 of +# the GNU General Public License. A copy of that license should have +# been provided with this software, but in any event can be snarfed +# from www.gnu.org. +# +# This work is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} +exec('sbin/rt-message-catalog', 'rosetta', @ARGV); diff --git a/rt/devel/tools/rt-attributes-editor b/rt/devel/tools/rt-attributes-editor new file mode 100644 index 000000000..92caeaf12 --- /dev/null +++ b/rt/devel/tools/rt-attributes-editor @@ -0,0 +1,130 @@ +#!/usr/bin/env perl +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC +# <sales@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# +# This work is made available to you under the terms of Version 2 of +# the GNU General Public License. A copy of that license should have +# been provided with this software, but in any event can be snarfed +# from www.gnu.org. +# +# This work is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} +use strict; +use warnings; +use Term::EditorEdit; +use Getopt::Long; +my ($help, $key, $id); +GetOptions('help|h' => \$help, 'key|k=s' => \$key, 'id=i' => \$id); + +if ( $help || !$id ) { + require Pod::Usage; + Pod::Usage::pod2usage({ verbose => 2 }); + exit; +} + +require RT; +RT::LoadConfig(); +RT::Init(); + +require RT::Attribute; +my $attr = RT::Attribute->new( RT->SystemUser ); +$attr->Load( $id ); +unless ( $attr->id ) { + print STDERR "Couldn't load attribute #$id\n"; + exit 1; +} + +my $orig; +if ($key) { + if (ref($attr->Content) ne 'HASH') { + print STDERR "The attribute's content must be a hashref for editing keys\n"; + exit 1; + } + $orig = $attr->Content->{$key} || ''; +} +else { + use Data::Dumper; + $orig = Dumper( $attr->Content ); +} + +my $edit = Term::EditorEdit->edit(document => $orig); + +if ($edit ne $orig) { + if ($key) { + my $content = $attr->Content; + $content->{$key} = $edit; + $attr->SetContent($content); + print "Attribute key saved.\n"; + } + else { + my $VAR1; eval $edit; + if ($@) { + print STDERR "Your change had an error: $@"; + exit 1; + } + $attr->SetContent($VAR1); + print "Attribute saved.\n"; + } +} +else { + print "Aborted.\n" +} + +__END__ + +=head1 NAME + +rt-attributes-editor - edit the content of an attribute + +=head1 SYNOPSIS + + # edit the Perl dump of attribute 2's content + rt-attributes-editor --id 2 + + # edit the dump of attribute 2's content (hash key: Query) + # note: this will error if the attribute content is not a hashref + rt-attributes-editor --id 2 --key Query + +=head1 DESCRIPTION + +This script deserializes and puts the content of an attribute defined +by <attribute id> into the preferred editor set in C<$EDITOR>. May be +useful for developers to editing attributes by hand if there is any +trouble editing it from the UI. diff --git a/rt/devel/tools/tweak-template-locstring b/rt/devel/tools/tweak-template-locstring new file mode 100644 index 000000000..7f8a8808f --- /dev/null +++ b/rt/devel/tools/tweak-template-locstring @@ -0,0 +1,55 @@ +#!/usr/bin/env perl +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC +# <sales@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# +# This work is made available to you under the terms of Version 2 of +# the GNU General Public License. A copy of that license should have +# been provided with this software, but in any event can be snarfed +# from www.gnu.org. +# +# This work is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} +use strict; +# run this script with: +# perl -0pi sbin/tweak-template-locstring `ack -f share/html -G 'html$'` +s!\<\&\|\/l([^&]*)\&\>[\n\s]+(.*?)[\n\s]*\<\/\&\>!;my ($arg, $x) = ($1, $2); $x =~ s/\s*\n\s*/ /g;"<&|/l$arg&>$x</&>"!smge; + + +1; |