Putting 4.2.0 on top of 4.0.17
[usit-rt.git] / lib / RT / Migrate.pm
1 # BEGIN BPS TAGGED BLOCK {{{
2 #
3 # COPYRIGHT:
4 #
5 # This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
6 #                                          <sales@bestpractical.com>
7 #
8 # (Except where explicitly superseded by other copyright notices)
9 #
10 #
11 # LICENSE:
12 #
13 # This work is made available to you under the terms of Version 2 of
14 # the GNU General Public License. A copy of that license should have
15 # been provided with this software, but in any event can be snarfed
16 # from www.gnu.org.
17 #
18 # This work is distributed in the hope that it will be useful, but
19 # WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21 # General Public License for more details.
22 #
23 # You should have received a copy of the GNU General Public License
24 # along with this program; if not, write to the Free Software
25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26 # 02110-1301 or visit their web page on the internet at
27 # http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
28 #
29 #
30 # CONTRIBUTION SUBMISSION POLICY:
31 #
32 # (The following paragraph is not intended to limit the rights granted
33 # to you to modify and distribute this software under the terms of
34 # the GNU General Public License and is only of importance to you if
35 # you choose to contribute your changes and enhancements to the
36 # community by submitting them to Best Practical Solutions, LLC.)
37 #
38 # By intentionally submitting any modifications, corrections or
39 # derivatives to this work, or any other work intended for use with
40 # Request Tracker, to Best Practical Solutions, LLC, you confirm that
41 # you are the copyright holder for those contributions and you grant
42 # Best Practical Solutions,  LLC a nonexclusive, worldwide, irrevocable,
43 # royalty-free, perpetual, license to use, copy, create derivative
44 # works based on those contributions, and sublicense and distribute
45 # those contributions and any derivatives thereof.
46 #
47 # END BPS TAGGED BLOCK }}}
48
49 package RT::Migrate;
50
51 use strict;
52 use warnings;
53
54 use Time::HiRes qw//;
55
56 sub format_time {
57     my $time = shift;
58     my $s = "";
59
60     $s .= int($time/60/60)."hr "
61         if $time > 60*60;
62     $s .= int(($time % (60*60))/60)."min "
63         if $time > 60;
64     $s .= int($time % 60)."s"
65         if $time < 60*60;
66
67     return $s;
68 }
69
70 sub progress_bar {
71     my %args = (
72         label => "",
73         now   => 0,
74         max   => 1,
75         cols  => 80,
76         char  => "=",
77         @_,
78     );
79     $args{now} ||= 0;
80
81     my $fraction = $args{max} ? $args{now} / $args{max} : 0;
82
83     my $max_width = $args{cols} - 30;
84     my $bar_width = int($max_width * $fraction);
85
86     return sprintf "%20s |%-" . $max_width . "s| %3d%%\n",
87         $args{label}, $args{char} x $bar_width, $fraction*100;
88 }
89
90 sub progress {
91     my %args = (
92         top    => sub { print "\n\n" },
93         bottom => sub {},
94         every  => 3,
95         bars   => [qw/Ticket Transaction Attachment User Group/],
96         counts => sub {},
97         max    => {},
98         @_,
99     );
100
101     my $max_objects = 0;
102     $max_objects += $_ for values %{ $args{max} };
103
104     my $last_time;
105     my $start;
106     my $left;
107     my $offset;
108     return sub {
109         my $obj = shift;
110         my $force = shift;
111         my $now = Time::HiRes::time();
112         return if defined $last_time and $now - $last_time <= $args{every} and not $force;
113
114         $start = $now unless $start;
115         $last_time = $now;
116
117         my $elapsed = $now - $start;
118
119         # Determine terminal size
120         print `clear`;
121         my ($cols, $rows) = (80, 25);
122         eval {
123             require Term::ReadKey;
124             ($cols, $rows) = Term::ReadKey::GetTerminalSize();
125         };
126         $cols -= 1;
127
128         $args{top}->($elapsed, $rows, $cols);
129
130         my %counts = $args{counts}->();
131         for my $class (map {"RT::$_"} @{$args{bars}}) {
132             my $display = $class;
133             $display =~ s/^RT::(.*)/@{[$1]}s:/;
134             print progress_bar(
135                 label => $display,
136                 now   => $counts{$class},
137                 max   => $args{max}{$class},
138                 cols  => $cols,
139             );
140         }
141
142         my $total = 0;
143         $total += $_ for map {$counts{$_}} grep {exists $args{max}{$_}} keys %counts;
144         $offset = $total unless defined $offset;
145         print "\n", progress_bar(
146             label => "Total",
147             now   => $total,
148             max   => $max_objects,
149             cols  => $cols,
150             char  => "#",
151         );
152
153         # Time estimates
154         my $fraction = $max_objects
155             ? ($total - $offset)/($max_objects - $offset)
156             : 0;
157         if ($fraction > 0.03) {
158             if (defined $left) {
159                 $left = 0.75 * $left
160                       + 0.25 * ($elapsed / $fraction - $elapsed);
161             } else {
162                 $left = ($elapsed / $fraction - $elapsed);
163             }
164         }
165         print "\n";
166         printf "%20s %s\n", "Elapsed time:",
167             format_time($elapsed);
168         printf "%20s %s\n", "Estimated left:",
169             (defined $left) ? format_time($left) : "-";
170
171         $args{bottom}->($elapsed, $rows, $cols);
172     }
173
174 }
175
176 sub setup_logging {
177     my ($dir, $file) = @_;
178
179     $RT::LogToScreen    = 'warning';
180     $RT::LogToFile      = 'warning';
181     $RT::LogDir         = $dir;
182     $RT::LogToFileNamed = $file;
183     $RT::LogStackTraces = 'error';
184
185     undef $RT::Logger;
186     RT->InitLogging();
187
188     my $logger = $RT::Logger->output('file') || $RT::Logger->output("rtlog");
189     return $logger ? $logger->{filename} : undef;
190 }
191
192 1;