# HG changeset patch
# User cin
# Date 1441579031 -10800
# Node ID 14a9663692787fb734cec3af07c6aa09969dbcfa
# Parent cc7244ab1b9f7dcfdaa79a3da92e4d36b6f04721
working version of exporting bugs from bugzilla in tj3 format (without bookings)
diff -r cc7244ab1b9f -r 14a966369278 bug-list.xsl
--- a/bug-list.xsl Sat Sep 05 22:01:12 2015 +0300
+++ b/bug-list.xsl Mon Sep 07 01:37:11 2015 +0300
@@ -22,9 +22,9 @@
-
+
-
+
@@ -33,11 +33,11 @@
-
+
-
+
@@ -49,7 +49,7 @@
-
+
-
+
-
+
-
@@ -128,7 +128,7 @@
+ select="depends_on[not(text() = exsl:node-set($parents)/bug/parent[@id=$id]/@bugid)][key('bugid', .)]" />
@@ -147,7 +147,7 @@
-
+
diff -r cc7244ab1b9f -r 14a966369278 lib/Benzin/Bugzilla/Bug.pm
--- a/lib/Benzin/Bugzilla/Bug.pm Sat Sep 05 22:01:12 2015 +0300
+++ b/lib/Benzin/Bugzilla/Bug.pm Mon Sep 07 01:37:11 2015 +0300
@@ -46,22 +46,10 @@
use constant { BUG_FIELDS => \@fields };
use IMPL::declare {
- require => {
- Strptime => 'DateTime::Format::Strptime'
- },
- base => [
- 'IMPL::Object::Fields' => undef
- ]
+ base => [ 'IMPL::Object::Fields' => undef ]
};
-
use fields @fields;
-my $dtparser = Strptime->new(
- pattern => '%Y%m%dT%H:%M:%S',
- time_zone => 'UTC',
- on_error => 'croak'
-);
-
sub CTOR {
my SELF $this = shift;
my $data = shift;
@@ -71,7 +59,7 @@
# returns {
# reports => [
-# { who => email:string, when => report-date-time:DateTime, work_time => hours:double }
+# { who => email:string, start => work-start-date-time:DateTime, end => report-date-time:DateTime, work_time => hours:double }
# ],
# actual => hours
# remaining => hours
@@ -79,16 +67,13 @@
sub GetTimeReports {
my SELF $this = shift;
my $resolution = shift || 0.25;
-
- warn "Processing: $this->{id}";
my @bookings;
my $actual = 0;
for my $history ( @{ $this->{history} || [] } ) {
- my $who = $history->{who};
- warn $history->{when};
- my $when = $dtparser->parse_datetime( $history->{when} );
+ my $who = $history->{who};
+ my $when = $history->{when};
my $changes = $history->{changes};
for my $change ( @{ $changes || [] } ) {
@@ -101,10 +86,11 @@
if ($dt) {
push @bookings,
{
- who => $who,
+ end => $who,
when => $when->iso8601(),
work_time => $dt,
- start => $when->clone()->subtract( hours => $dt )->iso8601()
+ start => $when->clone()->subtract( hours => $dt )
+ ->iso8601()
};
$actual += $dt;
}
@@ -125,4 +111,4 @@
return $resolution ? ceil( $value / $resolution ) * $resolution : $value;
}
-1;
\ No newline at end of file
+1;
diff -r cc7244ab1b9f -r 14a966369278 lib/Benzin/Bugzilla/XmlRpcClient.pm
--- a/lib/Benzin/Bugzilla/XmlRpcClient.pm Sat Sep 05 22:01:12 2015 +0300
+++ b/lib/Benzin/Bugzilla/XmlRpcClient.pm Mon Sep 07 01:37:11 2015 +0300
@@ -1,29 +1,20 @@
package Benzin::Bugzilla::XmlRpcClient;
use strict;
-use LWP::UserAgent;
-use XMLRPC::Lite;
use YAML::XS qw(Dump);
+use URI;
use IMPL::declare {
require => {
- Bug => 'Benzin::Bugzilla::Bug',
- BugComment => 'Benzin::Bugzilla::BugComment'
+ Bug => 'Benzin::Bugzilla::Bug',
+ BugComment => 'Benzin::Bugzilla::BugComment',
+ Deserializer => 'Benzin::Bugzilla::XmlRpcDeserializer',
+ XmlRpc => 'XMLRPC::Lite'
},
base => { 'IMPL::Object::Fields' => undef }
};
-use fields qw(url apikey);
-
-sub new {
- my $class = shift;
- $class = ref $class || $class;
-
- my $inst = fields::new($class);
- $inst->CTOR(@_);
-
- return $inst;
-}
+use fields qw(url apikey _client);
sub CTOR {
my SELF $this = shift;
@@ -31,6 +22,13 @@
$this->{url} = $params{url} or die "An url is required";
$this->{apikey} = $params{apikey} if $params{apikey};
+
+ #create slightly modified client to parse datetime values
+ my $url = URI->new_abs( 'xmlrpc.cgi', $this->{url} );
+
+ $this->{_client} =
+ XmlRpc->new( deserializer => Deserializer->new() )->proxy($url);
+
}
sub GetBugs {
@@ -42,7 +40,35 @@
];
}
-sub PopulateBugsWithComments {
+sub GetBugsHierarchy {
+ my SELF $this = shift;
+ my $args = shift || {};
+
+ my @queue = @{$args->{ids}};
+ my %visited;
+
+ my @fetched;
+
+ while (@queue) {
+ @queue = grep not( $visited{$_}++ ), @queue;
+
+ last unless @queue;
+
+ my $bugs = $this->GetBugs( { ids => \@queue } );
+ @queue = ();
+
+ foreach my Bug $bug (@$bugs) {
+
+ push @queue, @{ $bug->{depends_on} }
+ if ( $bug->{depends_on} );
+ push @fetched, $bug;
+ }
+ }
+
+ return \@fetched;
+}
+
+sub PopulateBugsComments {
my SELF $this = shift;
my $bugs = shift || [];
@@ -68,11 +94,12 @@
if ( keys %bugs ) {
my $resp =
- $this->_CallService( 'Bug.history', { ids => [ keys %bugs ] } )->{bugs};
+ $this->_CallService( 'Bug.history', { ids => [ keys %bugs ] } )
+ ->{bugs};
for my $data (@$resp) {
- my Bug $bug = $bugs{$data->{id}};
-
+ my Bug $bug = $bugs{ $data->{id} };
+
$bug->{history} = $data->{history};
}
}
@@ -87,9 +114,9 @@
$params ||= {};
$params->{api_key} = $this->{apikey};
- my $url = URI->new_abs( 'xmlrpc.cgi', $this->{url} );
+
- my $result = XMLRPC::Lite->proxy($url)->call( $method, $params );
+ my $result = $this->{_client}->call( $method, $params );
die $result->fault if $result->fault;
return $result->result;
diff -r cc7244ab1b9f -r 14a966369278 lib/Benzin/Bugzilla/XmlRpcDeserializer.pm
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/Benzin/Bugzilla/XmlRpcDeserializer.pm Mon Sep 07 01:37:11 2015 +0300
@@ -0,0 +1,51 @@
+package Benzin::Bugzilla::XmlRpcDeserializer;
+use strict;
+use mro;
+use parent qw(-norequire XMLRPC::Deserializer);
+use IMPL::require { Strptime => 'DateTime::Format::Strptime' };
+
+my $xmlRpcDateFormat = Strptime->new(
+ pattern => '%Y%m%dT%H:%M:%S',
+ time_zone => 'UTC',
+ on_error => 'croak'
+);
+
+sub decode_value {
+ my $this = shift;
+ my ( $name, $attrs, $children, $value ) = @{ $_[0] };
+
+ if ( $name eq 'dateTime.iso8601' ) {
+ return $xmlRpcDateFormat->parse_datetime($value);
+ }
+ else {
+ $this->next::method(@_);
+ }
+
+}
+
+1;
+
+__END__
+
+=pod
+
+=head1 NAME
+
+C - data deserializer for L.
+
+=head1 SYNOPSIS
+
+=begin code perl
+
+# override the default deserializer
+my $client = XMLRPC::Lite->new(
+ deserializer => Benzin::Bugzilla::XmlRpcDeserializer->new()
+);
+
+=end code perl
+
+=head1 DESCRIPTION
+
+Slightly tuned C to parse C values to L objects.
+
+=cut
diff -r cc7244ab1b9f -r 14a966369278 lib/Benzin/Bugzilla/XmlSerializer.pm
--- a/lib/Benzin/Bugzilla/XmlSerializer.pm Sat Sep 05 22:01:12 2015 +0300
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,67 +0,0 @@
-package Benzin::Bugzilla::XmlSerializer;
-
-use IMPL::declare {
- require => {
- XMLWriter => 'XML::Writer'
- },
- base => [
- 'IMPL::Object::Fields' => undef
- ]
-};
-
-use fields qw(_writer);
-
-sub CTOR {
- my SELF $this = shift;
-
- $this->{_writer} = XMLWriter->new(@_);
-}
-
-sub WriteBugList {
- my SELF $this = shift;
- my $bugs = shift || [];
- my $writer = $this->{_writer};
-
-
- $writer->xmlDecl("UTF-8");
- $writer->startTag("bugzilla");
-
- $writer->startElement("bugs");
-
- $this->WriteBug($_) foreach @$bugs;
-
- $writer->endTag();
- $writer->endTag();
-
-}
-
-sub WriteBug {
- my SELF $this = shift;
- my $bug = shift;
- my $writer = $this->{_writer};
-
- $writer->startTag("bug");
- foreach my $field ( @{ Bug->BUG_FIELDS } ) {
- next unless $bug->{$field};
- $this->WriteElement( $field, $bug->{$field} );
- }
- $writer->endTag();
-}
-
-sub WriteElement {
- my SELF $this = shift;
- my ( $name, $data ) = @_;
- my $writer = $this->{_writer};
-
- my @values =
- ref($data)
- && ref($data) eq 'ARRAY'
- ? @{$data}
- : $data;
-
- foreach my $v (@values) {
- $writer->dataElement( $name, $v );
- }
-}
-
-1;
diff -r cc7244ab1b9f -r 14a966369278 lib/Benzin/Bugzilla/XmlWriter.pm
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/Benzin/Bugzilla/XmlWriter.pm Mon Sep 07 01:37:11 2015 +0300
@@ -0,0 +1,110 @@
+package Benzin::Bugzilla::XmlWriter;
+
+our %Transform = (
+ 'Benzin::Bugzilla::Bug' => 'WriteBug',
+ 'Benzin::Bugzilla::BugComment' => 'WriteBugComment',
+ 'HASH' => 'WriteHash',
+ -plain => 'WriteValue',
+ -default => 'WriteValue'
+);
+
+use IMPL::Const qw(:prop);
+use IMPL::declare {
+ require => {
+ XMLWriter => 'XML::Writer',
+ Bug => 'Benzin::Bugzilla::Bug',
+ BugComment => 'Benzin::Bugzilla::BugComment'
+ },
+ base => [
+ 'IMPL::Transform' => sub { %Transform }
+ ],
+ props => [
+ _writer => PROP_RW
+ ]
+};
+
+use fields qw(_writer);
+
+sub CTOR {
+ my SELF $this = shift;
+
+ $this->_writer(XMLWriter->new(@_));
+}
+
+sub WriteBugList {
+ my SELF $this = shift;
+ my $bugs = shift || [];
+ my $writer = $this->_writer;
+
+
+ $writer->xmlDecl("UTF-8");
+ $writer->startTag("bugzilla");
+
+
+ foreach my $bug (@$bugs) {
+ $writer->startTag("bug");
+ $this->WriteBug($bug);
+ $writer->endTag();
+ }
+
+ $writer->endTag();
+
+}
+
+sub WriteBug {
+ my SELF $this = shift;
+ my $value = shift;
+ my $writer = $this->_writer;
+
+ foreach my $field ( @{ Bug->BUG_FIELDS } ) {
+ next unless $value->{$field};
+ $this->WriteElement( $field, $value->{$field} );
+ }
+}
+
+sub WriteBugComment {
+ my SELF $this = shift;
+ my $value = shift;
+ my $writer = $this->_writer;
+
+ foreach my $field ( @{ BugComment->COMMENT_FIELDS } ) {
+ next unless $value->{$field};
+ $this->WriteElement( $field, $value->{$field} );
+ }
+}
+
+sub WriteHash {
+ my SELF $this = shift;
+ my $value = shift;
+
+ while(my ($k,$v) = each %$value) {
+ $this->WriteElement($k,$v);
+ }
+}
+
+sub WriteElement {
+ my SELF $this = shift;
+ my ( $name, $data ) = @_;
+ my $writer = $this->_writer;
+
+ my @values =
+ ref($data)
+ && ref($data) eq 'ARRAY'
+ ? @{$data}
+ : $data;
+
+ foreach my $v (@values) {
+ $writer->startTag($name);
+ $this->Transform( $v );
+ $writer->endTag;
+ }
+}
+
+sub WriteValue {
+ my SELF $this = shift;
+ my $value = shift;
+
+ $this->_writer->characters($value) if defined $value;
+}
+
+1;
diff -r cc7244ab1b9f -r 14a966369278 translate.pl
--- a/translate.pl Sat Sep 05 22:01:12 2015 +0300
+++ b/translate.pl Mon Sep 07 01:37:11 2015 +0300
@@ -1,21 +1,13 @@
#!/usr/bin/perl -w
use IMPL::require {
- BzClient => 'Benzin::Bugzilla::XmlRpcClient',
- Bug => 'Benzin::Bugzilla::Bug'
+ BzClient => 'Benzin::Bugzilla::XmlRpcClient',
+ BugWriter => 'Benzin::Bugzilla::XmlWriter'
};
use YAML::XS qw(LoadFile Dump);
use XML::Writer;
use IPC::Run qw(start finish);
-our @ClassPath = qw(
- /usr/share/java/xalan-j2-serializer.jar
- /usr/share/java/xalan-j2.jar
- /usr/share/java/xerces-j2.jar
- /usr/share/java/xml-commons-resolver.jar
- .
-);
-
my $config = LoadFile("config.yaml");
if ( !( $config->{bugzilla}{url} =~ /\/$/ ) ) {
@@ -27,40 +19,30 @@
apikey => $config->{bugzilla}{apikey}
);
+my $bugs = $config->{bugzilla}{bugs} or die "No bugs specified";
+$bugs = [$bugs] unless ref $bugs eq 'ARRAY';
+
local (*HIN);
-my $proc = start( [ 'saxon8', '-novw', '-', 'bug-list.xsl' ],
- '', \*STDOUT )
- or die "failed to create pipe: $!";
+my $proc = start(
+ [ 'saxon8', '-novw', '-', 'bug-list.xsl' ],
+ #[ 'cat' ],
+ '', \*STDOUT
+) or die "failed to create pipe: $!";
+
+binmode *HIN, ":encoding(utf-8)";
+my $writer =
+ BugWriter->new( OUTPUT => *HIN, DATA_INDENT => 2, DATA_MODE => 'on' );
eval {
my %visited;
- my @queue = (283);
- my @fetched;
- while (@queue) {
- @queue = grep not( $visited{$_}++ ), @queue;
-
- last unless @queue;
-
- print "#Fetching: ", join( ', ', @queue ), "\n";
-
- my $bugs = $bz->GetBugs( { ids => \@queue } );
- @queue = ();
+ my $fetched = $bz->GetBugsHierarchy( { ids => [283] } );
- foreach my $bug (@$bugs) {
+ $bz->PopulateBugsComments($fetched);
+ $bz->PopulateBugsHistory($fetched);
- push @queue, @{ $bug->{depends_on} }
- if ( $bug->{depends_on} );
- push @fetched, $bug;
- }
- }
- print Dump( \@fetched );
-
- $bz->PopulateBugsWithComments( \@fetched );
- $bz->PopulateBugsHistory( \@fetched );
-
- print Dump( [ map $_->GetTimeReports(0.25), @fetched ] );
+ $writer->WriteBugList($fetched);
};
warn Dump($@) and die $@ if $@;