Login | Register
My pages Projects Community openCollabNet

Discussions > cvs > CVS update: /kamikaze-qscm/src/kamikaze-qscm/, /kamikaze-qscm/src/kamikaze-qscm/db/, /kamikaze-qscm/src/kamikaze-qscm/hooks/, /kamikaze-qscm/src/kamikaze-qscm/html/

kamikaze-qscm
Discussion topic

Back to topic list

CVS update: /kamikaze-qscm/src/kamikaze-qscm/, /kamikaze-qscm/src/kamikaze-qscm/db/, /kamikaze-qscm/src/kamikaze-qscm/hooks/, /kamikaze-qscm/src/kamikaze-qscm/html/

Reply

Author jduprey
Full name John Duprey
Date 2004-09-20 21:25:15 PDT
Message User: jduprey
Date: 04/09/20 21:25:15

Added:
 /kamikaze-qscm/src/k​amikaze-qscm/
  README.txt, RELNOTES.txt, TODO.txt, kamikaze.vpj, kamikaze.vpw
 /kamikaze-qscm/src/k​amikaze-qscm/db/
  author.sql, createdb.sql, repository.sql, resource.sql, revision.sql
 /kamikaze-qscm/src/k​amikaze-qscm/hooks/
  commit2db.pl
 /kamikaze-qscm/src/k​amikaze-qscm/html/
  config.inc, index.php, query.php

Log:
 This is the initial release of Kamikaze-QSCM version 0.1.

File Changes:

Directory: /kamikaze-qscm/src/k​amikaze-qscm/
====================​====================​====

File [added]: README.txt
Url: http://kamikaze-qscm​.tigris.org/source/b​rowse/kamikaze-qscm/​src/kamikaze-qscm/RE​ADME.txt?rev=1.1​&content-type=text/v​nd.viewcvs-markup
Added lines: 243
----------------
This README file is for Kamikaze-QSCM a source control query tool for
the Subversion (http://subversion.tigris.org) tool.

For best viewing,set your tab width to 4.

== Table of Contents ==
    [1] Introduction
    [2] Requirements
    [3] Getting Kamikaze-QSCM
    [4] Installation
    [5] Usage
    [6] Reporting problems and getting help

To jumpt to a specific heading, just search for "[#]" where
number is the topic number.

== [1] Introduction ==
    Kamikaze-QSCM is a tool that allows developers and CM related
    personnel to query the commits made to one or more source control
    repositories. It is very similar to Mozilla's bonsai tool.
    Kamikaze-QSCM currently works with Subversion, but a modular
    approach is planned for other SCM systems.
    
    Kamikaze for Subversion currently consists of a PERL back-end hook
    for inserting commit information into a MySQL database.
    (In the future, a modular approach to data storage is planned -
    allowing the use of many different data storage implementations. )
    A PHP front-end is used to perform repository queries and display
    results. (In the future a web service API (XML-RPC and/or SOAP)
    will be provided to access the same information for incorporation
    into other tools.)
    
    For the latest news and information visit: http://kamikaze-QSCM​.tigris.org.

== [2] Requirements ==
    * PHP with MySQL support
    * Perl::DBI with MySQL support

== [3] Getting Kamikaze-QSCM ==
    Kamikaze can be downloaded from the Kamikaze project site:
    http://kamikaze-QSCM.tigris.org
    
    If you have CVS access you can download the latest versions from here:
    http://kamikaze-QSCM​.tigris.org/source/b​rowse/kamikaze-QSCM/​src/
    
    Otherwise you can get the latest official releases here:
    http://kamikaze-QSCM​.tigris.org/servlets​/ProjectDocumentList​?folderID=3549
    
    Releases are packaged in tarball form and compressed using gzip.
    Winzip, and other gzip utilizes usually support extracting files from
    the tar format as well. In the GNU world you can type the
    following from a command prompt:
    tar -zxvf kamikaze-qscm.v0_1.tgz
    
    This will create a folder called kamikaze-qscm in the current
    working directory.

== [4] Installation ==
    This section assumes that you successfully got the latest version as
    described in [3]. You should have a folder called kamikaze-QSCM in a
    temporary folder. You should see directory contents similar to the
    following:
    
    * README.txt - this file
    * RELNOTES.txt - release notes
    * db/ - sql files for creating the necessary MySQL tables.
    * hooks/ - PERL back-end scripts for hooking into Subversion commit information
    * html/ - PHP front for performing queries on commits
    
    Perform the following steps:
    
    1) Create MySQL Database and Tables
    You must have a working MySQL database and a valid user(s) that can
    perform the necessary operations:
    * During Installation: CREATE DATABASE, CREATE TABLE
    * To use Kamikaze-QSCM: INSERT, UPDATE, SELECT
    
    For security reasons you may wish to use separate users - one for
    installing the database and tables, another for populating it with
    data.
    
        1.1) Create the database and tables by changing directory to
        db/ and execute the MySQL SQL code in createdb.sql as follows:
        
        mysql < createdb.sql
        
        depending on your mysql set-up you may need to specify
        the user and password:
        
        mysql -u username -p < createdb.sql
        
        Confirm that a database called svncommits now exists in MySQL and
        that the following tables exist:
        * author
        * repository
        * revision
        * resource
    
    2) Install the web interface
    
        2.1) Copy the html directory to a location that is accessible
        to your web server. Your web server must support PHP
        (with MySQL support).
        e.g. On 'NIX platforms:
        
            cp html /var/www/html/kamikaze
            cd /var/www/html
        
        2.2) Change ownership of the kamikaze directory accordingly:
        e.g. On 'NIX platforms:
        
            chown -R apache:apache /var/www/html/kamikaze
            chmod ug+rwX /var/www/html/kamikaze
        
        2.3) View the page in your browser
        Visit the Kamikaze web interface in your web browser.
        e.g.
            http://your-host/kamikaze
            
        You should see a query form with no entries for Repository
        or User except "**ALL**". This will change as commits are
        captured from Subversion.
    
    3) To get the commit information, Kamikaze requires that you
    install a post-commit hook that will populate the tables.
    You must do this for every repository that wish to query.
    Change directory to hooks/
    
        3.1) Edit commit2db.pl
        
            3.1.1) On the very first line:
            #!/usr/bin/PERL -w
            Change "/usr/bin/PERL" to the path to your PERL
            executable if your path is different.
            
            3.1.2) Edit the "# Kamikaze DB information" section to
            match your database settings:
            Set $host to the hostname that hosts your database:
            my $host = 'localhost';
    
            Set $db to the name of the kamikaze database that was created
            - svncommits was the default - you shouldn't have to change
            this:
            my $db = 'svncommits';
            
            Set $db_user and $db_password to the database user and
            password that has, at the very least, SELECT privileges
            on MySQL db $db:
            my $db_user = 'svnuser';
            my $db_password = 'svnuser';
            
            
            3.1.3) Edit the "# Svnlook path" section:
            Set $tmp_dir to a location that the web server user may write
            temporary data:
            my $tmp_dir = '/tmp';
            
            Set $svnlook to be the full path to the svnlook
            Subversion utility:
            my $svnlook = "/usr/bin/svnlook";
        
        3.2) Test commit2db.pl by calling it manually:
        PERL ./commit2db.pl /path/to/repository 1
        This command *should* insert the very first revision info
        for the repository at /path/to/repository

        e.g.
                $ PERL ./commit2db.pl /home/svnroot/repos1 1
        Repos:/home/svnroot/repos1, rev:1
        New repository /home/svnroot/repos1 with id 1.
        Created new author jduprey with id 1.
        
        If you refresh the Kamikaze query web page you will see that
        the repository has been added to Repository and the relevant
        user for revision 1 has been added as well. Click
        "Since the beginning of time" in the "Date Options" section of
        the query form and you should see the commit information for
        rev 1.
        
        3.3) Install the post-commit hook for each repository
        you wish to monitor. Refer to the subversion
        documentation for how to install hooks:
        * http://svnbook.red-bean.com/
        * Specifically (Subversion 1.1) http://svnbook.red-b​ean.com/svnbook-1.1/​svn-book.html#svn-ch​-5-sect-2.1
        
        If you have not already created a post-commit hook, you
        *should* be able to simply copy commit2db.pl
        to /path/to/repository/​hooks/post-commit
        Change its permissions accordingly - giving it execute
        permissions for the subversion user user.
        
        Alternatively you can call commit2db.pl from within an
        existing post-commit script as follows:
        /usr/bin/PERL /home/svnroot/repos1​/hooks/commit2db.pl $REPOS $REV
        
        The above example assumes that the post-commit script has defined the
        repository and revision for the variables $REPOS and $REV respectively.
        (It also assumes that commit2db.pl was copied to the hooks
        directory. A symbolic link could also be used to avoid
        multiple copies as long as the permissions were appropriate.)
        
        If you can, test the Kamikaze hook by, committing something
        to the repository.
        
        3.4) You may, optionally, back-fill commit information for each
        repository by calling commit2db.pl with 0 as the revision.
        e.g.
            perl ./commit2db.pl /path/to/revision 0
        
        This will collect all commits since the first revision 1.
        For repositories with a large revision history, it can
        take a while to populate.

