123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068 |
- #!/usr/bin/env perl -w
- # -*- Mode: perl; indent-tabs-mode: nil -*-
- #
- # 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 Gnats To Bugzilla Conversion Utility.
- #
- # The Initial Developer of the Original Code is Tom
- # Schutter. Portions created by Tom Schutter are
- # Copyright (C) 1999 Tom Schutter. All
- # Rights Reserved.
- #
- # Contributor(s): Tom Schutter <tom@platte.com>
- #
- # Perl script to convert a GNATS database to a Bugzilla database.
- # This script generates a file that contains SQL commands for MySQL.
- # This script DOES NOT MODIFY the GNATS database.
- # This script DOES NOT MODIFY the Bugzilla database.
- #
- # Usage procedure:
- # 1) Regenerate the GNATS index file. It sometimes has inconsistencies,
- # and this script relies on it being correct. Use the GNATS command:
- # gen-index --numeric --outfile=$GNATS_DIR/gnats-db/gnats-adm/index
- # 2) Modify variables at the beginning of this script to match
- # what your site requires.
- # 3) Modify translate_pr() and write_bugs() below to fixup mapping from
- # your GNATS policies to Bugzilla. For example, how do the
- # Severity/Priority fields map to bug_severity/priority?
- # 4) Run this script.
- # 5) Fix the problems in the GNATS database identified in the output
- # script file gnats2bz_cleanup.sh. Fixing problems may be a job
- # for a custom perl script. If you make changes to GNATS, goto step 2.
- # 6) Examine the statistics in the output file gnats2bz_stats.txt.
- # These may indicate some more cleanup that is needed. For example,
- # you may find that there are invalid "State"s, or not a consistent
- # scheme for "Release"s. If you make changes to GNATS, goto step 2.
- # 7) Examine the output data file gnats2bz_data.sql. If problems
- # exist, goto step 2.
- # 8) Create a new, empty Bugzilla database.
- # 9) Import the data using the command:
- # mysql -uroot -p'ROOT_PASSWORD' bugs < gnats2bz_data.sql
- # 10) Update the shadow directory with the command:
- # cd $BUGZILLA_DIR; ./processmail regenerate
- # 11) Run a sanity check by visiting the sanitycheck.cgi page.
- # 12) Manually verify that the database is ok. If it is not, goto step 2.
- #
- # Important notes:
- # Confidential is not mapped or exported.
- # Submitter-Id is not mapped or exported.
- #
- # Design decisions:
- # This script generates a SQL script file rather than dumping the data
- # directly into the database. This is to allow the user to check
- # and/or modify the results before they are put into the database.
- # The PR number is very important and must be maintained as the Bugzilla
- # bug number, because there are many references to the PR number, such
- # as in code comments, CVS comments, customer communications, etc.
- # Reading ENUMERATED and TEXT fields:
- # 1) All leading and trailing whitespace is stripped.
- # Reading MULTITEXT fields:
- # 1) All leading blank lines are stripped.
- # 2) All trailing whitespace is stripped.
- # 3) Indentation is preserved.
- # Audit-Trail is not mapped to bugs_activity table, because there
- # is no place to put the "Why" text, which can have a fair amount
- # of information content.
- #
- # 15 January 2002 - changes from Andrea Dell'Amico <adellam@link.it>
- #
- # * Adapted to the new database structure: now long_descs is a
- # separate table.
- # * Set a default for the target milestone, otherwise bugzilla
- # doesn't work with the imported database if milestones are used.
- # * In gnats version 3.113 records are separated by "|" and not ":".
- # * userid "1" is for the bugzilla administrator, so it's better to
- # start from 2.
- #
- use strict;
- # Suffix to be appended to username to make it an email address.
- my($username_suffix) = "\@platte.com";
- # Default organization that should be ignored and not passed on to Bugzilla.
- # Only bugs that are reported outside of the default organization will have
- # their Originator,Organization fields passed on.
- # The assumption here is that if the Organization is identical to the
- # $default_organization, then the Originator will most likely be only an
- # alias for the From field in the mail header.
- my($default_organization) = "Platte River Associates|platte";
- # Username for reporter field if unable to determine from mail header
- my($gnats_username) = "gnats\@platte.com";
- # Flag indicating if cleanup file should use edit-pr or ${EDITOR}.
- # Using edit-pr is safer, but may be too slow if there are too many
- # PRs that need cleanup. If you use ${EDITOR}, then you must make
- # sure that you have exclusive access to the database, and that you
- # do not screw up any fields.
- my($cleanup_with_edit_pr) = 0;
- # Component name and description for bugs imported from GNATS.
- my($default_component) = "GNATS Import";
- my($default_component_description) = "Bugs imported from GNATS.";
- # First generated userid. Start from 2: 1 is used for the bugzilla
- # administrator.
- my($userid_base) = 2;
- # Output filenames.
- my($cleanup_pathname) = "gnats2bz_cleanup.sh";
- my($stats_pathname) = "gnats2bz_stats.txt";
- my($data_pathname) = "gnats2bz_data.sql";
- # List of ENUMERATED and TEXT fields.
- my(@text_fields) = qw(Number Category Synopsis Confidential Severity
- Priority Responsible State Class Submitter-Id
- Arrival-Date Originator Release);
- # List of MULTITEXT fields.
- my(@multitext_fields) = qw(Mail-Header Organization Environment Description
- How-To-Repeat Fix Audit-Trail Unformatted);
- # List of fields to report statistics for.
- my(@statistics_fields) = qw(Category Confidential Severity Priority
- Responsible State Class Submitter-Id Originator
- Organization Release Environment);
- # Array to hold list of GNATS PRs.
- my(@pr_list);
- # Array to hold list of GNATS categories.
- my(@categories_list);
- # Array to hold list of GNATS responsible users.
- my(@responsible_list);
- # Array to hold list of usernames.
- my(@username_list);
- # Put the gnats_username in first.
- get_userid($gnats_username);
- # Hash to hold list of versions.
- my(%versions_table);
- # Hash to hold contents of PR.
- my(%pr_data);
- # String to hold duplicate fields found during read of PR.
- my($pr_data_dup_fields) = "";
- # String to hold badly labeled fields found during read of PR.
- # This usually happens when the user does not separate the field name
- # from the field data with whitespace.
- my($pr_data_bad_fields) = " ";
- # Hash to hold statistics (note that this a hash of hashes).
- my(%pr_stats);
- # Process commmand line.
- my($gnats_db_dir) = @ARGV;
- defined($gnats_db_dir) || die "gnats-db dir not specified";
- (-d $gnats_db_dir) || die "$gnats_db_dir is not a directory";
- # Load @pr_list from GNATS index file.
- my($index_pathname) = $gnats_db_dir . "/gnats-adm/index";
- (-f $index_pathname) || die "$index_pathname not found";
- print "Reading $index_pathname...\n";
- if (!load_index($index_pathname)) {
- return(0);
- }
- # Load @category_list from GNATS categories file.
- my($categories_pathname) = $gnats_db_dir . "/gnats-adm/categories";
- (-f $categories_pathname) || die "$categories_pathname not found";
- print "Reading $categories_pathname...\n";
- if (!load_categories($categories_pathname)) {
- return(0);
- }
- # Load @responsible_list from GNATS responsible file.
- my($responsible_pathname) = $gnats_db_dir . "/gnats-adm/responsible";
- (-f $responsible_pathname) || die "$responsible_pathname not found";
- print "Reading $responsible_pathname...\n";
- if (!load_responsible($responsible_pathname)) {
- return(0);
- }
- # Open cleanup file.
- open(CLEANUP, ">$cleanup_pathname") ||
- die "Unable to open $cleanup_pathname: $!";
- chmod(0744, $cleanup_pathname) || warn "Unable to chmod $cleanup_pathname: $!";
- print CLEANUP "#!/bin/sh\n";
- print CLEANUP "# List of PRs that have problems found by gnats2bz.pl.\n";
- # Open data file.
- open(DATA, ">$data_pathname") || die "Unable to open $data_pathname: $!";
- print DATA "-- Exported data from $gnats_db_dir by gnats2bz.pl.\n";
- print DATA "-- Load it into a Bugzilla database using the command:\n";
- print DATA "-- mysql -uroot -p'ROOT_PASSWORD' bugs < gnats2bz_data.sql\n";
- print DATA "--\n";
- # Loop over @pr_list.
- my($pr);
- foreach $pr (@pr_list) {
- print "Processing $pr...\n";
- if (!read_pr("$gnats_db_dir/$pr")) {
- next;
- }
- translate_pr();
- check_pr($pr);
- collect_stats();
- update_versions();
- write_bugs();
- write_longdescs();
- }
- write_non_bugs_tables();
- close(CLEANUP) || die "Unable to close $cleanup_pathname: $!";
- close(DATA) || die "Unable to close $data_pathname: $!";
- print "Generating $stats_pathname...\n";
- report_stats();
- sub load_index {
- my($pathname) = @_;
- my($record);
- my(@fields);
- open(INDEX, $pathname) || die "Unable to open $pathname: $!";
- while ($record = <INDEX>) {
- @fields = split(/\|/, $record);
- push(@pr_list, $fields[0]);
- }
- close(INDEX) || die "Unable to close $pathname: $!";
- return(1);
- }
- sub load_categories {
- my($pathname) = @_;
- my($record);
- open(CATEGORIES, $pathname) || die "Unable to open $pathname: $!";
- while ($record = <CATEGORIES>) {
- if ($record =~ /^#/) {
- next;
- }
- push(@categories_list, [split(/:/, $record)]);
- }
- close(CATEGORIES) || die "Unable to close $pathname: $!";
- return(1);
- }
- sub load_responsible {
- my($pathname) = @_;
- my($record);
- open(RESPONSIBLE, $pathname) || die "Unable to open $pathname: $!";
- while ($record = <RESPONSIBLE>) {
- if ($record =~ /^#/) {
- next;
- }
- push(@responsible_list, [split(/\|/, $record)]);
- }
- close(RESPONSIBLE) || die "Unable to close $pathname: $!";
- return(1);
- }
- sub read_pr {
- my($pr_filename) = @_;
- my($multitext) = "Mail-Header";
- my($field, $mail_header);
- # Empty the hash.
- %pr_data = ();
- # Empty the list of duplicate fields.
- $pr_data_dup_fields = "";
- # Empty the list of badly labeled fields.
- $pr_data_bad_fields = "";
- unless (open(PR, $pr_filename)) {
- warn "error opening $pr_filename: $!";
- return(0);
- }
- LINELOOP: while (<PR>) {
- chomp;
- if ($multitext eq "Unformatted") {
- # once we reach "Unformatted", rest of file goes there
- $pr_data{$multitext} = append_multitext($pr_data{$multitext}, $_);
- next LINELOOP;
- }
- # Handle ENUMERATED and TEXT fields.
- foreach $field (@text_fields) {
- if (/^>$field:($|\s+)/) {
- $pr_data{$field} = $'; # part of string after match
- $pr_data{$field} =~ s/\s+$//; # strip trailing whitespace
- $multitext = "";
- next LINELOOP;
- }
- }
- # Handle MULTITEXT fields.
- foreach $field (@multitext_fields) {
- if (/^>$field:\s*$/) {
- $_ = $'; # set to part of string after match part
- if (defined($pr_data{$field})) {
- if ($pr_data_dup_fields eq "") {
- $pr_data_dup_fields = $field;
- } else {
- $pr_data_dup_fields = "$pr_data_dup_fields $field";
- }
- }
- $pr_data{$field} = $_;
- $multitext = $field;
- next LINELOOP;
- }
- }
- # Check for badly labeled fields.
- foreach $field ((@text_fields, @multitext_fields)) {
- if (/^>$field:/) {
- if ($pr_data_bad_fields eq "") {
- $pr_data_bad_fields = $field;
- } else {
- $pr_data_bad_fields = "$pr_data_bad_fields $field";
- }
- }
- }
- # Handle continued MULTITEXT field.
- $pr_data{$multitext} = append_multitext($pr_data{$multitext}, $_);
- }
- close(PR) || warn "error closing $pr_filename: $!";
- # Strip trailing newlines from MULTITEXT fields.
- foreach $field (@multitext_fields) {
- if (defined($pr_data{$field})) {
- $pr_data{$field} =~ s/\s+$//;
- }
- }
- return(1);
- }
- sub append_multitext {
- my($original, $addition) = @_;
- if (defined($original) && $original ne "") {
- return "$original\n$addition";
- } else {
- return $addition;
- }
- }
- sub check_pr {
- my($pr) = @_;
- my($error_list) = "";
- if ($pr_data_dup_fields ne "") {
- $error_list = append_error($error_list, "Multiple '$pr_data_dup_fields'");
- }
- if ($pr_data_bad_fields ne "") {
- $error_list = append_error($error_list, "Bad field labels '$pr_data_bad_fields'");
- }
- if (!defined($pr_data{"Description"}) || $pr_data{"Description"} eq "") {
- $error_list = append_error($error_list, "Description empty");
- }
- if (defined($pr_data{"Unformatted"}) && $pr_data{"Unformatted"} ne "") {
- $error_list = append_error($error_list, "Unformatted text");
- }
- if (defined($pr_data{"Release"}) && length($pr_data{"Release"}) > 16) {
- $error_list = append_error($error_list, "Release > 16 chars");
- }
- if (defined($pr_data{"Fix"}) && $pr_data{"Fix"} =~ /State-Changed-/) {
- $error_list = append_error($error_list, "Audit in Fix field");
- }
- if (defined($pr_data{"Arrival-Date"})) {
- if ($pr_data{"Arrival-Date"} eq "") {
- $error_list = append_error($error_list, "Arrival-Date empty");
- } elsif (unixdate2datetime($pr, $pr_data{"Arrival-Date"}) eq "") {
- $error_list = append_error($error_list, "Arrival-Date format");
- }
- }
- # More checks should go here.
- if ($error_list ne "") {
- if ($cleanup_with_edit_pr) {
- my(@parts) = split("/", $pr);
- my($pr_num) = $parts[1];
- print CLEANUP "echo \"$error_list\"; edit-pr $pr_num\n";
- } else {
- print CLEANUP "echo \"$error_list\"; \${EDITOR} $pr\n";
- }
- }
- }
- sub append_error {
- my($original, $addition) = @_;
- if ($original ne "") {
- return "$original, $addition";
- } else {
- return $addition;
- }
- }
- sub translate_pr {
- # This function performs GNATS -> Bugzilla translations that should
- # happen before collect_stats().
- if (!defined($pr_data{"Organization"})) {
- $pr_data{"Originator"} = "";
- }
- if ($pr_data{"Organization"} =~ /$default_organization/) {
- $pr_data{"Originator"} = "";
- $pr_data{"Organization"} = "";
- }
- $pr_data{"Organization"} =~ s/^\s+//g; # strip leading whitespace
- if (!defined($pr_data{"Release"}) ||
- $pr_data{"Release"} eq "" ||
- $pr_data{"Release"} =~ /^unknown-1.0$/
- ) {
- $pr_data{"Release"} = "unknown";
- }
- if (defined($pr_data{"Responsible"})) {
- $pr_data{"Responsible"} =~ /\w+/;
- $pr_data{"Responsible"} = "$&$username_suffix";
- }
- my($rep_platform, $op_sys) = ("All", "All");
- if (defined($pr_data{"Environment"})) {
- if ($pr_data{"Environment"} =~ /[wW]in.*NT/) {
- $rep_platform = "PC";
- $op_sys = "Windows NT";
- } elsif ($pr_data{"Environment"} =~ /[wW]in.*95/) {
- $rep_platform = "PC";
- $op_sys = "Windows 95";
- } elsif ($pr_data{"Environment"} =~ /[wW]in.*98/) {
- $rep_platform = "PC";
- $op_sys = "Windows 98";
- } elsif ($pr_data{"Environment"} =~ /OSF/) {
- $rep_platform = "DEC";
- $op_sys = "OSF/1";
- } elsif ($pr_data{"Environment"} =~ /AIX/) {
- $rep_platform = "RS/6000";
- $op_sys = "AIX";
- } elsif ($pr_data{"Environment"} =~ /IRIX/) {
- $rep_platform = "SGI";
- $op_sys = "IRIX";
- } elsif ($pr_data{"Environment"} =~ /SunOS.*5\.\d/) {
- $rep_platform = "Sun";
- $op_sys = "Solaris";
- } elsif ($pr_data{"Environment"} =~ /SunOS.*4\.\d/) {
- $rep_platform = "Sun";
- $op_sys = "SunOS";
- }
- }
- $pr_data{"Environment"} = "$rep_platform:$op_sys";
- }
- sub collect_stats {
- my($field, $value);
- foreach $field (@statistics_fields) {
- $value = $pr_data{$field};
- if (!defined($value)) {
- $value = "";
- }
- if (defined($pr_stats{$field}{$value})) {
- $pr_stats{$field}{$value}++;
- } else {
- $pr_stats{$field}{$value} = 1;
- }
- }
- }
- sub report_stats {
- my($field, $value, $count);
- open(STATS, ">$stats_pathname") ||
- die "Unable to open $stats_pathname: $!";
- print STATS "Statistics of $gnats_db_dir collated by gnats2bz.pl.\n";
- my($field_stats);
- while (($field, $field_stats) = each(%pr_stats)) {
- print STATS "\n$field:\n";
- while (($value, $count) = each(%$field_stats)) {
- print STATS " $value: $count\n";
- }
- }
- close(STATS) || die "Unable to close $stats_pathname: $!";
- }
- sub get_userid {
- my($responsible) = @_;
- my($username, $userid);
- if (!defined($responsible)) {
- return(-1);
- }
- # Search for current username in the list.
- $userid = $userid_base;
- foreach $username (@username_list) {
- if ($username eq $responsible) {
- return($userid);
- }
- $userid++;
- }
- push(@username_list, $responsible);
- return($userid);
- }
- sub update_versions {
- if (!defined($pr_data{"Release"}) || !defined($pr_data{"Category"})) {
- return;
- }
- my($curr_product) = $pr_data{"Category"};
- my($curr_version) = $pr_data{"Release"};
- if ($curr_version eq "") {
- return;
- }
- if (!defined($versions_table{$curr_product})) {
- $versions_table{$curr_product} = [ ];
- }
- my($version_list) = $versions_table{$curr_product};
- my($version);
- foreach $version (@$version_list) {
- if ($version eq $curr_version) {
- return;
- }
- }
- push(@$version_list, $curr_version);
- }
- sub write_bugs {
- my($bug_id) = $pr_data{"Number"};
- my($userid) = get_userid($pr_data{"Responsible"});
- # Mapping from Class,Severity to bug_severity
- # At our site, the Severity,Priority fields have degenerated
- # into a 9-level priority field.
- my($bug_severity) = "normal";
- if ($pr_data{"Class"} eq "change-request") {
- $bug_severity = "enhancement";
- } elsif (defined($pr_data{"Synopsis"})) {
- if ($pr_data{"Synopsis"} =~ /crash|assert/i) {
- $bug_severity = "critical";
- } elsif ($pr_data{"Synopsis"} =~ /wrong|error/i) {
- $bug_severity = "major";
- }
- }
- $bug_severity = SqlQuote($bug_severity);
- # Mapping from Severity,Priority to priority
- # At our site, the Severity,Priority fields have degenerated
- # into a 9-level priority field.
- my($priority) = "P1";
- if (defined($pr_data{"Severity"}) && defined($pr_data{"Severity"})) {
- if ($pr_data{"Severity"} eq "critical") {
- if ($pr_data{"Priority"} eq "high") {
- $priority = "P1";
- } else {
- $priority = "P2";
- }
- } elsif ($pr_data{"Severity"} eq "serious") {
- if ($pr_data{"Priority"} eq "low") {
- $priority = "P4";
- } else {
- $priority = "P3";
- }
- } else {
- if ($pr_data{"Priority"} eq "high") {
- $priority = "P4";
- } else {
- $priority = "P5";
- }
- }
- }
- $priority = SqlQuote($priority);
- # Map State,Class to bug_status,resolution
- my($bug_status, $resolution);
- if ($pr_data{"State"} eq "open" || $pr_data{"State"} eq "analyzed") {
- $bug_status = "ASSIGNED";
- $resolution = "";
- } elsif ($pr_data{"State"} eq "feedback") {
- $bug_status = "RESOLVED";
- $resolution = "FIXED";
- } elsif ($pr_data{"State"} eq "closed") {
- $bug_status = "CLOSED";
- if (defined($pr_data{"Class"}) && $pr_data{"Class"} =~ /^duplicate/) {
- $resolution = "DUPLICATE";
- } elsif (defined($pr_data{"Class"}) && $pr_data{"Class"} =~ /^mistaken/) {
- $resolution = "INVALID";
- } else {
- $resolution = "FIXED";
- }
- } elsif ($pr_data{"State"} eq "suspended") {
- $bug_status = "RESOLVED";
- $resolution = "WONTFIX";
- } else {
- $bug_status = "NEW";
- $resolution = "";
- }
- $bug_status = SqlQuote($bug_status);
- $resolution = SqlQuote($resolution);
- my($creation_ts) = "";
- if (defined($pr_data{"Arrival-Date"}) && $pr_data{"Arrival-Date"} ne "") {
- $creation_ts = unixdate2datetime($bug_id, $pr_data{"Arrival-Date"});
- }
- $creation_ts = SqlQuote($creation_ts);
- my($delta_ts) = "";
- if (defined($pr_data{"Audit-Trail"})) {
- # note that (?:.|\n)+ is greedy, so this should match the
- # last Changed-When
- if ($pr_data{"Audit-Trail"} =~ /(?:.|\n)+-Changed-When: (.+)/) {
- $delta_ts = unixdate2timestamp($bug_id, $1);
- }
- }
- if ($delta_ts eq "") {
- if (defined($pr_data{"Arrival-Date"}) && $pr_data{"Arrival-Date"} ne "") {
- $delta_ts = unixdate2timestamp($bug_id, $pr_data{"Arrival-Date"});
- }
- }
- $delta_ts = SqlQuote($delta_ts);
- my($short_desc) = SqlQuote($pr_data{"Synopsis"});
- my($rep_platform, $op_sys) = split(/\|/, $pr_data{"Environment"});
- $rep_platform = SqlQuote($rep_platform);
- $op_sys = SqlQuote($op_sys);
- my($reporter) = get_userid($gnats_username);
- if (
- defined($pr_data{"Mail-Header"}) &&
- $pr_data{"Mail-Header"} =~ /From ([\w.]+\@[\w.]+)/
- ) {
- $reporter = get_userid($1);
- }
- my($version) = "";
- if (defined($pr_data{"Release"})) {
- $version = substr($pr_data{"Release"}, 0, 16);
- }
- $version = SqlQuote($version);
- my($product) = "";
- if (defined($pr_data{"Category"})) {
- $product = $pr_data{"Category"};
- }
- $product = SqlQuote($product);
- my($component) = SqlQuote($default_component);
- my($target_milestone) = "0";
- # $target_milestone = SqlQuote($target_milestone);
- my($qa_contact) = "0";
- # my($bug_file_loc) = "";
- # $bug_file_loc = SqlQuote($bug_file_loc);
- # my($status_whiteboard) = "";
- # $status_whiteboard = SqlQuote($status_whiteboard);
- print DATA "\ninsert into bugs (\n";
- print DATA " bug_id, assigned_to, bug_severity, priority, bug_status, creation_ts, delta_ts,\n";
- print DATA " short_desc,\n";
- print DATA " rep_platform, op_sys, reporter, version,\n";
- print DATA " product, component, resolution, target_milestone, qa_contact\n";
- print DATA ") values (\n";
- print DATA " $bug_id, $userid, $bug_severity, $priority, $bug_status, $creation_ts, $delta_ts,\n";
- print DATA " $short_desc,\n";
- print DATA " $rep_platform, $op_sys, $reporter, $version,\n";
- print DATA " $product, $component, $resolution, $target_milestone, $qa_contact\n";
- print DATA ");\n";
- }
- sub write_longdescs {
- my($bug_id) = $pr_data{"Number"};
- my($who) = get_userid($pr_data{"Responsible"});;
- my($bug_when) = "";
- if (defined($pr_data{"Arrival-Date"}) && $pr_data{"Arrival-Date"} ne "") {
- $bug_when = unixdate2datetime($bug_id, $pr_data{"Arrival-Date"});
- }
- $bug_when = SqlQuote($bug_when);
- my($thetext) = $pr_data{"Description"};
- if (defined($pr_data{"How-To-Repeat"}) && $pr_data{"How-To-Repeat"} ne "") {
- $thetext =
- $thetext . "\n\nHow-To-Repeat:\n" . $pr_data{"How-To-Repeat"};
- }
- if (defined($pr_data{"Fix"}) && $pr_data{"Fix"} ne "") {
- $thetext = $thetext . "\n\nFix:\n" . $pr_data{"Fix"};
- }
- if (defined($pr_data{"Originator"}) && $pr_data{"Originator"} ne "") {
- $thetext = $thetext . "\n\nOriginator:\n" . $pr_data{"Originator"};
- }
- if (defined($pr_data{"Organization"}) && $pr_data{"Organization"} ne "") {
- $thetext = $thetext . "\n\nOrganization:\n" . $pr_data{"Organization"};
- }
- if (defined($pr_data{"Audit-Trail"}) && $pr_data{"Audit-Trail"} ne "") {
- $thetext = $thetext . "\n\nAudit-Trail:\n" . $pr_data{"Audit-Trail"};
- }
- if (defined($pr_data{"Unformatted"}) && $pr_data{"Unformatted"} ne "") {
- $thetext = $thetext . "\n\nUnformatted:\n" . $pr_data{"Unformatted"};
- }
- $thetext = SqlQuote($thetext);
- print DATA "\ninsert into longdescs (\n";
- print DATA " bug_id, who, bug_when, thetext\n";
- print DATA ") values (\n";
- print DATA " $bug_id, $who, $bug_when, $thetext\n";
- print DATA ");\n";
- }
- sub write_non_bugs_tables {
- my($categories_record);
- foreach $categories_record (@categories_list) {
- my($component) = SqlQuote($default_component);
- my($product) = SqlQuote(@$categories_record[0]);
- my($description) = SqlQuote(@$categories_record[1]);
- my($initialowner) = SqlQuote(@$categories_record[2] . $username_suffix);
- print DATA "\ninsert into products (\n";
- print DATA
- " product, description, milestoneurl, disallownew\n";
- print DATA ") values (\n";
- print DATA
- " $product, $description, '', 0\n";
- print DATA ");\n";
- print DATA "\ninsert into components (\n";
- print DATA
- " value, program, initialowner, initialqacontact, description\n";
- print DATA ") values (\n";
- print DATA
- " $component, $product, $initialowner, '', $description\n";
- print DATA ");\n";
- print DATA "\ninsert into milestones (\n";
- print DATA
- " value, product, sortkey\n";
- print DATA ") values (\n";
- print DATA
- " 0, $product, 0\n";
- print DATA ");\n";
- }
- my($username);
- my($userid) = $userid_base;
- my($password) = "password";
- my($realname);
- my($groupset) = 0;
- foreach $username (@username_list) {
- $realname = map_username_to_realname($username);
- $username = SqlQuote($username);
- $realname = SqlQuote($realname);
- print DATA "\ninsert into profiles (\n";
- print DATA
- " userid, login_name, cryptpassword, realname, groupset\n";
- print DATA ") values (\n";
- print DATA
- " $userid, $username, encrypt('$password'), $realname, $groupset\n";
- print DATA ");\n";
- $userid++;
- }
- my($product);
- my($version_list);
- while (($product, $version_list) = each(%versions_table)) {
- $product = SqlQuote($product);
- my($version);
- foreach $version (@$version_list) {
- $version = SqlQuote($version);
- print DATA "\ninsert into versions (value, program) ";
- print DATA "values ($version, $product);\n";
- }
- }
- }
- sub map_username_to_realname() {
- my($username) = @_;
- my($name, $realname);
- # get the portion before the @
- $name = $username;
- $name =~ s/\@.*//;
- my($responsible_record);
- foreach $responsible_record (@responsible_list) {
- if (@$responsible_record[0] eq $name) {
- return(@$responsible_record[1]);
- }
- if (defined(@$responsible_record[2])) {
- if (@$responsible_record[2] eq $username) {
- return(@$responsible_record[1]);
- }
- }
- }
- return("");
- }
- sub detaint_string {
- my ($str) = @_;
- $str =~ m/^(.*)$/s;
- $str = $1;
- }
- sub SqlQuote {
- my ($str) = (@_);
- $str =~ s/([\\\'])/\\$1/g;
- $str =~ s/\0/\\0/g;
- # If it's been SqlQuote()ed, then it's safe, so we tell -T that.
- $str = detaint_string($str);
- return "'$str'";
- }
- sub unixdate2datetime {
- my($bugid, $unixdate) = @_;
- my($year, $month, $day, $hour, $min, $sec);
- if (!split_unixdate($bugid, $unixdate, \$year, \$month, \$day, \$hour, \$min, \$sec)) {
- return("");
- }
- return("$year-$month-$day $hour:$min:$sec");
- }
- sub unixdate2timestamp {
- my($bugid, $unixdate) = @_;
- my($year, $month, $day, $hour, $min, $sec);
- if (!split_unixdate($bugid, $unixdate, \$year, \$month, \$day, \$hour, \$min, \$sec)) {
- return("");
- }
- return("$year$month$day$hour$min$sec");
- }
- sub split_unixdate {
- # "Tue Jun 6 14:50:00 1995"
- # "Mon Nov 20 17:03:11 [MST] 1995"
- # "12/13/94"
- # "jan 1, 1995"
- my($bugid, $unixdate, $year, $month, $day, $hour, $min, $sec) = @_;
- my(@parts);
- $$hour = "00";
- $$min = "00";
- $$sec = "00";
- @parts = split(/ +/, $unixdate);
- if (@parts >= 5) {
- # year
- $$year = $parts[4];
- if ($$year =~ /[A-Z]{3}/) {
- # Must be timezone, try next field.
- $$year = $parts[5];
- }
- if ($$year =~ /\D/) {
- warn "$bugid: Error processing year part '$$year' of date '$unixdate'\n";
- return(0);
- }
- if ($$year < 30) {
- $$year = "20" . $$year;
- } elsif ($$year < 100) {
- $$year = "19" . $$year;
- } elsif ($$year < 1970 || $$year > 2029) {
- warn "$bugid: Error processing year part '$$year' of date '$unixdate'\n";
- return(0);
- }
- # month
- $$month = $parts[1];
- if ($$month =~ /\D/) {
- if (!month2number($month)) {
- warn "$bugid: Error processing month part '$$month' of date '$unixdate'\n";
- return(0);
- }
- } elsif ($$month < 1 || $$month > 12) {
- warn "$bugid: Error processing month part '$$month' of date '$unixdate'\n";
- return(0);
- } elsif (length($$month) == 1) {
- $$month = "0" . $$month;
- }
- # day
- $$day = $parts[2];
- if ($$day < 1 || $$day > 31) {
- warn "$bugid: Error processing day part '$day' of date '$unixdate'\n";
- return(0);
- } elsif (length($$day) == 1) {
- $$day = "0" . $$day;
- }
- @parts = split(/:/, $parts[3]);
- $$hour = $parts[0];
- $$min = $parts[1];
- $$sec = $parts[2];
- return(1);
- } elsif (@parts == 3) {
- # year
- $$year = $parts[2];
- if ($$year =~ /\D/) {
- warn "$bugid: Error processing year part '$$year' of date '$unixdate'\n";
- return(0);
- }
- if ($$year < 30) {
- $$year = "20" . $$year;
- } elsif ($$year < 100) {
- $$year = "19" . $$year;
- } elsif ($$year < 1970 || $$year > 2029) {
- warn "$bugid: Error processing year part '$$year' of date '$unixdate'\n";
- return(0);
- }
- # month
- $$month = $parts[0];
- if ($$month =~ /\D/) {
- if (!month2number($month)) {
- warn "$bugid: Error processing month part '$$month' of date '$unixdate'\n";
- return(0);
- }
- } elsif ($$month < 1 || $$month > 12) {
- warn "$bugid: Error processing month part '$$month' of date '$unixdate'\n";
- return(0);
- } elsif (length($$month) == 1) {
- $$month = "0" . $$month;
- }
- # day
- $$day = $parts[1];
- $$day =~ s/,//;
- if ($$day < 1 || $$day > 31) {
- warn "$bugid: Error processing day part '$day' of date '$unixdate'\n";
- return(0);
- } elsif (length($$day) == 1) {
- $$day = "0" . $$day;
- }
- return(1);
- }
- @parts = split(/:/, $unixdate);
- if (@parts == 3 && length($unixdate) <= 8) {
- $$year = "19" . $parts[2];
- $$month = $parts[0];
- if (length($$month) == 1) {
- $$month = "0" . $$month;
- }
- $$day = $parts[1];
- if (length($$day) == 1) {
- $$day = "0" . $$day;
- }
- return(1);
- }
- warn "$bugid: Error processing date '$unixdate'\n";
- return(0);
- }
- sub month2number {
- my($month) = @_;
- if ($$month =~ /jan/i) {
- $$month = "01";
- } elsif ($$month =~ /feb/i) {
- $$month = "02";
- } elsif ($$month =~ /mar/i) {
- $$month = "03";
- } elsif ($$month =~ /apr/i) {
- $$month = "04";
- } elsif ($$month =~ /may/i) {
- $$month = "05";
- } elsif ($$month =~ /jun/i) {
- $$month = "06";
- } elsif ($$month =~ /jul/i) {
- $$month = "07";
- } elsif ($$month =~ /aug/i) {
- $$month = "08";
- } elsif ($$month =~ /sep/i) {
- $$month = "09";
- } elsif ($$month =~ /oct/i) {
- $$month = "10";
- } elsif ($$month =~ /nov/i) {
- $$month = "11";
- } elsif ($$month =~ /dec/i) {
- $$month = "12";
- } else {
- return(0);
- }
- return(1);
- }
|