diff options
-rw-r--r-- | contrib/gnats2bz.pl | 1012 |
1 files changed, 1012 insertions, 0 deletions
diff --git a/contrib/gnats2bz.pl b/contrib/gnats2bz.pl new file mode 100644 index 000000000..449fb4424 --- /dev/null +++ b/contrib/gnats2bz.pl @@ -0,0 +1,1012 @@ +#!/usr/bin/perl -w +# -*- Mode: perl; indent-tabs-mode: nil -*- +# +# The contents of this file are subject to the Mozilla Public License +# Version 1.0 (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. +# +# 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' < gnats2bz_data.sql +# 10) 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. +# + +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; + +# First generated userid. +my($userid_base) = 10; + +# 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_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 = "LATER"; + } 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($long_desc) = $pr_data{"Description"}; + if (defined($pr_data{"How-To-Repeat"}) && $pr_data{"How-To-Repeat"} ne "") { + $long_desc = + $long_desc . "\n\nHow-To-Repeat:\n" . $pr_data{"How-To-Repeat"}; + } + if (defined($pr_data{"Fix"}) && $pr_data{"Fix"} ne "") { + $long_desc = $long_desc . "\n\nFix:\n" . $pr_data{"Fix"}; + } + if (defined($pr_data{"Originator"}) && $pr_data{"Originator"} ne "") { + $long_desc = $long_desc . "\n\nOriginator:\n" . $pr_data{"Originator"}; + } + if (defined($pr_data{"Organization"}) && $pr_data{"Organization"} ne "") { + $long_desc = $long_desc . "\n\nOrganization:\n" . $pr_data{"Organization"}; + } + if (defined($pr_data{"Audit-Trail"}) && $pr_data{"Audit-Trail"} ne "") { + $long_desc = $long_desc . "\n\nAudit-Trail:\n" . $pr_data{"Audit-Trail"}; + } + if (defined($pr_data{"Unformatted"}) && $pr_data{"Unformatted"} ne "") { + $long_desc = $long_desc . "\n\nUnformatted:\n" . $pr_data{"Unformatted"}; + } + $long_desc = SqlQuote($long_desc); + + 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) = ""; + my($component) = ""; + if (defined($pr_data{"Category"})) { + $product = $pr_data{"Category"}; + $component = $product; + } + $product = SqlQuote($product); + $component = SqlQuote($component); + + my($target_milestone) = ""; + $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 " long_desc\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 " $long_desc\n"; + print DATA ");\n"; +} + +sub write_non_bugs_tables { + + my($categories_record); + foreach $categories_record (@categories_list) { + 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, 'NULL', 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 + " $product, $product, $initialowner, 'NULL', $description\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, password, cryptpassword, realname, groupset\n"; + print DATA ") values (\n"; + print DATA + " $userid, $username, '$password', 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(""); +} + +# This routine was copied from globals.pl which was largely copied +# from Mysql.pm. +sub SqlQuote { + my($str) = @_; + $str =~ s/([\\\'])/\\$1/g; + $str =~ s/\0/\\0/g; + 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); +} + |