== [5] Usage ==
    You're on your own for now. ;)

== [6] Reporting problems and getting help ==
    == BUGS ==
    If you think you've found a bug, please first check the RELNOTES.txt
    file. This may explain any known issues with the software.
    Second, check the open issues with Kamikaze here:
    http://kamikaze-QSCM​.tigris.org/servlets​/ProjectIssues
    
    == Help ==
    If you are having problems installing or using Kamikaze, check the
    mailing list archives:
    http://kamikaze-QSCM​.tigris.org/servlets​/ProjectMailingListL​ist
    If you don't find anything useful there, join the appropriate list
    and ask.
    
    NOTE: Please make use of these resources *before* e-mailing me directly.
    Using a mailing list is the appropriate medium for help and the discussion
    is saved for posterity. It could help another person in the future.
    
    Lastly, if you still have not resolved your issue, please do contact me.
    
    I hope you find the software useful and not a waste of bits. ;>
    
    Sincerely,
    
    John Duprey
    jduprey at tigris dot org


File [added]: RELNOTES.txt
Url: http://kamikaze-qscm​.tigris.org/source/b​rowse/kamikaze-qscm/​src/kamikaze-qscm/RE​LNOTES.txt?rev=1.1​&content-type=text​/vnd.viewcvs-markup
Added lines: 15
---------------
== Kamikaze-QSCM 0.1 ==
Release : 0.1

Description : This is the initial release of Kamikaze-QSCM.

New Features:
    1) Query commits by repository, user, file/dir path, log message,
    date, and commit action

Fixes : NA

Known Issues:
    1) Query date option: "In the last month" is currently broken. See
    defect: http://kamikaze-qscm​.tigris.org/issues/s​how_bug.cgi?id=2
    

File [added]: TODO.txt
Url: http://kamikaze-qscm​.tigris.org/source/b​rowse/kamikaze-qscm/​src/kamikaze-qscm/TO​DO.txt?rev=1.1&c​ontent-type=text/vnd​.viewcvs-markup
Added lines: 40
---------------
In general
- Clean up all the code so that I'm not ashamed of it.
- Put these TODO's into Tigris' issue tracker

commit2db.pl
- Validate revision number before trying to insert bogus rows into the db.
- Provide option to purge db of entries for a given repository - start from
    scratch..

*.php
- Limit results to the top N latest commits, make this an option with
    next, previous buttons, total count button
- Provide a custom sql query form
- Put hooks in for websvn


Big Plans...

- RSS support
- Web service API: XML-RPC and/or SOAP
- PHP modules for GForge, postnuke, etc...


- Subversion administration
    - Block repository
    - "On the hook concept"
    - Access control
    
- Provide query stats:
    - author count and list (with link to author info.)
    - repositor count and list (with link to repo info.)
    - files count
- Collect stats for
    - users:
        - total number of commits / per rep /total
        - lines changed / per rep / total
        - activity by date, time / per rep / total
    - repository
        - total number of commits
        

File [added]: kamikaze.vpj
Url: http://kamikaze-qscm​.tigris.org/source/b​rowse/kamikaze-qscm/​src/kamikaze-qscm/ka​mikaze.vpj?rev=1.1​&content-type=text​/vnd.viewcvs-markup
Added lines: 88
---------------
<!DOCTYPE Project SYSTEM "http://www.slickedit​.com/dtd/vse/9.1/vpj​.dtd">
<Project
    WorkingDir="."
    Version="9.1"
    VendorName="SlickEdit">
    <Config
        Name="Release"
        OutputFile=""
        CompilerConfigName="Latest Version">
        <Menu>
            <Target
                Name="Compile"
                MenuCaption="&amp;Compile"
                CaptureOutputWith="P​rocessBuffer"
                SaveOption="SaveCurrent"
                RunFromDir="%rw">
                <Exec/>
            </Target>
            <Target
                Name="Build"
                MenuCaption="&amp;Build"
                CaptureOutputWith="P​rocessBuffer"
                SaveOption="SaveWorkspaceFiles"
                RunFromDir="%rw">
                <Exec/>
            </Target>
            <Target
                Name="Rebuild"
                MenuCaption="&amp;Rebuild"
                CaptureOutputWith="P​rocessBuffer"
                SaveOption="SaveWorkspaceFiles"
                RunFromDir="%rw">
                <Exec/>
            </Target>
            <Target
                Name="Debug"
                MenuCaption="&amp;Debug"
                SaveOption="SaveNone"
                RunFromDir="%rw">
                <Exec/>
            </Target>
            <Target
                Name="Execute"
                MenuCaption="E&amp;xecute"
                SaveOption="SaveNone"
                RunFromDir="%rw">
                <Exec CmdLine='"kamikaze.exe"'/>
            </Target>
        </Menu>
    </Config>
    <CustomFolders>
        <Folder
            Name="Source Files"
            Filters="*.c;*.C;*.c​c;*.cpp;*.cp;*.cxx;*​.prg;*.pas;*.dpr;*.a​sm;*.s;*.bas;*.java;​*.cs;*.sc;*.e;*.cob;​*.html;*.rc;*.tcl;*.​py;*.pl">
        </Folder>
        <Folder
            Name="Header Files"
            Filters="*.h;*.H;*.h​h;*.hpp;*.hxx;*.inc;​*.sh;*.cpy;*.if"/​>
        <Folder
            Name="Resource Files"
            Filters="*.ico;*.cur​;*.dlg"/>
        <Folder
            Name="Bitmaps"
            Filters="*.bmp"/>
        <Folder
            Name="Other Files"
            Filters="">
        </Folder>
    </CustomFolders>
    <Files AutoFolders="DirectoryView">
        <Folder Name="db">
            <F N="db/author.sql"/>
            <F N="db/createdb.sql"/>
            <F N="db/repository.sql"/>
            <F N="db/resource.sql"/>
            <F N="db/revision.sql"/>
        </Folder>
        <Folder Name="hooks">
            <F N="hooks/commit2db.pl"/>
        </Folder>
        <Folder Name="html">
            <F N="html/index.php"/>
            <F N="html/query.php"/>
        </Folder>
        <F N="README.txt"/>
        <F N="TODO.txt"/>
    </Files>
