summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CGI.pl2
-rwxr-xr-xchecksetup.pl6
-rwxr-xr-xcollectstats.pl17
-rw-r--r--css/duplicates.css27
-rwxr-xr-xduplicates.cgi12
-rw-r--r--duplicates.xul133
-rw-r--r--js/duplicates.js153
-rw-r--r--skins/standard/duplicates.css27
-rw-r--r--template/en/default/reports/duplicates.rdf.tmpl51
9 files changed, 426 insertions, 2 deletions
diff --git a/CGI.pl b/CGI.pl
index d6dca3a39..2069d9235 100644
--- a/CGI.pl
+++ b/CGI.pl
@@ -206,7 +206,7 @@ sub get_netaddr {
my ($ipaddr) = @_;
# Check for a valid IPv4 addr which we know how to parse
- if ($ipaddr !~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/) {
+ if (!$ipaddr || $ipaddr !~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/) {
return undef;
}
diff --git a/checksetup.pl b/checksetup.pl
index 3a60a3937..aa91c3a34 100755
--- a/checksetup.pl
+++ b/checksetup.pl
@@ -837,8 +837,12 @@ END
open HTACCESS, ">data/.htaccess";
print HTACCESS <<'END';
# nothing in this directory is retrievable unless overriden by an .htaccess
-# in a subdirectory
+# in a subdirectory; the only exception is duplicates.rdf, which is used by
+# duplicates.xul and must be loadable over the web
deny from all
+<Files duplicates.rdf>
+ allow from all
+</Files>
END
close HTACCESS;
chmod $fileperm, "data/.htaccess";
diff --git a/collectstats.pl b/collectstats.pl
index 8caf92d77..61e7cf204 100755
--- a/collectstats.pl
+++ b/collectstats.pl
@@ -53,6 +53,23 @@ foreach (@myproducts) {
&calculate_dupes();
+# Generate a static RDF file containing the default view of the duplicates data.
+open(CGI, "REQUEST_METHOD=GET QUERY_STRING=ctype=rdf ./duplicates.cgi |")
+ || die "can't fork duplicates.cgi: $!";
+open(RDF, ">data/duplicates.tmp")
+ || die "can't write to data/duplicates.tmp: $!";
+my $headers_done = 0;
+while (<CGI>) {
+ print RDF if $headers_done;
+ $headers_done = 1 if $_ eq "\n";
+}
+close CGI;
+close RDF;
+if (-s "data/duplicates.tmp") {
+ rename("data/duplicates.rdf", "data/duplicates-old.rdf");
+ rename("data/duplicates.tmp", "data/duplicates.rdf");
+}
+
sub check_data_dir {
my $dir = shift;
diff --git a/css/duplicates.css b/css/duplicates.css
new file mode 100644
index 000000000..aab36fb2a
--- /dev/null
+++ b/css/duplicates.css
@@ -0,0 +1,27 @@
+/* The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ *
+ * The Original Code is the Bugzilla Bug Tracking System.
+ *
+ * The Initial Developer of the Original Code is Netscape Communications
+ * Corporation. Portions created by Netscape are
+ * Copyright (C) 1998 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s): Myk Melez <myk@mozilla.org>
+ */
+
+treechildren:-moz-tree-cell-text(resolution-FIXED) {
+ text-decoration: line-through;
+}
+
+treecol#id_column { width: 6em; }
+treecol#duplicate_count_column { width: 5em; }
+treecol#duplicate_delta_column { width: 5em; }
diff --git a/duplicates.cgi b/duplicates.cgi
index 643a54423..e95d4b02c 100755
--- a/duplicates.cgi
+++ b/duplicates.cgi
@@ -32,6 +32,18 @@ use lib qw(.);
require "globals.pl";
require "CGI.pl";
+use vars qw($buffer);
+
+# Go directly to the XUL version of the duplicates report (duplicates.xul)
+# if the user specified ctype=xul. Adds params if they exist, and directs
+# the user to a signed copy of the script in duplicates.jar if it exists.
+if ($::FORM{'ctype'} eq "xul") {
+ my $params = CanonicaliseParams($::buffer, ["format", "ctype"]);
+ print "Location: " . (-e "duplicates.jar" ? "duplicates.jar!/" : "") .
+ "duplicates.xul" . ($params ? "?$params" : "") . "\n\n";
+ exit;
+}
+
# Use global templatisation variables.
use vars qw($template $vars);
diff --git a/duplicates.xul b/duplicates.xul
new file mode 100644
index 000000000..be647c188
--- /dev/null
+++ b/duplicates.xul
@@ -0,0 +1,133 @@
+<?xml version="1.0"?>
+<!--
+ -
+ - The contents of this file are subject to the Mozilla Public
+ - License Version 1.1 (the "License"); you may not use this file
+ - except in compliance with the License. You may obtain a copy of
+ - the License at http://www.mozilla.org/MPL/
+ -
+ - Software distributed under the License is distributed on an "AS
+ - IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ - implied. See the License for the specific language governing
+ - rights and limitations under the License.
+ -
+ - The Original Code is the Bugzilla Bug Tracking System.
+ -
+ - The Initial Developer of the Original Code is Netscape Communications
+ - Corporation. Portions created by Netscape are
+ - Copyright (C) 1998 Netscape Communications Corporation. All
+ - Rights Reserved.
+ -
+ - Contributor(s): Myk Melez <myk@mozilla.org>
+ -
+ -->
+
+<!DOCTYPE window [
+ <!ENTITY idColumn.label "ID">
+ <!ENTITY duplicateCountColumn.label "Count">
+ <!ENTITY duplicateDeltaColumn.label "Delta">
+ <!ENTITY componentColumn.label "Component">
+ <!ENTITY severityColumn.label "Severity">
+ <!ENTITY osColumn.label "OS">
+ <!ENTITY targetMilestoneColumn.label "Milestone">
+ <!ENTITY summaryColumn.label "Summary">
+]>
+
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+<?xml-stylesheet href="css/duplicates.css" type="text/css"?>
+
+<window id="duplicates_report"
+ xmlns:html="http://www.w3.org/1999/xhtml"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ title="Duplicates Report">
+
+ // Code for populating the tree from the RDF data source
+ // and loading bug reports when the user selects rows in the tree.
+ <script type="application/x-javascript" src="js/duplicates.js" />
+
+ <tree id="results-tree" flex="1"
+ flags="dont-build-content"
+ enableColumnDrag="true"
+ datasources="rdf:null"
+ ref=""
+ onselect="loadBugInPane();"
+ ondblclick="loadBugInWindow();">
+ <treecols>
+ <treecol id="id_column" label="&idColumn.label;" primary="true" sort="?id"
+ persist="width hidden sortActive sortDirection ordinal" />
+ <splitter class="tree-splitter"/>
+
+ <treecol id="duplicate_count_column" label="&duplicateCountColumn.label;" sort="?duplicate_count"
+ sortActive="true" sortDirection="descending"
+ persist="width hidden sortActive sortDirection ordinal" />
+ <splitter class="tree-splitter" />
+
+ <treecol id="duplicate_delta_column" label="&duplicateDeltaColumn.label;" sort="?duplicate_delta"
+ persist="width hidden sortActive sortDirection ordinal" />
+ <splitter class="tree-splitter"/>
+
+ <treecol id="component_column" label="&componentColumn.label;" flex="3" sort="?component"
+ persist="width hidden sortActive sortDirection ordinal" />
+ <splitter class="tree-splitter"/>
+
+ <treecol id="severity_column" label="&severityColumn.label;" flex="1" sort="?severity"
+ persist="width hidden sortActive sortDirection ordinal" />
+ <splitter class="tree-splitter"/>
+
+ <treecol id="os_column" label="&osColumn.label;" flex="2" sort="?os"
+ persist="width hidden sortActive sortDirection ordinal" />
+ <splitter class="tree-splitter"/>
+
+ <treecol id="target_milestone_column" label="&targetMilestoneColumn.label;" flex="1" sort="?target_milestone"
+ persist="width hidden sortActive sortDirection ordinal" />
+ <splitter class="tree-splitter"/>
+
+ <treecol id="summary_column" label="&summaryColumn.label;" flex="12" sort="?summary"
+ persist="width hidden sortActive sortDirection ordinal" />
+ </treecols>
+ <template>
+ <rule>
+ <conditions>
+ <treeitem uri="?uri" />
+ <triple subject="?uri" predicate="http://www.bugzilla.org/rdf#bugs" object="?bugs" />
+ <member container="?bugs" child="?bug" />
+ <triple subject="?bug" predicate="http://www.bugzilla.org/rdf#id" object="?id" />
+ </conditions>
+ <bindings>
+ <binding subject="?bug" predicate="http://www.bugzilla.org/rdf#duplicate_count" object="?duplicate_count" />
+ <binding subject="?bug" predicate="http://www.bugzilla.org/rdf#duplicate_delta" object="?duplicate_delta" />
+ <binding subject="?bug" predicate="http://www.bugzilla.org/rdf#component" object="?component" />
+ <binding subject="?bug" predicate="http://www.bugzilla.org/rdf#severity" object="?severity" />
+ <binding subject="?bug" predicate="http://www.bugzilla.org/rdf#priority" object="?priority" />
+ <binding subject="?bug" predicate="http://www.bugzilla.org/rdf#os" object="?os" />
+ <binding subject="?bug" predicate="http://www.bugzilla.org/rdf#target_milestone" object="?target_milestone" />
+ <binding subject="?bug" predicate="http://www.bugzilla.org/rdf#summary" object="?summary" />
+ <binding subject="?bug" predicate="http://www.bugzilla.org/rdf#resolution" object="?resolution" />
+ </bindings>
+ <action>
+ <treechildren>
+ <treeitem uri="?bug">
+ <treerow properties="resolution-?resolution">
+ <treecell ref="id_column" label="?id" properties="resolution-?resolution" />
+ <treecell ref="duplicate_count_column" label="?duplicate_count" properties="resolution-?resolution" />
+ <treecell ref="duplicate_delta_column" label="?duplicate_delta" properties="resolution-?resolution" />
+ <treecell ref="component_column" label="?component" properties="resolution-?resolution" />
+ <treecell ref="severity_column" label="?severity" properties="resolution-?resolution" />
+ <treecell ref="os_column" label="?os" properties="resolution-?resolution" />
+ <treecell ref="target_milestone_column" label="?target_milestone" properties="resolution-?resolution" />
+ <treecell ref="summary_column" label="?summary" properties="resolution-?resolution" />
+ </treerow>
+ </treeitem>
+ </treechildren>
+ </action>
+ </rule>
+ </template>
+ </tree>
+
+ <splitter id="report-content-splitter" collapse="after" state="open" persist="state">
+ <grippy/>
+ </splitter>
+
+ <iframe id="content-browser" src="about:blank" flex="2" persist="height" />
+
+</window>
diff --git a/js/duplicates.js b/js/duplicates.js
new file mode 100644
index 000000000..b1e94a8a6
--- /dev/null
+++ b/js/duplicates.js
@@ -0,0 +1,153 @@
+/* The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ *
+ * The Original Code is the Bugzilla Bug Tracking System.
+ *
+ * The Initial Developer of the Original Code is Netscape Communications
+ * Corporation. Portions created by Netscape are
+ * Copyright (C) 1998 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s): Myk Melez <myk@mozilla.org>
+ */
+
+// When the XUL window finishes loading, load the RDF data into it.
+window.addEventListener('load', loadData, false);
+
+// The base URL of this Bugzilla installation; derived from the page's URL.
+var gBaseURL = window.location.href.replace(/duplicates\.(jar!|xul).*/, "");
+
+function loadData()
+{
+ // Loads the duplicates data as an RDF data source, attaches it to the tree,
+ // and rebuilds the tree to display the data.
+
+ netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+
+ // Get the RDF service so we can use it to load the data source.
+ var rdfService =
+ Components
+ .classes["@mozilla.org/rdf/rdf-service;1"]
+ .getService(Components.interfaces.nsIRDFService);
+
+ // When a bug report loads in the content iframe, a 'load' event bubbles up
+ // to the browser window, which calls this load handler again, which reloads
+ // the RDF data, which causes the tree to lose the selection. To prevent
+ // this, we have to remove this handler.
+ window.removeEventListener('load', loadData, false);
+
+ // The URL of the RDF file; by default for performance a static file
+ // generated by collectstats.pl, but a call to duplicates.cgi if the page's
+ // URL contains parameters (so we can dynamically generate the RDF data
+ // based on those parameters).
+ var dataURL = gBaseURL + "data/duplicates.rdf";
+ if (window.location.href.search(/duplicates\.xul\?.+/) != -1)
+ dataURL = window.location.href.replace(/(duplicates\.jar!\/)?duplicates\.xul\?/, "duplicates.cgi?ctype=rdf&");
+
+ // Get the data source and add it to the XUL tree's database to populate
+ // the tree with the data.
+ var dataSource = rdfService.GetDataSource(dataURL);
+
+ // If we're using the static file, add an observer that detects failed loads
+ // (in case this installation isn't generating the file nightly) and redirects
+ // to the CGI version when loading of the static version fails.
+ if (window.location.href.search(/duplicates\.xul\?.+/) == -1)
+ {
+ var sink = dataSource.QueryInterface(Components.interfaces.nsIRDFXMLSink);
+ sink.addXMLSinkObserver(StaticDataSourceObserver);
+ }
+
+ // Add the data source to the tree, set the tree's "ref" attribute
+ // to the base URL of the data source, and rebuild the tree.
+ var resultsTree = document.getElementById('results-tree');
+ resultsTree.database.AddDataSource(dataSource);
+ resultsTree.setAttribute('ref', gBaseURL + "data/duplicates.rdf");
+ resultsTree.builder.rebuild();
+}
+
+function getBugURI()
+{
+ var tree = document.getElementById('results-tree');
+ var index = tree.currentIndex;
+
+ netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+ var builder = tree.builder.QueryInterface(Components.interfaces.nsIXULTreeBuilder);
+ var resource = builder.getResourceAtIndex(index);
+
+ return resource.Value;
+}
+
+function loadBugInWindow()
+{
+ // Loads the selected bug in the browser window, replacing the duplicates report
+ // with the bug report.
+
+ var bugURI = getBugURI();
+ window.location = bugURI;
+}
+
+function loadBugInPane()
+{
+ // Loads the selected bug in the iframe-based content pane that is part of
+ // this XUL document.
+
+ var splitter = document.getElementById('report-content-splitter');
+ var state = splitter.getAttribute('state');
+ if (state != "collapsed")
+ {
+ var bugURI = getBugURI();
+ var browser = document.getElementById('content-browser');
+ browser.setAttribute('src', bugURI);
+ }
+}
+
+var StaticDataSourceObserver = {
+ onBeginLoad: function(aSink) { } ,
+ onInterrupt: function(aSink) { } ,
+ onResume: function(aSink) { } ,
+ onEndLoad: function(aSink)
+ {
+ // Removes the observer from the data source so it doesn't stay around
+ // when duplicates.xul is reloaded from scratch.
+
+ netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+
+ aSink.removeXMLSinkObserver(StaticDataSourceObserver);
+ } ,
+ onError: function(aSink, aStatus, aErrorMsg)
+ {
+ // Tries the dynamic data source since the static one failed to load.
+
+ netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+
+ // Get the RDF service so we can use it to load the data source.
+ var rdfService =
+ Components
+ .classes["@mozilla.org/rdf/rdf-service;1"]
+ .getService(Components.interfaces.nsIRDFService);
+
+ // Remove the observer from the data source so it doesn't stay around
+ // when duplicates.xul is reloaded from scratch.
+ aSink.removeXMLSinkObserver(StaticDataSourceObserver);
+
+ // Remove the static data source from the tree.
+ var oldDataSource = aSink.QueryInterface(Components.interfaces.nsIRDFDataSource);
+ var resultsTree = document.getElementById('results-tree');
+ resultsTree.database.RemoveDataSource(oldDataSource);
+
+ // Munge the URL to point to the CGI and load the data source.
+ var dataURL = gBaseURL + "duplicates.cgi?ctype=rdf";
+ newDataSource = rdfService.GetDataSource(dataURL);
+
+ // Add the data source to the tree and rebuild the tree with the new data.
+ resultsTree.database.AddDataSource(newDataSource);
+ resultsTree.builder.rebuild();
+ }
+};
diff --git a/skins/standard/duplicates.css b/skins/standard/duplicates.css
new file mode 100644
index 000000000..aab36fb2a
--- /dev/null
+++ b/skins/standard/duplicates.css
@@ -0,0 +1,27 @@
+/* The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ *
+ * The Original Code is the Bugzilla Bug Tracking System.
+ *
+ * The Initial Developer of the Original Code is Netscape Communications
+ * Corporation. Portions created by Netscape are
+ * Copyright (C) 1998 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s): Myk Melez <myk@mozilla.org>
+ */
+
+treechildren:-moz-tree-cell-text(resolution-FIXED) {
+ text-decoration: line-through;
+}
+
+treecol#id_column { width: 6em; }
+treecol#duplicate_count_column { width: 5em; }
+treecol#duplicate_delta_column { width: 5em; }
diff --git a/template/en/default/reports/duplicates.rdf.tmpl b/template/en/default/reports/duplicates.rdf.tmpl
new file mode 100644
index 000000000..941f9f70f
--- /dev/null
+++ b/template/en/default/reports/duplicates.rdf.tmpl
@@ -0,0 +1,51 @@
+[% template_version = "1.0@bugzilla.org" %]
+[%# The contents of this file are subject to the Mozilla Public
+ # License Version 1.1 (the "License"); you may not use this file
+ # except in compliance with the License. You may obtain a copy of
+ # the License at http://www.mozilla.org/MPL/
+ #
+ # Software distributed under the License is distributed on an "AS
+ # IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ # implied. See the License for the specific language governing
+ # rights and limitations under the License.
+ #
+ # The Original Code is the Bugzilla Bug Tracking System.
+ #
+ # The Initial Developer of the Original Code is Netscape Communications
+ # Corporation. Portions created by Netscape are
+ # Copyright (C) 1998 Netscape Communications Corporation. All
+ # Rights Reserved.
+ #
+ # Contributor(s): Myk Melez <myk@mozilla.org>
+ #%]
+
+<?xml version="1.0"?>
+<!-- [% template_version %] -->
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:bz="http://www.bugzilla.org/rdf#"
+ xmlns:nc="http://home.netscape.com/NC-rdf#">
+
+<bz:duplicates_report rdf:about="[% Param('urlbase') %]data/duplicates.rdf">
+ <bz:bugs>
+ <Seq>
+ [% FOREACH bug = bugs %]
+ <li>
+ <bz:bug rdf:about="[% Param('urlbase') %]show_bug.cgi?id=[% bug.id %]">
+ <bz:id nc:parseType="Integer">[% bug.id %]</bz:id>
+ <bz:resolution>[% bug.resolution FILTER html %]</bz:resolution>
+ <bz:duplicate_count nc:parseType="Integer">[% bug.count %]</bz:duplicate_count>
+ <bz:duplicate_delta nc:parseType="Integer">[% bug.delta %]</bz:duplicate_delta>
+ <bz:component>[% bug.component FILTER html %]</bz:component>
+ <bz:severity>[% bug.bug_severity FILTER html %]</bz:severity>
+ <bz:os>[% bug.op_sys FILTER html %]</bz:os>
+ <bz:target_milestone>[% bug.target_milestone FILTER html %]</bz:target_milestone>
+ <bz:summary>[% bug.short_desc FILTER html %]</bz:summary>
+ </bz:bug>
+ </li>
+ [% END %]
+ </Seq>
+ </bz:bugs>
+</bz:duplicates_report>
+
+</RDF>