Skip to content

Commit 113260d

Browse files
committed
Initial version of rt-config
1 parent 0a69109 commit 113260d

File tree

3 files changed

+266
-0
lines changed

3 files changed

+266
-0
lines changed

Makefile.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ SYSTEM_BINARIES = rt-attributes-viewer \
166166
rt-test-dependencies \
167167
rt-validator \
168168
rt-validate-aliases \
169+
rt-config \
169170
standalone_httpd
170171

171172

configure.ac

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,7 @@ AC_CONFIG_FILES([
500500
sbin/rt-importer
501501
sbin/rt-passwd
502502
sbin/rt-munge-attachments
503+
sbin/rt-config
503504
bin/rt-crontool
504505
bin/rt-run-scheduled-processes
505506
bin/rt-mailgate

sbin/rt-config.in

Lines changed: 264 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,264 @@
1+
#!@PERL@
2+
# BEGIN BPS TAGGED BLOCK {{{
3+
#
4+
# COPYRIGHT:
5+
#
6+
# This software is Copyright (c) 1996-2026 Best Practical Solutions, LLC
7+
# <sales@bestpractical.com>
8+
#
9+
# (Except where explicitly superseded by other copyright notices)
10+
#
11+
#
12+
# LICENSE:
13+
#
14+
# This work is made available to you under the terms of Version 2 of
15+
# the GNU General Public License. A copy of that license should have
16+
# been provided with this software, but in any event can be snarfed
17+
# from www.gnu.org.
18+
#
19+
# This work is distributed in the hope that it will be useful, but
20+
# WITHOUT ANY WARRANTY; without even the implied warranty of
21+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22+
# General Public License for more details.
23+
#
24+
# You should have received a copy of the GNU General Public License
25+
# along with this program; if not, write to the Free Software
26+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
27+
# 02110-1301 or visit their web page on the internet at
28+
# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
29+
#
30+
#
31+
# CONTRIBUTION SUBMISSION POLICY:
32+
#
33+
# (The following paragraph is not intended to limit the rights granted
34+
# to you to modify and distribute this software under the terms of
35+
# the GNU General Public License and is only of importance to you if
36+
# you choose to contribute your changes and enhancements to the
37+
# community by submitting them to Best Practical Solutions, LLC.)
38+
#
39+
# By intentionally submitting any modifications, corrections or
40+
# derivatives to this work, or any other work intended for use with
41+
# Request Tracker, to Best Practical Solutions, LLC, you confirm that
42+
# you are the copyright holder for those contributions and you grant
43+
# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable,
44+
# royalty-free, perpetual, license to use, copy, create derivative
45+
# works based on those contributions, and sublicense and distribute
46+
# those contributions and any derivatives thereof.
47+
#
48+
# END BPS TAGGED BLOCK }}}
49+
use strict;
50+
use warnings;
51+
52+
# fix lib paths, some may be relative
53+
BEGIN {
54+
require File::Spec;
55+
my @libs = ( "@RT_LIB_PATH@", "@LOCAL_LIB_PATH@" );
56+
my $bin_path;
57+
58+
for my $lib (@libs) {
59+
unless ( File::Spec->file_name_is_absolute($lib) ) {
60+
unless ($bin_path) {
61+
if ( File::Spec->file_name_is_absolute(__FILE__) ) {
62+
$bin_path = ( File::Spec->splitpath(__FILE__) )[1];
63+
}
64+
else {
65+
require FindBin;
66+
no warnings "once";
67+
$bin_path = $FindBin::Bin;
68+
}
69+
}
70+
$lib = File::Spec->catfile( $bin_path, File::Spec->updir, $lib );
71+
}
72+
unshift @INC, $lib;
73+
}
74+
75+
}
76+
77+
use RT::Interface::CLI qw/Init loc/;
78+
use 5.26.3;
79+
use Encode;
80+
81+
82+
my %opt = ();
83+
Init( \%opt, 'value=s', 'format=s' );
84+
85+
my $action = shift @ARGV or RT::Interface::CLI->ShowHelp( Message => loc('Missing action.') );
86+
my $config_name = shift @ARGV or RT::Interface::CLI->ShowHelp( Message => loc('Missing configuration name.') );
87+
88+
binmode STDOUT, ':encoding(UTF-8)';
89+
binmode STDERR, ':encoding(UTF-8)';
90+
91+
if ( $action eq 'show' ) {
92+
my $value = RT->Config->Get($config_name);
93+
if ( ref $value ) {
94+
my $format = lc( $opt{format} || 'perl' );
95+
if ( $format eq 'json' ) {
96+
eval { print json($value) }; # json output has newline already
97+
if ($@) {
98+
say STDERR loc( "[_1] can not be formatted as json, switching to perl", $config_name );
99+
}
100+
else {
101+
exit 0;
102+
}
103+
}
104+
105+
no warnings 'once';
106+
require Data::Dumper;
107+
local $Data::Dumper::Terse = 1;
108+
local $Data::Dumper::Indent = 2;
109+
local $Data::Dumper::Sortkeys = 1;
110+
local $Data::Dumper::Deparse = 1;
111+
print Data::Dumper::Dumper($value); # Dumper output has newline already.
112+
}
113+
elsif ( defined $value ) {
114+
say $value;
115+
}
116+
else {
117+
say loc('Not defined');
118+
}
119+
}
120+
elsif ( $action eq 'edit' ) {
121+
no warnings 'once';
122+
if ( my $meta = $RT::Config::META{$config_name} ) {
123+
if ( $meta->{Immutable} || $meta->{Obfuscate} ) {
124+
say STDERR loc( "[_1] can be modified only in config file.", $config_name );
125+
exit 1;
126+
}
127+
else {
128+
my $value = $opt{value};
129+
if ( defined $value ) {
130+
$value = decode( 'UTF-8', $value );
131+
}
132+
else {
133+
my $old_value = RT->Config->Get($config_name);
134+
chomp( $value = edit( ref $old_value ? json($old_value) : $old_value ) );
135+
}
136+
137+
if ( $meta->{Type} ne 'SCALAR' ) {
138+
require JSON;
139+
$value = JSON::from_json($value);
140+
}
141+
142+
my $old_value = RT->Config->Get($config_name);
143+
if ( ( ref $old_value ? RT::Configuration->_SerializeContent($old_value) : $old_value ) eq
144+
( ref $value ? RT::Configuration->_SerializeContent($value) : $value ) )
145+
{
146+
say loc('Nothing changed.');
147+
exit 0;
148+
}
149+
150+
my $config = RT::Configuration->new( RT->SystemUser );
151+
$config->LoadByCols( Name => $config_name, Disabled => 0 );
152+
my ( $ret, $msg );
153+
if ( $config->Id ) {
154+
( $ret, $msg ) = $config->SetContent($value);
155+
}
156+
else {
157+
( $ret, $msg ) = $config->Create(
158+
Name => $config_name,
159+
Content => $value,
160+
);
161+
}
162+
163+
if ($ret) {
164+
say $msg;
165+
}
166+
else {
167+
say STDERR $msg;
168+
exit 1;
169+
}
170+
}
171+
}
172+
else {
173+
say STDERR loc('No metadata found.');
174+
exit 1;
175+
}
176+
}
177+
elsif ( $action eq 'reset' ) {
178+
my $config = RT::Configuration->new( RT->SystemUser );
179+
$config->LoadByCols( Name => $config_name, Disabled => 0 );
180+
if ( $config->Id ) {
181+
my ( $ret, $msg ) = $config->Delete;
182+
if ($ret) {
183+
say $msg;
184+
}
185+
else {
186+
say STDERR $msg;
187+
exit 1;
188+
}
189+
}
190+
else {
191+
say STDERR loc( '[_1] is not set in database.', $config_name );
192+
exit 1;
193+
}
194+
}
195+
else {
196+
RT::Interface::CLI->ShowHelp( Message => loc( 'Invalid action [_1].', $action ) );
197+
}
198+
199+
sub json {
200+
my $value = shift;
201+
require JSON;
202+
state $JSON = JSON->new->pretty->canonical;
203+
return $JSON->encode($value);
204+
}
205+
206+
sub edit {
207+
my ($text) = @_;
208+
my $editor = $ENV{EDITOR} || $ENV{VISUAL} || "vi";
209+
210+
local $/ = undef;
211+
212+
my $handle = File::Temp->new;
213+
binmode $handle, ":utf8";
214+
print $handle $text;
215+
close($handle);
216+
217+
system( $editor, $handle->filename ) && die "Couldn't run $editor.\n";
218+
219+
open( $handle, '<:utf8', $handle->filename ) or die "$handle: $!\n";
220+
$text = <$handle>;
221+
close($handle);
222+
223+
return $text;
224+
}
225+
226+
__END__
227+
228+
=head1 NAME
229+
230+
rt-config - Manage RT configurations
231+
232+
=head1 SYNOPSIS
233+
234+
rt-config show DefaultQueue
235+
rt-config show PriorityAsString
236+
rt-config show PriorityAsString --format perl
237+
rt-config show PriorityAsString --format json
238+
239+
# Update configs in Database
240+
rt-config edit DefaultQueue # Invoke default editor to set the new value
241+
rt-config edit PriorityAsString --value '{"Default": {"High": 100, "Low": 0, "Medium": 50}}'
242+
243+
# Revert config changes to the file version
244+
rt-config reset DefaultQueue
245+
rt-config reset PriorityAsString
246+
247+
=head1 OPTIONS
248+
249+
=over
250+
251+
=item B<--value>
252+
253+
For C<edit> only, you can specify the new value using this option.
254+
Reference values must be encoded as C<json>.
255+
256+
=item B<--format>
257+
258+
For C<show> only. This is used to format reference values.
259+
Available options are C<perl> and C<json>.
260+
By default, it prefers C<perl> and also falls back to C<perl> when C<json> is not applicable.
261+
262+
=back
263+
264+
=cut

0 commit comments

Comments
 (0)