</Project>

File [added]: kamikaze.vpw
Url: http://kamikaze-qscm​.tigris.org/source/b​rowse/kamikaze-qscm/​src/kamikaze-qscm/ka​mikaze.vpw?rev=1.1​&content-type=text​/vnd.viewcvs-markup
Added lines: 6
--------------
<!DOCTYPE Workspace SYSTEM "http://www.slickedit​.com/dtd/vse/9.1/vpw​.dtd">
<Workspace Version="9.1" VendorName="SlickEdit">
    <Projects>
        <Project File="kamikaze.vpj"/>
    </Projects>
</Workspace>

Directory: /kamikaze-qscm/src/k​amikaze-qscm/db/
====================​====================​=======

File [added]: author.sql
Url: http://kamikaze-qscm​.tigris.org/source/b​rowse/kamikaze-qscm/​src/kamikaze-qscm/db​/author.sql?rev=1.1​&content-type=tex​t/vnd.viewcvs-markup​
Added lines: 13
---------------
CREATE TABLE IF NOT EXISTS author (
  id int(11) NOT NULL auto_increment,
  rep_id int(11) unsigned NOT NULL default '0',
  user varchar(254) NOT NULL default '',
  full_name varchar(254) default NULL,
  email varchar(254) default NULL,
  url tinytext,
  picture tinytext,
  comment text,
  UNIQUE KEY id (id),
  PRIMARY KEY( rep_id, user)
) TYPE=InnoDB


File [added]: createdb.sql
Url: http://kamikaze-qscm​.tigris.org/source/b​rowse/kamikaze-qscm/​src/kamikaze-qscm/db​/createdb.sql?rev=1.​1&content-type=t​ext/vnd.viewcvs-mark​up
Added lines: 14
---------------
CREATE DATABASE IF NOT EXISTS svncommits;
USE svncommits;

SOURCE author.sql;
SOURCE repository.sql;
SOURCE revision.sql;
SOURCE resource.sql;
SOURCE commitlog.sql;







File [added]: repository.sql
Url: http://kamikaze-qscm​.tigris.org/source/b​rowse/kamikaze-qscm/​src/kamikaze-qscm/db​/repository.sql?rev=​1.1&content-type​=text/vnd.viewcvs-ma​rkup
Added lines: 9
--------------
CREATE TABLE IF NOT EXISTS repository (
  id tinyint(4) NOT NULL auto_increment,
  repository varchar(254) NOT NULL default '',
  alias varchar(254) default NULL,
  owner int(11) default NULL,
  UNIQUE KEY id (id),
  PRIMARY KEY (id),
  KEY (repository)
) TYPE=InnoDB

File [added]: resource.sql
Url: http://kamikaze-qscm​.tigris.org/source/b​rowse/kamikaze-qscm/​src/kamikaze-qscm/db​/resource.sql?rev=1.​1&content-type=t​ext/vnd.viewcvs-mark​up
Added lines: 10
---------------
CREATE TABLE IF NOT EXISTS resource
(
  id int(11) unsigned NOT NULL auto_increment,
  rev_id int(11) unsigned NOT NULL default '0',
  rep_id int(11) NOT NULL default '0',
  resource VARCHAR(255) NOT NULL,
  action CHAR(1) DEFAULT '-',
  PRIMARY KEY(rev_id, rep_id,resource ),
  KEY(id)
) TYPE=InnoDB

File [added]: revision.sql
Url: http://kamikaze-qscm​.tigris.org/source/b​rowse/kamikaze-qscm/​src/kamikaze-qscm/db​/revision.sql?rev=1.​1&content-type=t​ext/vnd.viewcvs-mark​up
Added lines: 12
---------------
CREATE TABLE IF NOT EXISTS revision
(
  id int(11) unsigned NOT NULL auto_increment,
  rev int(11) unsigned NOT NULL default 0,
  rep_id int(11) NOT NULL default 0,
  author_id int(11) NOT NULL default 0,
  date datetime NOT NULL default '0000-00-00 00:00:00',
  log text,
  UNIQUE KEY id (id),
  PRIMARY KEY (rep_id,rev),
  FULLTEXT KEY log (log)
) TYPE=MyISAM

Directory: /kamikaze-qscm/src/k​amikaze-qscm/hooks/
====================​====================​==========

File [added]: commit2db.pl
Url: http://kamikaze-qscm​.tigris.org/source/b​rowse/kamikaze-qscm/​src/kamikaze-qscm/ho​oks/commit2db.pl?rev​=1.1&content-typ​e=text/vnd.viewcvs-m​arkup
Added lines: 347
----------------
#!/usr/bin/perl -w

## NOTE: I borrowed the safe_read_from_pipe() and read_from_process()
## functions with some modification from the subversion
## repo-tools/hook-scripts directory.

use strict;
use DBI;

# Kamikaze DB information
my $host = 'localhost';
my $db = 'svncommits';
my $db_user = 'svnuser';
my $db_password = 'svnuser';

# Svnlook path.
my $tmp_dir = '/tmp';
my $svnlook = "/usr/bin/svnlook";

my($repos, $rev) = @ARGV;

#############
## EXECUTE ##
my $dbh = open_dbi( $host, $db, $db_user, $db_password );

commit2db( $repos, $rev, 0 );
$dbh->disconnect or warn "Disconnection failed: $DBI::errstr\n";
exit;
#############

#############################
## Functions

sub commit2db
{
   my($repos, $rev, $quiet) = @_;

   if( 1 != $quiet )
   {
       print("Repos:$repos, rev:$rev\n");
   }

   if( $rev <= 0 )
   {
       my @youngestRevLines =
           &read_from_proce​ss($svnlook, 'youngest', $repos);
       my $latestRev = shift @youngestRevLines;

       print("Rebuilding commit log info for $repos revisions 1 - $latestRev.\n");
       for( my $i = 1; $i <= $latestRev; $i++ )
       {
           print(".");
           commit2db( $repos, $i, 1 );
       }
       print( "\n$latestRev revisions logged. Done.\n" );
       return(0);
   }

   ####################​####################​####################​##########
   # Harvest data using svnlook.
   
   # Change into /tmp so that svnlook diff can create its .svnlook
   # directory.
   chdir($tmp_dir) or die "$0: cannot chdir `$tmp_dir': $!\n";

   # Get the author, date, and log from svnlook.
   my @svnlooklines = &read_from_proce​ss($svnlook, 'info', $repos, '-r', $rev);
   my $author = shift @svnlooklines;
   my $date = shift @svnlooklines;
   shift @svnlooklines;
   my @log = map { "$_\n" } @svnlooklines;
   
   # Figure out what directories have changed using svnlook.
   my @dirschanged = &read_from_proce​ss($svnlook, 'dirs-changed', $repos,
                                        '-r', $rev);
   # Lose the trailing slash in the directory names if one exists, except
   # in the case of '/'.
   my $rootchanged = 0;
   for (my $i=0; $i<@dirschanged; ++$i)
   {
     if ($dirschanged[$i] eq '/')
     {
        $rootchanged = 1;
     }
     else
     {
        $dirschanged[$i] =~ s#^(.+)[/\\]$#$1#;
     }
   }
   
   # Figure out what files have changed using svnlook.
   @svnlooklines = &read_from_proce​ss($svnlook, 'changed', $repos, '-r', $rev);

   my $textLog = "@log";
   my $insertID = -1;
   my $repID = -1;
   my $authorID = -1;
   ($insertID, $repID, $authorID) =
       insertRevisionIntoDB( $dbh, $rev, $repos, $author, $date, $textLog );
   if( $insertID == -1 )
   {
       print "Failed to insert the revision into the DB.\n";
       return( 1 );
   }
   
   
   # Parse the changed nodes.
   my @adds;
   my @dels;
   my @mods;
   foreach my $line (@svnlooklines)
   {
       my $path = '';
       my $code = '';
   
       # Split the line up into the modification code and path, ignoring
       # property modifications.
       if ($line =~ /^(.). (.*)$/)
       {
          $code = $1;
          $path = $2;
       }
   
       if ($code eq 'A')
       {
         push(@adds, $path);
       }
       elsif ($code eq 'D')
       {
         push(@dels, $path);
       }
       else
       {
           push(@mods, $path);
       }
   }

   foreach my $item (@adds)
   {
      insertResourceIntoDB($dbh, $insertID, $repID, $item, 'A' );
   }

   foreach my $item (@mods)
   {
      insertResourceIntoDB($dbh, $insertID, $repID, $item, 'M' );
   }

   foreach my $item (@dels)
    {
        insertResourceIntoDB($dbh, $insertID, $repID, $item, 'D');
    }
}


sub insertRevisionIntoDB
{
    my( $dbh, $rev, $repository, $author, $date, $log ) = @_;
## print( "$rev, $repository, $author, $date, $log\n" );

    my $sth;
    my $rep_id = -1;
    my $author_id = -1;

    ####################​####################​####################​
    ## Does the repository exist in the respository table?
    my $queryString = "SELECT id FROM repository where repository=" . $dbh->quote($repository);
    $rep_id = $dbh->selectrow_array( $queryString );
    if( !defined( $rep_id ) ) ## The repository doesn't already exist
    {
        my $revsth = $dbh->prepare(
            q{
                INSERT INTO repository( repository, alias, owner )
                    VALUES( ?, ?, ? )
            }) || die $dbh->errstr;
        $revsth->execute​($repository, $repository, $author_id) || die $dbh->errstr;

        $rep_id = $dbh->selectrow_array( $queryString );
        if( !defined($rep_id) ) ## The repository doesn't already exist
        {
            print( "Failed to insert repository: $repository.\n" );
            exit( 1 );
        }
        print( "New repository $repository with id $rep_id.\n" );
        $revsth->finish();
    }
    ####################​####################​####################​###

    ####################​####################​####################​###
    ## Does the author exist in the author table
    $queryString = "SELECT id FROM author where user=" . $dbh->quote($author) .
        " AND rep_id=" . $dbh->quote($rep_id);
    $author_id = $dbh->selectrow_array( $queryString );
    if( !defined($author_id) ) ## The author doesn't already exist
    {
        my $authorsth = $dbh->prepare(
            q{
                INSERT INTO author( rep_id, user, full_name )
                    VALUES( ?, ?, ? )
            }) || die $dbh->errstr;
        $authorsth->execute($rep_id, $author, $author);

        $author_id = $dbh->selectrow_array( $queryString );
        if( !defined($author_id) ) ## The repository doesn't already exist
        {
            print( "Failed to insert new author: $author.\n" );
            exit(1);
        }
        print( "Created new author $author with id $author_id.\n" );
        $authorsth->finish();
    }
    ####################​####################​####################​###

    ####################​####################​####################​###
    ## Insert a new revision entry
    $sth = $dbh->prepare(
    q{
        INSERT INTO revision( rev, rep_id, author_id, date, log )
                                VALUES (?, ?, ?, ?, ?)
    }) || die $dbh->errstr;
    $sth->execute($rev, $rep_id, $author_id, $date, $log) || warn $dbh->errstr;
    ####################​####################​####################​###

    ## Autocommit is on and this will produce an error emssage..
    ## $dbh->commit || die $dbh->errstr;

    ####################​####################​####################​###
    ## Get the revision id
    $sth = $dbh->prepare(
        q{
            SELECT id FROM revision WHERE rev = ? AND rep_id = ?
        }) || die $dbh->errstr;
    $sth->execute($rev, $rep_id) || die $dbh->errstr;
    my $id = -1;
    $id = $sth->fetchrow_array;

    ## Return the revsion id...
    return( ($id, $rep_id, $author_id ) );
}


sub insertResourceIntoDB
{
    my( $dbh, $rev_id, $rep_id, $resource, $action ) = @_;

## print( "$rev_id, $resource, $action\n" );

    my $sth = $dbh->prepare(
    q{
        INSERT INTO resource( rev_id, rep_id, resource, action )
                                VALUES (?, ?, ?, ?)
    }) || die $dbh->errstr;
    
    $sth->execute($rev_id, $rep_id, $resource, $action) || warn $dbh->errstr;

}


sub open_dbi
{
   # Declare and initialize variables
    my( $host, $db, $db_user, $db_password ) = @_;

   # Connect to the requested server
   my $dbh = DBI->connect(
              "dbi:mysql:$db:$host",
              "$db_user",
              "$db_password",
              {
                  RaiseError => 0,
                  PrintError => 0}
              ) or err_trap("Cannot connect to the database");
   return $dbh;
}#end: open_dbi



####################​####################​####################​
####################​####################​####################​
####################​####################​####################​
####################​####################​####################​
## These functions were taken from the subversion example/contrib area

# Start a child process safely without using /bin/sh.
sub safe_read_from_pipe
{
  unless (@_)
    {
      print( "$0: safe_read_from_pipe passed no arguments.\n" );
    }

  my $pid = open(SAFE_READ, '-|');
  unless (defined $pid)
    {
      die "$0: cannot fork: $!\n";
    }
  unless ($pid)
    {
      open(STDERR, ">&STDOUT")
        or die "$0: cannot dup STDOUT: $!\n";
      exec(@_)
        or die "$0: cannot exec `@_': $!\n";
    }
  my @output;
  while (<SAFE_READ>)
    {
      s/[\r\n]+$//;
      push(@output, $_);
    }
  close(SAFE_READ);
  my $result = $?;
  my $exit = $result >> 8;
  my $signal = $result & 127;
  my $cd = $result & 128 ? "with core dump" : "";
  if ($signal or $cd)
    {
      warn "$0: pipe from `@_' failed $cd: exit=$exit signal=$signal\n";
    }
  if (wantarray)
    {
      return ($result, @output);
    }
  else
    {
      return $result;
    }
}

# Use safe_read_from_pipe to start a child process safely and return
# the output if it succeeded or an error message followed by the output
# if it failed.
sub read_from_process
{
  unless (@_)
    {
      print( "$0: read_from_process passed no arguments.\n" );
    }
  my ($status, @output) = &safe_read_from_pipe(@_);
  if ($status)
    {
      return ("$0: `@_' failed with this output:", @output);
    }
  else
    {
      return @output;
    }
}


Directory: /kamikaze-qscm/src/k​amikaze-qscm/html/
====================​====================​=========

File [added]: config.inc
Url: http://kamikaze-qscm​.tigris.org/source/b​rowse/kamikaze-qscm/​src/kamikaze-qscm/ht​ml/config.inc?rev=1.​1&content-type=t​ext/vnd.viewcvs-mark​up
Added lines: 8
--------------
<?php

$dbhost = "localhost"; //!< MySQL DB hostname
$dbname = "svncommits"; //!< MySQL database that contains the kamikaze tables
$dbuser = "svnuser"; //!< MySQL DB user name with read permission to $dbname
$dbpass = "svnuser"; //!< MySQL DB user password for $dbuser

?>

File [added]: index.php
Url: http://kamikaze-qscm​.tigris.org/source/b​rowse/kamikaze-qscm/​src/kamikaze-qscm/ht​ml/index.php?rev=1.1​&content-type=te​xt/vnd.viewcvs-marku​p
Added lines: 51
---------------
<HTML>
<HEAD>
  <TITLE>SVN QUERY COMMITS</TITLE>
</HEAD>
<BODY>
<?php
include_once( "query.php" );
$query = new KamikazeQuery();
?>
<A name="top"></A>
<?php
         $query->displayQ​ueryHeader();
?>

<TABLE >
  <TR>
    <TD valign="top">
      <?php
      $query->displayQueryForm();
        ?>
    </TD>
    <TD valign="top">
        <?php
           if(isset($_REQUEST['action']) && $_REQUEST['action'] == 'Submit')
           {
               $query->doQuery();
           }
           ?>
    </TD>
    <TD valign="top">
        <?php
           if(isset($_REQUEST['action']) && $_REQUEST['action'] == 'Submit')
           {
               $query->displayQ​ueryResultsStats();
           }
           ?>
    </TD>
</TABLE>
<A href="#top">Back to top</A>
<?php
if(isset($_REQUEST['action']) && $_REQUEST['action'] == 'Submit')
{
// $query->displayResults();
// $query->displayQ​ueryResults();
}
?>

<A name="bottom"></A>

</BODY>
</HTML>

File [added]: query.php
Url: http://kamikaze-qscm​.tigris.org/source/b​rowse/kamikaze-qscm/​src/kamikaze-qscm/ht​ml/query.php?rev=1.1​&content-type=te​xt/vnd.viewcvs-marku​p
Added lines: 888
----------------
<HTML>
<HEAD>
</HEAD>
</HTML>
<BODY>
<?php
include_once( "config.inc" );

global $dbhost;
global $dbuser;
global $dbpass;
global $dbname;

class KamikazeQuery
{
    var $pathContains = "";
    var $logContains = "";

    var $dateOption = "hours";
  var $numHours = "3"; //!< For hours option
    var $betweenDates = array( array( "YYYY", "MM", "DD", "hh", "mm", "ss" ),
                               array( "YYYY", "MM", "DD", "hh", "mm", "ss" ) );

    var $action_added = "checked";
    var $action_deleted = "checked";
    var $action_modified = "checked";

    var $queryString;
    var $queryResults;
    var $parsedResults = array();
    var $relevantUsers;
    var $relevantRevs = 0;

    var $dbconnection; //-- database connection

    //-- rep_id => repos name, selected=1,
    var $repositories = array( "*" => array( "**ALL**", 0 ) );

    //-- author_id, alias, selected=1
    var $users = array( "*" => array( "**ALL**", 0 ) );


    function KamikazeQuery()
    {
        global $dbhost, $dbuser, $dbpass,$dbname;
        register_shutdown_function( array( &$this, "KamikazeQueryDestructor" ) );

        /* Connecting, selecting database */
        $this->queryResults = -1;
        $this->dbconnection = -1;
        $this->dbconnection = mysql_connect($dbho​st,$dbuser,$dbuser​)
                or die("Could not connect to MySQL DB at $dbhost: " . mysql_error());
        mysql_select_db($dbname) or die("Could not select database $dbname");

        $this->PopulateU​sersAndRepositoriesF​romDB();
    
        if( isset( $_REQUEST['pathContains'] ) )
        {
            $this->pathContains = $_REQUEST['pathContains'];
        }
        if( isset( $_REQUEST['logContains'] ) )
        {
            $this->logContains = $_REQUEST['logContains'];
        }

        if( isset( $_REQUEST['repository'] ) )
        {
            foreach( $_REQUEST['repository'] as $k => $v )
            {
                if( array_key_exists( $v, $this->repositories ) )
                {
                    $this->repositories[$v][1] = 1; //-- Selected
                }
            }
        }
        else
        {
            $this->repositories["*"][1] = 1; //-- Selected
        }

        if( isset( $_REQUEST['user'] ) )
        {
            foreach( $_REQUEST['user'] as $k => $v )
            {
                if( array_key_exists( $v, $this->users ) )
                {
                    $this->users[$v][1] = 1; //-- Selected
                }
            }
        }
        else
        {
            $this->users["*"][1] = 1; //-- Selected
        }


        if( isset( $_REQUEST['dateOption'] ) )
        {
            $this->dateOption = $_REQUEST['dateOption'];
        }
        if( isset( $_REQUEST['hours'] ) )
        {
            $this->numHours = $_REQUEST['hours'];
        }

        if( isset( $_REQUEST['action'] ) &&
            $_REQUEST['action'] == "Submit" )
        {
            $this->betweenDates[0] = array( $_REQUEST['year1'],
                                        $_REQUEST['month1'],
                                        $_REQUEST['day1'],
                                        $_REQUEST['hour1'],
                                        $_REQUEST['minute1'],
                                        $_REQUEST['second1'] );
            $this->betweenDates[1] = array( $_REQUEST['year2'],
                                        $_REQUEST['month2'],
                                        $_REQUEST['day2'],
                                        $_REQUEST['hour2'],
                                        $_REQUEST['minute2'],
                                        $_REQUEST['second2'] );

            $this->action_added = $_REQUEST['action_added'];
            $this->action_deleted = $_REQUEST['action_deleted'];
            $this->action_modified = $_REQUEST['action_modified'];

            $this->queryString =
                    "SELECT
                        revision.date,
                        author.user,
                        repository.alias,
                        revision.rev,
                        resource.resource,
                        resource.action,
                        revision.log
                    FROM
                        author,
                        repository,
                        revision,
                        resource
                    WHERE [WHERE_CLAUSE]
                    ORDER BY
                        repository.alias,
                        revision.rev DESC,
                        resource.action,
                        resource.resource";
        }
    }

    function KamikazeQueryDestructor()
    {
      if( $this->queryResults != -1 )
                    mysql_free_result($​this->queryResult​s );

            if( $this->dbconnection != -1 )
            {
                    mysql_close($this-​>dbconnection);
            }
    }


    function getMainQuery()
    {
            return $this->queryString;
    }


    function displayQueryHeader()
    {
print <<<END
            <TABLE width="100%" bgcolor="beige">
                        <TR><TD>
                    <TABLE cellpadding="5">
                        <TR>
END;
    if(isset($_REQUEST['action']) && $_REQUEST['action'] == 'Submit')
    {
        print( "<TD><a href=\"" .
                         $_SERVER['PHP_SELF'] . "\">Reset</a​></TD>" );
    print( "<TD><a href=\"" . $_SERVER['PHP_SELF'] . "?" .
            $_SERVER['QUERY_STRING'] . "\">Re-Submit​</a></TD>" );
        print( "<TD><a href=\"#results\"​>Results</a>​</TD>" );
    }
    else
    {
        print( "<TD>Reset</TD>" );
        print( "<TD>Re-submit​</TD>" );
        print( "<TD>Results</TD>" );
    }
print <<<END
                        </TR>
                    </TABLE>
                        </TD></TR>
            </TABLE>
END;

    }

    function doQuery()
    {
        //-- BUILD Repository list
        $repList = "";
        foreach( $this->repositories as $k => $v )
        {
            if( $k == "*" && $v[1] == 1)
            {
                $repList = "";
                break;
            }
            if( $repList != "" && $v[1] == 1 )
            {
                $repList = $repList . " OR ";
            }
            if( $v[1] == 1 )
                $repList = $repList . "revision.rep_id='" . $k . "'";
        }
        if( $repList != "" )
        {
            $repList = '(' . $repList . ')';
        }

        //-- BUILD User list
        $userList = "";
        foreach( $this->users as $k => $v )
        {
            if( $k == "*" && $v[1] == 1)
            {
                $userList = "";
                break;
            }
            if( $userList != "" && $v[1] == 1 )
            {
                $userList = $userList . " OR ";
            }
            if( $v[1] == 1 )
                $userList = $userList . " revision.author_id='" . $k . "'";
        }
        if( $userList != "" )
        {
            $userList = '(' . $userList . ')';
        }

        //-- BUILD action list
        $actionList = "";
        if( $this->action_added == "checked" )
            $actionList = "resource.action='A'";
        if( $this->action_modified == "checked" )
        {
            if( $actionList == "" )
                $actionList = "resource.action='M'";
            else
                $actionList = $actionList . " OR " . "action='M'";
        }
        if( $this->action_deleted == "checked" )
        {
            if( $actionList == "" )
                $actionList = "rsource.action='D'";
            else
                $actionList = $actionList . " OR " . "resource.action='D'";
        }
        if( $actionList != "" )
        {
            $actionList = '(' . $actionList . ')';
        }

        //-- BUILD date clause
        if( $this->dateOption == "formatted" )
        {
            $dateClause =
                "(revision.date >= '" .
                $this->betweenDates[0][0] . '-' .
                $this->betweenDates[0][1] . '-' .
                $this->betweenDates[0][2] . ' ' .
                $this->betweenDates[0][3] . ':' .
                $this->betweenDates[0][4] . ':' .
                $this->betweenDates[0][5] . "'" .
                " AND " .
                "revision.date <= '" .
                $this->betweenDates[1][0] . '-' .
                $this->betweenDates[1][1] . '-' .
                $this->betweenDates[1][2] . ' ' .
                $this->betweenDates[1][3] . ':' .
                $this->betweenDates[1][4] . ':' .
                $this->betweenDates[1][5] . "'" .
                ")";
        }
        else if( $this->dateOption == "hours" )
        {
            $tNow = time();
            $tBefore = $tNow - $this->numHours * 60 * 60;
            $endDate = date( "Y-m-d H:i:s", $tNow );
            $startDate = date( "Y-m-d H:i:s", $tBefore );
            $dateClause =
                "(revision.date >= '$startDate' AND revision.date <= '$endDate')";
        }
        else if( $this->dateOption == "day" )
        {
            $tNow = time();
            $tBefore = $tNow - (60 * 60 * 24);
            $endDate = date( "Y-m-d H:i:s", $tNow );
            $startDate = date( "Y-m-d H:i:s", $tBefore );
            $dateClause =
                "(revision.date >= '$startDate' AND revision.date <= '$endDate')";
        }
        else if( $this->dateOption == "week" )
        {
            $tNow = time();
            $tBefore = $tNow - (60 * 60 * 24 * 7);
            $endDate = date( "Y-m-d H:i:s", $tNow );
            $startDate = date( "Y-m-d H:i:s", $tBefore );
            $dateClause =
                "(revision.date >= '$startDate' AND revision.date <= '$endDate')";
        }

// //-- BUILD FULL TEXT SEARCH clause
// $textSearch = "";
//
// if( $this->pathContains != "" )
// {
// $textSearch = "+" . $this->pathContains . " ";
// }
// if( $this->logContains != "" )
// {
// $textSearch = $textSearch . $this->logContains;
// }
// if( $textSearch != "" )
// {
// $textSearch = " MATCH (resource, log) AGAINST ('" . $textSearch . "' IN BOOLEAN MODE)";
// }

     //-- BUILD TEXT SEARCH clause
     $textSearch = "";

         if( $this->logContains != "" )
         {
             $textSearch = $textSearch . " (revision.log LIKE '%" . $this->logContains . "%') ";
         }
     if( $this->pathContains != "" )
     {
                 if( $textSearch != "" )
                         $textSearch = $textSearch . " AND ";

       $textSearch = $textSearch . " (resource.resource LIKE '%" . $this->pathContains . "%') ";
     }
         if( $textSearch != "" )
                    $textSearch = " ( " . $textSearch . " ) ";


        //-- BUILD WHERE clause
        $whereClause = " repository.id = revision.rep_id AND revision.id = resource.rev_id AND revision.author_id = author.id ";
        if( $repList != "" )
        {
            $whereClause = $whereClause . " AND " . $repList;
        }
        if( $userList != "" )
        {
                $whereClause = $whereClause . " AND " . $userList;
        }

        if( $actionList != "" )
        {
                $whereClause = $whereClause . " AND " . $actionList;
        }

        if( $dateClause != "" )
        {
                $whereClause = $whereClause . " AND " . $dateClause;
        }

        if( $textSearch != "" )
        {
            $whereClause = $whereClause . " AND " . $textSearch;
        }
        
    
        /* Performing SQL query */
// $query = "SELECT * FROM revision,resource $whereClause ORDER BY revision.id, revision.date, revision.author, resource.resource, resource.action";
// $query = "
// SELECT
// revision.date,
// revision.repository,
// resource.resource,
// revision.rev,
// resource.action,
// revision.author,
// revision.log
// FROM revision,resource
// $whereClause
// ORDER BY
// revision.id DESC,
// revision.date,
// revision.repository,
// resource.resource,
// resource.action";

        $this->queryString = str_replace( "[WHERE_CLAUSE]", $whereClause,
                                                                                 $this->queryString );
        $this->queryResults = mysql_query($this-​>queryString)
                or die("Query failed: \"$this->queryString\" with error : " . mysql_error());

// /* Closing connection */
// mysql_close($link);
    }

    function displayQueryResults()
    {
            print( "<a name=\"results\"​></a>\n" );
        mysql_draw_table( $this->queryResults );
// mysql_free_result($​this->queryResult​s );

        print "\"$this->queryString\"";
        print "<PRE>";
    print_r($_REQUEST);
        print "<PRE>";
    }


    function displayQueryForm()
{
    //-- Creates a variable called whatever the dateOption is set to
    //-- e.g. hours and sets it to checked. This is used in the create
    //-- query form - avoiding a bunch of "if" logic to check the radio button
    ${$this->dateOption} = "checked";

print <<<END
        <a name="queryForm"></a>
      <FORM name="svnquery" action="index.php">
        <FIELDSET>
          <LEGEND title="Search subversion repostiories for commit information">Kami​kaze</LEGEND>
          <TABLE width="280">
            <TR>
              <TD valign="top">
                  <FIELDSET>
                <LEGEND title="Select one or more repositories to search. **ALL** to search all listed repositories">Rep​ository</LEGEND​>
                <SELECT multiple height="3" name="repository[]">
END;
    foreach( $this->repositories as $k => $v )
    {
        print( "<OPTION value=\"$k\"" );
        if( $v[1] == 1 )
            print( " selected " );
        print( ">$v[0]</OPTION>" );
    }

print <<<END
                </SELECT>
                </FIELDSET>
              </TD>
              <TD>
                  <FIELDSET>
                <LEGEND>User​</LEGEND>
                <SELECT multiple height="3" name="user[]">
END;
    foreach( $this->users as $k => $v )
    {
        print( "<OPTION value=\"$k\"" );
        if( $v[1] == 1 )
            print( " selected " );
        print( ">$v[0]</OPTION>" );
    }
print <<<END
                </SELECT>
                </FIELDSET>

              </TD>
            </TR>
            <TR>
                <TD colspan="2">
                <FIELDSET>
                    <LEGEND>Path​</LEGEND>
                    <INPUT name="pathContains" type="text" size="33" title="Enter a substring to match against the path. Leave it blank to skip this criteria." value="
END;
        echo "$this->pathContains";
print <<<END
                    ">
                </FIELDSET>
                </TD>
            </TR>
            <TR>
                <TD colspan="2">
                <FIELDSET>
                    <LEGEND>Log​</LEGEND>
                    <INPUT name="logContains" type="text" size="33" title="Enter a substring to match against the log text. Leave it blank to skip this criteria." value="
END;
        echo "$this->logContains";
print <<<END
                ">
                </FIELDSET>
                </TD>
            <TR>
              <TD colspan="2">
                <FIELDSET>
                  <LEGEND>
                    Date Options
                  </LEGEND>
                  <TABLE>
                    <TR>
                      <TD>
                        <INPUT type="radio" name="dateOption" value="hours"
END;
    echo ' ' . $hours . '>';
print <<<END
                      </TD>
                      <TD>In the last
                        <INPUT type="text" name="hours" size="4" value=
END;
    echo "\"$this->numHours\">";
print <<<END

                        hours</TD>
                    </TR>
                    <TR>
                      <TD>
                        <INPUT type="radio" name="dateOption" value="day"
END;
    echo ' ' . $day . '>';
print <<<END

                      </TD>
                      <TD>In the last day</TD>
                    </TR>
                    <TR>
                      <TD>
                        <INPUT type="radio" name="dateOption" value="week"
END;
    echo ' ' . $week . '>';
print <<<END

                      </TD>
                      <TD>In the last week</TD>
                    </TR>
                    <TR>
                      <TD>
                        <INPUT type="radio" name="dateOption" value="month"
END;
    echo ' ' . $month . '>';
print <<<END

                      </TD>
                      <TD>In the last month</TD>
                    </TR>
                    <TR>
                      <TD>
                        <INPUT type="radio" name="dateOption" value="all"
END;
    echo ' ' . $all . '>';
print <<<END

                      </TD>
                      <TD>Since the beginning of time</TD>
                    </TR>
                    <TR>
                      <TD valign="top">
                        <INPUT align="top" type="radio" name="dateOption" value="formatted"
END;
    echo ' ' . $formatted . '>';
print <<<END

                      </TD>
                      <TD>
                        Between:<BR>
                        <font size="-1">
                        <INPUT name="year1" type="text" size="4" value=
END;
    echo "\"" . $this->betweenDates[0][0] . "\">";
print <<<END
                        -
                        <INPUT name="month1" type="text" size="2" value=
END;
    echo "\"" . $this->betweenDates[0][1] . "\">";
print <<<END
                        -
                        <INPUT name="day1" type="text" size="2" value=
END;
    echo "\"" . $this->betweenDates[0][2] . "\">";
print <<<END
                        &nbsp;
                        <INPUT name="hour1" type="text" size="2" value=
END;
    echo "\"" . $this->betweenDates[0][3] . "\">";
print <<<END
                        :
                        <INPUT name="minute1" type="text" size="2" value=
END;
    echo "\"" . $this->betweenDates[0][4] . "\">";
print <<<END
                        :
                        <INPUT name="second1" type="text" size="2" value=
END;
    echo "\"" . $this->betweenDates[0][5] . "\">";
print <<<END
                        <BR>
                        <INPUT name="year2" type="text" size="4" value=
END;
    echo "\"" . $this->betweenDates[1][0] . "\">";
print <<<END
                        -
                        <INPUT name="month2" type="text" size="2" value=
END;
    echo "\"" . $this->betweenDates[1][1] . "\">";
print <<<END
                        -
                        <INPUT name="day2" type="text" size="2" value=
END;
    echo "\"" . $this->betweenDates[1][2] . "\">";
print <<<END
                        &nbsp;
                        <INPUT name="hour2" type="text" size="2" value=
END;
    echo "\"" . $this->betweenDates[1][3] . "\">";
print <<<END
                        :
                        <INPUT name="minute2" type="text" size="2" value=
END;
    echo "\"" . $this->betweenDates[1][4] . "\">";
print <<<END
                        :
                        <INPUT name="second2" type="text" size="2" value=
END;
    echo "\"" . $this->betweenDates[1][5] . "\">";
print <<<END
                        </font>
                        <BR><font size="-2" >e.g. "2004-09-01 12:29:01" - "2004-09-02 12:29:01"<BR>
                            (Between Sept. 1 and 2, 2004, 12:29 PM)</font></TD>
                    </TR>
                  </TABLE>
                </FIELDSET>
              </TD>
            </TR>
            <TR>
              <TD colspan="2">
                <FIELDSET>
                <LEGEND>Action​</LEGEND>
                <CENTER>
                  <INPUT name="action_added" type="checkbox" value="checked"
END;
    echo ' ' . $this->action_added . '>';
print <<<END

                  Added
                  <INPUT name="action_modified" type="checkbox" value="checked"
END;
    echo ' ' . $this->action_modified . '>';
print <<<END

                  Modified
                  <INPUT name="action_deleted" type="checkbox" value="checked"
END;
    echo ' ' . $this->action_deleted . '>';
print <<<END

                  Deleted
                </CENTER>
                </FIELDSET>
              </TD>
            </TR>
            <TR>
              <TD colspan="2">
                <CENTER>
                  <HR>
                  <INPUT name="action" align="top" type="submit" value="Submit">
                </CENTER>
              </TD>
            </TR>
          </TABLE>

        </FIELDSET>

      </FORM>
END;
}

    function displayQueryResultsStats()
{
        if( 0 == count( $this->parsedResults ) )
        {
                $this->parseResults();
        }

print <<<END
        <TABLE><TR​><TD><FIE​LDSET><LEGEND​>Query Results</LEGEND>
END;
    print "Your query found " . mysql_num_rows($thi​s->queryResults) .
            " matches involving:<BR>";
print <<<END
        <UL>
END;
    $userCount = 0;
        $userList;
        $reposList;
        if( 0 < count( $this->relevantUsers ) )
        {
                foreach( $this->relevantUsers as $repos => $user )
                {
                        list($userName, $count) = each($user);
                        $userCount++;
                        $userList = $userList . "$userName/$repos/$count, ";
                        $reposList = $reposList . "$repos, ";
                }
        }
        print( "<LI>$userCount authors: $userList</LI>\n" );
        print( "<LI>" . count($this->relevantUsers) . " repositories: $reposList</LI>" );
        print( "<LI>" . $this->relevantRevs . " total revisions</LI>\n" );
print <<<END
        </UL>

<!-- <p>Scroll down to see the <a href="#results">r​esults</a>.--​>
        <hr width="80%">
END;
        $this->displayResults();
print <<<END
        <HR width="80%">
        The results of this query were generated using the SQL statement:<BR>
                "<font color="gray" size="-1">
END;
                print( $this->queryString );
print <<<END
                </font>"

    </FIELDSET>
        </TD></TR​></TABLE>
END;

// print( "<a href=\"" .
// $_SERVER['PHP_SELF'] . "\">Reset</a​>&nbsp;" );
// print( "<a href=\"" . $_SERVER['PHP_SELF'] . "?" .
// $_SERVER['QUERY_STRING'] . "\">Re-Submit​</a>&nbsp;" );
        print( "" );


}

    function PopulateUsersAndRepo​sitoriesFromDB()
        {
                /* Performing SQL query */
                $reposListQuery = "SELECT id, alias FROM repository ORDER BY alias";
                $reposListResults = mysql_query($reposListQuery)
                        or die("Query failed: \"$reposListQuery\" with error: " . mysql_error());
                
                for ($i=0; $i < mysql_num_rows($rep​osListResults); $i++)
                {
                        $row = mysql_fetch_row($re​posListResults);
                        $this->repositories[$row[0]] = array( $row[1], 0 );
                }
                
                $authorListQuery = "SELECT author.id, author.user, repository.alias FROM author, repository where repository.id = author.rep_id";
                $authorListResults = mysql_query($authorListQuery)
                        or die("Query failed: \"$authorListQuery\" with error: " . mysql_error());
                for ($i=0; $i < mysql_num_rows($aut​horListResults); $i++)
                {
                        $row = mysql_fetch_row($au​thorListResults);
                        $this->users[$row[0]] = array( $row[1] . "(" . $row[2] . ")" , 0 );
                }
                
                //mysql_draw_table( $authorListResults );
                mysql_free_result($​authorListResults );
                //mysql_draw_table( $reposListResults );
                mysql_free_result($​reposListResults );
//
// /* Closing connection */
// mysql_close($link);
        }

        function parseResults()
        {
                if( 0 != count( $this->parsedResults ) )
                {
                        print "Already parsed...";
                        return;
                }
                //-- array(
                //-- array( alias => "", [rev] =>
                //-- array( rev => "", user => "", log => "", resources=>
                //-- array( path=>"", action=>"" ) ) ) );

                $curRep = "";
                $curRev = "";
                while ($row = mysql_fetch_array($​this->queryResult​s, MYSQL_ASSOC))
                {
                        //-- New repository encountered..
                        if( $curRep != $row["alias"] )
                        {
                                $curRep = $row["alias"];
// $this->parsedRes​ults[$curRep] = array();
                        }
                        if( $curRev != $row["rev"] )
                        {
                $curRev = $row["rev"];
                                $this->relevantU​sers[$curRep][$row​["user"]] += 1;
                                $this->relevantRevs += 1;

                                $this->parsedRes​ults[$curRep][$cur​Rev] =
                                        array( "date" => $row["date"],
                                                     "user" => $row["user"],
                                                     "log" => $row["log"],
                                                     "resources" => array() );
                        }
                        array_push($this-​>parsedResults[$cu​rRep][$curRev]["res​ources"],
                                array( "path" => $row[resource], "action" => $row["action"] ) );
                        
                }
        }


        function displayResults()
        {
                if( 0 == count( $this->parsedResults ) )
                {
                        $this->parseResults();
                }

        foreach( $this->parsedResults as $repos => $revisions )
                {
                        print( "<a name=\"results\"​></a>\n" );
                        print "<TABLE >";
                        foreach( $revisions as $rev => $revInfo )
                        {
                                print "<TR valign=top><TD​>$repos</TD​><TD>";
                                print "<TABLE >";
                                print "<TR valign=top><TD​>Revision: </TD><TD​>$rev</TD>​</TR>";
                                print "<TR valign=top><TD>Date: </TD><TD>" . $revInfo["date"] . "</TD></TR>";
                                print "<TR valign=top><TD>User: </TD><TD>" . $revInfo["user"] . "</TD></TR>";
                                print "<TR valign=top><TD​>Log:</TD>​<TD>" . $revInfo["log"] . "</TD></TR>";
                                print "<TR valign=top><TD​></TD><T​D>";
                                        print "<TABLE >";
                                        foreach( $revInfo["resources"] as $resource )
                                        {
                                                print "<TR valign=top><TD>" . $resource["action"] . "</TD><TD>" . $resource["path"] . "</TD></TR>";
                                        }
                                        print "</TABLE>";
                                print "</TD></TR>";
                                print "</TABLE>";
                        }
                        print "</TABLE>";
                }

// print "<PRE>";
// print_r( $this->parsedResults );
// print_r( $this->relevantUsers );
// print "</PRE>";
        }
}




/**
 * Replicate the output from `mysql --html`
 *
 * Draws a HTML table from a query resource
 *
 * @author idan Lister <aidan at php dot net>
 * @version 1.0
 */
function mysql_draw_table($result)
{
$out = "<table border=1>\n";
// Print Table Title
$out .= "\t<tr>";
for ($i=0; $i < mysql_num_fields($result); $i++)
{
$out .= '<th>' . mysql_field_name($result, $i) . '</th>';
}
$out .= "</tr>\n";

// Print table Content
for ($i=0; $i < mysql_num_rows($result); $i++)
{
    $out .= "\t<tr>";
    $row = mysql_fetch_row($result);
    foreach ($row as $value)
    {// Make sure 0's are displayed
        if (is_numeric($value))
        {
            $value = (int) $value;
        }
        // Fix empty cells
        $value = (empty($value) && ($value !== 0)) ? '&nbsp;' : htmlspecialchars($value);
        $out .= '<td>' . $value . '</td>';
    }
    $out .= "</tr>\n";
}
$out .= "</table>\n";
echo $out;
}

?>
</BODY>
</HTML>




--------------------​--------------------​--------------------​---------
To unsubscribe, e-mail: cvs-unsubscribe@kami​kaze-qscm.tigris.org​
For additional commands, e-mail: cvs-help@kamikaze-qs​cm.tigris.org

« Previous message in topic | 1 of 1 | Next message in topic »

Messages

Show all messages in topic

CVS update: /kamikaze-qscm/src/kamikaze-qscm/, /kamikaze-qscm/src/kamikaze-qscm/db/, /kamikaze-qscm/src/kamikaze-qscm/hooks/, /kamikaze-qscm/src/kamikaze-qscm/html/ jduprey John Duprey 2004-09-20 21:25:15 PDT
Messages per page: