add p4db to tinderbox2. This is a web query based tool for Perforce, I found the code on the net and it appears to be unmaintained at this time. This version of p4db has had security patches found on the internet added to it as well as numerous changes to make the code taint perl safe and new features to make it look more like Bonsai in some respect.

This commit is contained in:
kestesisme%yahoo.com 2006-01-27 03:52:56 +00:00
Родитель 05efb984b6
Коммит 05ba11ec37
65 изменённых файлов: 11719 добавлений и 0 удалений

Просмотреть файл

@ -0,0 +1,22 @@
%.class : %.java
javac $<
default: p4jdb/TreeDisplay.class p4jdb/P4File.class p4jdb/P4Folder.class \
p4jdb/P4DirTree.class p4jdb/P4DirTreeApplet.class
p4jdb/TreeDisplay.class p4jdb/P4File.class p4jdb/P4Folder.class \
p4jdb/P4DirTree.class p4jdb/P4DirTreeApplet.class: $(wildcard p4jdb/*.java)
javac p4jdb/*.java
doc :
javadoc -link http://localhost/~fredric/java_docs/api $(wildcard p4jdb/*.java)
#p4jdb/P4File.class: p4jdb/TreeDisplay.class p4jdb/P4DirTree.class
#p4jdb/P4Folder.class: p4jdb/TreeDisplay.class p4jdb/P4DirTree.class
#p4jdb/P4DirTree.class: p4jdb/P4Folder.class
#p4jdb/P4DirTreeApplet.class: p4jdb/TreeDisplay.class p4jdb/P4DirTree.class

Просмотреть файл

@ -0,0 +1,128 @@
################################################################
# P4DB configuration file #
# Release: 2.01 #
################################################################
#
# The general format of the file is:
# <identifier>:<data>
# Whitespace is allowed before identifier and before data.
# The data format depends on the identifier
#
# In general whitespaces are NOT allowed in filenames. Sorry.
#
### ###
### Set up environment ###
### ###
### Specify path to p4 program
P4PATH: /usr/local/bin/p4
### Specify path to icons (well, icon for 2.0)
# If this is modified, be sure to move image as well
HTML_ICON_PATH: ./icons
### Specify path to help files and other html
# If this is modified, be sure to move README.html, P4DB_Help.html
# and P4CGI.html.
HTML_HELPFILE_PATH: .
### Set administrator(s) for P4DB.
# Data Format: <email address> <full name>
# One or more administrators can be specified.
P4DB_ADMIN: MrDDuck@disney.com Donald Duck
P4DB_ADMIN: MrMMouse@disney.com M. Mouse
### ###
### Variables to facilitate ports ###
### ###
# NOTE!
# You should pay special attention to this part if your OS is
# Windows NT.
### NT needs the SHELL variable set to some UNIX-style shell
# program (like kornshell in MKS toolkit, check out
# http://www.datafocus.com/products/tk/ )
SHELL:
### P4DB sometimes needs to redirect error messages that should be
# ignored to a null device. God named the null device /dev/null
# but Bill G. et.al. ignored this and called it NUL:
# Make sure it is set to whatever your OS calls the null device.
# Don't remove the "2>"-part
REDIRECT_ERROR_TO_NULL_DEVICE: 2>/dev/null
# >>>> this line should work for NT: (not tested)
# REDIRECT_ERROR_TO_NULL_DEVICE: 2>NUL:
### P4DB sometimes needs to redirect error messages that should be
# parsed to the standard out stream. This is the command used
# for this. Set to nothing if your OS does not differ between
# stdout and stderr.
REDIRECT_ERROR_TO_STDOUT: 2>&1
### ###
### Specify shortcut files ###
### ###
# Format: <file name> ; <short description>
# NOTE! Spaces are not allowed in filename here (sorry)
# See README.html for details about shortcut files
SHORTCUT_FILE: ; No shortcuts
SHORTCUT_FILE: ./P4DB.shortcuts.txt ; Sample shortcuts
SHORTCUT_FILE: ./P4DB.shortcuts2.txt; Sample shortcuts 2
### ###
### Specify depots ###
### ###
# Format: <host>:<port> <user> <client> <password> ; <short description>
# (no spaces in password, user or client).
# For password: '*' equals no password
# One depot per line
# DEPOT: localhost:1666 fredric fredric_client * ; My local depot
# DEPOT: p4:1666 fredric fredric_client1 passwrd ; At work
# DEPOT: public.perforce.com:1666 fredric none * ; Perforce Public Depot
DEPOT: gdepot1.mhe.mhc:1666 build anyClient aPassword ; Nonexisting, for test
### ###
### Color schemes ###
### ###
# Format:
# <BGCOL> <TEXT COL> <LINK COL> <VLINK COL> <T-BGCOL> <T-TEXT COL> <HF-BGCOL> <HF-TEXT COL> ; <desc>
# where: BGCOL is background color
# TEXT COL text color
# LINK COL link color
# VLINK COL visited link color
# T-BGCOL title background color
# T-TEXT COL title text color
# HF-BGCOL header/footer background color
# HF-TEXT COL header/footer text color
# L-COL legend color
COLORS: #f0f0f0 black #0000A0 #0000A0 #f0f0f0 blue #e0e0e0 #e02020 ; Standard
COLORS: #f0f8f0 black #0000A0 #005050 #d0f0ff blue #D0e0D0 #e02020 ; Some green
COLORS: #ffffe0 black blue blue #F0F080 red #f0f0d0 #e02020 ; Some yellow
COLORS: white black blue blue black white white black ; B&W
COLORS: #202020 white yellow yellow white blue black white ; Inverted B&W
COLORS: #f0f0f0 black blue blue #e0e0e0 black #d0d0d0 black ; Grayscale
COLORS: #307030 #00f090 #00ee00 #008866 #B0FFD0 green #002000 #20f020 ; Green
COLORS: #FFF0F0 red #CC33CC #CC55CC #FFE0FF blue #ffe0e0 red ; Pink

Просмотреть файл

@ -0,0 +1,597 @@
#!/usr/bin/perl -w
# -*- perl -*-
$doc=<<EOF
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<STYLE TYPE="text/css"><!--
A
{color:blue; text-decoration:none;}
A:hover
{color:blue; text-decoration:underline;}
H1, H2, H3, H4 {
font-family: Arial, Helvetica ;
background-color: #e0e0e0 ;
}
H3 {
margin-left: 15pt ;
margin-right: 15pt ;
}
H4 {
margin-left: 30pt ;
margin-right: 30pt ;
}
P.Norm
{
margin-left: 40pt ;
margin-right: 40pt ;
font-family: Arial, Helvetica ;
}
P.Norm UL, P.Norm OL, P.Norm DL, P.Norm TABLE
{
margin-left: 50pt ;
margin-right: 50pt ;
font-family: Arial, Helvetica ;
}
P.Norm TABLE TR TH
{
background-color: white ;
}
P.Hint, DIV.Hint {
margin-left: 40pt ;
margin-right: 40pt ;
text-decoration:border ;
border-width: 2pt ;
border-color: yellow;
color: #804040 ;
background-color: white ;
foreground-color: #f0e0e0 ;
font-family: Arial, Helvetica ;
}
P.Note, DIV.Note {
margin-left: 80pt ;
margin-right: 80pt ;
background-color: white ;
font-weight: bold ;
border: 5pt dashed red ;
}
FONT.Note {
font-weight: bold ;
}
--></STYLE>
</head>
<body text="#000000" bgcolor="#FFFFFF" link="#0000FF" vlink="#000099" alink="#FF0000">
<hr SIZE=8 NOSHADE WIDTH="99%" align=center>
<h1 align=center>
P4DB Help File
</h1>
<p align=center>
<b><tt><blink><font color="#FF0000" size=+3>Under construction</font></blink></tt></b>
</p>
<h2>Introduction</h2>
<P class=Norm>
This page is a brief user manual for P4DB.
<P class=Norm>
The reader is assumed to have working knowledge of Perforce P4 and web
browsers.
</p>
<h3>What is P4DB?</h3>
<P Class=Norm>
P4DB is a http depot browser for <a href="http://www.Perforce.com">Perforce
p4</a>. The depot browser is implemented as a set of CGIs that present
information about the status of the p4 depot using HTML.
</P>
<P Class=Norm>
The purpose of P4DB is to provide a convenient way to browse the p4
depot for p4 administrators, project managers, developers, testers etc.
that need information about changes in the depot.
<br>
Some typical uses for P4DB are:
<ul Class=Norm>
<li>View diff between file revisions</li>
<li>Find out when a line in a file was changed</li>
<li>View labels</li>
<li>List changes between labels or for a specific set of
files</li>
<li>Stay abreast with the development</li>
</ul>
</P>
<P Class=Note>
P4DB can only present information in the depot and have
no access to the files in the users file space.
</P>
<P Class=Norm>
P4DB use the standard p4 commands to retrieve information from the depot.
P4DB does not add any other information but will often combine output
from more than one command to get the information.
</P>
<P Class=Norm>
P4DB produces almost only plain html. No javascript, very little CSS
(Cascades Style Sheets), one gif. P4DB use one http cookie to store user
preferences.
</P>
<h3>P4DB Support and Supported Platforms</h3>
<P Class=Norm>
P4DB is developed using Netscape Communicator 4.7 browser and
Apache http server. Both browser and server run on a Linux system.
<br>I perform some basic testing with Explorer but that's it.
<P Class=Norm>
There are no supported platforms basically because there is no support.
P4DB is open source software and I expect the brave p4 administrator that
installs P4DB to provide support for end users. I will of course answer
questions if I can and is more than willing to listen to suggestions or
constructive criticism but please forward all this through your administrator.
</P>
<h3>How Do I.....? (a.k.a. FAQ)</h3>
<P Class=Norm>
Here is examples on how to use P4DB to answer some questions
about files in the depot. The list is by no means complete but should give
some idea of what P4DB can be used for.
<h4>Is there any help available?</h4>
<P Class=Norm>
Sure! You are looking at it, only it's not finished yet. This help page
can be reached in two ways:
<ol>
<li>Click on the help link at the top right corner of each page.</li>
<br>This will usually bring you to the part in the help file that describes
this current page.
<li>In some places in there are help links (currently a question mark but this
may change into something more obvious).
<br>These links brings you directly to the paragraph in the help file that
describes the adjacent feature or selection.
</ol>
<h4>
How do I view the latest changes in the depot?</h4>
<P Class=Norm>
Easy! But there are several ways:
<ul>
<li>
By far the easiest is to click on "Submitted Changes" in the main
page. This will show the submitted changes in reverse chronological
order, that is the latest on top.
<li>
If you are <FONT Class=Note>not interested in the whole depot</FONT> you
could select "Browse
Depot Tree" on the main page. Using the browser you can move down the
depot tree and select "View changes".
<li>
If you are interested in a <FONT Class=Note>special file or set of
files</FONT> you could
enter a file spec (in p4 depot notation) in the "List Changes For
File spec" field in the main page. If you, for example, enter
<tt>//.../main/.../*.doc</tt> you will see the changes for all files
with extension "<tt>.doc</tt>" below a directory named "<tt>main</tt>"
<br>You can change file spec to anything and even use some wildcards. P4DB
accepts the perforce style wildcards ("<tt>...</tt>" for a series of any
characters and "<tt>*</tt>" for any character except "<tt>/</tt>").
<DIV Class=Hint>
<b>Hint: </b>P4DB lets you specify more than one file spec here. For
example "<tt>//...*.c + //...*.h</tt>" will show changes in and *.c and
*.h files. Multiple file specifications are separated with "&lt;optional
whitespace> + &lt;optional whitespace>".</DIV><br>
<li>
Sometimes you may be interested in changes made by a
<FONT Class=Note>specific user or group of users</FONT>. Select
"Changes by User or Group" on the main page. You will get a page with
a list of users and a list of user groups (if any). Select the desired
users and groups and click on OK.
<DIV Class=Hint>
In windows Ctrl-Mouseclick will let you make an arbitrary selection in
the list.</DIV><br>
<li>
A special case is when you are looking for changes with a specific
<FONT class=note>keyword in the description</font>. If you select
"Search Changes by Descriptions" on the main page you will get a page
where you can specify a file spec and a pattern to search for.
<li>
There may be a "shortcut" (see below) that views the changes for the
whole depot or the part of the depot you are interested in.</li>
</ul>
<P Class=Norm>
And there are more ways. If you browse around in P4DB you will see
that for virtually all items, like labels or branches, that refer to
the depot you can select "View changes".
<h4>
"Shortcuts", what's that?</h4>
<P Class=Norm>
You administrator may create one or mote of shortcut files where each
file contains a set of shortcuts that are presented as links on the main
page. See the "Set Preferences" page to select a shortcut file, if there
are any shortcut files defined.</P>
<h4>
How to I view history for a file</h4>
<P Class=Norm>
There are many ways here too.
<UL>
<li>On the <font class=note>main page</font> you can <font
class=note>search for the file</font>. Enter the file name in the
"Search for file" field and press OK. You will now get a list of files
that matches your search. Click on the desired file to view the file
log for the file.
<li>You can <font class=note>browse the depot</font> with the "Browse
Deport" link on the main page. When the desired directory is found
just click on the file name.
</UL>
<P Class=Norm>
In general, in all pages that show a file name a click on the file
name will show the file log.
<br>
<br>
<center><hr SIZE=8 NOSHADE WIDTH="90%"></center>
<h1 align=center>HELP FOR PAGES</h1>
<h2>Common to all pages</h2>
<h3>Page header</h3>
<P Class=Norm>
To the left in the header the P4DB version information and the current
change level in the depot.
<br>
At the top center of each page is a title that describes the content
of the page.
<br>
To the top left of the page there is a link to the paragraph in this
document that describes the current page.
<br>
Below the current level and page title there is a field that contains
some more information about the page and sometimes links that links to
information related to the page or change the information displayed on
the page.
<br>
Below the help link there is a link to the main page, except on the
main page where this place is empty.
<h3>Page Footer</h3>
<P Class=Norm>
To the bottom left the current p4 port and host is displayed.
<br>
To the right there is one or more mail-to-links to the administrator(s)
and to the far right is a link to the page top.
<h2><a NAME="index"></a><a href="index.cgi">Main
page (or index page)</a></h2>
<P class=norm>
This is the start page for P4DB. The start page contains four
sections:
<h4>
Links to browser pages</h4>
<P class=norm>
A set of links to pages that lets you browse the depot, view pending changes,
view branches or labels etc.
<br>For detailed information click on the link and select help in the page
header.
<h4>
(Optional) Shortcuts</h4>
<P class=norm>
This section will only exist if the P4DB administrator have created shortcut
file and you have selected one in "Set Preferences".
<br>The section contains a set of shortcut links to various pages.
<h4>
Advanced searches</h4>
<P class=norm>
This section contains a set of advanced searches with text fields for user
input.
<h4>
<a NAME="index_listCh"></a>List changes for file spec</h4>
<P class=norm>
View changes for the file spec.
<br>The file spec may contain wildcards (p4 style).
<br>Two or more file specifications may be specified if they are separated
by a "<tt>+</tt>"-sign.
<h4>
<a NAME="index_fileSrch"></a>Search for file</h4>
<P class=Norm>
View all files in the depot matching a file specification. The file specification
will typically contain wildcards (p4 style).
<h4>
<a NAME="index_viewCh"></a>View change</h4>
<P class=Norm>
View a change specified by change number.
<h4>
Miscellaneous</h4>
<P class=Norm>
This section contains three links.
<ol>
<li>
A link to a documentation page targeting the system administrators.</li>
<li>
A link to the "Set Preferences" page</li>
<li>
A link to "The Great Submit Race".</li>
</ol>
<h2>
<a NAME="SetPreferences"></a><a href="SetPreferences.cgi">Set Preferences</a></h2>
<P class=norm>
P4DB allows the user to set some preferences. Some of the choices
are defined in the configuration file by the P4DB administrator.
<P Class=Norm>
The preferences are:
<P Class=Norm>
<TABLE Class=Norm BORDER>
<tr class=Norm NOSAVE>
<th class=Norm NOSAVE>P4 Depot</th>
<td class=Norm NOSAVE>Select depot from a set of depots defined in the configuration
file by the P4DB administrator. A typical installation will probably only
have one single depot to choose.</td>
</tr>
<tr NOSAVE>
<th NOSAVE>Shortcut file to use</th>
<td NOSAVE>The P4DB administrator can define a set of shortcut files that
provides handy shortcuts for the user.</td>
</tr>
<tr NOSAVE>
<th NOSAVE>Shortcuts on top of main page</th>
<td>If a shortcut file is selected the shortcuts can be displayed on top
of page or not.</td>
</tr>
<tr NOSAVE>
<th NOSAVE>Ignore case (like NT)</th>
<td>Set to "yes" if you work in a Windows environment.</td>
</tr>
<tr NOSAVE>
<th NOSAVE>Max changes to show</th>
<td>When changes are listed it is convenient to limit the number of changes
per page or the page might take very long to load. I have found 100 to
be a reasonable number in a fast LAN and probably about 20 or so if you
work over modem.</td>
</tr>
<tr NOSAVE>
<th NOSAVE>Default tab stop</th>
<td>Default tab stop for your source code. If not set correctly the indentation
will look funny when you view your source code.</td>
</tr>
<tr NOSAVE>
<th NOSAVE>View files with colors</th>
<td>The file viewer in P4DB can colorize HTML, perl and C code. Set this to Yes to turn
this function on. Set to off (No) if you want to use a color scheme with dark background.</td>
</tr>
<tr NOSAVE>
<th NOSAVE>Underline links</th>
<td>Some people want their links underlined some don't.</td>
</tr>
<tr NOSAVE>
<th NOSAVE>Color scheme</th>
<td>Select a color scheme to use. There are a few predefined to choose from.</td>
</tr>
<tr NOSAVE>
<th NOSAVE>Enable experimental java depot tree browser</th>
<td>Once I wrote this small java applet to get a GUI to go with P4DB. Does
not work in all installations but neat to have when it does.</td>
</tr>
<tr NOSAVE>
<th NOSAVE>Print log information</th>
<td>Print a log at the bottom of each page. Really only useful for debugging.</td>
</tr>
</table>
<h2>
<a NAME="depotTreeBrowser"></a>
<a href="depotTreeBrowser.cgi">Depot Tree Browser</a></h2>
<P class=norm>
Used to browse the file tree in the depot.
<br>The Depot Tree Browser presents data in three sections.
<ol>
<li>
The top section shows the current directory in the depot.</li>
<br>Click on a directory in the path to ascend to it.
<li>
The middle section shows the currently available subdirs.</li>
<br>Click on a subdir to descend to it.
<li>
The bottom section shows the files in the current directory. Deleted files
are marked with a strike through style.
<br>The file name links to the file log for the file. The version number
links to the file viewer for latest version.
</ol></li>
<P Class=Norm>
In the top of the page there is a link to view changes below current
directory and a link to toggle show/hide deleted files.
<h2>
<a NAME="userList"></a><a href="userList.cgi">P4 Users (and Groups)</a></h2>
<P Class=Norm>
Lists all users and user groups.
<P Class=Norm>For each user the p4-user-name. name as specified in user description,
email address and last access time is displayed. If the user has not been
accessed for more than 10 weeks a message about this is printed.
<P Class=Norm>Click on p4 user name to get details about user.
<br>Click on e-mail address to send email to user.
<P Class=Norm>If any groups are defined they are listed below the users. Click on
group name to see details about group.
<h2>
<a NAME="changeList"></a><a href="changeList.cgi?FSPC=//...">Change List</a></h2>
<P Class=Norm>
This page lists changes with different selection criteria.
The selection criteria is displayed in the header.
<br>Since the list may be very long it is limited to a specific number
of changes (see <a href="#SetPreferences">Set Preferences</a>). If there
are more changes there is a "More..." link at the bottom of the page.
<ul>
<li>
Each change is presented as a change number, date, user and client followed
by the description.</li>
<li>
The change number is a link to view details about the change. There is
a switch in the preferences (see <a href="#SetPreferences">Set Preferences</a>)
that makes the change show up in separate window.</li>
<li>
The user and client links to user and client views.</li>
<li>
If change number are mentioned in the description they are converted to
a link to that specific change, e.g. "change 123" is converted to "<a href="changeView.cgi?CH=123">change
123</a>". <br>P4DB parses the description and tries to find references to
other changes to convert to links. The algorithm assumes english and
can sometimes mistake other numbers in the description for references
to changes.</li>
</ul>
<P Class=Norm>
At the top of the page is a link that automatically lists the change descriptions
for change the numbers referred to in the change description (try it and
you will understand what I mean).
<h2>
<a NAME="searchPattern"></a><a href="searchPattern.cgi">Search Descriptions</a></h2>
<P Class=Norm>
Search changes for text pattern in description.
<P Class=Norm>
The pattern fields contains a pattern that is searched for in the change
descriptions.
<P Class=Norm>
The search is not case sensitive and the following wildcard characters
are accepted:
<dl>
<dt>
&lt;white space></dt>
<dd>
Matches one or more whitespace characters or newlines</dd>
<dt>
*</dt>
<dd>
Matches zero or more characters</dd>
<dt>
?</dt>
<dd>
Matches exactly one character</dd>
</dl>
<h2>
<a NAME="DepotStats"></a><a href="depotStats.cgi">Depot Statistics</a></h2>
<P Class=Norm>
Shows some statistics from the depot or part of the depot.
<ul>
<li>
The first part shows general statistics from the depot such as counters
and number of users, clients etc.</li>
<li>
The second part shows submit and files statistics for the selected part
of the depot</li>
<li>
The third part shows weekly submit rate for the selected part of the depot.
Weeks are here defined as Sunday to Saturday.</li>
<li>
The fourth parts shows number of submits per user sorted by number of submits</li>
</ul>
<P Class=Norm>
I can't honestly say what all this is good for other than satisfying your
curiosity.
<h2>
<a NAME="P4Race"></a><a href="p4race.cgi">The Great Submit Race</a></h2>
<P Class=Norm>
This is the great submit race. The Submit Race reads the last
499 submits and ranks the users after the number of submits.<br>
There is also some assessment of the "speed" based on the average position
of the users submits in the list.
<br>The last user among the 499 changes gets her submit number in red.
This means that this number will be decremented the next time somebody submits
a change.
<br>The user that made the most recent submit gets a green background to
her submit number.
<P Class=Norm>To be able to enjoy the race there is a link that replays the last 30
submits.
<P Class=Norm>Please don't take the Submit Race to seriously.....
<br>
<br>
<center><hr SIZE=8 NOSHADE WIDTH="99%"></center>
</body>
</html>
EOF
;
print $doc

Просмотреть файл

@ -0,0 +1,100 @@
#!/usr/bin/perl -w
# -*- perl -*-
use P4CGI ;
use strict ;
#
#################################################################
# CONFIGURATION INFORMATION
# All config info should be in P4CGI.pm
#
#################################################################
#
# Set Prefereces
#
#################################################################
my $newp = &P4CGI::cgi()->param("SET_PREFERENCES") ;
$newp = "Yes" if defined $newp;
my $fullURL = &P4CGI::cgi()->url(-full=>1) ;
if((defined $newp) and
(&P4CGI::CURRENT_CHANGE_LEVEL() >= 0)) {
&P4CGI::EXTRAHEADER(-Refresh => "1; URL=index.cgi") ;
} ;
&P4CGI::ERRLOG("fullURL: $fullURL") ;
&P4CGI::ERRLOG("server_name: ". &P4CGI::cgi()->server_name()) ;
&P4CGI::SET_HELP_TARGET("SetPreferences") ;
print "",
&P4CGI::start_page("Set Preferences","") ;
my %pref_list=&P4CGI::PREF_LIST() ;
my %pref=&P4CGI::PREF() ;
print "",
&P4CGI::cgi()->start_form(-method=>"GET",
-action=>"SetPreferences.cgi"),
&P4CGI::start_table("") ;
my $p ;
foreach $p (sort { $ {$pref_list{$a}}[0] cmp $ {$pref_list{$b}}[0] } keys %pref_list) {
my @data = @{$pref_list{$p}} ;
my $type = shift @data ;
$type =~ s/^\w:// ;
my $desc = shift @data ;
my $default = shift @data ;
my $cval = $pref{$p} ;
my $cell ;
if($type eq "BOOL") {
$cell = &P4CGI::cgi()->radio_group(-name=>$p,
"values"=>[0,1],
-default=> $cval,
-labels=>{1 => "Yes", 0 => "No"}) ;
}
if($type eq "LIST") {
my $n = -1 ;
my %alts = map { $n++ ; s/^.*;\s+// ; ($n,$_) ; } @data ;
my @d = keys %alts ;
$cell = &P4CGI::cgi()->popup_menu(-name=>$p,
"values"=>\@d,
-default=>$cval,
-labels=>\%alts) ;
}
if($type eq "BGCOLOR") {
my $n = -1 ;
my %alts = map { $n++ ; ($n,"<TABLE BORDER BGCOLOR=\"$_\"><TR><TD>&nbsp;&nbsp;&nbsp;</TD></TR></TABLE>\n") } @data ;
# my %alts = map { $n++ ; ($n,"$_") } @data ;
my @d = keys %alts ;
$cell = &P4CGI::cgi()->radio_group(-name=>$p,
"values"=>\@d,
-default=> $cval,
# -linebreak=>'true',
-labels=>\%alts,
-rows=>1) ;
}
if($type eq "INT") {
$cell = &P4CGI::cgi()->textfield(-name=>$p,
-size=>6,
-default=>$cval,
-maxlength=>6) ;
} ;
print &P4CGI::table_row({-type=>"th",
-text=>"$desc:",
-align=>"right"},
{
-align=>"left",
-text=>$cell}) ;
}
print &P4CGI::table_row("",&P4CGI::cgi()->submit(-value=>'Change preferences',
-name=>'SET_PREFERENCES') . " " .
&P4CGI::cgi()->defaults("Reset")) ;
print "",&P4CGI::end_table(),"<HR>" ;
print
&P4CGI::end_page() ;
#
# That's all folks
#

Просмотреть файл

@ -0,0 +1,317 @@
#!/usr/bin/perl -w
# -*- perl -*-
use P4CGI ;
use strict ;
#
#################################################################
# CONFIGURATION INFORMATION
# All config info should be in P4CGI.pm
#
#################################################################
#
# Search changes for pattern
#
#################################################################
my $FSPC = &P4CGI::cgi()->param("FSPC") ;
$FSPC = "//..." unless defined $FSPC ;
&P4CGI::bail("Invalid file spec.") if ($FSPC =~ /[<>"&:;'`]/);
my @legend ;
my $legend = "" ;
$legend = &P4CGI::ul_list(@legend) if @legend > 0 ;
my $FSPC = P4CGI::cgi()->param("FSPC") || "//..." ;
$FSPC = P4CGI::extract_filename_chars($FSPC);
my $COMPLETE= &P4CGI::cgi()->param("COMPLETE") ;
if (defined($COMPLETE)) {
$COMPLETE ="Yes";
}
unless(defined $COMPLETE) {
push @legend,&P4CGI::ahref("COMPLETE=Yes",
"FSPC=$FSPC",
"Include old users in list") ;
} ;
$legend = '';
print "", &P4CGI::start_page("General Perforce Query Fourm",$legend) ;
# Get users
my @users ;
@users=&P4CGI::run_cmd("users");
my @listOfUsers = sort { uc($a) cmp uc ($b) } map { /^(\S+).*> \((.+)\) .*$/ ; $1 ; } @users ;
my %userCvt = map { /^(\S+).*> \((.+)\) .*$/ ; ($1,$2) ; } @users ;
@listOfUsers = ('', @listOfUsers);
if(defined $COMPLETE) {
my %allUsers ;
local *P ;
&P4CGI::p4call(*P, "changes $FSPC") ;
while(<P>) {
/.*by (\S+)@/ ;
if(exists $allUsers{$1}) { $allUsers{$1} += 1 ; }
else { $allUsers{$1} = 1 ; }
} ;
foreach (keys %allUsers) {
if(!exists $userCvt{$_}) {
$userCvt{$_} = "Old user: $_ ($allUsers{$_} changes)" ;
push @listOfUsers,$_ ;
} else {
$userCvt{$_} .= " ($allUsers{$_} changes)" ;
}
} ;
}
# Get groups
my @listOfgroups ;
@listOfgroups=&P4CGI::run_cmd("groups");
&P4CGI::SET_HELP_TARGET("searchPattern") ;
print "",
&P4CGI::start_table("bgcolor=".&P4CGI::HDRFTR_BGCOLOR()." align=center cellpadding=0 cellspacing=2"),
"<tr><td>\n" ;
sub prSelection($$$$ )
{
my $cgitarget = shift @_ ;
my $desc = shift @_ ;
my $fields = shift @_ ;
my $helpTarget = shift @_ ;
print "", &P4CGI::table_row(-valign=>"center",
{-align=>"center",
-text =>
join("\n",
&P4CGI::cgi()->startform(-action => $cgitarget,
-method => "GET"),
"<font size=+1>$desc</font>")},
{-align=>"left",
-valign=>"top",
-text => $fields},
{-align=>"left",
-text => " "},
{-align=>"left",
-valign=>"bottom",
-width=>"1",
-text => &P4CGI::cgi()->submit(-name => "ignore",
-value => "GO!")
},
{ -valign=>"bottom",
-text => &P4CGI::cgi()->endform()
},
) ;
} ;
print "", &P4CGI::start_table("width=100% cellspacing=4") ;
my $ulistSize = @listOfUsers ;
$ulistSize= 15 if $ulistSize > 15 ;
my $glistSize = @listOfgroups ;
$glistSize= 15 if $glistSize > 15 ;
my %allUsers;
my %dayValues = ( 0 => "Zero days",
1 => "One day",
2 => "Two days",
3 => "Three days",
4 => "Four days",
5 => "Five days",
6 => "Six days") ;
my %hourValues = ( 0 => "Zero hours",
1 => "One hour",
2 => "Two hours",
3 => "Three hours",
4 => "Four hours",
5 => "Five hours",
6 => "Six hours",
7 => "Seven hours",
8 => "Eight hours",
9 => "Nine hours") ;
{
my $n = 9 ;
while($n++ < 24) {
$hourValues{$n} = "$n hours" ;
}
}
my %weekValues = ( 0 => "Zero weeks",
1 => "One week",
2 => "Two weeks",
3 => "Three weeks",
4 => "Four weeks",
5 => "Five weeks",
6 => "Six weeks",
7 => "Seven weeks",
8 => "Eight weeks",
9 => "Nine weeks") ;
{
my $n = 9 ;
while($n++ < 24) {
$weekValues{$n} = "$n weeks" ;
}
}
my @dayValues = sort { $a <=> $b } keys %dayValues ;
my @hourValues = sort { $a <=> $b } keys %hourValues ;
my @weekValues = sort { $a <=> $b } keys %weekValues ;
my $SHOWFILES= &P4CGI::cgi()->param("SHOWFILES") || "";
my $DATESPECIFIER= &P4CGI::cgi()->param("DATESPECIFIER") ;
my $browse_checked = '';
my $picklist_checked = '';
my $explicit_checked = '';
if ($DATESPECIFIER eq 'browse') {
$browse_checked = 'CHECKED';
} elsif ($DATESPECIFIER eq 'picklist') {
$picklist_checked = 'CHECKED';
} elsif ($DATESPECIFIER eq 'explicit') {
$explicit_checked = 'CHECKED';
} else {
# default value if none checked
$picklist_checked = 'CHECKED';
}
prSelection("changeList.cgi",
"General Perforce Query Fourm",
join("\n",(&P4CGI::start_table(),
"<tr>",
"<td align=right valign=center>File spec:</td>",
"<td align=right valign=center></td>",
"<td align=left valign=center><font face=fixed>",
&P4CGI::cgi()->textfield(-name => "FSPC",
-default => "//...",
-size => 50,
-maxlength => 256),
"</font></td></tr>",
"<tr>",
"<td align=right valign=center>Browse</td>",
"<td><input type='radio' name='DATESPECIFIER' value='browse' $browse_checked></td>",
"<td align=left valign=center><font face=fixed>",
"</font></td></tr>",
"<tr>",
"<tr>",
"<td align=right valign=center>Changes within the last:</td>",
"<td><input type='radio' name='DATESPECIFIER' value='picklist' $picklist_checked></td>",
"<td align=left valign=center><font face=fixed>",
&P4CGI::cgi()->popup_menu(-name => "HOURS",
-default => 0,
-values => \@hourValues,
-labels => \%hourValues),
" <br>",
&P4CGI::cgi()->popup_menu(-name => "DAYS",
-default => 1,
-values => \@dayValues,
-labels => \%dayValues),
" <br>",
&P4CGI::cgi()->popup_menu(-name => "WEEKS",
-default => 0,
-values => \@weekValues,
-labels => \%weekValues),
"</font></td></tr>",
"<td align=right valign=center>Between</td>",
"<td><input type='radio' name='DATESPECIFIER' value='explicit' $explicit_checked></td>",
"<td align=left valign=center><font face=fixed>",
&P4CGI::cgi()->textfield(-name => "MINDATE",
-default => "2005/03/27 18:13:00",
-size => 25,
),
"</font></td></tr>",
"<td align=right valign=center>and</td>",
"<td align=right valign=center></td>",
"<td align=left valign=center><font face=fixed>",
&P4CGI::cgi()->textfield(-name => "MAXDATE",
-default => &P4CGI::DateStr2Time("now"),
-size => 25,
),
"</font></td></tr>",
"<tr>",
"<td align=right valign=center>Description Pattern:</td>",
"<td align=right valign=center></td>",
"<td align=left valign=center><font face=fixed>",
&P4CGI::cgi()->textfield(-name => "SEARCHDESC",
-default => "<pattern>",
-size => 50,
-maxlength => 256),
"</font></td></tr>",
"<td align=right valign=center>Invert search:</td>",
"<td align=right valign=center></td>",
"<td align=left valign=center><font face=fixed>",
&P4CGI::cgi()->checkbox(-name => "SEARCH_INVERT",
-value => 1,
-label => " Search descriptions <B>NOT</B> including pattern"),
"</font></td></tr>",
"<td align=right valign=center>Show files:</td>",
"<td align=right valign=center></td>",
"<td align=left valign=center><font face=fixed>",
&P4CGI::cgi()->checkbox(-name => "SHOWFILES",
-value => $SHOWFILES,
-label => " Show the files for each change"),
"</font></td></tr>",
"<td align=right valign=center>User(s):</td>",
"<td align=right valign=center></td>",
"<td align=left valign=center><font face=fixed>",
&P4CGI::cgi()->scrolling_list(-name => "USERS",
-values => \@listOfUsers,
-size => $ulistSize,
-multiple => 'true',
-labels => \%userCvt) .
"</font>",
"</font></td></tr>",
"<td align=right valign=center>Group(s):</td>",
"<td align=right valign=center></td>",
"<td align=left valign=center><font face=fixed>",
&P4CGI::cgi()->scrolling_list(-name => "GROUPS",
-values => \@listOfgroups,
-size => $glistSize,
-multiple => 'true') .
"</font>",
"</font></td></tr>",
&P4CGI::end_table())),
"searchPatt") ;
print &P4CGI::end_table() ;
print "</tr></td>",&P4CGI::end_table() ;
print
&P4CGI::end_page() ;
#
# That's all folks
#

Просмотреть файл

@ -0,0 +1,71 @@
#!/usr/bin/perl -Tw
# -*- perl -*-
use lib '.';
use P4CGI ;
use strict ;
#
#################################################################
# CONFIGURATION INFORMATION
# All config info should be in P4CGI.pm
#
#################################################################
#
# List all branches
#
#################################################################
my $SORTBY=&P4CGI::cgi()->param("SORTBY") ;
$SORTBY="DATE" unless ($SORTBY == 'NAME');
my $otherSort ;
if($SORTBY eq "NAME") {
$otherSort = &P4CGI::ahref("SORTBY=DATE",
"Sort by date") ;
}
else {
$otherSort = &P4CGI::ahref("SORTBY=NAME",
"Sort by name") ;
} ;
# Print header
print "",
&P4CGI::start_page("List of branches",
&P4CGI::ul_list("<b>Name</b> -- view branch info",
$otherSort)) ;
# Get list of all brances
local *P4 ;
print "",
&P4CGI::start_table(""),
&P4CGI::table_header("Name/view branch","Updated","Description") ;
&P4CGI::p4call(*P4, "branches" );
my %rows ;
while(<P4>) {
if(/^Branch (\S+)\s+(\S+)\s+\'([^\']*)\'/) {
my ($name,$cdate,$desc) = ($1,$2,$3) ;
$name = &P4CGI::ahref(-url => "branchView.cgi" ,
"BRANCH=$name",
$name) ;
my $s = $SORTBY eq "NAME"? uc("$name $cdate") : "$cdate $name" ;
$rows{$s} = &P4CGI::table_row($name,$cdate,$desc) ;
}
}
my $s ;
if($SORTBY eq "NAME") {
foreach $s (sort keys %rows) {
print $rows{$s} ;
}
}
else {
foreach $s (sort { $b cmp $a } keys %rows) {
print $rows{$s} ;
}
} ;
print "",
&P4CGI::end_table(""),
&P4CGI::end_page("") ;
#
# That's all folks
#

Просмотреть файл

@ -0,0 +1,174 @@
#!/usr/bin/perl -w
# -*- perl -*-
use P4CGI ;
use strict ;
#
#################################################################
# CONFIGURATION INFORMATION
# All config info should be in P4CGI.pm
#
#################################################################
#
# View a branch
#
#################################################################
###
### Get branch name
###
my $branch = P4CGI::cgi()->param("BRANCH") ;
$branch = &P4CGI::extract_printable_chars($branch);
&P4CGI::bail("No branch specified") unless defined $branch ;
&P4CGI::bail("Invalid branch specified") if $branch =~ /[<>"&:;'`]/;
###
### Get info about branch
###
my %values ;
my @fields = &P4CGI::p4readform("branch -o $branch",\%values) ;
# Get real user names...
my %userCvt ;
{
my @users ;
@users=&P4CGI::run_cmd("users" );
%userCvt = map { /^(\S+).*> \((.+)\) .*$/ ; ($1,$2) ; } @users ;
}
# Fix owner field
if (exists $values{"Owner"}) {
my $u = $values{"Owner"} ;
if(exists $userCvt{$u}) {
$values{"Owner"} = &P4CGI::ahref(-url=>"userView.cgi",
"USER=$u",
"$u") . " (" . $userCvt{$u} . ")" ;
}
else {
$values{"Owner"} = "$u (Unknown user)" ;
}
}
# Fix description field
if(exists $values{"Description"}) {
my $d = $values{"Description"} ;
$values{"Description"} = "<pre>$d</pre>" ;
}
# Fix up view info
my $viewFrom ="";
my $viewTo ="";
my $allfrom ="";
my $allto ="";
foreach (split("\n",$values{"View"})) {
/^\s*\/\/(.+)\s+\/\/(.+)/ ;
my ($from,$to) = ($1,$2) ;
$allfrom .= "//$from" ;
$allto .= "+//$to" ;
my @from = split /\//,$from ;
my @to = split /\//,$to ;
my $common = "//" ;
while(@from != 0 and @to != 0 and ($from[0] eq $to[0])) {
$common .= shift @from ;
$common .= "/" ;
shift @to ;
}
$from = $common . "<FONT COLOR=red>" . join("/",@from) . "</FONT>" ;
$to = $common . "<FONT COLOR=red>" . join("/",@to) . "</FONT>" ;
if (length($viewFrom) > 0) {
$viewFrom .= "<br>" ;
$viewTo .= "<br>" ;
}
$viewFrom .= "<tt>$from&nbsp;</tt>" ;
$viewTo .= "<tt>$to</tt>" ;
} ;
$allto =~ s/^\+// ;
$values{"View"} = join("\n",(&P4CGI::start_table("cellspacing=0 cellpadding=0"),
&P4CGI::table_row($viewFrom,$viewTo),
&P4CGI::end_table())) ;
my $allToURL = &P4CGI::ahref(-url => "changeList.cgi",
"FSPC=$allto",
"List changes in branch") ;
my $recentlyChanged = &P4CGI::ahref(-url => "filesChangedSince.cgi",
"FSPC=$allto",
"List recently changed files in branch") ;
my $listByUser = &P4CGI::ahref(-url => "changeByUsers.cgi",
"FSPC=$allto",
"List changes in branch for selected user") ;
my $depotStats = &P4CGI::ahref(-url => "depotStats.cgi",
"FSPC=$allto",
"View depot statistics for branch") ;
my $allFromURL = &P4CGI::ahref(-url => "changeList.cgi",
"FSPC=$allfrom",
"View changes in branch source") ;
my $searchDesc = &P4CGI::ahref(-url => "searchPattern.cgi",
"FSPC=$allto",
"Search for pattern in change descriptions") ;
my $openFiles = &P4CGI::ahref(-url => "fileOpen.cgi",
"FSPC=$allto",
"List open files in branch") ;
###
### Print html
###
print "",
&P4CGI::start_page("Branch $branch",
&P4CGI::ul_list("<b>owner</b> -- view user info",
$allFromURL)) ;
print &P4CGI::start_table("") ;
my $f ;
foreach $f (@fields) {
print &P4CGI::table_row({-align => "right",
-valign => "top",
-type => "th",
-text => "$f"},
$values{$f}) ;
} ;
print
&P4CGI::end_table(),
"<hr>";
my @labels ;
&P4CGI::p4call(*P4, "labels" );
while(<P4>) {
chomp ;
/^Label\s+(\S+)\s/ and do { push @labels,$1 ; } ;
}
close P4 ;
my $chnotinlabel= join("\n",(&P4CGI::cgi()->startform(-action => "changeList.cgi",
-method => "GET"),
&P4CGI::cgi()->hidden(-name=>"FSPC",
-value=>"$allto"),
"View changes not in label:<font size=+0>",
&P4CGI::cgi()->popup_menu(-name => "EXLABEL",
-value => \@labels),
&P4CGI::cgi()->submit(-name => "Go",
-value => "Go"),
"</font>",
&P4CGI::cgi()->endform())) ;
print "<font size=+1>" , &P4CGI::ul_list($allToURL,
$chnotinlabel,
$listByUser,
$recentlyChanged,
$openFiles,
$searchDesc,
$depotStats) , "</font>" ;
print
&P4CGI::end_page() ;
#
# That's all folks
#

Просмотреть файл

@ -0,0 +1,166 @@
#!/usr/bin/perl -Tw
# -*- perl -*-
use lib '.';
use P4CGI ;
use strict ;
#
#################################################################
# CONFIGURATION INFORMATION
# All config info should be in P4CGI.pm
#
#################################################################
#
# List changes by user and group
#
#################################################################
my $FSPC = P4CGI::cgi()->param("FSPC") || "//..." ;
$FSPC = P4CGI::extract_filename_chars($FSPC);
my $COMPLETE= &P4CGI::cgi()->param("COMPLETE") ;
if (defined($COMPLETE)) {
$COMPLETE ="Yes";
}
my @legend ;
unless(defined $COMPLETE) {
push @legend,&P4CGI::ahref("COMPLETE=Yes",
"FSPC=$FSPC",
"Include old users in list") ;
} ;
my $legend = "" ;
$legend = &P4CGI::ul_list(@legend) if @legend > 0 ;
print "", &P4CGI::start_page("View changes by<br>User(s) and Group(s)",$legend) ;
# Get users
my @users ;
@users=&P4CGI::run_cmd("users");
my @listOfUsers = sort { uc($a) cmp uc ($b) } map { /^(\S+).*> \((.+)\) .*$/ ; $1 ; } @users ;
my %userCvt = map { /^(\S+).*> \((.+)\) .*$/ ; ($1,$2) ; } @users ;
if(defined $COMPLETE) {
my %allUsers ;
local *P ;
&P4CGI::p4call(*P, "changes $FSPC") ;
while(<P>) {
/.*by (\S+)@/ ;
if(exists $allUsers{$1}) { $allUsers{$1} += 1 ; }
else { $allUsers{$1} = 1 ; }
} ;
foreach (keys %allUsers) {
if(!exists $userCvt{$_}) {
$userCvt{$_} = "Old user: $_ ($allUsers{$_} changes)" ;
push @listOfUsers,$_ ;
} else {
$userCvt{$_} .= " ($allUsers{$_} changes)" ;
}
} ;
}
# Get groups
my @listOfgroups ;
@listOfgroups=&P4CGI::run_cmd("groups");
print "",
&P4CGI::start_table("bgcolor=".&P4CGI::HDRFTR_BGCOLOR()." align=center cellpadding=0 cellspacing=2"),
"<tr><td>\n" ;
sub prSelection($$$$ )
{
my $cgitarget = shift @_ ;
my $desc = shift @_ ;
my $fields = shift @_ ;
my $helpTarget = shift @_ ;
print "", &P4CGI::table_row(-valign=>"center",
{-align=>"center",
-text =>
join("\n",
&P4CGI::cgi()->startform(-action => $cgitarget,
-method => "GET"),
"<font size=+1>$desc</font>")},
{-align=>"left",
-valign=>"top",
-text => $fields},
{-align=>"left",
-text => " "},
{-align=>"left",
-valign=>"bottom",
-width=>"1",
-text => &P4CGI::cgi()->submit(-name => "ignore",
-value => "GO!")
},
{ -valign=>"bottom",
-text => &P4CGI::cgi()->endform()
},
) ;
} ;
print "", &P4CGI::start_table("width=100% cellspacing=4") ;
my $ulistSize = @listOfUsers ;
$ulistSize= 15 if $ulistSize > 15 ;
my $glistSize = @listOfgroups ;
$glistSize= 15 if $glistSize > 15 ;
prSelection("changeList.cgi",
"Select users and groups",
join("\n",
&P4CGI::start_table(),
&P4CGI::table_row(
"File spec:",
"<font face=fixed>" .
&P4CGI::cgi()->textfield(-name => "FSPC",
-default => $FSPC,
-size => 50,
-maxlength => 256) .
"</font>"),
&P4CGI::table_row(-valign=>"top",
"User(s):",
"<font face=fixed>" .
&P4CGI::cgi()->scrolling_list(-name => "USERS",
-values => \@listOfUsers,
-size => $ulistSize,
-multiple => 'true',
-labels => \%userCvt) .
"</font>"),
&P4CGI::table_row(-valign=>"top",
"Group(s):<font face=fixed>",
"<font face=fixed>" .
&P4CGI::cgi()->scrolling_list(-name => "GROUPS",
-values => \@listOfgroups,
-size => $glistSize,
-multiple => 'true') .
"</font>"),
&P4CGI::end_table()),
"user_and_group") ;
print &P4CGI::end_table() ;
print "</tr></td>",&P4CGI::end_table() ;
print
&P4CGI::end_page() ;
#
# That's all folks
#

Просмотреть файл

@ -0,0 +1,998 @@
#!/usr/bin/perl -Tw
# -*- perl -*-
use lib '.';
use P4CGI ;
use strict ;
#
#################################################################
# CONFIGURATION INFORMATION
# All config info should be in P4CGI.pm
#
#################################################################
#
# P4 change browser
# View list of changes for selected part of depot
#
#################################################################
#####
# This is (or was) the most complicated and insane script in P4DB.
# The reason for this is that features where added and added and added until
# the script became impossible to maintain and no more features could
# be added. Despite this I still wanted MORE FEATURES and finally I
# decided to start all over again and see if it is possible to add the
# new features if I rewrote it all. And maybe, just maybe, I will
# manage to make it maintainable this time. We will see......
# Jan 7 - 2000/Fredric
####
#######
# Arguments:
#
# FSPC
# File specification. Should start with //. Can be more than one file spec
# in which case they are concatenated (no space, but start each file spec
# with //).
# The file specification should not contain any label or revision numbers.
#
# LABEL
# Label specification. Label for which changes should be listed.
# There can be only one label.
#
# NOTE! FSPC or LABEL must be specified.
#
# STATUS
# Status of changes. Allowed values are "submitted" and "pending".
# If not supplied "submitted" is assumed.
#
# EXLABEL (optional)
# Specify a label to exclude. Same format as LABEL. The changes made for
# this label are excluded from list.
#
# MAXCH (optional)
# Max changes to display. To avoid very large html pages this argument
# limits the number of changes displayed at one page.
# If not specified there is a default value used (from config file)
#
# FIRSTCH (optional)
# When MAXCH is specified this specifies change to start at (for second
# and subsequent pages)
#
# CHOFFSET (optional)
# Number of changes already displayed.
#
# SEARCHDESC (optional)
# View only changes with pattern in description
#
# SEARCH_INVERT (optional)
# If specified, invert pattern search
#
# USER (optional)
# View only changes for users specified in comma-separated list
#
# GROUP (optional)
# View only changes for users in comma-separated list of groups
#
# CLIENT (optional)
# View only changes for clients specified in comma-separated list
#
# SHOWREFERENCED (optional)
# If present and set to "Y" will try to display description for changes
# referred to in change description
#
######
my $MAGIC_RED=":::RED:::~~~" ;
### ###
### Get command arguments ###
### ###
#
# Get file spec argument
#
my $filespec = P4CGI::cgi()->param("FSPC") ;
$filespec = &P4CGI::extract_printable_chars($filespec) if ($filespec);
my $FSPC_WasSpecified = $filespec ;
$filespec = "//..." unless $filespec ;
$filespec =~ s/\s*\+\s*\/\//\/\//g ; # replace <space>+<space>// with //
# where <space> is 0 or more whitespace charcaters
&P4CGI::bail("Invalid file spec.") if ($filespec =~ /[<>"&:;'`]/);
my @FSPC =
map {
if($_) { "//".$_ ; }
else { () ; } ;
} split("//", $filespec ) if defined $filespec ;
#
# Get label argument
#
my $LABEL = P4CGI::cgi()->param("LABEL") ;
$LABEL = &P4CGI::extract_printable_chars($LABEL) if ($LABEL);
if(defined $LABEL and $LABEL eq "-") { $LABEL = undef ; } ;
&P4CGI::bail("Invalid label.") if ($LABEL) && ($LABEL =~ /[<>"&:;'`]/);
#
# Check that FSPC or LABEL is specified
#
unless(defined $LABEL or defined $FSPC_WasSpecified) {
&P4CGI::bail("File spec OR label must be specified") ;
}
#
# Get label to exclude
#
my $EXLABEL = &P4CGI::cgi()->param("EXLABEL") ;
if(defined $EXLABEL and $EXLABEL eq "-") { $EXLABEL = undef ; } ;
&P4CGI::bail("Invalid label to exclude: '$EXLABEL'.") if ($EXLABEL) && ($EXLABEL =~ /[<>"&:;'`]/);
#
# Get status
#
my $STATUS = &P4CGI::cgi()->param("STATUS") ;
unless(defined $STATUS) { $STATUS = "submitted" ; } ;
unless ($STATUS =~ /^\w+$/) { &P4CGI::bail("Invalid status: '$STATUS'."); };
#
# Get max changes to display
#
my $MAXCH = P4CGI::cgi()->param("MAXCH") ;
$MAXCH = &P4CGI::extract_digits($MAXCH) if ($MAXCH);
$MAXCH = &P4CGI::MAX_CHANGES() unless($MAXCH) ;
#
# Get first change No. to display and offset from start
#
my $FIRSTCH ;
my $CHOFFSET=0 ;
if(defined $MAXCH) {
$FIRSTCH = P4CGI::cgi()->param("FIRSTCH") ;
$FIRSTCH = P4CGI::extract_digits($FIRSTCH) if ($FIRSTCH);
$CHOFFSET = P4CGI::cgi()->param("CHOFFSETDISP") ;
$CHOFFSET = P4CGI::extract_digits( $CHOFFSET) if ($CHOFFSET);
}
my $SHOWREFERENCED = P4CGI::cgi()->param("SHOWREFERENCED") ;
$SHOWREFERENCED = undef if defined $SHOWREFERENCED and $SHOWREFERENCED ne "Y" ;
#
# Get search data, user and client parameters
#
my $SEARCHDESC = &P4CGI::cgi()->param("SEARCHDESC") ;
$SEARCHDESC= &P4CGI::extract_printable_chars($SEARCHDESC) if ($SEARCHDESC);
$SEARCHDESC =~ s/^<pattern>$//;
$SEARCHDESC=undef if defined $SEARCHDESC and $SEARCHDESC eq "" ;
&P4CGI::bail("Invalid search terms: '$SEARCHDESC'.") if ($SEARCHDESC) && ($SEARCHDESC =~ /[<>"&:;'`]/);
my $SEARCH_INVERT = &P4CGI::cgi()->param("SEARCH_INVERT") ;
&P4CGI::bail("Invalid search terms: '$SEARCH_INVERT'.") if ($SEARCH_INVERT) && ($SEARCH_INVERT =~ /[<>"&:;'`]/);
my $USER = &P4CGI::cgi()->param("USER") ;
$USER = &P4CGI::extract_user($USER) if ($USER);
{
my @tmp = map { &P4CGI::extract_user($_) } &P4CGI::cgi()->param("USERS") ;
if(@tmp) {
if(defined $USER) {
$USER .= "," . join(',',@tmp) ;
}
else {
$USER = join(',',@tmp) ;
}
}
}
$USER=undef if defined $USER and $USER eq "" ;
&P4CGI::bail("Invalid user(s).")
unless (!defined($USER) || ($USER =~ /^\w+(,\w+)*$/));
my $GROUP = &P4CGI::cgi()->param("GROUP") ;
$GROUP = &P4CGI::extract_user($GROUP) if ($GROUP);
{
my @tmp = map { &P4CGI::extract_user($_) } &P4CGI::cgi()->param("GROUPS") ;
if(@tmp) {
if(defined $GROUP) {
$GROUP .= "," . join(',',@tmp) ;
}
else {
$GROUP = join(',',@tmp) ;
}
}
}
$GROUP=undef if defined $GROUP and $GROUP eq "" ;
&P4CGI::bail("Invalid group(s).") if ($GROUP =~ /[<>"&:;'`]/);
my $CLIENT = &P4CGI::cgi()->param("CLIENT") ;
$CLIENT = &P4CGI::extract_printable_chars($CLIENT) if ($CLIENT);
$CLIENT=undef if defined $CLIENT and $CLIENT eq "" ;
&P4CGI::bail("Invalid client specified.") if ($CLIENT) && ($CLIENT =~ /[<>"&:;'`]/);
my $WEEKS = P4CGI::cgi()->param("WEEKS") ;
if(defined $WEEKS) {
$WEEKS = P4CGI::extract_digits($WEEKS) ;
}
else {
$WEEKS = 0 ;
}
my $DAYS = P4CGI::cgi()->param("DAYS");
if(defined $DAYS) {
$DAYS = P4CGI::extract_digits($DAYS);
}
else {
$DAYS=0 ;
}
my $HOURS = P4CGI::cgi()->param("HOURS");
if(defined $HOURS) {
$HOURS = P4CGI::extract_digits($HOURS);
}
else {
$HOURS = 0 ;
}
my $SUBMIT = P4CGI::cgi()->param("SUBMIT");
if(defined $SUBMIT) {
$SUBMIT=1;
} else {
$SUBMIT='';
}
my $MINDATE = P4CGI::cgi()->param("MINDATE") ;
$MINDATE = &P4CGI::extract_printable_chars($MINDATE);
my $MAXDATE = P4CGI::cgi()->param("MAXDATE") ;
$MAXDATE = &P4CGI::extract_printable_chars($MAXDATE);
my $DATESPECIFIER = P4CGI::cgi()->param("DATESPECIFIER") ;
$DATESPECIFIER = &P4CGI::extract_printable_chars($DATESPECIFIER);
my $TIMEINTERVALSTR;
if ($DATESPECIFIER eq 'explicit') {
$TIMEINTERVALSTR = "\@".&P4CGI::DateStr2Time($MINDATE).",\@".&P4CGI::DateStr2Time($MAXDATE);
} elsif ($DATESPECIFIER eq 'picklist') {
$TIMEINTERVALSTR = &P4CGI::DateList2Time($WEEKS, $DAYS, $HOURS);
} else {
$TIMEINTERVALSTR = '';
}
my $SHOWFILES = P4CGI::cgi()->param("SHOWFILES") ;
if(defined $SHOWFILES) {
$SHOWFILES='Y';
} else {
undef $SHOWFILES;
;
}
my %allUsers;
###
### Sub getChanges
###
# This subroutine is used to get a set of changes from depot. The parameter is a hash containing
# a set of switches:
# -long If set, get changes in "long" format (i.e. full description,
# not only the first 27 chars)
# -file File spec for changes
# -firstch First change to look for (or "offset")
# -maxch Max changes to get
# -status Status ("submitted" or "pending")
# -label Label for file spec
# -lastch Reference to scalar to receive last change parsed
# -lastrch Reference to scalar to receive last change parsed and returned in result
# -resultto A reference to a hash to receive result
# -select A reference to a subroutine to call that determine if a change should be included
# in list. The subroutine gets parameters: (<change>,<date>,<user>,<client>,<description>)
# The <description> parameter is passed as a reference and can be modified
# The subroutine should return true if the change should be included.
# NOTE! The -select parameter is very important to understand if you plan to
# understand more of this code.
#
# Another important thing to understand is that this subroutine getChanges is frequently called
# more than once.
#
sub getChanges(%)
{
my %pars = @_ ;
my $long ; # defined if -l flag
my $filespec = "" ; # file spec
my $firstch = &P4CGI::CURRENT_CHANGE_LEVEL() ; # first change to look for
my $maxch = 0 ; # max no changes
my $status="submitted" ; # status
my $label ; # label
my $rhash ; # result
my $select ; # selection funtion
my $lastch ; # Last change parsed
my $lastrch ; # Last change parsed and returned
my $linkedch ; # linked ch ref
my $k ;
foreach $k (keys %pars) {
$k = lc($k) ;
$k eq "-long" and do { $long = $pars{$k} ; next } ;
$k eq "-file" and do { $filespec = $pars{$k} ; next } ;
$k eq "-firstch" and do { $firstch = $pars{$k} ; next } ;
$k eq "-maxch" and do { $maxch = $pars{$k} ; next } ;
$k eq "-status" and do { $status = $pars{$k} ; next } ;
$k eq "-label" and do { $label = $pars{$k} ; next } ;
$k eq "-resultto" and do { $rhash = $pars{$k} ; next } ;
$k eq "-select" and do { $select = $pars{$k} ; next } ;
$k eq "-lastch" and do { $lastch = $pars{$k} ; next } ;
$k eq "-lastrch" and do { $lastrch = $pars{$k} ; next } ;
$k eq "-magiclinked" and do { $linkedch = $pars{$k} ; next } ;
} ;
my $tmpLastch ;
$lastch = \$tmpLastch unless defined $lastch ;
$lastrch = \$tmpLastch unless defined $lastrch ;
if($long) { $long = " -l " ; } else { $long = "" } ;
if ($TIMEINTERVALSTR) {
$filespec .= $TIMEINTERVALSTR;
} elsif($label) {
$filespec .= "\@$label" ;
} else {
if ($firstch) {
$filespec .= "\@$firstch" ;
} ;
} ;
if($maxch) { $maxch = " -m $maxch " ;} else { $maxch = "" ; } ;
if($status eq "pending") {
$filespec = "" ;
} ;
if($filespec =~ /\s/) {
$filespec = "\"$filespec\"" ;
} ;
my $command = "changes $long -s $status $maxch $filespec" ;
local *P4 ;
my $n = 0 ;
&P4CGI::p4call(*P4,$command) ;
$$lastrch = 0 ;
while(<P4>) {
chomp ;
if(/Change (\d+) on (\S+) by (\w+)\@(\S+)/) {
$n++ ;
my ($change,$date,$user,$client) = ($1,$2,$3,$4) ;
$$lastch = $change ;
my $desc = "" ;
if($long) {
<P4> ;
while(<P4>) {
chomp ;
last if length($_) == 0 ;
s/^\t// ;
if(length($desc) > 0) { $desc .="\n" ; } ;
$desc .= $_ ;
}
# &P4CGI::ERRLOG("select: $select") ;
if(defined $select) {
next unless &$select($change,$date,$user,$client,\$desc) ;
}
my @ch;
$desc = "<pre>" . &P4CGI::magic(&P4CGI::fixSpecChar($desc),\@ch) . "</pre>\n" ;
$desc =~ s/$MAGIC_RED(.*?)$MAGIC_RED/<font color=red>$1<\/font>/gi ;
if(defined $linkedch and @ch > 0) {
$$linkedch{$change} = \@ch ;
} ;
} ;
$$lastrch = $change ;
$$rhash{$change} = {'date'=>$date,'user'=>$user,'client'=>$client,'desc'=>$desc} ;
}
}
close P4 ;
return $n ;
} ;
sub getDescription
{
my ($change, $rhash) = @_ ;
my $command = "describe -s $change" ;
local *P4 ;
my $n = 0 ;
&P4CGI::p4call(*P4,$command) ;
while(<P4>) {
chomp ;
if(/Change (\d+) by (\w+)\@(\S+) on (\S+) (\S+)/) {
$n++ ;
my ($change,$user,$client,$date,$time) = ($1,$2,$3,$4,$5) ;
my @files =();
my $desc = "" ;
<P4> ;
while(<P4>) {
chomp ;
last if length($_) == 0 ;
s/^\t// ;
if(length($desc) > 0) { $desc .="\n" ; } ;
$desc .= $_ ;
}
<P4> ;
<P4> ;
while(<P4>) {
chomp ;
if (m/... (\S+)\#(\d+)/) {
my ($file, $rev) = ($1, $2);
push @files, (
&P4CGI::ahref("-url","fileLogView.cgi",
"FSPC=$file", "$file"),
"\#",
&P4CGI::ahref("-url","fileViewer.cgi",
"FSPC=$file",
"REV=$rev","$rev"),
&P4CGI::ahref("-url","fileDiffView.cgi",
"FSPC=$file",
"REV=$rev",
"ACT=edit",
"edit"),
"<br>\n"
);
}
}
my @ch;
$desc = "<pre>" . &P4CGI::magic(&P4CGI::fixSpecChar($desc),\@ch) . "</pre>\n" ;
$desc =~ s/$MAGIC_RED(.*?)$MAGIC_RED/<font color=red>$1<\/font>/gi ;
$$rhash{$change} = {
'date'=>$date,'time'=>$time,
'user'=>$user,'client'=>$client,
'desc'=>$desc, 'files'=>[@files],
} ;
}
}
close P4 ;
return $n ;
} ;
sub get_params {
my @params='';
@params = ("STATUS=$STATUS",
"MAXCH=$MAXCH") ;
if(defined $EXLABEL) {
push @params,"EXLABEL=$EXLABEL" ;
} ;
if(defined $LABEL) {
push @params,"LABEL=$LABEL" ;
} ;
if(defined $USER) {
push @params,"USER=$USER" ;
} ;
if(defined $GROUP) {
push @params,"GROUP=$GROUP" ;
} ;
if(defined $SEARCHDESC) {
push @params,"SEARCHDESC=$SEARCHDESC" ;
} ;
if(defined $SEARCH_INVERT) {
push @params,"SEARCH_INVERT=1" ;
} ;
if(defined $SHOWREFERENCED) {
push @params,"SHOWREFERENCED=$SHOWREFERENCED" ;
} ;
if(defined $WEEKS) {
push @params,"WEEKS=$WEEKS" ;
} ;
if(defined $DAYS) {
push @params,"DAYS=$DAYS" ;
} ;
if(defined $HOURS) {
push @params,"HOURS=$HOURS" ;
} ;
if(defined $MINDATE) {
push @params,"MINDATE=$MINDATE" ;
} ;
if(defined $MAXDATE) {
push @params,"MAXDATE=$MAXDATE" ;
} ;
if(defined $DATESPECIFIER) {
push @params,"DATESPECIFIER=$DATESPECIFIER" ;
} ;
if(defined $SHOWFILES) {
push @params,"SHOWFILES=$SHOWFILES" ;
} ;
if($FSPC_WasSpecified) {
push @params,"FSPC=".P4CGI::cgi()->param("FSPC") ;
}
return @params;
}
### get target ###
my %extraUrlOptions ;
if(&P4CGI::CHANGES_IN_SEPPARATE_WIN()) {
$extraUrlOptions{"-target"}="CHANGES" ;
}
### ###
### Fix page title ###
### ###
my $title = "Changes for " ;
if($FSPC_WasSpecified) {
$title .= "<br><tt>" . join("<br>",@FSPC) . "</tt>" ;
if(defined $LABEL) {
$title .= "<br>and label <tt>$LABEL</tt>" ;
}
}
else {
$title .= "label <tt>$LABEL</tt>" ;
} ;
if(defined $EXLABEL) {
$title .= "<br>excluding changes for label <tt>$EXLABEL</tt>" ;
}
if(defined $CHOFFSET and $CHOFFSET > 0) {
$title .= "<br><small>(offset $CHOFFSET from top)</small>" ;
} ;
if(defined $USER) {
$title .= "<br>user: <tt>$USER</tt>" ;
} ;
if(defined $GROUP) {
$title .= "<br>group: <tt>$GROUP</tt>" ; #
} ;
if(defined $CLIENT) {
$title .= "<br>client: <tt>$CLIENT</tt>" ; #
} ;
if(defined $SEARCHDESC) {
my $not="" ;
if(defined $SEARCH_INVERT) {
$not = " does not"
}
$title .= "<br>where description$not match: <tt>$SEARCHDESC</tt>" ;
} ;
if($STATUS eq "pending") {
$title .= "<br>(status: pending)" ;
} ;
### ###
### Get changes to exclude (if any) ###
### ###
local *P4 ;
my %excludeChanges ;
my $f ;
my $lastChangeInLabel = 0 ;
if(defined $EXLABEL ) {
getChanges(-label=>$EXLABEL,
-resultto=> \%excludeChanges) ;
my $n = scalar keys(%excludeChanges) ;
my @tmp = sort { $b <=> $a } keys %excludeChanges ;
$lastChangeInLabel = $tmp[0] ;
&P4CGI::ERRLOG("Exclude from label \"$EXLABEL\":$n lastCh:$lastChangeInLabel") ;
} ;
### ###
### Start page ###
### ###
my @legend ;
push @legend,
"<b>Change No.</b> -- see details of change",
"<b>User</b> -- Information about user" ;
unless(defined $SHOWREFERENCED) {
push @legend,&P4CGI::ahref(-url => &P4CGI::cgi()->self_url . "&SHOWREFERENCED=Y",
"Show description of changes referenced in change description") ;
}
&P4CGI::SET_HELP_TARGET("changeList") ;
print
"",
&P4CGI::start_page($title,&P4CGI::ul_list(@legend)) ;
### ###
### Get changes ###
### ###
my %changes ;
my $cchange = "0" ;
my $oldestSafeCh = 0 ; # The last change in %changes that is "safe" (after this change changes
# may be missing)
my $gotAll="No" ; # Set to "Yes" if there are no more changes to display
my %magicLinks ;
###
### If "pending" get all pending changes
###
if($STATUS eq "pending") {
# Pending. All file and label specifications ignored...
$title = "Pending changes" ;
my $choffstr = "" ;
my %chs ;
getChanges(-status => "pending",
-long => 1,
-resultto => \%changes) ;
my $ch ;
foreach $ch (sort { $b <=> $a } keys %changes) {
&setDisplay($ch, \%changes);
}
}
###
### If not "pending" get all changes
###
else {
my $max = $MAXCH ; # max
##
## Create subroutines for selection
##
my @selectFuncs ; # Variable to hold subroutines
if(defined $SEARCHDESC) { # Search description
$max = (1+$max)*10 ;
my $s = "($SEARCHDESC)" ;
# $s =~ s/\s*\+\s*/|/g ;
$s =~ s/\./\\\./g ;
$s =~ s/\*/.\*/g ;
$s =~ s/\?/./g ;
$s =~ s/\s+/[\\\s+\n]+/g ;
my $sq = $s ;
$sq =~ s/\n/\\n/g ;
&P4CGI::ERRLOG("select: ".$sq) ;
if(defined $SEARCH_INVERT) {
push @selectFuncs , sub { my ($ch,$date,$user,$client,$desc) = @_ ;
return $$desc !~ /$s/gi ;
} ;
}
else {
push @selectFuncs , sub { my ($ch,$date,$user,$client,$desc) = @_ ;
return $$desc =~ s/$s/$MAGIC_RED$1$MAGIC_RED/gi ;
} ;
}
} ;
if(defined $GROUP) { # Group(s) specified
my @grps = split(',',$GROUP) ;
while(@grps) {
my $grp = shift @grps ;
&P4CGI::ERRLOG("group: $grp") ;
my %data ;
&P4CGI::p4readform("group -o $grp",\%data) ;
if(exists $data{"Subgroups"}) {
push @grps,split("\n",$data{"Subgroups"}) ;
}
my $u ;
foreach $u (split("\n",$data{"Users"}))
{
if(defined $USER) {
$USER .= ",$u";
}
else {
$USER = "$u" ;
}
}
}
}
if(defined $USER) { # User(s) specified
my %users ;
my $usersToCheck = 0 ;
foreach (split(',',$USER)) {
$users{$_} = 1 ;
$usersToCheck++ ;
}
&P4CGI::ERRLOG("users: ".join(",",(keys %users))) ;
push @selectFuncs , sub { my ($ch,$date,$user,$client,$desc) = @_ ;
return exists $users{$user} ;
} ;
my @users ;
@users=&P4CGI::run_cmd("users") ;
$max *= 3+int(@users/(5*$usersToCheck)) ;
} ;
if(defined $CLIENT) { # Client specified
my %clients ;
my $clientsToCheck = 0 ;
foreach (split(',',$CLIENT)) {
$clients{$_} = 1 ;
$clientsToCheck++ ;
}
&P4CGI::ERRLOG("client: $CLIENT") ;
push @selectFuncs , sub { my ($ch,$date,$user,$client,$desc) = @_ ;
return exists $clients{$client} ;
} ;
my @clients ;
@clients=&P4CGI::run_cmd("clients") ;
$max *= 3+int(@clients/(5*$clientsToCheck)) ;
} ;
if((keys %excludeChanges) > 0) { # Exclude changes from a list
push @selectFuncs , sub { my ($ch,$date,$user,$client,$desc) = @_ ;
return ! exists $excludeChanges{$ch} ;
} ;
}
##
## Create a select subroutine for selection functions defined (if any)
##
my $selectFunc ;
if(@selectFuncs > 0) {
$selectFunc = sub {
my @params = @_ ;
foreach (@selectFuncs) {
return undef unless &$_(@params) ;
}
return 1 ;
}
}
##
## Set max changes to return for each search
##
$max = 2000 if $max < 2000 ; # There is no point searching less than 2000 at the time.
# Absolutely no point.
my %chLevel ; # Store how far back we have traced by file spec
my %ended ; # Set to true for a file spec where we have hit the end
# HINT: We can merge changes from more than one file spec
my $noFSPCsNotEnded = 0 ; # Store number of file speces that has not ended (so we know
# when there is no point to keep trying)
##
## Initialize variable above
##
my $firstch = &P4CGI::CURRENT_CHANGE_LEVEL() ; # First change we are interested in
$firstch = $FIRSTCH if defined $FIRSTCH ; # Set if parameter FIRSTCH given
my $fspc ;
foreach $fspc (@FSPC) {
$chLevel{$fspc} = $firstch ; # Set level to current for all filespec's
$ended{$fspc} = 0 ; # Not ready with flespec yet...
$noFSPCsNotEnded++ ; # Increment filespecs not ready
}
my %chs ; # result hash
while(1) { # Loop until ready
##
## Loop over each file spec
##
$oldestSafeCh = 0 ;
my $filespec ;
foreach $filespec (@FSPC) { # for each filespec.....
next if $ended{$filespec} ; # Skip if all changes read for file spec
my $lastIncludedCh ; # Store last change included in selection
#
# Set up parameters for getChanges()
#
my %params = (-file => $filespec ,
-resultto => \%changes,
-long => 1,
-maxch => $max+1,
-select => $selectFunc,
-lastch => \$chLevel{$filespec},
-lastrch => \$lastIncludedCh,
-firstch => $chLevel{$filespec},
-magiclinked => \%magicLinks ) ;
if(defined $LABEL) {
$params{"-label"} = $LABEL ;
}
#
# Call getChanges
#
my $gotCh = getChanges(%params) ;
#
# Evaluate returned data
#
if($gotCh != ($max+1)) { # Did we get all changes we asked for? If no....
$ended{$filespec} = 1 ; # ... there is no more data for this file spec
$noFSPCsNotEnded-- ;
&P4CGI::ERRLOG("file spec \"$filespec\" ended") ;
}
else {
if($lastIncludedCh > $oldestSafeCh) { # Update oldes safe ch.
$oldestSafeCh = $lastIncludedCh ;
}
}
} # End loop over each filespec
if($noFSPCsNotEnded == 0) { # Did we get all changes there are for the filespecs?
# No more changes for these filespecs
$gotAll = "Yes" ;
last ;
}
# Count number of changes that we can "trust" (for more than
# one file spec we reach different number of changes back in time)
my $okchs = 0 ;
my $c ;
foreach $c (keys %changes) {
$okchs++ if $c >= $oldestSafeCh ;
}
&P4CGI::ERRLOG("okchs: $okchs, max: $max") ;
last if $okchs >= $MAXCH ; # Did we get enough changes...
}
##
## Build data for changes to display
##
my $changesDisplayed=0 ;
my $ch ;
my @sorted = sort { $b <=> $a } keys %changes ;
while($ch = shift(@sorted)) {
if((exists $changes{$ch}{'display'}) or (defined $FIRSTCH and ($ch > $FIRSTCH))) {
&P4CGI::ERRLOG("skip ch $ch") ;
}
else {
&setDisplay($ch, \%changes);
$changesDisplayed++ ;
if(defined $SHOWREFERENCED and exists $magicLinks{$ch}) {
my $refch = "<small><dl compact>" ;
my $n = 0 ;
my $c ;
foreach $c (@{$magicLinks{$ch}}) {
my %data ;
&P4CGI::p4readform("change -o $c",\%data) ;
if(exists $data{"Description"}) {
$n++ ;
my $d = &P4CGI::fixSpecChar($data{"Description"}) ;
$d =~ s/\n/<br>\n/g ;
$c = &P4CGI::ahref("-url" => "changeView.cgi",
%extraUrlOptions,
"CH=$c",
"Change $c") ;
if(exists $data{"User"}) {
$c .= " by " . &P4CGI::ahref("-url" => "userView.cgi",
"USER=$data{User}",
$data{"User"}) ;
}
$refch .= "<dt>$c:\n<dd><tt>$d</tt>" ;
}
}
if($n > 0) {
$changes{$ch}{'display'} .= "$refch</dl></small><hr width=50% align=left>" ;
}
}
}
if($changesDisplayed == $MAXCH) {
if(@sorted > 0) {
$gotAll = "No" ;
}
last ;
}
}
} ;
sub min {
my ($a,$b) = @_;
if ($a < $b) {
return $a;
} else {
return $b;
}
}
sub setDisplay {
my ($change, $chs) = @_;
my @files = ();
my $time = '';
if ($SHOWFILES) {
&getDescription($change, $chs);
@files= @{ $$chs{$change}{'files'} } ;
$time = $$chs{$change}{'time'} ;
}
my $display;
$display = "<dt> ". &P4CGI::ahref("-url" => "changeView.cgi",
%extraUrlOptions,
"CH=$change",
"Change $change") . "\n" ;
$display .= " $$chs{$change}{'date'} $time by ";
$display .= &P4CGI::ahref("-url" => "userView.cgi",
"USER=$$chs{$change}{'user'}",
$$chs{$change}{'user'}) . "\@" ;
$display .= &P4CGI::ahref("-url" => "clientView.cgi",
"CLIENT=$$chs{$change}{'client'}",
$$chs{$change}{'client'}) . "\n<dd>" ;
$display .= $$chs{$change}{'desc'} ;
$display .= "@files <br>\n";
$$chs{$change}{'display'} = $display;
return $display;
}
### ###
### Start print ###
### ###
my @params = &get_params();
my @changes = (sort { $b <=> $a } keys %changes);
my $firstch = $changes[0];
my $lastch=$changes[&min($#changes,$MAXCH)];
#print "first: $firstch last: $lastch maxch: $MAXCH choffset $CHOFFSET <br>";
print &P4CGI::ahref(-url => "bonsai.cgi" , @params,
"Modify Query"
)."<br><br>\n" ;
my $current_change_level = &P4CGI::CURRENT_CHANGE_LEVEL();
my $firstch = $FIRSTCH+$MAXCH+1;
if($firstch <= $current_change_level) {
my @params = &get_params();
print
"",
&P4CGI::ahref("-url","changeList.cgi",
@params,"FIRSTCH=".($firstch+1),
"CHOFFSETDISP=".($CHOFFSET-$MAXCH),
"<b>Previous....</b>") ;
}
print "<dl>\n" ;
my $debug_size = scalar keys %changes ;
&P4CGI::ERRLOG("$debug_size changes to display") ;
my $ch ;
my $maxch = $MAXCH ;
#my $skipped = 0 ;
foreach $ch (@changes) {
last if ($maxch == 0) ;
if($ch < $oldestSafeCh) { # Can not happend???
&P4CGI::ERRLOG("ch:$ch oldestSafeCh:$oldestSafeCh") ; # DEBUG
$maxch = 0 ;
last ;
} ;
$maxch-- ;
$CHOFFSET++ ;
if(defined $EXLABEL and $ch < $lastChangeInLabel) {
print
"</dl><table width=90% align=center cols=3 bgcolor=",
&P4CGI::HDRFTR_BGCOLOR(),
"><tr><th width=4 align=center><hr>Last change in Label $EXLABEL is $lastChangeInLabel<hr>",
"</th></tr></table><dl>\n" ;
$lastChangeInLabel = 0 ;
}
my $user = $changes{$ch}{'user'} ;
$allUsers{$user} = 1;
print $changes{$ch}{'display'} ;
}
print "</dl>\n" ;
&P4CGI::ERRLOG("gotAll:$gotAll maxch:$maxch") ;
if(($maxch == 0) and ($gotAll ne "Yes")) {
print
"",
&P4CGI::ahref("-url","changeList.cgi",
@params,"FIRSTCH=".($lastch-1),
"CHOFFSETDISP=$CHOFFSET",
"<b>More....</b>")."<br><br>\n" ;
}
print &P4CGI::ahref(-url => "mailto:".join( ',', (sort keys %allUsers)) ,
( "Mail everyone on this page".
" (" . scalar(keys %allUsers) . " people)"
)
)."<br>\n" ;
print &P4CGI::ahref(-url => "bonsai.cgi" , @params,
"Modify Query"
)."<br>\n" ;
print "",&P4CGI::end_page();
#
# That's all folks
#

Просмотреть файл

@ -0,0 +1,284 @@
#!/usr/bin/perl -Tw
# -*- perl -*-
use lib '.';
use P4CGI ;
use strict ;
#
#################################################################
# CONFIGURATION INFORMATION
# All config info should be in P4CGI.pm
#
#################################################################
#
# P4 change viewer
# View a change by number
#
#################################################################
# Get file spec argument
my $change = P4CGI::cgi()->param("CH") ;
$change = &P4CGI::extract_digits($change);
&P4CGI::bail("No change number specified") unless defined $change ;
&P4CGI::bail("Invalid change number specified") unless ($change =~ /^\d+$/);
$change =~ /^\d+$/ or &P4CGI::bail("\"$change\" is not a positive number");
my @desc ;
my $currlev = &P4CGI::CURRENT_CHANGE_LEVEL() ;
if($change > $currlev or $change < 1) {
&P4CGI::signalError("\"$change\" is not a valid change number (0 < change <= $currlev)");
} ;
@desc=&P4CGI::run_cmd("describe", "-s", $change);
$_ = &P4CGI::fixSpecChar(shift @desc) ;
/^$/ and &P4CGI::bail("- no such changelist.");
/no such changelist/ and &P4CGI::bail("- no such changelist.");
/^Change (\d+) by (\S+)@(\S+) on (\S+) (\d\d:\d\d:\d\d)(.*)$/ or &P4CGI::bail("Illegal syntax on line returned. $_");
my ($chn, $user, $client, $date, $time, $status) = ($1,$2,$3,$4,$5,$6) ;
my $statstr = "" ;
my $pending ;
if ( defined $status and $status =~ /pending/) {
$statstr="<br>(pending)" ;
$pending = "yes" ;
} ;
my $legend =&P4CGI::ul_list( "<B>User name</B> -- see user info",
"<B>Client name</B> -- see client info",
"<B>Filename</B> -- see the complete file history",
"<B>Revision Number</B> -- see the file text",
"<B>Action</B> -- see the deltas (diffs)") ;
if($pending) {
$legend =&P4CGI::ul_list( "<B>User name</B> -- see user info",
"<B>Client name</B> -- see client info",
"<B>Filename</B> -- see the complete file history") ;
}
# Create title
print "", &P4CGI::start_page("Change $change$statstr",$legend) ;
my $description="" ;
my $leadDescSpace ;
while(@desc > 0) {
$_ = &P4CGI::fixSpecChar(shift @desc) ;
chomp ;
next if /^\s*$/;
last if /^Jobs fixed/;
last if /^Affected files/;
if($_ !~ /^\s*$/) {
if(defined $leadDescSpace) {
s/^$leadDescSpace// ;
}
else {
s/^(\s+)// ;
$leadDescSpace = $1 ;
};
$description .= "\n$_";
}
}
my $jobsFixed="-" ;
if( /^Jobs fixed/ )
{
$jobsFixed = "\n" ;
shift @desc ;
while (@desc > 0) {
$_ = &P4CGI::fixSpecChar(shift @desc) ;
my( $job, $time, $user, $client );
while( ( $job, $time, $user ) =
/(\S*) on (\S*) by (\S*)/ )
{
$jobsFixed .= &P4CGI::ahref("-url","jobView.cgi",
"JOB=$job",
$job) . "\n<br><tt>";
shift @desc ;
while(@desc > 0){
$_ = &P4CGI::fixSpecChar(shift @desc) ;
last if /^\S/;
$jobsFixed .= $_ . "<br>";
}
$jobsFixed .= "</tt>\n";
}
last if /^Affected files/;
}
$jobsFixed .= "\n" ;
}
my @referenced ;
my $desc = &P4CGI::magic($description,\@referenced) ;
my $referenced="" ;
if(@referenced > 0) {
my $c ;
$referenced .= "<dl>\n" ;
foreach $c (@referenced) {
my %data ;
&P4CGI::p4readform("change -o $c",\%data) ;
if(exists $data{"Description"}) {
my $d = &P4CGI::fixSpecChar($data{"Description"}) ;
$d =~ s/\n/<br>\n/g ;
$c = &P4CGI::ahref("-url" => "changeView.cgi",
"CH=$c",
"Change $c") ;
$referenced .= "<dt>$c description:\n<dd><tt>$d</tt>\n" ;
}
}
$referenced .= "</dl>\n" ;
}
print
"",
&P4CGI::start_table(""),
&P4CGI::table_row("-valign","top",{"-type","th", "-align","right", "-text","Author"},
&P4CGI::ahref(-url => "userView.cgi",
"USER=$user",
$user)),
&P4CGI::table_row("-valign","top",{"-type","th", "-align","right", "-text","Client"},
&P4CGI::ahref(-url => "clientView.cgi",
"CLIENT=$client",
$client)),
&P4CGI::table_row("-valign","top",{"-type","th", "-align","right", "-text","Date"},
"$date $time"),
&P4CGI::table_row("-valign","top",
{"-type","th", "-align","right", "-text","Description"},
{"-text","<pre>$desc</pre>"}) ;
print
"",
&P4CGI::table_row(-valign => "top",
"",
"<small>$referenced</small>") ;
if ( ! defined $pending ) {
print
"",
&P4CGI::table_row("-valign","top",{"-type","th", "-align","right", "-text","Jobs fixed"},
"$jobsFixed") ;
} ;
print
"",
&P4CGI::end_table();
if(! defined $pending ) {
print
"",
&P4CGI::start_table("cellpadding=1 "),
&P4CGI::table_header("Action/view diff","Rev/view file","File/file log") ;
# Sample:
# ... //main/p4/Jamrules#71 edit
my $allfiles ;
my $allrevs ;
my $allmodes ;
my $cnt = 0 ;
while(@desc > 0) {
$_ = &P4CGI::fixSpecChar(shift @desc) ;
if(/^\.\.\. (.*)#(\d*) (\S*)$/) {
my( $file, $rev, $act ) = ($1,$2,$3) ;
if($act ne "delete") {
$cnt++ ;
if(defined $allfiles) {
$allfiles .= ",$file" ;
$allrevs .= " $rev" ;
$allmodes .= " $act" ;
}
else {
$allfiles = "$file" ;
$allrevs = "$rev" ;
$allmodes = "$act" ;
}
print
"",
&P4CGI::table_row(&P4CGI::ahref("-url","fileDiffView.cgi",
"FSPC=$file",
"REV=$rev",
"ACT=$act",
"$act"),
&P4CGI::ahref("-url","fileViewer.cgi",
"FSPC=$file",
"REV=$rev","$rev"),
&P4CGI::ahref("-url","fileLogView.cgi",
"FSPC=$file", "$file")) ;
}
else {
print
"",
&P4CGI::table_row("$act",
"$rev",
&P4CGI::ahref("-url","fileLogView.cgi",
"FSPC=$file", "$file"));
}
} ;
} ;
print &P4CGI::end_table(),"<P>" ;
if($cnt > 1) {
print
"<B>",
&P4CGI::ahref("-url","fileDiffView.cgi",
"FSPC=$allfiles",
"REV=$allrevs",
"ACT=$allmodes",
"CH=$change",
"View diff for all files in change"),
"</B>" ;
} ;
}
else {
print
"",
&P4CGI::start_table("cellpadding=1 "),
&P4CGI::table_header("Action","Rev","File/file log") ;
my @openfiles ;
@openfiles=&P4CGI::run_cmd("opened", "-a") ;
my @files ;
my @revs ;
my @actions ;
foreach (@openfiles) {
if(/(\S+)#(\d+) - (\w+) change $change /) {
push @files,$1 ;
push @revs,$2 ;
push @actions,$3 ;
}
}
while(@files > 0) {
my $file = shift @files ;
# my $rev = shift @revs ;
my $act = shift @actions ;
if($act eq "edit") {
print
"",
&P4CGI::table_row($act,
shift @revs,
&P4CGI::ahref("-url","fileLogView.cgi",
"FSPC=$file", "$file")) ;
}
else {
print
"",&P4CGI::table_row($act,
shift @revs,
$file) ;
} ;
} ;
print &P4CGI::end_table(),"<P>" ;
} ;
print &P4CGI::end_page();
#
# That's all folks
#

Просмотреть файл

@ -0,0 +1,203 @@
#!/usr/bin/perl -Tw
# -*- perl -*-
use lib '.';
use P4CGI ;
use strict ;
#
#################################################################
# CONFIGURATION INFORMATION
# All config info should be in P4CGI.pm
#
#################################################################
#
# List p4 clients
#
#################################################################
sub weeksago($$$ ) {
# Take Year, month and day of month as parameter and return the number
# of week that has passed since that date
my ($y,$m,$d) = @_ ;
$y -= 1900 ;
$m-- ;
my $_now = time() ;
my $_then = $_now ;
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
localtime($_then);
if(($y > $year) or
(($y == $year) and ($m > $mon)) or
(($y == $year) and ($m == $mon) and ($d > $mday))) {
return 0 ;
}
# The algorithm is not very robust, take current date and
# remove one day at the time until the date match the requested
# date. Can fail miserably for a number of combinations of
# illegal input....
while(1) {
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
localtime($_then);
if(($y == $year) and ($m == $mon) and ($d == $mday)) {
return int(( $_now - $_then)/(3600*24*7)) ;
}
$_then -= 3600*24 ;
} ;
}
my $user = P4CGI::cgi()->param("USER") ;
$user = &P4CGI::extract_user($user) ;
my $mode = P4CGI::cgi()->param("MODE") ;
$mode = "Brief" unless (defined $mode) and ($mode eq "Complete") ;
$mode = "Complete" if ($user ne '');
# Get clients
my @tmp ;
@tmp=&P4CGI::run_cmd( "clients" );
my @clients ;
my %clientInfo ;
my $c ;
foreach $c (@tmp) {
if($c =~ /^Client\s+(\S+)\s+(\S+)\s+root\s+(.*)\s+'(.*)'/)
{
my ($client,$updated,$root,$desc) = ($1,$2,$3,$4) ;
push @clients,$client ;
my %tmp = ("Update" => $updated,
"Root" => $root,
"Description" => $desc) ;
$clientInfo{$client} = \%tmp ;
}
} ;
my $clients = @clients ;
my $warnings = 0 ;
my $title = "P4 clients" ;
if(defined $user) {
$title .= "<br>for user $user" ;
}
$| = 1 ;
my @legend = ("<b>client</b> -- see more info",
"<b>owner</b> -- see user info") ;
my $lastaccess = undef ;
my $owner = undef ;
if($mode eq "Brief") {
push @legend,&P4CGI::ahref("MODE=Complete",
"<B>Show owner and access info</B>") ;
}
else {
$lastaccess = "Last access" ;
$owner = "Owner/view user" ;
} ;
if(defined $user) {
push @legend,&P4CGI::ahref("<B>Show all clients</B>") ;
}
print "",
&P4CGI::start_page($title,
&P4CGI::ul_list(@legend)) ;
unless(defined $user) {
print "<B>", $clients," clients</B><br> " ;
}
print "",
&P4CGI::start_table(" cellpadding=1"),
&P4CGI::table_header("Client/view client",$owner,"Description",
"Updated ",$lastaccess);
# Get users
my @users ;
@users=&P4CGI::run_cmd( "users" );
my %users ;
map { s/^(\S+).*$/$1/ ; $users{$_}="" ; } @users ;
if($mode ne "Brief") {
my $client ;
foreach $client (sort { uc($a) cmp uc($b) } @clients)
{
my %values ;
print "user $user mode $mode";
my @fields = &P4CGI::p4readform("client -o $client",\%values) ;
my $warning = "" ;
if(exists $values{"Date"}) {
$values{"Update"} = $values{"Date"} ;
$values{"Access"} = "---" ;
delete $values{"Date"} ;
}
else {
if($values{"Access"} =~ /(\d\d\d\d)\/(\d\d)\/(\d\d)/) {
my $weeksOld = weeksago($1,$2,$3) ;
if($weeksOld > 10) {
if($warning ne "") { $warning .= "<br>\n" ; } ;
$warning .= "Not used for $weeksOld weeks!" ;
}
}
}
if(exists $values{"Owner"}) {
$owner = $values{"Owner"} ;
$values{"OwnerName"} = $owner ;
if(exists $users{$owner}) {
$values{"Owner"} = &P4CGI::ahref(-url => "userView.cgi" ,
"USER=$owner",
$owner),
}
else {
if($warning ne "") { $warning .= "<br>\n" ; } ;
$warning .= "Owner does not exist!" ;
}
} ;
if(exists $values{"Description"}) {
$values{"Description"} = P4CGI::fixSpecChar($values{"Description"}) ;
$values{"Description"} =~ s/\n/<br>\n/sg ;
}
unless((defined $user) and ( uc($user) ne uc($owner))) {
$values{"Warnings"} = $warning ;
$clientInfo{$client} = { %{$clientInfo{$client}},%values} ;
if($warning ne "") { $warnings++ ; } ;
}
} ;
}
my $client ;
foreach $client (sort { uc($a) cmp uc($b) } @clients)
{
my %info = %{$clientInfo{$client}} ;
$info{"Warnings"} = "" unless defined $info{"Warnings"} ;
if((!defined $user) or (uc($user) eq uc($info{"OwnerName"}))) {
print &P4CGI::table_row(-valign=>"top",
&P4CGI::ahref(-url => "clientView.cgi",
"CLIENT=$client",
$client),
$info{"Owner"},
{
-text => "<tt>" . $info{"Description"} . "</tt>",
},
$info{"Update"},
$info{"Access"},
"<font color=red><b>$info{Warnings}</b></font>") ;
}
}
print &P4CGI::end_table() ;
if($warnings > 0) {
my $s = "" ;
$s = "s" if $warnings != 1 ;
$warnings = "<font color=red>($warnings warning$s)</font>" ;
}
else {
$warnings = "" ;
}
print
" $warnings<br>",
&P4CGI::end_page() ;
#
# That's all folks
#

Просмотреть файл

@ -0,0 +1,151 @@
#!/usr/bin/perl -Tw
# -*- perl -*-
use lib '.';
use P4CGI ;
use strict ;
#
#################################################################
# CONFIGURATION INFORMATION
# All config info should be in P4CGI.pm
#
#################################################################
#
# View a p4 client
#
#################################################################
# Get parameter
my $client = P4CGI::cgi()->param("CLIENT") ;
$client = &P4CGI::extract_printable_chars($client);
unless(defined $client) {
&P4CGI::bail("No client specified!") ;
} ;
&P4CGI::bail("Invalid client specified!") if ($client =~ /[<>"&:;'`]/);
# Get list of users and full names
my @users ;
@users=&P4CGI::run_cmd("users" );
my %users ;
map { s/^(\S+).* \((.*)\).*$/$1/ ; $users{$_}=$2 ; } @users ;
# Get client info
my %values ;
my @fields = &P4CGI::p4readform("client -o $client",\%values);
# Fix owner field
if(exists $users{$values{"Owner"}}) {
$values{"Owner"} = &P4CGI::ahref(-url => "userView.cgi" ,
"USER=$values{Owner}",
$values{"Owner"}) . " ($users{$values{Owner}})" ;
}
else {
$values{"Owner"} .= " <font color=red>No such user</font>" ;
} ;
# Fix up description
{
my $d = &P4CGI::fixSpecChar($values{"Description"}) ;
$d =~ s/\n/<br>/g ;
$values{"Description"} = $d ;
}
# Fix Root
if(exists $values{"Root"}) {
$values{"Root"} = "<tt>$values{Root}</tt>" ;
} ;
# Fix Options
if(exists $values{"Options"}) {
$values{"Options"} = "<tt>$values{Options}</tt>" ;
} ;
# Fix view
{
my $view = &P4CGI::start_table("border=0 cellspacing=0 cellpadding=0") ;
foreach (split("\n",$values{"View"})) {
last if /^\s*$/ ;
my ($d,$c) = split(/\s+\/\//,$_) ;
$view .= &P4CGI::table_row("<tt>$d</tt>","<tt>&nbsp;//$c</tt>") ;
} ;
$view .= &P4CGI::end_table() ;
$values{"View"} = $view ;
}
$| = 1 ;
print "",
&P4CGI::start_page("Client<br><tt>$client</tt>",
&P4CGI::ul_list("<b>user</b> -- view user info",
"<b>open file</b> -- view file log",
&P4CGI::ahref(-url => "changeList.cgi",
"CLIENT=$client",
"FSPC=//...",
"List changes by client") .
" -- List changes made by client $client")) ;
# Check that client exist
unless(exists $values{"Client"}) {
&P4CGI::signalError("Client $client does not exist") ;
}
print
&P4CGI::start_table("") ;
my $f ;
foreach $f (@fields)
{
print &P4CGI::table_row({-align => "right",
-valign => "top",
-type => "th",
-text => $f},
$values{$f}) ;
} ;
my $openfiles ;
&P4CGI::p4call(*P4, "opened -a" );
while(<P4>) {
chomp ;
/^(.+\#\d+) - (\S+) .* by (\S+)\@(\S+)/ and do {
my $f = $1 ;
my $u = $3 ;
my $r = "<b>$2</b>" ;
my $c = $4 ;
if($c eq $client) {
$f =~ /(.*)\#(\d+)/ ;
$f = &P4CGI::ahref(-url => "fileLogView.cgi",
"FSPC=$1",
"REV=$2",
"<tt>$f</tt>") ;
if(defined $openfiles) {
$openfiles .= "<br>$f -&nbsp;$r" ;
} else {
$openfiles = "$f -&nbsp;$r" ;
} ;
if($u ne $values{"Owner"}) {
$openfiles .= "&nbsp;by&nbsp;user&nbsp;$u" ;
}
} ;
} ;
} ;
if(defined $openfiles) {
print &P4CGI::table_row({-align => "right",
-type => "th",
-valign => "top",
-text => "Open&nbsp;files:"},
"$openfiles") ;
} ;
print
&P4CGI::end_table(),
&P4CGI::end_page() ;
#
# That's all folks
#

Просмотреть файл

@ -0,0 +1,175 @@
#!/usr/bin/perl -w
# -*- perl -*-
#
# This script is eval'ed by the fileViewer.cgi script.
#
# Input is a scalar, $FILE, that contains the file text
#
#
#################################################################
#
# Add color to C and C++ code (html) (really simple)
#
# This is a quick late-night hack and far from complete. It also
# tries to work for both C and C++ which might be a mistake
#
#################################################################
my $COMMENT_COLOR="red" ;
my $MACRO_COLOR="#006000" ;
my $STRING_CONSTANT_COLOR="green" ;
my $RESERVED_WORD_COLOR="blue" ;
sub c_comment {
my $token = shift @_ ;
my $inr = shift @_ ;
my $outr = shift @_ ;
$$inr =~ s/(.*?\*\/)//s ;
$$outr .= "<font color=\"$COMMENT_COLOR\">${token}$1</font>" ;
}
sub cpp_comment {
my $token = shift @_ ;
my $inr = shift @_ ;
my $outr = shift @_ ;
$$inr =~ s/(.*?)\n/\n/i ;
$$outr .= "<font color=\"$COMMENT_COLOR\">${token}$1</font>" ;
}
sub hash {
my $token = shift @_ ;
my $inr = shift @_ ;
my $outr = shift @_ ;
$$inr =~ s/(\s*\w+)//i ;
$$outr .= "<font color=\"$MACRO_COLOR\">${token}$1</font>" ;
}
sub string {
my $token = shift @_ ;
my $inr = shift @_ ;
my $outr = shift @_ ;
$$inr =~ s/(.*?)(?<!\\)&quot;// ;
$$outr .= "$token<font color=\"$STRING_CONSTANT_COLOR\">$1</font>&quot;" ;
}
sub blueBold {
my $token = shift @_ ;
my $inr = shift @_ ;
my $outr = shift @_ ;
$$outr .= "<font color=\"$RESERVED_WORD_COLOR\"><b>$token</b></font>" ;
}
sub blue {
my $token = shift @_ ;
my $inr = shift @_ ;
my $outr = shift @_ ;
$$outr .= "<font color=\"$RESERVED_WORD_COLOR\">$token</font>" ;
}
sub bold {
my $token = shift @_ ;
my $inr = shift @_ ;
my $outr = shift @_ ;
$$outr .= "<b>$token</b>" ;
}
my @blueBoldWords=("if","else","while","do","goto","for","until") ;
my @blueWords=(
"asm",
"auto",
"bool",
"break",
"case",
"catch",
"char",
"class",
"const",
"continue",
"default",
"delete",
"do",
"double",
"else",
"enum",
"extern",
"false",
"float",
"for",
"friend",
"goto",
"if",
"inline",
"int",
"long",
"new",
"operator",
"private",
"protected",
"public",
"register",
"return",
"short",
"signed",
"sizeof",
"static",
"struct",
"switch",
"template",
"this",
"throw",
"true",
"try",
"typedef",
"union",
"unsigned",
"virtual",
"void",
"volatile",
"while"
) ;
my $boldchars="{}" ;
my %routine = (
"/*" => \&c_comment,
"//" => \&cpp_comment,
"#" => \&hash,
"&quot;" => \&string
) ;
my @re ;
my $b ;
foreach $b (keys %routine) {
push @re,"\Q$b\E" ;
}
foreach $b (@blueWords) {
$routine{"$b"} = \&blue ;
push @re,'\b'.$b.'\b' ;
}
foreach $b (@blueBoldWords) {
if(! exists $routine{"$b"}) {
push @re,'\b'.$b.'\b' ;
}
$routine{"$b"} = \&blueBold ;
}
foreach $b (split('',$boldchars)) {
$routine{"$b"} = \&blue ;
push @re,"\Q$b\E" ;
}
my $in = $FILE ;
$FILE = "" ;
my $re = join("|",@re) ;
while($in =~ s/^(.*?)($re)//s) {
$FILE .= $1 ;
my $tok = $2 ;
if(exists $routine{$tok}) {
&{$routine{$tok}}($tok,\$in,\$FILE) ;
}
else {
$FILE .= $tok ;
}
}
$FILE .= $in ;
#
# End
#

Просмотреть файл

@ -0,0 +1,27 @@
#!/usr/bin/perl -w
#
# This script is eval'ed by the fileViewer.cgi script.
#
# Input is a scalar, $FILE, that contains the file text
#
#
#################################################################
#
# Add colour to html
#
#################################################################
my $bracketColor="blue" ;
my $firstWordColor="blue" ;
my $restWordsColor="green" ;
my $leftbr = "<font color=$bracketColor>&lt;</font>" ;
my $rightbr = "<font color=$bracketColor>&gt;</font>" ;
$FILE =~ s/&lt;(\/{0,1}\w+)(.*?)&gt;/$leftbr<font color=$firstWordColor>$1<\/font><font color=$restWordsColor>$2<\/font>$rightbr/g ;
$FILE =~ s/&lt;(!.*?)&gt;/$leftbr<font color=$bracketColor><b>$1<\/b><\/font>$rightbr/ ;
#
# End
#

Просмотреть файл

@ -0,0 +1,150 @@
#!/usr/bin/perl -w
#
# This script is eval'ed by the fileViewer.cgi script.
#
# Input is a scalar, $FILE, that contains the file text
#
#
#################################################################
#
# Add colour to perl code (html)
#
#################################################################
my $COMMENT_COLOR="red" ;
my $MACRO_COLOR="#006000" ;
my $STRING_CONSTANT_COLOR="green" ;
my $RESERVED_WORD_COLOR="blue" ;
my $VARIABLE_WORD_COLOR="#a000a0" ;
sub comment {
my $token = shift @_ ;
my $inr = shift @_ ;
my $outr = shift @_ ;
$$inr =~ s/(.*?\n)//is ;
$$outr .= "<font color=\"$COMMENT_COLOR\"><b>${token}</b>$1</font>" ;
}
sub string {
my $token = shift @_ ;
my $inr = shift @_ ;
my $outr = shift @_ ;
$$inr =~ s/(.*?)(?<!\\)&quot;// ;
$$outr .= "$token<font color=\"$STRING_CONSTANT_COLOR\">$1</font>&quot;" ;
}
sub resword {
my $token = shift @_ ;
my $inr = shift @_ ;
my $outr = shift @_ ;
$$outr .= "<font color=\"$RESERVED_WORD_COLOR\"><b>$token</b></font>" ;
}
sub variable {
my $token = shift @_ ;
my $inr = shift @_ ;
my $outr = shift @_ ;
$token =~ s/^(.)// ;
$$outr .= "<font color=\"$VARIABLE_WORD_COLOR\"><b>$1</b>$token</font>" ;
}
# "Reserved words"
my @reswrds = ("if", "else", "elsif", "unless",
"while", "foreach", "until", "do",
"chomp", "abs", "accept", "alarm",
"atan2", "bind", "binmode", "bless",
"caller", "chdir", "chmod", "chomp",
"chop", "chown", "chr", "chroot",
"close", "closedir", "connect", "continue",
"cos", "crypt", "dbmclose", "dbmopen",
"defined", "delete", "die", "do",
"dump", "each", "endgrent", "endhostent",
"endnetent", "endprotoent", "endpwent", "endservent",
"eof", "eval", "exec", "exists",
"exit", "exp", "fcntl", "fileno",
"flock", "fork", "format", "formline",
"getc", "getgrent", "getgrgid", "getgrnam",
"gethostbyaddr", "gethostbyname", "gethostent", "getlogin",
"getnetbyaddr", "getnetbyname", "getnetent", "getpeername",
"getpgrp", "getppid", "getpriority", "getprotobyname",
"getprotobynumber","getprotoent", "getpwent", "getpwnam",
"getpwuid", "getservbyname", "getservbyport", "getservent",
"getsockname", "getsockopt", "glob", "gmtime",
"goto", "grep", "hex", "import",
"index", "int", "ioctl", "join",
"keys", "kill", "last", "lc",
"lcfirst", "length", "link", "listen",
"local", "localtime", "log", "lstat",
"map", "mkdir", "msgctl", "msgget",
"msgrcv", "msgsnd", "my", "next",
"no", "oct", "open", "opendir",
"ord", "pack", "package", "pipe",
"pop", "pos", "print", "printf",
"prototype", "push", "q", "qq",
"qr\/", "quotemeta", "qw", "qw\/",
"qx", "qx\/", "rand", "read",
"readdir", "readline", "readlink", "readpipe",
"recv", "redo", "ref", "rename",
"require", "reset", "return", "reverse",
"rewinddir", "rindex", "rmdir", "s\/",
"scalar", "seek", "seekdir", "select",
"semctl", "semget", "semop", "send",
"setgrent", "sethostent", "setnetent", "setpgrp",
"setpriority", "setprotoent", "setpwent", "setservent",
"setsockopt", "shift", "shmctl", "shmget",
"shmread", "shmwrite", "shutdown", "sin",
"sleep", "socket", "socketpair", "sort",
"splice", "split", "sprintf", "sqrt",
"srand", "stat", "study", "sub",
"substr", "symlink", "syscall", "sysopen",
"sysread", "sysseek", "system", "syswrite",
"tell", "telldir", "tie", "tied",
"time", "times", "tr\/", "truncate",
"uc", "ucfirst", "umask", "undef",
"unlink", "unpack", "unshift", "untie",
"use", "utime", "values", "vec",
"wait", "waitpid", "wantarray", "warn",
"write", "y\/") ;
my %routines ;
my @re ;
my $w ;
foreach $w (@reswrds) {
$routines{$w} = \&resword ;
push @re,'\b'.$w.'\b' ;
}
# Comment
$routines{"\#"} = \&comment ;
push @re,"\#" ;
# String
$routines{"&quot;"} = \&string ;
push @re,"&quot;" ;
# Var
push @re,"[\$\@\%][\\w][\\w_-\\d]*" ;
my $in = $FILE ;
$FILE = "" ;
my $re = join("|",@re) ;
while($in =~ s/^(.*?)($re)//s) {
$FILE .= $1 ;
my $tok = $2 ;
if(exists $routines{$tok}) {
&{$routines{$tok}}($tok,\$in,\$FILE) ;
}
else {
if($tok =~ /^[\$\@\%]/) {
&variable($tok,\$in,\$FILE) ;
}
else {
$FILE .= $tok ;
}
}
}
$FILE .= $in ;
#
# End
#

Просмотреть файл

@ -0,0 +1,72 @@
#!/usr/bin/perl -w
# -*- perl -*-
package colorView ;
use strict ;
#
#
#################################################################
# Configuration file for color view of files
#################################################################
#
#
# This module is designed to add colors to
# file view.
# The idea is to apply a filter (in this case
# eval a perl script) that adds color to
# the file. The filter is selected using
# one of two methods:
# 1. Check file name (typicall extension)
# 2. Check first line in file
my %fileNameRegexp ;
# Store filter name by regexp for file name
my %firstLineRegexp ;
# Store filter name by regexp for first line in file to color
# Initialize variables
BEGIN()
{
%fileNameRegexp = ("\\\.html\$" => "colorHtml.pl" ,
"\\\.htm\$" => "colorHtml.pl" ,
"\\\.pl\$" => "colorPerl.pl",
"\\\.c\$" => "colorC.pl",
"\\\.C\$" => "colorC.pl",
"\\\.cxx\$" => "colorC.pl",
"\\\.cpp\$" => "colorC.pl",
"\\\.h\$" => "colorC.pl",
"\\\.H\$" => "colorC.pl",
"\\\.hxx\$" => "colorC.pl",
"\\\.hpp\$" => "colorC.pl",
) ;
%firstLineRegexp = ("perl" => "colorPerl.pl") ;
} ;
# Subroutine to call
sub color($,\$) {
my $filename = shift @_ ;
my $textref = shift @_ ;
my $t ;
my $FILE = $$textref ;
foreach $t (keys %fileNameRegexp) {
if($filename =~ /$t/) {
eval `cat $fileNameRegexp{$t}` ;
$$textref = $FILE unless $@ ;
return ;
}
} ;
$FILE =~ /^(.*?)\n/ ;
my $firstLine = $1 ;
foreach $t (keys %firstLineRegexp) {
if($firstLine =~ /$t/) {
eval `cat $firstLineRegexp{$t}` ;
$$textref = $FILE unless $@ ;
return ;
}
}
} ;
1;

Просмотреть файл

@ -0,0 +1,417 @@
#!/usr/bin/perl -w
# -*- perl -*-
use P4CGI ;
use strict ;
#
#################################################################
# CONFIGURATION INFORMATION
# All config info should be in P4CGI.pm
#
#################################################################
#
# P4 change browser
# Depot statistics
#
#################################################################
#######
# Parameters:
#
######
$| = 1 ;
#
# Get parameter(s)
#
my $FSPC = P4CGI::cgi()->param("FSPC") ;
$FSPC = "//..." unless defined $FSPC ;
&P4CGI::bail("Invalid file spec.") if ($FSPC =~ /[<>"&:;'`]/);
my @FSPC = split(/\s*\+?\s*(?=\/\/)/,$FSPC) ;
$FSPC = "<tt>".join("</tt> and <tt>",@FSPC)."</tt>" ;
my $FSPCcmd = "\"" . join("\" \"",@FSPC) . "\"" ;
###
### subroutine findTime
### A (really) poor mans version of mktime(3).
### Parameters: year,month,day,hour,min
### Returns: time_t value that corresponds to above result (almost)
sub findTime($$$$$)
{
my ($iyear,$imon,$iday,$ihour,$imin) = @_ ;
$iyear -= 1900 ;
$imon-- ;
my $time = time() ;
my $delta = int($time/2)+1 ;
my $lastsgn = -1 ;
my $n = 300 ;
while($delta > 10) {
last if $n-- == 0 ;
my $sgn = 1 ;
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($time) ;
my $i = ((((((((($iyear * 12) + $imon) * 32) + $iday) * 24) + $ihour) * 60) + $imin) * 60) + 30 ;
my $o = ((((((((($year * 12) + $mon) * 32) + $mday) * 24) + $hour) * 60) + $min) * 60) + $sec ;
last if $i == $o ;
$sgn = -1 if $i < $o ;
$time += ($sgn * $delta) ;
$delta = int(($delta+1)/2) ;
$lastsgn = $sgn ;
}
return $time ;
} ;
&P4CGI::SET_HELP_TARGET("DepotStats") ;
print &P4CGI::start_page("Depot Statistics for<br><tt>".
join("<br></tt>and<tt><br>\n",@FSPC) . "</tt>" ,
&P4CGI::ul_list(&P4CGI::ahref(-url => &P4CGI::cgi()->self_url . "#weekly",
"Weekly Submit Statistics"),
&P4CGI::ahref(-url => &P4CGI::cgi()->self_url . "#byuser",
"Submit Statistics by user")
)) ;
sub printStat($$) {
my $prompt = shift @_ ;
my $data = shift @_ ;
print
&P4CGI::table_row({-type => "th",
-align => "right",
-valign => "top",
-width => "50%",
-text => "$prompt:"},
{-type => "td",
-align => "left",
-width => "50%",
-text => $data}) ;
};
print
"<h2>Depot statistics</h2>",
&P4CGI::start_table("") ;
{
my @counters ;
&P4CGI::p4call(\@counters,"counters") ;
# printStat("P4 counters","") ;
foreach (@counters) {
s/(\S+) = /P4 $1 counter = / ;
&printStat(split(" = ","$_")) ;
}
}
# Users
my @users ;
&P4CGI::p4call(\@users,"users") ;
printStat("Users",@users) ;
# Clients
my @clients ;
&P4CGI::p4call(\@clients,"clients") ;
printStat("Clients",@clients) ;
# Labels
my @labels ;
&P4CGI::p4call(\@labels,"labels") ;
printStat("Labels",@labels) ;
# branches
my @branches ;
&P4CGI::p4call(\@branches,"branches") ;
printStat("Branches",@branches) ;
# jobs
my @jobs ;
&P4CGI::p4call(\@jobs,"jobs") ;
printStat("Jobs",@jobs) ;
print &P4CGI::end_table(),"<hr>" ;
# Get changes
my @changes ;
&P4CGI::p4call(\@changes,"changes -s submitted $FSPCcmd") ;
# Sort and remove duplicates
{
my @ch = sort { $a =~ /Change (\d+)/ ; my $ac = $1 ;
$b =~ /Change (\d+)/ ; my $bc = $1 ;
$bc <=> $ac } @changes ;
my $last="" ;
@changes = grep {my $l = $last ;
$last = $_ ;
$_ ne $l } @ch ;
}
## File list stats
print
"<h2>Statistics for \"$FSPC\"</h2>",
&P4CGI::start_table("") ;
printStat("Submitted changes",scalar @changes) ;
# Data about first submit
my $first = pop @changes ;
push @changes,$first ;
$first =~ s/Change (\d+).*/$1/ ;
my %data ;
my $firstTime = 0;
my $firstDate = "";
my $daysSinceFirstSubmit = 0 ;
&P4CGI::p4readform("change -o $first",\%data) ;
if(exists $data{"Date"}) {
$firstDate = $data{"Date"} ;
if($data{"Date"} =~ /(\d+).(\d+).(\d+).(\d+).(\d+)/) {
$firstTime = findTime($1,$2,$3,$4,$5) ;
my $seconds = time() - $firstTime ;
$daysSinceFirstSubmit = int($seconds/(24*3600)) ;
}
}
# Last submit
my $last = shift @changes ;
unshift @changes,$last ;
$last =~ s/Change (\d+).*/$1/ ;
my $lastTime=0 ;
my $lastDate="" ;
my $daysSinceLastSubmit=0 ;
&P4CGI::p4readform("change -o $last",\%data) ;
if(exists $data{"Date"}) {
$lastDate = $data{"Date"} ;
if($data{"Date"} =~ /(\d+).(\d+).(\d+).(\d+).(\d+)/) {
$lastTime = findTime($1,$2,$3,$4,$5) ;
my $seconds = time() - $lastTime ;
$daysSinceLastSubmit = int($seconds/(24*3600)) ;
}
} ;
printStat("First submit","$first ($firstDate)") ;
printStat("Latest submit","$last ($lastDate)") ;
printStat("Days between first and latest submit",$daysSinceFirstSubmit-$daysSinceLastSubmit) ;
if(($daysSinceFirstSubmit-$daysSinceLastSubmit) > 0) {
printStat("Average submits per day",
sprintf("%.2f",@changes/($daysSinceFirstSubmit-$daysSinceLastSubmit))) ;
};
# Read and parse file list
my $files=0 ;
my $deletedFiles=0 ;
my %revlevels ;
my $maxrevlevel=0 ;
my $totrevs=0 ;
my $file ;
foreach $file (@FSPC) {
local *F ;
&P4CGI::p4call(*F,"files \"$file\"") ;
while(<F>) {
$files++ ;
/\#(\d+) - (\S+)/ ;
my ($r,$s) = ($1,$2) ;
$deletedFiles++ if $s eq "delete" ;
$totrevs += $r ;
$maxrevlevel = $r if $r > $maxrevlevel ;
$revlevels{$r} = 0 unless exists $revlevels{$r} ;
$revlevels{$r}++ ;
}
close F ;
}
printStat("Current number of files",$files) ;
printStat("Deleted files",$deletedFiles) ;
printStat("Average revision level for files ",sprintf("%.2f",$totrevs/$files)) ;
printStat("Max revision level",$maxrevlevel) ;
print &P4CGI::end_table(),"<hr>" ;
# File revision statistics
# print
# "<a name=\"revstat\"><hr></a>",
# &P4CGI::start_table("width=90%"),
# &P4CGI::table_row(-type=>"th",
# undef,
# undef,
# "File Revision Statistics"),
# &P4CGI::table_row({-type=>"th",
# -text => "Revision Level",
# -width => "20%",
# -align => "right"},
# {-text => "No. of<br>files",
# -type=>"th",
# -width => "10%"},
# {-text => "&nbsp;",
# -bgcolor=>&P4CGI::BGCOLOR()}),
# &P4CGI::end_table() ;
#
#my $max = 0 ;
#
#foreach (keys %revlevels) {
# $max = $revlevels{$_} if $max < $revlevels{$_} ;
#} ;
#
# my $rev=$maxrevlevel ;
# while($rev > 0) {
# my $n = 0 ;
# $n = $revlevels{$rev} if exists $revlevels{$rev} ;
# my $w = int((65.0 * $n)/$max) ;
# if($w == 0) { $w = 1 ; } ;
# print
# &P4CGI::start_table("colums=4 width=90% cellspacing=0"),
# &P4CGI::table_row({-text => "$rev",
# -width => "20%",
# -align => "right"},
# {-text => $n==0?"-":"$n",
# -align => "center",
# -width => "10%"},
# {-text => "&nbsp; ",
# -bgcolor => $n!=0?"blue":&P4CGI::BGCOLOR(),
# -width => "$w\%"},
# {-text => "&nbsp;",
# -bgcolor=>&P4CGI::BGCOLOR()}) ;
# print &P4CGI::end_table() ;
# $rev-- ;
# }
my %dailySubStat ;
my %userSubStat ;
my $n ;
#my $time = time() ;
my $time = $lastTime ;
my $ONE_DAY=3600*24 ;
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($time);
while($wday != 0) {
$time -= $ONE_DAY ;
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($time);
}
sub getNextDate() {
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($time);
$time -= $ONE_DAY * 7 ;
my $day = sprintf("%4d/%02.2d/%02.2d",$year + 1900, $mon + 1, $mday) ;
$dailySubStat{$day} = 0 ;
return $day ;
} ;
# Read and parse change list
my $day = getNextDate() ;
my $max = 0 ;
while(@changes > 0) {
$_ = shift @changes ;
if(/Change \d+ on (\S+) by (\S+)\@/) {
my $d = $1 ;
my $user = $2 ;
while($d lt $day) {
$day = getNextDate() ;
}
$dailySubStat{$day}++ ;
$max = $dailySubStat{$day} if $dailySubStat{$day} > $max ;
$userSubStat{$user} = 0 unless exists $userSubStat{$user} ;
$userSubStat{$user}++ ;
}
}
# Weekly Submit Statistics
print "<a name=\"weekly\"></a><H2>Weekly Submit Rate for $FSPC</H2>",
&P4CGI::start_table("width=90%"),
&P4CGI::table_row({-type=>"th",
-text => "Week starting",
-width => "20%",
-align => "right"},
{-text => "submits",
-type=>"th",
-width => "10%"},
{-text => "&nbsp;",
-bgcolor=>&P4CGI::BGCOLOR()}),
&P4CGI::end_table() ;
my $d ;
foreach $d (sort { $b cmp $a } keys %dailySubStat) {
print &P4CGI::start_table("colums=4 width=90% cellspacing=0") ;
my $n = $dailySubStat{$d} ;
my $w = int((65.0 * $n)/$max) ;
if($w == 0) { $w = 1 ; } ;
print &P4CGI::table_row({-text => "$d",
-width => "20%",
-align => "right"},
{-text => $n==0?"-":"$n",
-align => "center",
-width => "10%"},
{-text => "&nbsp; ",
-bgcolor => $n!=0?"blue":&P4CGI::BGCOLOR(),
-width => "$w\%"},
{-text => "&nbsp;",
-bgcolor=>&P4CGI::BGCOLOR()}) ;
print &P4CGI::end_table() ;
}
# Submits per user
print
"<a name=\"byuser\"><hr></a><h2>Submits by user in $FSPC</h2>",
&P4CGI::start_table("width=90%"),
&P4CGI::table_row({-type=>"th",
-text => "User",
-width => "20%",
-align => "right"},
{-text => "Submits",
-type=>"th",
-width => "10%"},
{-text => "&nbsp;",
-bgcolor=>&P4CGI::BGCOLOR()}),
&P4CGI::end_table() ;
# Get users
my @listOfUsers = sort { uc($a) cmp uc ($b) } map { /^(\S+).*> \((.+)\) .*$/ ; $1 ; } @users ;
my %userCvt = map { /^(\S+).*> \((.+)\) .*$/ ; ($1,$2) ; } @users ;
my $u ;
$max = 0 ;
foreach $u (sort {$userSubStat{$b} <=> $userSubStat{$a} ; } keys %userSubStat) {
my $n = $userSubStat{$u} ;
$max = $n if $max == 0 ;
my $w = int((65.0 * $n)/$max) ;
if($w == 0) { $w = 1 ; } ;
if(exists $userCvt{$u}) {
my $fullUser = $userCvt{$u} ;
$u = &P4CGI::ahref(-url => "userView.cgi",
"USER=$u",
$fullUser) ;
}
else {
$u = "<b>Old user:</b> $u"
}
print
&P4CGI::start_table("colums=4 width=90% cellspacing=0"),
&P4CGI::table_row({-text => "$u",
-width => "20%",
-align => "right"},
{-text => $n==0?"-":"$n",
-align => "center",
-width => "10%"},
{-text => "&nbsp; ",
-bgcolor => $n!=0?"blue":&P4CGI::BGCOLOR(),
-width => "$w\%"},
{-text => "&nbsp;",
-bgcolor=>&P4CGI::BGCOLOR()}) ;
print &P4CGI::end_table() ;
}
print &P4CGI::end_page() ;
#
# That's all folks
#

Просмотреть файл

@ -0,0 +1,270 @@
#!/usr/bin/perl -w
# -*- perl -*-
use P4CGI ;
use strict ;
#
#################################################################
# CONFIGURATION INFORMATION
# All config info should be in P4CGI.pm
#
#################################################################
#
# P4 depot tree browser
#
#################################################################
###
### Handle file spec argument
###
my $err2null = &P4CGI::REDIRECT_ERROR_TO_NULL_DEVICE() ;
my $ROOT = &P4CGI::root();
# * Get path from argument
my $fspc = P4CGI::cgi()->param("FSPC") ;
&P4CGI::bail("Invalid file spec.") if ($fspc =~ /[<>"&:;'`]/);
# canonicalize to either "/.../" or "/"
$fspc =~ s/\.\.\.$// if defined $fspc ;
$fspc = $ROOT unless defined $fspc ;
$fspc = "/$fspc/" ;
while($fspc =~ s|//|/|) {} ;
# Find out if we are at root
my $weAreAtROOT = ($fspc eq $ROOT) ;
###
### handle "Hide deleted files" argument
###
# * Get HIDEDEL argument (Hide deleted files)
my $hidedel = P4CGI::cgi()->param("HIDEDEL") ;
$hidedel = "NO" unless defined $hidedel ;
$hidedel = "YES" unless $hidedel eq "NO" ;
my $p4DirsDOption = "" ; # Set -D option for "p4 dirs" if hide deleted
$p4DirsDOption = " -D" if $hidedel eq "NO" ;
###
### Figure out "back" buttons
###
my @back ;
my $tmp = "$fspc" ; # Copy arg
$tmp =~ s|([^/]+)/$|| ; # Remove last subdir
unshift @back,"/".$1; #
while($tmp ne $ROOT) {
$tmp =~ s|([^/]+)/$|| or last ;
my $f = $1 ;
unshift @back,&P4CGI::ahref("FSPC=$tmp$f",
"HIDEDEL=$hidedel",
"/$f") ;
} ;
unless($weAreAtROOT) {
unshift @back,&P4CGI::ahref("FSPC=$ROOT",
"HIDEDEL=$hidedel",
"[ROOT]") ;
}
###
### Create link to changes for all files below
###
my $linkToAllbelow = &P4CGI::ahref(-url => "changeList.cgi",
"CMD=changes",
"FSPC=/$fspc...",
"View changes") ;
###
### Create link to view changes for a specific user below this point
###
my $linkToChangeByUser = &P4CGI::ahref(-url => "changeByUsers.cgi",
"FSPC=/$fspc...",
"View changes by user or group") ;
###
### Create link to search for pattern
###
my $linkToPatternSearch = &P4CGI::ahref(-url => "searchPattern.cgi",
"FSPC=/$fspc...",
"Search for pattern in change descriptions") ;
###
### Create link to recently modified files
###
my $recentlyModified = &P4CGI::ahref(-url => "filesChangedSince.cgi",
"FSPC=/$fspc...",
"Recently modified files") ;
###
### Create link to depot statistics
###
my $depotStatistics = &P4CGI::ahref(-url => "depotStats.cgi",
"FSPC=/$fspc...",
"Depot Statistics") ;
###
### Get subdirs
###
my @subdirs ;
&P4CGI::p4call(\@subdirs,"dirs $p4DirsDOption \"/$fspc*\" $err2null") ;
map { my $dir = $_ ;
my $dirname ;
($dirname = $dir) =~ s|^.*/|/| ;
$_ = P4CGI::ahref("FSPC=$dir",
"HIDEDEL=$hidedel",
$dirname) ;
} @subdirs ;
###
### Get files
###
my @files ;
my @tmp ;
&P4CGI::p4call(\@tmp,"files \"/$fspc*\" $err2null") ;
@files = map { /([^\#]+)\#(.*)/ ;
my $file=$1 ;
my $info=$2 ;
$file =~ s/^.*\/// ;
my ($rev,$inf) = split / - /,$info ;
my $pfile = "$file" ;
my $prev ;
if($inf =~ /^delete/) {
$prev = "<STRIKE>$rev</STRIKE>";
if($hidedel eq "YES") {
$pfile = undef ;
}
else {
$pfile= "<STRIKE>$file</STRIKE>";
}
}
else {
$prev = &P4CGI::ahref(-url => "fileViewer.cgi",
"FSPC=/$fspc$file",
"REV=$rev",
"$rev") ;
};
if($pfile) {
$pfile = &P4CGI::ahref(-url => "fileLogView.cgi",
"FSPC=/$fspc$file",
"$pfile").
"<font color=#808080>&nbsp;\#</font>$prev" ;
} ;
defined $pfile?$pfile:() ;
} @tmp ;
###
### Create link for "hide/view deleted files"
###
my $toggleHide ;
if($hidedel eq "YES") {
$toggleHide = P4CGI::ahref("FSPC=/$fspc",
"HIDEDEL=NO",
"Show deleted files") ;
}
else {
$toggleHide = P4CGI::ahref("FSPC=/$fspc",
"HIDEDEL=YES",
"Hide deleted files") ;
}
###
### Set help target
###
&P4CGI::SET_HELP_TARGET("depotTreeBrowser") ;
###
### Start page printout
###
print
"",
&P4CGI::start_page("Depot Tree Browser",
&P4CGI::ul_list("<b>Subdir</b> -- Descend to subdir",
"<b>File</b> -- Show file log",
"<b>Rev</b> -- View current revision",
"$toggleHide")) ;
my $sarg=$weAreAtROOT?"[ROOT]":"/$fspc" ; # replace // with [ROOT]
# Print current directory
print "<H2 align=center><TT>".join("",@back)."</TT></H2>" ;
# Print "back buttons"
if(@back > 0) {
print &P4CGI::image("back.gif")," Back to: ", join(' ',@back) ;
}
###
# Make table with three columns
#
sub makeThreeColumns(@)
{
my $l = @_ ;
my $len = int((@_+2)/3) ;
while(@_ < ($len*3)) { push @_,"" ;} ; # To avoid error messages
return join("\n",(&P4CGI::start_table(" COLS=4 width=100%"),
&P4CGI::table_row({-valign => "top",
-width => "10",
-text => ""},
{-valign => "top",
-text => join("<br>\n",@_[0..$len-1])},
{-valign => "top",
-text => join("<br>\n",@_[$len..(2*$len)-1])},
{-valign => "top",
-text => join("<br>\n",@_[(2*$len)..(3*$len)-1])}),
&P4CGI::end_table())) ;
}
if ($fspc eq "/") {
print "<P><b>Depots</b>\n" ;
if(@subdirs>0) {
print makeThreeColumns(@subdirs) ;
}
}
else {
print "<P><b>Subdirs</b>\n" ;
if(@subdirs>0) {
print makeThreeColumns(@subdirs) ;
}
else {
print "<br>[No more subdirectories]" ;
}
print "<P><b>Files</b>\n" ;
if(@files>0) {
print makeThreeColumns(@files) ;
}
else {
print "<br>[No files in this directory]<br>" ;
}
} ;
print "<hr>\n" ;
print &P4CGI::start_table("bgcolor=".
&P4CGI::HDRFTR_BGCOLOR().
" align=center cellpadding=0 cellspacing=2") ;
print &P4CGI::table_row(-align=>"right",
"$linkToAllbelow...") ;
print &P4CGI::table_row(-align=>"right",
"$linkToChangeByUser...") ;
print &P4CGI::table_row(-align=>"right",
"$linkToPatternSearch...") ;
print &P4CGI::table_row(-align=>"right",
"$recentlyModified...") ;
print &P4CGI::table_row({-align=>"right",
-text => "$depotStatistics..."},
"...for <tt>/$fspc...</tt> :") ;
print &P4CGI::end_table() ;
print
"",
&P4CGI::end_page() ;
#
# That's all folks
#

Просмотреть файл

@ -0,0 +1,359 @@
#!/usr/bin/perl -Tw
# -*- perl -*-
use lib '.';
use P4CGI ;
use strict ;
#use FileHandle; Can't do! Won't work for all perls... Y? Who knows?
#
#################################################################
# CONFIGURATION INFORMATION
# All config info should be in P4CGI.pm
#
#################################################################
#
# P4 file diff viewer
# View diff between two files or two revisions
#
#################################################################
# Get file spec argument
my $FSPC = P4CGI::cgi()->param("FSPC") ;
$FSPC = &P4CGI::extract_printable_chars($FSPC);
&P4CGI::bail("Invalid file spec.") if ($FSPC =~ /[<>"&:;'`]/);
my @files = split /,/,$FSPC;
&P4CGI::bail("No file specified") unless @files > 0 ;
my $REV = P4CGI::cgi()->param("REV");
$REV = &P4CGI::extract_digits($REV);
my @revs = split / /,$REV if defined $REV;
&P4CGI::bail("Invalid file revisions.") unless ($REV =~ /^[0-9 ]*$/);
$files[0] =~ s/^([^\#]+)\#(\d+)/$1/ and do { $revs[0] = $2 ; } ;
&P4CGI::bail("No revision specified") unless @revs > 0 ;
my $ACT = P4CGI::cgi()->param("ACT");
&P4CGI::bail("Invalid mode(s).") if ($ACT =~ /[<>"&:;'`]/);
my @modes = split / /,$ACT if defined $ACT;
&P4CGI::bail("No mode specified") unless @modes > 0 ;
my $FSPC2 = P4CGI::cgi()->param("FSPC2");
$FSPC2 = &P4CGI::extract_printable_chars($FSPC2);
&P4CGI::bail("Invalid file spec.") if ($FSPC2 =~ /[<>"&:;'`]/);
my @files2 = split /,/,$FSPC2 if defined $FSPC2;
my $REV2 = P4CGI::cgi()->param("REV2");
$REV2 = &P4CGI::extract_digits($REV2);
my @revs2 = split / /,$REV2 if defined $REV2;
&P4CGI::bail("Invalid revisions specified.") unless ($REV2 =~ /^[0-9 ]*$/);
if(defined $files2[0]) {
$files2[0] =~ s/^([^\#]+)\#(\d+)/$1/ and do { $revs2[0] = $2 ; } ;
} ;
my $change = P4CGI::cgi()->param("CH") ;
$change = &P4CGI::extract_digits($change);
&P4CGI::bail("Invalid change specified.") unless ($change =~ /^[0-9]*$/);
# Constants for the file diff display
# $NCONTEXT - number of lines context before and after a diff
my $NCONTEXT = P4CGI::cgi()->param("CONTEXT") ;
$NCONTEXT = &P4CGI::extract_digits($NCONTEXT);
$NCONTEXT = 10 unless defined $NCONTEXT ;
&P4CGI::bail("Invalid number of context lines.") unless ($NCONTEXT =~ /^[0-9]*$/);
# $MAXCONTEXT - max number of lines context between diffs
my $MAXCONTEXT = $NCONTEXT+20;
my $n ;
for($n = 0; $n < @files ; $n++) {
$files2[$n] = $files[$n] unless defined $files2[$n] ;
$revs2[$n] = $revs[$n]-1 unless defined $revs2[$n] ;
}
if((@files != @revs) ||
(@files != @files2) ||
(@files != @revs2)) {
&P4CGI::bail("Argument counts not correct") ;
} ;
my $title ;
if(@files == 1) {
if($files[0] eq $files2[0]) {
if($revs[0] < $revs2[0]) {
my $r = $revs2[0] ;
$revs2[0] = $revs[0] ;
$revs[0] = $r ;
}
$title = "Diff<br><code>$files[0]</code><br>\#$revs2[0] -&gt; \#$revs[0] " ;
}
else {
$title = "Diff between<br><code>$files[0]\#$revs[0]</code><br>and<br><code>$files2[0]\#$revs2[0]" ;
}
}
else {
$title = "Diffs for change $change" ;
}
my $nextNCONTEXT= $NCONTEXT*2 ;
my @pstr ;
my $p ;
foreach $p (&P4CGI::cgi()->param) {
next if $p eq "CONTEXT" ;
push @pstr, $p . "=" . P4CGI::cgi()->param($p) ;
}
my $moreContext=&P4CGI::ahref(@pstr,
"CONTEXT=$nextNCONTEXT",
"Show more context") ;
my $showWholeFile=&P4CGI::ahref(@pstr,
"CONTEXT=9999999",
"Show complete file") ;
my $legend ;
if($NCONTEXT < 9999999) {
$legend =
&P4CGI::ul_list("<b>Line numbers</b> -- Goto line in file vewer",
"<b>$moreContext</b> -- Click here to get more context",
"<b>$showWholeFile</b> -- Click here to see whole file with diffs") ;
}
else {
$legend =
&P4CGI::ul_list("<b>Line numbers</b> -- Goto line in file vewer") ;
}
print
"",
&P4CGI::start_page($title,$legend) ;
my $currentFile ;
my $currentRev ;
local *P4 ;
my $P4lineNo ;
sub getLine()
{
$P4lineNo++ if defined $P4lineNo ;
return <P4> ;
}
while(@files>0) {
my $f1start= "<font color=blue>" ;
my $f1end="</font>" ;
my $f2start = "<font color=red><strike>" ;
my $f2end = "</strike></font>" ;
my $file = shift @files ;
my $file2 = shift @files2 ;
my $rev = shift @revs ;
my $rev2 = shift @revs2 ;
my $mode = shift @modes ;
if($file eq $file2) {
if($rev < $rev2) {
my $r = $rev2 ;
$rev2 = $rev ;
$rev = $r ;
}
}
else {
$f2start = "<font color=green>" ;
$f2end = "</font>" ;
}
$currentFile = $file ;
$currentRev = $rev ;
print
&P4CGI::start_table("width=100% align=center bgcolor=white"),
&P4CGI::table_row({-align=>"center",
-text =>"<BIG>$f1start$file\#$rev$f1end<br>$f2start$file2\#$rev2$f2end</BIG>"}),
&P4CGI::end_table(),
"<pre>" ;
my $f1 = "$file#$rev";
my $f2 = "$file2#$rev2";
##
## Use "p4 diff2" to get a list of modifications (diff chunks)
##
my $nchunk =0; # Counter for diff chunks
my @start ; # Start line for chunk in latest file
my @dels ; # No. of deleted lines in chunk
my @adds ; # No. of added lines in chunk
my @delLines ; # Memory for deleted lines
if ($mode ne 'add' && $mode ne 'delete' && $mode ne 'branch') {
&P4CGI::p4call(*P4, "diff2 \"$f2\" \"$f1\"");
$_ = <P4>;
while (<P4>) {
# Check if line matches start of a diff chunk
/(\d+),?(\d*)([acd])(\d+),?(\d*)/ or do { next ; } ;
# $la, $lb: start and end line in old (left) file
# $op: operation (one of a,d or c)
# $ra, $rb: start and end line in new (right) file
my ( $la, $lb, $op, $ra, $rb ) = ($1,$2,$3,$4,$5) ;
# End lines may have to be calculated
if( !$lb ) { $lb = $op ne 'a' ? $la : $la - 1; }
if( !$rb ) { $rb = $op ne 'd' ? $ra : $ra - 1; }
my ( $dels, $adds ); # Temporary vars for No of adds/deletes
# Calc. start position in new (right) file
$start[ $nchunk ] = $op ne 'd' ? $ra : $ra + 1;
# Calc. No. of deleted lines
$dels[ $nchunk ] = $dels = $lb - $la + 1;
# Calc. No. of added lines
$adds[ $nchunk ] = $adds = $rb - $ra + 1;
# Init deleted lines
$delLines[ $nchunk ] = "";
# Get the deleted lines from the old (left) file
while( $dels-- ) {
$_ = <P4>;
s/^. //;
$_ = &P4CGI::fixSpecChar($_) ;
$delLines[ $nchunk ] .=
"<small> </small> <font color=red>|</font>$_";
}
# If it was a change, skip over separator
if ($op eq 'c') {
$_ = <P4>;
}
# Skip over added lines (we don't need to know them yet)
while( $adds-- ) {
$_ = <P4>;
}
# Next chunk.
$nchunk++;
}
close P4;
}
# Now walk through the diff chunks, reading the new (right) file and
# displaying it as necessary.
&P4CGI::p4call(*P4, "print -q \"$f1\"");
$P4lineNo = 0; # Current line
my $n ;
for( $n = 0; $n < $nchunk; $n++ )
{
# print up to this chunk.
&catchup($start[ $n ] - $P4lineNo - 1) ;
# display deleted lines -- we saved these from the diff
if( $dels[ $n ] )
{
print "$f2start";
print $delLines[ $n ];
print "$f2end";
}
# display added lines -- these are in the file stream.
if( $adds[ $n ] )
{
print "$f1start";
&display($adds[ $n ] );
print "$f1end";
}
# $curlin = $start[ $n ] + $adds[ $n ];
}
&catchup(999999999 );
close P4;
print "</pre>" ;
}
print &P4CGI::end_page() ;
# Support for processing diff chunks.
#
# skip: skip lines in source file
# display: display lines in source file, handling funny chars
# catchup: display & skip as necessary
#
##
## skip(<handle>,no of lines)
## Returns: 0 or No. of lines not skipped if file ends
sub skip {
my $to = shift @_;
while( $to > 0 && ( $_ = &getLine() ) ) {
$to--;
}
return $to;
}
##
## display(<handle>,no of lines)
## Displays a number of lines from handle
sub display {
my $to = shift @_;
while( $to-- > 0 && ( $_ = &getLine() ) ) {
my $line = &P4CGI::fixSpecChar($_) ;
my $ls ;
if(($P4lineNo % 5) == 0) {
$ls = sprintf("<small>%5d:</small>",$P4lineNo) ;
$ls = &P4CGI::ahref(-url=>"fileViewer.cgi",
-anchor => "L$P4lineNo",
"FSPC=$currentFile",
"REV=$currentRev",
$ls) ;
}
else {
$ls = "<small> </small>" ;
}
print "$ls <font color=red>|</font>$line" ;
}
}
##
## catchup(<handle>,no of lines)
## Print/skip lines to next diff chunk
sub catchup {
my $to = shift @_;
if( $to > $MAXCONTEXT )
{
my $skipped = $to - $NCONTEXT ;
if($P4lineNo > 0) {
&display($NCONTEXT );
$skipped -= $NCONTEXT ;
}
$skipped -= &skip($skipped );
print
"<hr><center><strong>",
"$skipped lines skipped",
"</strong></center><hr>\n" if( $skipped );
&display($NCONTEXT );
}
else
{
&display($to);
}
}
#
# That's all folks
#

Просмотреть файл

@ -0,0 +1,46 @@
#!/usr/bin/perl -w
# -*- perl -*-
use P4CGI ;
use strict ;
#
#################################################################
# CONFIGURATION INFORMATION
# All config info should be in P4CGI.pm
#
#################################################################
#
# P4 file download
# Download a file
#
#################################################################
# Get file spec argument
my $file = P4CGI::cgi()->param("FSPC") ;
&P4CGI::bail("No file specified") unless defined $file ;
&P4CGI::bail("Invalid file.") if ($file =~ /[<>"&:;'`]/);
my $filename = $file ;
$filename =~ s/.*\/// ;
my $revision = P4CGI::cgi()->param("REV") ;
&P4CGI::bail("No revision specified") unless defined $revision ;
&P4CGI::bail("Invalid revision specified") unless $revision =~ /^\d*$/;
local *P4 ;
&P4CGI::p4call( *P4, "print -q \"$file#$revision\"" );
$file = join('',<P4>) ;
close P4 ;
my $len = length($file) ;
print
"Content-type: application/octet-stream\n",
"Content-Disposition: attachment;filename=$filename;size=$len\n",
"Content-Description: Download file:$filename Rev:$revision\n",
"\n" ;
print $file ;
#
# That's all folks
#

Просмотреть файл

@ -0,0 +1,445 @@
#!/usr/bin/perl -Tw
# -*- perl -*-
use lib '.';
use P4CGI ;
use strict ;
use CGI::Carp ;
#
#################################################################
# CONFIGURATION INFORMATION
# All config info should be in P4CGI.pm
#
#################################################################
#
# P4 file log viewer
#
#################################################################
sub offsetOf($@ ) {
my $v = shift @_ ;
my $pos = 0 ;
while(@_ > 0) {
if($v eq (shift @_)) {
return $pos ;
}
$pos++ ;
}
return -1 ;
}
my $err2null = &P4CGI::REDIRECT_ERROR_TO_NULL_DEVICE() ;
my $err2stdout = &P4CGI::REDIRECT_ERROR_TO_STDOUT() ;
local *P ;
# File argument
my $file = P4CGI::cgi()->param("FSPC") ;
$file = &P4CGI::extract_printable_chars($file);
&P4CGI::bail("No file spec") unless defined $file ;
&P4CGI::bail("Invalid file spec.") if ($file =~ /[<>"&:;'`]/);
# Label x-reference argument
my $listLabel = P4CGI::cgi()->param("LISTLAB") ;
$listLabel = "No" unless defined $listLabel and $listLabel eq "Yes";
# Show branch info argument
my $showBranch = P4CGI::cgi()->param("SHOWBRANCH") ;
$showBranch="No" unless defined $showBranch and $showBranch eq "Yes";
# Get file data
my @filelog ;
@filelog=&P4CGI::run_cmd("filelog", $file) ;
&P4CGI::bail("No data for file \"$file\"") if @filelog == 0 ;
# Get info about opened status
&P4CGI::p4call(*P,"opened -a \"$file\" $err2null") ;
my %opened ;
my $openedText = "" ;
while(<P>) {
$openedText = "Opened by" ;
chomp ;
/\w+\#(\d+) - .* by (\w+)\@(\S+)/ or
&P4CGI::bail("Can not read info from \"p4 opened\"") ;
my $user = &P4CGI::ahref(-url => "userView.cgi",
"USER=$2",
"$2") ;
my $client = &P4CGI::ahref(-url => "clientView.cgi",
"CLIENT=$3",
"$3") ;
if(exists $opened{$1}) {
$opened{$1} .= "<br> and $user\@$client" ;
} else {
$opened{$1} = "$user\@$client" ;
} ;
} ;
close *P ;
# Get list of labels (if $listLabel is set)
my @labels ;
if($listLabel eq "Yes") {
&P4CGI::p4call(*P,"labels") ;
while(<P>) {
/^Label (\S+)/ and do { push @labels,$1 ; } ;
}
close P ;
}
# Create hash containing labels by file name and
# version
my %fileToLabels ;
if(@labels > 0) {
# Try to speed things up by looking up
# file view for each label and removing all
# labels that don't match
# This is an act of desperation because in our
# p4 depot the label search takes forever (well..
# a long time, 20 secs or so...)
if(1) {
my $l ;
my @l ;
LABEL: foreach $l (@labels) {
my %data ;
&P4CGI::p4readform("label -o \"$l\"",\%data) ;
if(exists $data{"View"}) {
my @v = split("\n",$data{"View"}) ;
foreach (@v) {
# p4-to-perl regexp conversion
my $in = $_ ;
my $re = "" ;
while($in =~ s/(.*?)(\Q...\E|\Q*\E)//) {
$re .= "\Q$1\E" ;
if($2 eq "...") { $re .= ".*" ; }
else { $re .= "[^/]*" ; }
}
$re .= "\Q$in\E" ;
if($file =~ /$re/) {
push @l,$l ;
next LABEL ;
}
}
}
}
my $lb = @labels ;
my $la = @l ;
&P4CGI::ERRLOG("reduced from $lb to $la labels") ; # DEBUG
@labels = @l ;
}
# <RANT>
# Frankly, I find it very strange that I can speed
# up the search by "manually" reading all label
# specs, parsing them, and checking if the file
# matches any part of the view before actually
# asking p4 to do it. Some developer must have had
# a bad day at perforce. And p4 is not open
# source.... sigh.
# </RANT>
my $filelabels = "" ;
foreach (@labels) {
$filelabels .= " \"$file\@$_\"" ;
}
my @filesInLabels ;
&P4CGI::p4call(\@filesInLabels,"files $filelabels $err2stdout") ;
my $l ;
# Remove labels not in list
# NOTE! The errors (file not in label-messages)
# are printed to stderr and there
# is no guarantee that output from stderr and
# stdout will come in order. This is why
# we first must figure out which labels
# that NOT affected the file
foreach $l (reverse map {/.*@(\S+)\s.*not in label/?$1:()} @filesInLabels) {
my $offset = offsetOf($l,@labels) ;
splice @labels,$offset,1 ;
}
# Build file-to-label hash. Use only data from
# stdout (not stderr). (grep is used to filter)
foreach (grep(!/not in label/,@filesInLabels)) {
my $lab = shift @labels ;
/^(\S+)/ ;
if(defined $fileToLabels{$1}) {
$fileToLabels{$1} .= "<br>$lab" ;
}
else {
$fileToLabels{$1} = "$lab" ;
}
}
} ;
my @legendList ;
push @legendList,
"<b>Revision Number</b> -- see the file text",
"<b>Action</b> -- see the deltas (diffs)",
"<b>User</b> -- see info about user",
"<b>Change</b> -- see the complete change description, including other files",
&P4CGI::ahref("-url","changeList.cgi",
"FSPC=$file",
"Changes") . "-- see list of all changes for this file" ;
my @parsListLab ;
my @parsShowBranch ;
my $p ;
foreach $p (&P4CGI::cgi()->param()) {
push @parsListLab, "$p=" . &P4CGI::cgi()->param($p) unless $p eq "LISTLAB" ;
push @parsShowBranch, "$p=" . &P4CGI::cgi()->param($p) unless $p eq "SHOWBRANCH" ;
}
if($listLabel ne "Yes") {
push @legendList,
&P4CGI::ahref(@parsListLab,
"LISTLAB=Yes",
"List labels") . "-- list cross ref. for labels" ;
} ;
if($showBranch ne "No") {
push @legendList,
&P4CGI::ahref(@parsShowBranch,
"SHOWBRANCH=No",
"Hide branch info") . "-- hide info about branches, merges and copy of file" ;
}
else {
push @legendList,
&P4CGI::ahref(@parsShowBranch,
"SHOWBRANCH=Yes",
"Show branch info") . "-- show info about branches, merges and copy of file" ;
} ;
# Get file directory part
my $fileDir=$file ;
$fileDir =~ s#/[^/]+$## ;
push @legendList,
&P4CGI::ahref("-url","depotTreeBrowser.cgi",
"FSPC=$fileDir",
"Browse directory") .
"-- Browse depot tree at $fileDir" ;
my @back = &P4CGI::back_buttons($file);
print "",&P4CGI::start_page("File log<br>@back",&P4CGI::ul_list(@legendList)) ;
my $labelHead ="";
if($listLabel eq "Yes") {
$labelHead="In label(s)" ;
} ;
print
"",
&P4CGI::start_table(""),
&P4CGI::table_header("Rev/view file",
"Action/view diff",
"Date",
"User/view user",
"Change/view change",
"Type",
"Desc",
$labelHead,
$openedText) ;
my $log ;
my @revs ;
my %relatedFiles ;
my ($rev,$change,$act,$date,$user,$client,$type,$desc) ;
my $chbuffer = "" ;
while($log = shift @filelog) {
$_ = &P4CGI::fixSpecChar($log) ;
if(/^\.\.\. \#(\d+) \S+ (\d+) (\S+) on (\S+) by (\S*)@(\S*) (\S*)\s*'(.*)'/ ) {
print $chbuffer ;
$chbuffer = "" ;
($rev,$change,$act,$date,
$user,$client,$type,$desc) = ($1,$2,$3,$4,$5,$6,$7,$8) ;
$type =~ s/\((.*)\)/$1/ ;
$desc = &P4CGI::magic($desc) ;
push @revs,$rev ;
my $labels = $fileToLabels{"$file\#$rev"} ;
$labels = "" unless defined $labels ;
$labels = "<b>$labels</b>" ;
if ($act eq 'branch') {
$chbuffer .=
&P4CGI::table_row(-valign => "top",
&P4CGI::ahref("-url","fileViewer.cgi",
"FSPC=$file",
"REV=$rev",
"$rev"),
"$act",
"$date",
&P4CGI::ahref(-url => "userView.cgi" ,
"USER=$user",
"$user"),
&P4CGI::ahref("-url","changeView.cgi",
"CH=$change",
"$change"),
"$type",
"<tt>$desc</tt>",
$labels,
exists $opened{$rev}?$opened{$rev}:"") ;
}
elsif ($act eq 'delete') {
$chbuffer .=
&P4CGI::table_row(-valign => "top",
"$rev",
"<strike>delete</strike>",
"$date",
&P4CGI::ahref(-url => "userView.cgi" ,
"USER=$user",
"$user"),
&P4CGI::ahref("-url","changeView.cgi",
"CH=$change",
"$change"),
"$type",
"<tt>$desc</tt>",
$labels,
exists $opened{$rev}?$opened{$rev}:"") ;
}
else {
$chbuffer .=
&P4CGI::table_row(-valign => "top",
&P4CGI::ahref("-url","fileViewer.cgi",
"FSPC=$file",
"REV=$rev",
"$rev"),
&P4CGI::ahref("-url","fileDiffView.cgi",
"FSPC=$file",
"REV=$rev",
"ACT=$act",
"$act"),
"$date",
&P4CGI::ahref(-url => "userView.cgi" ,
"USER=$user",
"$user"),
&P4CGI::ahref("-url","changeView.cgi",
"CH=$change",
"$change"),
"$type",
"<tt>$desc</tt>",
$labels,
exists $opened{$rev}?$opened{$rev}:"") ;
}
}
else {
if(/^\.\.\. \.\.\. (\w+) (\w+) (\S+?)\#(\S+)/) {
my ($op,$direction,$ofile,$orev) = ($1,$2,$3,$4) ;
my $file = $ofile ;
$file =~ s/\#.*$// ;
$relatedFiles{$file} = 1 ;
if($showBranch ne "No") {
my ($b1,$b2) = ("","") ;
if($op eq "copy") {
($b1,$b2) = ("<b> ! ","</b>") ;
}
my $d = &P4CGI::table_row(-valign => "top",
"",
undef,
undef,
undef,
undef,
undef,
undef,
undef,
undef,
"$b1$op $direction ".
&P4CGI::ahref("-url","fileLogView.cgi",
"FSPC=$ofile",
"$ofile\#$orev"). "$b2") ;
if($direction ne "from") {
$chbuffer = "$d\n$chbuffer" ;
}
else {
print "$chbuffer\n$d\n" ;
$chbuffer = "" ;
}
}
}
}
}
print "$chbuffer\n" ;
print
"",
&P4CGI::end_table("") ;
if(@revs > 2) {
print
"<hr>",
&P4CGI::cgi()->startform("-action","fileDiffView.cgi",
"-method","GET"),
&P4CGI::cgi()->hidden("-name","FSPC",
"-value",&P4CGI::fixspaces("$file")),
&P4CGI::cgi()->hidden("-name","ACT",
"-value","edit"),
"\nShow diff between revision: ",
&P4CGI::cgi()->popup_menu(-name =>"REV",
"-values" =>\@revs);
shift @revs ;
print
" and ",
&P4CGI::cgi()->popup_menu(-name =>"REV2",
"-values" =>\@revs),
" ",
&P4CGI::cgi()->submit(-name =>"Go",
-value =>"Go"),
&P4CGI::cgi()->endform() ;
} ;
sub getRelatedFiles($ )
{
my $file = shift @_ ;
my @data ;
&P4CGI::p4call(\@data,"filelog \"$file\"") ;
my %res ;
map { if(/^\.\.\. \.\.\. \w+ \w+ (\S+?)\#/) { $res{$1} = 1 ; } ; } @data ;
return ( sort keys %res ) ;
} ;
if((keys %relatedFiles) > 0) {
my @rel = sort keys %relatedFiles ;
my @fileLinks = map { &P4CGI::ahref("-url","fileLogView.cgi",
"FSPC=$_",
"$_") ; } @rel ;
my %indrel ;
$relatedFiles{$file} = 1 ;
while(@rel > 0) {
my $r ;
foreach $r (map { exists $relatedFiles{$_} ? () : $_ } getRelatedFiles(shift @rel)) {
&P4CGI::ERRLOG("found: $r") ;
$indrel{$r} = 1;
push @rel, $r ;
$relatedFiles{$r} = 1 ;
}
}
my @indFileLinks = map { &P4CGI::ahref("-url","fileLogView.cgi",
"FSPC=$_",
"$_") ; } sort keys %indrel ;
print
"",
&P4CGI::start_table(),
&P4CGI::table_row({ -valign => "top",
-align => "right",
-type => "th",
-text => "Related files:" },
{ -text => &P4CGI::ul_list(@fileLinks) }) ;
if(@indFileLinks > 0) {
print "", &P4CGI::table_row({ -valign => "top",
-align => "right",
-type => "th",
-text => "Indirect:" },
{ -text => &P4CGI::ul_list(@indFileLinks) }) ;
} ;
print "", &P4CGI::end_table() ;
} ;
print
"",
&P4CGI::end_page() ;
#
# That's all folks
#

Просмотреть файл

@ -0,0 +1,135 @@
#!/usr/bin/perl -w
# -*- perl -*-
use P4CGI ;
use strict ;
use CGI::Carp ;
#
#################################################################
# CONFIGURATION INFORMATION
# All config info should be in P4CGI.pm
#
#################################################################
#
# List open files
#
#################################################################
# File argument
my $FSPC = P4CGI::cgi()->param("FSPC") ;
$FSPC = "//..." unless defined $FSPC ;
&P4CGI::bail("Invalid file spec.") if ($FSPC =~ /[<>"&:;'`]/);
my @FSPC = split(/\s*\+?\s*(?=\/\/)/,$FSPC) ;
$FSPC = "<tt>".join("</tt> and <tt>",@FSPC)."</tt>" ;
my $FSPCcmd = "\"" . join("\" \"",@FSPC) . "\"" ;
my $SORTBY = P4CGI::cgi()->param("SORTBY") ;
$SORTBY="NAME" unless defined $SORTBY and $SORTBY eq "USER" ;
my $err2null = &P4CGI::REDIRECT_ERROR_TO_NULL_DEVICE() ;
# Get info about opened status
my @opened ;
&P4CGI::p4call(\@opened,"opened -a $FSPCcmd $err2null") ;
map { /(.*)\#(\d+) - (\S+) (\S+\s\S+) \S+ by (\S+)@(\S+)/ ;
$_ = [$1,$2, $3,$4, $5,$6] ; } @opened ;
# file status user
# rev change client
my @legend ;
if($SORTBY eq "USER") {
my @tmp = sort { my @a = @$a ;
my @b = @$b ;
uc("$a[4] $a[5]").$a[0] cmp uc("$b[4] $b[5]").$b[0] ; } @opened ;
@opened = @tmp ;
push @legend, &P4CGI::ahref("SORTBY=NAME",
"Sort list by file name") ;
}
else {
push @legend, &P4CGI::ahref("SORTBY=USER",
"Sort list by user") ;
} ;
# Create converstion hash for user -> fullname
my %userCvt ;
{
my @users ;
&P4CGI::p4call(\@users, "users" );
%userCvt = map { /^(\S+).*> \((.+)\) .*$/ ; ($1,$2) ; } @users ;
} ;
print &P4CGI::start_page("List open files for<br>$FSPC",&P4CGI::ul_list(@legend)) ;
my ($lastFile,$lastRev,$lastUser,$lastClient) = ("","","","") ;
sub printLine(@) {
my ($file,$rev,$status,$change,$user,$client) = @_ ;
$change =~ s/\s*change\s*// ;
my $Puser = &P4CGI::ahref(-url => "userView.cgi",
"USER=$user",
"$user ($userCvt{$user})") ;
my $Pclient = &P4CGI::ahref(-url => "clientView.cgi",
"CLIENT=$client",
"$client") ;
my $Pfile = &P4CGI::ahref(-url => "fileLogView.cgi",
"FSPC=$file",
"$file") ;
my $Prev = &P4CGI::ahref(-url => "fileViewer.cgi",
"FSPC=$file",
"REV=$rev",
"$rev") ;
if($SORTBY eq "NAME") {
if($file eq $lastFile) {
$Pfile = "" ;
if($rev eq $lastRev) {
$Prev = "" ;
}
}
print &P4CGI::table_row($Pfile,$Prev,$status,$change,$Puser,$Pclient) ;
}
elsif ($SORTBY eq "USER") {
if($user eq $lastUser) {
$Puser = "" ;
if($client eq $lastClient) {
$Pclient = "" ;
}
}
print &P4CGI::table_row($Puser,$Pclient,$Pfile,$Prev,$status,$change) ;
} ;
($lastFile,$lastRev,$lastUser,$lastClient) = ($file,$rev,$user,$client) ;
} ;
print &P4CGI::start_table("") ;
if($SORTBY eq "NAME") {
print &P4CGI::table_header("File/view log","Rev/view file","Status","Change","User/view","Client/view") ;
}
elsif($SORTBY eq "USER") {
print &P4CGI::table_header("User/view","Client/view","File/view log","Rev/view file","Status","Change") ;
} ;
map { printLine(@$_) ; } @opened ;
print &P4CGI::end_table() ;
print &P4CGI::end_page() ;
#
# That's all folks
#

Просмотреть файл

@ -0,0 +1,145 @@
#!/usr/bin/perl -Tw
# -*- perl -*-
use lib '.';
use P4CGI ;
use strict ;
#
#################################################################
# CONFIGURATION INFORMATION
# All config info should be in P4CGI.pm
#
#################################################################
#
# P4 search for file
# Search depot for files matching spec
#
#################################################################
# Get file spec argument
my $filespec = P4CGI::cgi()->param("FSPC") ;
$filespec = &P4CGI::extract_printable_chars($filespec);
$filespec = "" unless defined $filespec ;
&P4CGI::bail("Invalid file spec.") if ($filespec =~ /[<>"&:;'`]/);
my $label = P4CGI::cgi()->param("LABEL") ;
if(!defined $label) {
$label = "" ;
}
&P4CGI::bail("Invalid label.") if ($label =~ /[<>"&:;'`]/);
my $filedesc ;
my $showDiffSelection="Y" ;
if($filespec eq "") {
$filedesc = " <small>label</small><br><code>$label</code>" ;
$showDiffSelection= undef ;
}
else {
$filedesc = "<br><code>$filespec</code>" ;
if($label ne "") {
$filedesc .= "<br><small>in label</small><br><code>$label</code>" ;
}
}
if($label ne "") {
$label = "\@$label" ;
}
# Add //... if not there
if($filespec !~ /^\/\//) {
$filespec = "//...$filespec" ;
}
while($filespec =~ s/\.\.\.\.\.\./\.\.\./) { ; } ;
while($filespec =~ s/\*\*/\*/) { ; } ;
my $MAX_RESTART=100 ; # Restart table after this number of lines...
# Check if file exists
my @matches ;
&P4CGI::p4call(\@matches, "files \"$filespec$label\"" );
my $tableStart ;
$tableStart = &P4CGI::start_table("cellpadding=1") .
"\n" .
&P4CGI::table_header("Rev/view","Action/diff","Change/view ch.","File/view log");
my $tableSize = 0 ;
print "",
&P4CGI::start_page("<small>Search result for</small>$filedesc",
&P4CGI::ul_list("<b>Filename</b> -- see the complete file history",
"<b>Revision Number</b> -- see the file text",
"<b>Action</b> -- see the deltas (diffs)",
"<b>Change</b> -- see the complete change description, including other files")) ;
if(scalar(@matches) == 0) {
print "<font color=red>No files found matching $filespec</font>\n" ;
}
else {
print "<font color=green>",scalar(@matches)," files found:</font>" ;
if(@matches > $MAX_RESTART) {
my $n = 2 ; # Compute a value for $MAX_RESTART that does not leave widows..
while(@matches/$n > $MAX_RESTART) { $n++ ; } ;
$MAX_RESTART = int(@matches/$n) ;
} ;
my $f ;
foreach $f (@matches) {
$f =~ /([^\#]+)\#(\d+) - (\w+) change (\d+)/ ;
my ($name,$rev,$act,$change)=($1,$2,$3,$4) ;
print $tableStart if $tableSize == 0 ;
$tableSize++ ;
print
"",
&P4CGI::table_row(&P4CGI::ahref("-url","fileViewer.cgi",
"FSPC=$name",
"REV=$rev",
$rev),
&P4CGI::ahref("-url","fileDiffView.cgi",
"FSPC=$name",
"REV=$rev",
"ACT=$act",
$act),
&P4CGI::ahref("-url","changeView.cgi",
"CH=$change",
$change),
&P4CGI::ahref("-url","fileLogView.cgi",
"FSPC=$name",
$name)) ;
if($tableSize > $MAX_RESTART) {
print "",&P4CGI::end_table() ;
$tableSize = 0 ;
} ;
} ;
print "",&P4CGI::end_table() if $tableSize > 0 ;
my @files ;
my %filesToFiles ;
foreach $f (@matches) {
$f =~ /([^\#]+)\#(\d+) - (\w+) change (\d+)/ ;
my ($name,$rev,$act,$change)=($1,$2,$3,$4) ;
if($act ne "delete"){
push @files,"$name\#$rev" ;
}
} ;
if(defined $showDiffSelection and @files > 1) {
print
&P4CGI::cgi()->startform("-action","fileDiffView.cgi",
"-method","GET"),
&P4CGI::cgi()->hidden("-name","ACT",
"-value","edit"),
"View diff between:<br>",
&P4CGI::cgi()->popup_menu(-name => "FSPC",
-values => \@files),
"and<br>",
&P4CGI::cgi()->popup_menu(-name => "FSPC2",
-values => \@files),
&P4CGI::cgi()->submit("-name","ignore",
"-value"=>"Go"),
&P4CGI::cgi()->endform() ;
} ;
} ;
print
"",
&P4CGI::end_page() ;
#
# That's all folks
#

Просмотреть файл

@ -0,0 +1,193 @@
#!/usr/bin/perl -w
# -*- perl -*-
use P4CGI ;
use strict ;
#
#################################################################
# CONFIGURATION INFORMATION
# All config info should be in P4CGI.pm
#
#################################################################
#
# P4 file viewer
# View a file
#
#################################################################
use viewConfig ;
use colorView ;
# A hash containing file extensions that can be viewed with special viewers
# Data is:
# <extension> => <semicolon separated list of:
# url - Url to be used
# typecode - Will be sent as parameter TYPE to url
# text - A text for the href to url>
# Other than the TYPE parameter mentioned above the file name (depot format) will
# be sent as FILE parameter and file revision as REV parameter.
#
# Get file spec argument
my $file = P4CGI::cgi()->param("FSPC") ;
$file = &P4CGI::extract_printable_chars($file);
&P4CGI::bail("No file specified") unless defined $file ;
&P4CGI::bail("Invalid file spec.") if ($file =~ /[<>"&:;'`]/);
my $ext = $file ;
$ext =~ s/^.*\.// ;
my $revision = P4CGI::cgi()->param("REV") ;
$revision = &P4CGI::extract_digits($revision);
# &P4CGI::bail("No revision specified") unless defined $revision ;
$revision = "#$revision" if defined $revision ;
$revision = "" unless defined $revision ;
&P4CGI::bail("Invalid revision.") unless ($revision =~ /^#?\d*$/);
my $force = P4CGI::cgi()->param("FORCE") ;
$force = "Yes" if defined $force;
# find out if p4br.perl is available, if true set smart
local *P4 ;
my $smart;
my ( $name, $rev, $type ) ;
if(-x "p4pr.perl") {
open(P4,"./p4pr.perl \"$file$revision\" |") or
&P4CGI::bail("Can't start p4pr!!!!. too bad!") ;
# Get header line
# line author/branch change rev //main/jam/Jamfile#39 - edit change 1749 (text)
$_ = <P4>;
if(defined $_ and (/^\s+\S+\s+\S+\s+\S+\s+\S+\s+(\S+)\#(\d+) - \S+ \S+ \S+ \((.+)\)/)) {
( $name, $rev, $type ) = ($1,$2,$3) ;
$_ = <P4>;
$smart="Yes";
}
else {
close P4 ;
}
}
if(!defined $smart) {
&P4CGI::p4call( *P4, "print \"$file$revision\"" );
$smart="No, stupid." ;
# Get header line
# //main/jam/Jamfile#39 - edit change 1749 (text)
$_ = <P4>;
if(defined $_ and (/^(.+)\#(\d+) - \S+ \S+ \S+ \((\w+)\)/)) {
( $name, $rev, $type ) = ($1,$2,$3) ;
} ;
}
my $legend = "" ;
if($smart eq "Yes") {
$legend =
&P4CGI::ul_list("<b>Change number</b> -- see the change description",
"<b>Revision number</b> -- see diff at selected revision") ;
}
$ext = uc($ext) ;
if(exists $viewConfig::ExtensionToType{$ext}) {
my $type = $viewConfig::ExtensionToType{$ext} ;
my ($url,$desc,$content,$about) = @{$viewConfig::TypeData{$type}} ;
$legend .= &P4CGI::ahref(-url => $url,
"TYPE=$type",
"FSPC=$file",
"REV=$rev",
"View $desc") ;
$legend .= "&nbsp;&nbsp;&nbsp;<small><i>$about</i></small>" if defined $about ;
$legend .= "<br>";
} ;
$legend .= &P4CGI::ahref(-url => "fileDownLoad.cgi",
"FSPC=$file",
"REV=$rev",
"Download file") ;
my @back = &P4CGI::back_buttons($file);
print
"",
&P4CGI::start_page("File<br>@back<code>\#$rev</code>",$legend) ;
if(!defined $force and ($type =~ /.*binary/))
{
print
"<h2>Type is $type.</h2>\n",
&P4CGI::ahref(-url => &P4CGI::cgi()->url,
"FSPC=$file",
"REV=$rev",
"FORCE=Y",
"View anyway!") ;
}
else
{
print "Type: $type<br>\n<pre>\n";
my @prompts ;
my @filetext ;
if(!defined $force and $smart eq "Yes"){
my ($lineno,$authorBranch,$change,$rev,$line) ;
print "<small>Line<tt> Author </tt>Ch. Rev</small>\n";
my $oldch=-1;
while( <P4> ) {
($lineno,$authorBranch,$change,$rev,$line) =
m/^\s+(\d+)\s+(\S+)\s+(\d+)\s+(\d+) (.*)$/ ;
my $linenos = sprintf("<A Name=\"L%d\"></A><tt>%3d:</tt>",$lineno,$lineno) ;
my($chstr,$revstr,$authorstr)=(" "," ", " ");
if($oldch != $change){
$chstr=
substr(" ",0,5-length("$change")) .
&P4CGI::ahref("-url","changeView.cgi",
"CH=$change",
"$change") ;
$revstr =
substr(" ",0,3-length("$rev")) .
&P4CGI::ahref("-url","fileDiffView.cgi",
"FSPC=$name",
"REV=$rev","ACT=edit",
"$rev");
$authorstr =
substr(" ",0,8-length("$authorBranch")).
&P4CGI::ahref("-url","changeList.cgi",
"FSPC=$name",
"USERS=$authorBranch",
"$authorBranch");
}
$oldch= $change ;
if(($lineno % 5) != 0) {
while($linenos =~ s/>( *)\d/>$1 /) {} ;
$linenos =~ s/:<\/tt>/ <\/tt>/ ;
}
$authorBranch = $change =~ m/\d/ ;
push @filetext,&P4CGI::fixSpecChar($line) ;
push @prompts,"<small>$linenos $authorstr $chstr$revstr </small><font color=red>|</font>" ;
}
}
else {
while( <P4> ) {
chomp ;
push @filetext,&P4CGI::fixSpecChar($_) ;
push @prompts,"" ;
}
}
my $FILE = join("\n",@filetext) ;
if(&P4CGI::VIEW_WITH_COLORS()) {
&colorView::color($file,\$FILE) ;
@filetext = split("\n",$FILE) unless $@ ;
} ;
while(@filetext) {
print (shift @prompts,shift @filetext,"\n") ;
}
print "</pre>\n";
}
close P4;
print
"",
&P4CGI::end_page() ;
#
# That's all folks
#

Просмотреть файл

@ -0,0 +1,415 @@
#!/usr/bin/perl -Tw
# -*- perl -*-
use lib '.';
use P4CGI ;
use strict ;
#
#################################################################
# CONFIGURATION INFORMATION
# All config info should be in P4CGI.pm
#
#################################################################
#
# View files affected by a set of changes
#
#################################################################
my $err2null = &P4CGI::REDIRECT_ERROR_TO_NULL_DEVICE() ;
####
# Parameters
# FSPC = file spec
#
# NEWER_THAN = restrict to changes newer than specified No. of hours
#
my $FSPC = P4CGI::cgi()->param("FSPC") || "//..." ;
$FSPC = P4CGI::extract_filename_chars($FSPC);
my @FSPC = split(/\s*\+?\s*(?=\/\/)/,$FSPC) ;
my $WEEKS = P4CGI::cgi()->param("WEEKS") ;
if(defined $WEEKS) {
$WEEKS = P4CGI::extract_digits($WEEKS) ;
}
else {
$WEEKS = 0 ;
}
my $DAYS = P4CGI::cgi()->param("DAYS");
if(defined $DAYS) {
$DAYS = P4CGI::extract_digits($DAYS);
}
else {
$DAYS=0 ;
}
my $HOURS = P4CGI::cgi()->param("HOURS");
if(defined $HOURS) {
$HOURS = P4CGI::extract_digits($HOURS);
}
else {
$HOURS = 0 ;
}
my $SUBMIT = P4CGI::cgi()->param("SUBMIT");
if(defined $SUBMIT) {
$SUBMIT=1;
} else {
$SUBMIT='';
}
my $seconds = 3600 * ( $HOURS + (24 * ($DAYS + (7 * $WEEKS)))) ;
my $MINDATE = P4CGI::cgi()->param("MINDATE") ;
my $MAXDATE = P4CGI::cgi()->param("MAXDATE") ;
my $DATESPECIFIER = P4CGI::cgi()->param("DATESPECIFIER") ;
my $TIMEINTERVALSTR;
if ($DATESPECIFIER eq 'explicit') {
$TIMEINTERVALSTR = "\@".&P4CGI::DateStr2Time($MINDATE).",\@".&P4CGI::DateStr2Time($MAXDATE);
} elsif ($DATESPECIFIER eq 'picklist') {
$TIMEINTERVALSTR = &P4CGI::DateList2Time($WEEKS, $DAYS, $HOURS);
} else {
$TIMEINTERVALSTR = '';
}
my %allUsers;
if (($SUBMIT) && ($seconds)) {
#
# get time strings to compare to
#
my $time = time() ;
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($time);
my $currentTimeString = sprintf("\@%d/%02.2d/%02.2d:%02.2d:%02.2d:%02.2d",
1900+$year,$mon+1,$mday,$hour,$min,$sec) ;
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($time - $seconds);
my $afterTimeString = sprintf("\@%d/%02.2d/%02.2d:%02.2d:%02.2d:%02.2d",
1900+$year,$mon+1,$mday,$hour,$min,$sec) ;
my $niceAfterTimeString = sprintf("%d/%02.2d/%02.2d %02.2d:%02.2d",
1900+$year,$mon+1,$mday,$hour,$min) ;
&P4CGI::ERRLOG("currentTimeString: $currentTimeString") ;
&P4CGI::ERRLOG("afterTimeString: $afterTimeString") ;
#
# Start page
#
print
"",
&P4CGI::start_page("Files matching<br><TT>".
join("<br></tt>or<tt><br>\n",@FSPC).
"</TT><br> changed after $niceAfterTimeString ","") ;
#
# Get list of files changed
#
my %toRev ;
my %mode ;
foreach $FSPC (@FSPC) {
my @files ;
my @cmd = ("files","${FSPC}${TIMEINTERVALSTR}");
@files = P4CGI::run_cmd(@cmd);
map { chomp;
s/\#(\d+) - (\S+).*$// ;
$toRev{$_}=$1 ;
$mode{$_} =$2 ; } @files ;
}
my @affectedFiles = sort keys %toRev ;
#
# Get revision at start of interval
#
my %fromRev ;
my @filesToCheck = @affectedFiles ;
while(@filesToCheck > 0) {
my @files ;
while(($#files) < 1000 and @filesToCheck > 0) {
my $file = shift(@filesToCheck);
chomp $file;
push @files, $file.$TIMEINTERVALSTR ;
}
my @res ;
my @cmd = ("files",@files);
@res = P4CGI::run_cmd(@cmd);
map { chomp; s/\#(\d+) - .*// ; $fromRev{$_}=$1 } @res ;
}
if(@affectedFiles == 0) {
print "<font size=+1 color=red>No files found</font>\n" ;
}
else {
print scalar @affectedFiles," files found<br>\n" ;
print
"",
&P4CGI::start_table(""),
&P4CGI::table_header("From/view",
"/Diff",
"To/view",
"File/View file log",
"Change(s)/View change",
"Users") ;
my $f ;
foreach $f (@affectedFiles) {
my @tmp ;
my $changes ;
my $users ;
chomp $f;
my @cmd = ("changes","$f${TIMEINTERVALSTR}");
@tmp = P4CGI::run_cmd(@cmd);
map { chomp;
/^Change (\d+).*$/ ;
my $c = &P4CGI::ahref(-url => "changeView.cgi",
"CH=$1",
$1) ;
if(defined $changes) {
$changes .= ", $c" ;
}
else {
$changes = "$c" ;
} ;
} @tmp ;
map { chomp;
/ by ([^@]+)@/ ;
my $user = $1;
my $u = &P4CGI::ahref("-url" => "userView.cgi",
"USER=$user",
$user) ;
if(defined $users) {
$users .= ", $u" ;
}
else {
$users = "$u" ;
} ;
$allUsers{$user} = 1 ;
} @tmp ;
my $file = &P4CGI::ahref(-url => "fileLogView.cgi",
"FSPC=$f",
$f) ;
my $fromRev ;
my $diff ;
if(exists $fromRev{$f}) {
$fromRev = &P4CGI::ahref(-url => "fileViewer.cgi",
"FSPC=$f",
"REV=$fromRev{$f}",
$fromRev{$f}) ;
$diff = &P4CGI::ahref(-url => "fileDiffView.cgi",
"FSPC=$f",
"REV=$fromRev{$f}",
"REV2=$toRev{$f}",
"ACT=$mode{$f}",
"<font size=1>(diff)</font>") ;
}
else {
$fromRev = "" ;
$diff = "<font size=-1 color=red>New</font>" ;
} ;
my $toRev ;
if($mode{$f} eq "delete") {
$toRev = $toRev{$f} ;
$diff = "<font size=-1 color=red>Deleted</font>" ;
}
else {
$toRev = &P4CGI::ahref(-url => "fileViewer.cgi",
"FSPC=$f",
"REV=$toRev{$f}",
$toRev{$f}) ;
} ;
print &P4CGI::table_row(-align => "center",
$fromRev,
$diff,
$toRev,
{-align=>"left",
-text => $file},
{-align=>"left",
-text => $changes},
{-align=>"left",
-text => $users},
) ;
} ;
} ;
print "", &P4CGI::end_table(),"<hr>" ;
}
else {
print
"",
&P4CGI::start_page("View recently changed files","") ;
} ;
print "",
&P4CGI::start_table("bgcolor=".&P4CGI::HDRFTR_BGCOLOR()." align=center cellpadding=0 cellspacing=2"),
"<tr><td>\n" ;
sub prSelection($$$$ )
{
my $cgitarget = shift @_ ;
my $desc = shift @_ ;
my $fields = shift @_ ;
my $helpTarget = shift @_ ;
print "", &P4CGI::table_row(-valign=>"center",
{-align=>"center",
-text =>
join("\n",
&P4CGI::cgi()->startform(-action => $cgitarget,
-method => "GET"),
"<font size=+1>$desc</font>")},
{-align=>"left",
-valign=>"top",
-text => $fields},
{-align=>"left",
-text => " "},
{-align=>"left",
-valign=>"bottom",
-width=>"1",
-text => &P4CGI::cgi()->submit(-name => "SUBMIT",
-value => "GO!")
},
{ -valign=>"bottom",
-text => &P4CGI::cgi()->endform()
},
) ;
} ;
print "", &P4CGI::start_table("width=100% cellspacing=5") ;
my %dayValues = ( 0 => "Zero days",
1 => "One day",
2 => "Two days",
3 => "Three days",
4 => "Four days",
5 => "Five days",
6 => "Six days") ;
my %hourValues = ( 0 => "Zero hours",
1 => "One hour",
2 => "Two hours",
3 => "Three hours",
4 => "Four hours",
5 => "Five hours",
6 => "Six hours",
7 => "Seven hours",
8 => "Eight hours",
9 => "Nine hours") ;
{
my $n = 9 ;
while($n++ < 24) {
$hourValues{$n} = "$n hours" ;
}
}
my %weekValues = ( 0 => "Zero weeks",
1 => "One week",
2 => "Two weeks",
3 => "Three weeks",
4 => "Four weeks",
5 => "Five weeks",
6 => "Six weeks",
7 => "Seven weeks",
8 => "Eight weeks",
9 => "Nine weeks") ;
{
my $n = 9 ;
while($n++ < 24) {
$weekValues{$n} = "$n weeks" ;
}
}
my @dayValues = sort { $a <=> $b } keys %dayValues ;
my @hourValues = sort { $a <=> $b } keys %hourValues ;
my @weekValues = sort { $a <=> $b } keys %weekValues ;
prSelection("filesChangedSince.cgi",
"List recently changed files",
join("\n",(&P4CGI::start_table(),
"<tr>",
"<td align=right valign=center>File spec:</td>",
"<td align=right valign=center></td>",
"<td align=left valign=center><font face=fixed>",
&P4CGI::cgi()->textfield(-name => "FSPC",
-default => $FSPC,
-size => 50,
-maxlength => 256),
"</font></td></tr>",
"<tr>",
"<td align=right valign=center>Changes within the last:</td>",
"<td><input type=radio name=DATESPECIFIER value=picklist CHECKED></td>",
"<td align=left valign=center><font face=fixed>",
&P4CGI::cgi()->popup_menu(-name => "HOURS",
-default => 0,
-values => \@hourValues,
-labels => \%hourValues),
" <br>",
&P4CGI::cgi()->popup_menu(-name => "DAYS",
-default => 1,
-values => \@dayValues,
-labels => \%dayValues),
" <br>",
&P4CGI::cgi()->popup_menu(-name => "WEEKS",
-default => 0,
-values => \@weekValues,
-labels => \%weekValues),
"</font></td></tr>",
"<tr>",
"<td align=right valign=center>Between</td>",
"<td><input type=radio name=DATESPECIFIER value=explicit></td>",
"<td align=left valign=center><font face=fixed>",
&P4CGI::cgi()->textfield(-name => "MINDATE",
-default => "2005/03/27 18:13:00",
-size => 25,
),
"</font></td></tr>",
"<td align=right valign=center>and</td>",
"<td align=right valign=center></td>",
"<td align=left valign=center><font face=fixed>",
&P4CGI::cgi()->textfield(-name => "MAXDATE",
-default => &P4CGI::DateStr2Time("now"),
-size => 25,
),
"</font></td></tr>",
"<tr>",
"</table>")),
"searchPatt") ;
print &P4CGI::end_table() ;
print "</tr></td>",&P4CGI::end_table() ;
print &P4CGI::ahref(-url => "mailto:".join( ',', (sort keys %allUsers)) ,
( "Mail everyone on this page".
" (" . scalar(keys %allUsers) . " people)")
) ;
print &P4CGI::end_page() ;
#
# That's all folks
#

Просмотреть файл

@ -0,0 +1,128 @@
#!/usr/bin/perl -w
# -*- perl -*-
use P4CGI ;
use strict ;
#
#################################################################
# CONFIGURATION INFORMATION
# All config info should be in P4CGI.pm
#
#################################################################
#
# P4 view a group
#
#
#################################################################
$| = 1 ; # turn off output buffering
# Get parameter
my $group = P4CGI::cgi()->param("GROUP") ;
unless(defined $group) {
&P4CGI::bail("No group specified!") ;
} ;
&P4CGI::bail("Invalid group.") if ($group =~ /[<>"&:;'`]/);
# Get real user names...
my %userCvt ;
{
my @users ;
&P4CGI::p4call(\@users, "users" );
%userCvt = map { /^(\S+).*> \((.+)\) .*$/ ; ($1,$2) ; } @users ;
}
my %groups ;
{
my @groups ;
&P4CGI::p4call(\@groups, "groups" );
%groups = map { ($_,1) ; } @groups ;
}
# Get user info
my %values ;
my @fields = &P4CGI::p4readform("group -o $group",\%values);
print "",
&P4CGI::start_page("Group $group",
&P4CGI::ul_list("<b>user</b> -- view user",
&P4CGI::ahref(-url => "changeList.cgi",
"GROUP=$group",
"FSPC=//...",
"List changes by group") .
" -- List changes made by group $group")) ;
unless(exists $groups{$group}) {
&P4CGI::signalError("No such group \"$group\"") ;
}
print
&P4CGI::start_table("") ;
my @emailUsers ;
if(exists $values{"Users"}) {
my @users ;
foreach (split( /\s+/,$values{"Users"})) {
my $fullname ;
if(exists $userCvt{$_}) {
$fullname = "($userCvt{$_})" ;
push @emailUsers,$_ ;
}
else {
$fullname = "(<font color=red>No such user</font>)" ;
} ;
push @users, &P4CGI::ahref(-url => "userView.cgi",
"USER=$_",
"$_ $fullname") ;
} ;
$values{"Users"} = join("<br>\n",@users) ;
} ;
if(exists $values{"Subgroups"}) {
my @subgroups ;
foreach (split( /\s+/,$values{"Subgroups"})) {
my $sg ;
if(exists $groups{$_}) {
push @subgroups, &P4CGI::ahref(-url => "groupView.cgi", #
"GROUP=$_",
$_) ;
}
else {
push @subgroups, "$_ (<font color=red>No such group</font>)" ;
} ;
} ;
$values{"Subgroups"} = join("<br>\n",@subgroups) ;
} ;
my $f ;
foreach $f (@fields) {
print &P4CGI::table_row({-align => "right",
-valign => "top",
-type => "th",
-text => "$f"},
$values{$f}) ;
} ;
print &P4CGI::end_table() ;
if(@emailUsers > 0) {
my @email ;
foreach (@emailUsers) {
my %data ;
&P4CGI::p4readform("user -o $_",\%data) ;
if(exists $data{"Email"}) {
push @email,$data{"Email"} ;
}
}
my $email = join(",",@email) ;
print "<br><a href=\"mailto:$email?Subject=To members in group $group\">Email all group members</a><br>" ;
}
print &P4CGI::end_page() ;
#
# That's all folks
#

Просмотреть файл

@ -0,0 +1,134 @@
#!/usr/bin/perl -w
# -*- perl -*-
use P4CGI ;
use strict ;
#
#################################################################
# CONFIGURATION INFORMATION
# All config info should be in P4CGI.pm
#
#################################################################
#
# P4 "smart" HTML file viewer (maybe too smart....)
# View a HTML file
#
#################################################################
use viewConfig ;
# Get type arg
my $type = P4CGI::cgi()->param("TYPE") ;
&P4CGI::bail("No file type specified") unless defined $type ;
&P4CGI::bail("Invalid file type.") if ($type =~ /[<>"&:;'`]/);
my $err2null = &P4CGI::REDIRECT_ERROR_TO_NULL_DEVICE() ;
if($type ne "ABOUT") {
my $content = "text/html" ;
# Get file spec argument
my $file = P4CGI::cgi()->param("FSPC") ;
&P4CGI::bail("No file specified") unless defined $file ;
&P4CGI::bail("Invalid file spec.") if ($file =~ /[<>"&:;'`]/);
my $revision = P4CGI::cgi()->param("REV") ;
$revision = "#$revision" if defined $revision ;
$revision = "" unless defined $revision ;
&P4CGI::bail("Invalid file spec.") unless ($revision =~ /^#?\d*$/);
my $filename=$file ;
$filename =~ s/^.*\///;
print
"Content-Type: $content\n",
"Content-Disposition: filename=$filename\n",
"\n" ;
my $fileText ;
&P4CGI::p4call(\$fileText, "print -q \"$file$revision\"" );
my @file = split(/(<[^>]+>)/,$fileText) ;
my $l ;
foreach $l (@file) {
if($l =~ /^<(\w+)/) {
my $fld=uc($1) ;
my $prompt ;
$prompt = "href" if $fld eq "A" ;
$prompt = "src" if $fld eq "FRAME" ;
$prompt = "src" if $fld eq "IMG" ;
$prompt = "background" if $fld eq "BODY" ;
unless(defined $prompt) {
print $l ;
next ;
}
if ($l =~ /^(<.*$prompt=\")([^\"]+)(\".*)/i ) { #"
my ($s,$url,$e) = ($1,$2,$3) ;
if ($url =~ m|^\w+://| or
$url =~ m|^/| or
$url =~ m|:\d+$|) {
print $l ;
next ;
} ;
my $ext = "" ;
my $anchor = "" ;
if($url =~ /(.*)\#(.*)/) {
$url = $1 ;
$anchor = "#$2" ;
}
if($url =~ /.*\.(\w+)$/) {
$ext = uc($1) ;
}
my $dir = $file ;
$dir =~ s|[^/]*$|| ;
my $lnfile = &P4CGI::fixspaces("$dir$url") ;
my @log ;
&P4CGI::p4call(\@log, "filelog \"$dir$url\" $err2null" );
if(@log == 0 or $log[1] =~ /delete on/) {
print $l ;
next ;
}
if(exists $viewConfig::ExtensionToType{$ext}) {
my $type = $viewConfig::ExtensionToType{$ext} ;
my ($nurl,$desc,$content,$about) =
@{$viewConfig::TypeData{$type}} ;
$url = "$nurl?FSPC=$lnfile&TYPE=$type$anchor" ;
}
else {
$url = "fileViewer.cgi" . "?FSPC=$lnfile" ;
}
print "$s$url$e" ;
next ;
}
}
print "$l" ;
} ;
}
else {
while(<DATA>) {
print ;
} ;
}
#
# That's all folks
#
__END__
Content-Type: text/html
<HTML><HEAD><TITLE>P4DB: About HTML Viewer</TITLE>
</HEAD>
<BODY BGCOLOR="#e0f0f0" VLINK="#663366" TEXT="#000000" LINK="#000099" ALINK="#993399">
<table bgcolor="#FFFFFF" border=0 cellspacing=8>
<tr>
<th>Note about the HTML viewer</th>
</tr>
<tr>
<td>
The "smart" HTML viewer translate relative links to links to
files in the depot.
</td>
</tr>
</table>
</body>
</html>

Двоичные данные
webtools/tinderbox2/src/bonsai_p4db/icons/back.gif Executable file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 216 B

Просмотреть файл

@ -0,0 +1,275 @@
#!/usr/bin/perl -w
# -*- perl -*-
use P4CGI ;
use strict ;
#
#################################################################
# CONFIGURATION INFORMATION
# All config info should be in P4CGI.pm
#
#################################################################
#
# P4 depot browser, top
#
#################################################################
print "",
&P4CGI::start_page("P4DB<br> P4 Depot Browser",
"<CENTER><SMALL>Hint:".
"You can bookmark any page you want to get back to later</SMALL></CENTER>") ;
# Read and parse shortcut file
my $shortcut_file = &P4CGI::SHORTCUT_FILE() ;
my $SHORTCUTS="" ;
if(defined $shortcut_file and -r $shortcut_file) {
# Read file
local *D ;
open(*D, "<$shortcut_file") or &P4CGI::bail("Failed to open $shortcut_file for read") ;
my $tmps = join("\n",<D>) ;
$tmps =~ s/^#.*$//gm ;
close *D ;
my $shortcut_text = "" ;
# Find all <P4DB [par=data...]>...</P4DB>
while($tmps =~ s/^(.*?)<p4db\s+(.*?)\s*>(.*?)<\/P4DB>//is) {
$shortcut_text .= $1 ;
my $pars = $2 ;
my $text = $3 ;
# Extract arguments for <P4DB>
my %pars ;
while($pars =~ s/(\S+)\s*=\s*(?:"(.*?)"|(\S+))\s*//) {
my $par = $1 ;
my $val ;
if(defined $2) {
$val = $2 ;
}
else {
$val = $3 ;
} ;
$pars{uc($par)} = $val;
} ;
my $type = "" ;
if ( defined $pars{"TYPE"} ) {
$type = uc($pars{"TYPE"});
delete $pars{"TYPE"};
}
my $url ;
if($type eq "CHANGELIST") {
$url = "changeList.cgi" ;
} ;
if($type eq "BROWSE") {
$url = "depotTreeBrowser.cgi" ;
} ;
if($type eq "JOBLIST") {
$url = "jobList.cgi" ;
my %flds ;
&P4CGI::p4readform("jobspec -o",\%flds) ;
my %fldtrans = map { /\s*(\d+) (\S+)/ ; (uc($2),"FLD$1") ;} split("\n",$flds{"Fields"}) ;
my @pars = keys %pars ;
while(@pars) {
my $p = shift @pars ;
if(exists $fldtrans{$p}) {
$pars{$fldtrans{$p}} = $pars{$p} ;
delete $pars{$p} ;
}
}
$pars{"LIST"}="Y" ;
} ;
if(defined $url) {
my @pars = map { "$_=$pars{$_}" ; } keys %pars ;
$shortcut_text .= &P4CGI::ahref(-url=>$url,
@pars,
$text) ;
} ;
}
$shortcut_text .= $tmps;
$SHORTCUTS = join("\n",(&P4CGI::start_table("align=center cellpadding=10 bgcolor=".&P4CGI::HDRFTR_BGCOLOR()),
&P4CGI::table_row($shortcut_text),
&P4CGI::end_table())) ;
} ;
if(&P4CGI::SHORTCUTS_ON_TOP()) {
print "$SHORTCUTS",
} ;
my @MENU = (&P4CGI::ahref(-url => "depotTreeBrowser.cgi",
"Browse Depot"),
&P4CGI::ahref(-url => "changeList.cgi",
"FSPC=//...",
"DATESPECIFIER=browse",
"SHOWFILES=1",
"Submitted Changes"),
&P4CGI::ahref(-url => "changeList.cgi",
"FSPC=//...",
"STATUS=pending",
"Pending Changes"),
&P4CGI::ahref(-url => "fileOpen.cgi",
"Open files"),
&P4CGI::ahref(-url => "branchList.cgi",
"Branches"),
&P4CGI::ahref(-url => "labelList.cgi",
"Labels"),
&P4CGI::ahref(-url => "jobList.cgi",
"Jobs"),
&P4CGI::ahref(-url => "userList.cgi",
"Users and Groups"),
&P4CGI::ahref(-url => "clientList.cgi",
"Clients"),
&P4CGI::ahref(-url => "changeByUsers.cgi",
"Changes by User or Group"),
&P4CGI::ahref(-url => "searchPattern.cgi",
"Search Changes by Descriptions"),
&P4CGI::ahref(-url => "filesChangedSince.cgi",
"List Recently Modified Files"),
&P4CGI::ahref(-url => "depotStats.cgi",
"Depot Statistics")
) ;
if(uc(&P4CGI::USE_JAVA()) eq "YES") {
push @MENU, ("<APPLET CODE=\"p4jdb/P4DirTreeApplet.class\" WIDTH=100 HEIGHT=30>\n".
"<param name=File value=\"javaDataView.cgi\">\n".
"</APPLET>") ;
} ;
my $COLS = 3 ;
print "",
&P4CGI::start_table("width=100% cols=3 cellspacing=0 cellpadding=0") ;
my $colorCnt=0 ;
while(@MENU > 0) {
my $n ;
my @alts ;
for($n = 0;($n < $COLS) and (@MENU > 0);$n++) {
my $t = shift @MENU ;
push @alts, "<font size=+1>$t</font>";
} ;
my $tmp = @alts ;
my @color = (&P4CGI::BGCOLOR(),&P4CGI::HDRFTR_BGCOLOR()) ;
print &P4CGI::table_row(-align => "center",
map {
{-width => "33%",
-bgcolor => $color[$colorCnt++ & 1],
-text => "$_" } ; } @alts) ."\n" ;
} ;
print &P4CGI::end_table() ;
if(!&P4CGI::SHORTCUTS_ON_TOP()) {
print "$SHORTCUTS\n"
} ;
print "",
&P4CGI::start_table("bgcolor=".&P4CGI::HDRFTR_BGCOLOR()." align=center cellpadding=0 cellspacing=2"),
"<tr><td>\n" ;
sub prSelection($$$$ )
{
my $cgitarget = shift @_ ;
my $desc = shift @_ ;
my $fields = shift @_ ;
my $helpTarget = shift @_ ;
print "", &P4CGI::table_row(-valign=>"center",
{-align=>"center",
-text =>
join("\n",
&P4CGI::cgi()->startform(-action => $cgitarget,
-method => "GET"),
"<font size=+1>$desc</font>")},
{-align=>"left",
-text => $fields},
{-align=>"left",
-text => " "},
{-align=>"left",
-valign=>"center",
-width=>"1",
-text => &P4CGI::cgi()->submit(-name => "ignore",
-value => "GO!")
},
{ -text => &P4CGI::cgi()->endform()
}
) ;
} ;
print "", &P4CGI::start_table("width=100% cellspacing=4") ;
my $limiter="<tr><td colspan=5><hr></td></tr>\n" ;
print $limiter ;
prSelection("changeList.cgi",
"List changes for<br>file spec",
join("","File spec:<font face=fixed>",
&P4CGI::cgi()->textfield(-name => "FSPC",
-default => "//...",
-size => 50,
-maxlength => 256),
"</font>"),
"listCh") ;
print $limiter ;
prSelection("fileSearch.cgi",
"Search for file",
join("","File spec:<font face=fixed>",
&P4CGI::cgi()->textfield(-name => "FSPC",
-default => "//...",
-size => 50,
-maxlength => 256),
"</font>"),
"fileSrch") ;
print $limiter ;
prSelection("changeView.cgi",
"View change",
join("","Change number:<font face=fixed>",
&P4CGI::cgi()->textfield(-name => "CH",
-default => "1",
-size => 10,
-maxlength => 10),
"</font>"),
"viewCh") ;
print &P4CGI::end_table() ;
print "</tr></td>",&P4CGI::end_table() ;
print
"<hr>",
&P4CGI::start_table("width=100% cols=3"),
&P4CGI::table_row(-align => "left",
&P4CGI::ahref(-url => &P4CGI::HELPFILE_PATH() . "/README.html",
"Readme file<br>for admin"),
{-align => "center",
-text => &P4CGI::ahref(-url => "SetPreferences.cgi",
"<FONT SIZE=+2>Set Preferences</FONT>"),
},
{ -text => &P4CGI::ahref(-url => "p4race.cgi",
"<font size=-1>The Great<br>Submit Race</font>"),
-align => "right" }),
&P4CGI::end_table() ;
print "<hr>" ;
print
&P4CGI::end_page() ;
#
# That's all folks
#

Просмотреть файл

@ -0,0 +1,60 @@
#!/usr/bin/perl -w
# -*- perl -*-
use P4CGI ;
use strict ;
#
#################################################################
# CONFIGURATION INFORMATION
# All config info should be in P4CGI.pm
#
#################################################################
#
# Java depot browser cgi
#
#################################################################
# * Get path from argument
my $cmd = P4CGI::cgi()->param("CMD") ;
&P4CGI::bail("Invalid command.") unless ($cmd =~ /^\w*$/);
my $err2null = &P4CGI::REDIRECT_ERROR_TO_NULL_DEVICE() ;
local *P4 ;
print
"Content-type: text/plain\n" .
"Pragma: no-cache\n" .
"\n\n" ;
if($cmd eq "DIRSCAN") {
my $fspc = P4CGI::cgi()->param("FSPC") ;
my @dirs ;
&P4CGI::p4call(\@dirs,"dirs -D \"$fspc\" $err2null") ;
foreach (@dirs) {
s/^.*\/// ;
print "D \"$_\"\n" ;
} ;
my @files ;
&P4CGI::p4call(\@files,"files \"$fspc\" $err2null") ;
foreach (@files) {
s/^.*\/(.*)\#(\d+) - (\w\w).*$/"$1" $2 $3/;
print "F $_\n" ;
} ;
}
if($cmd eq "FILES") {
my $dir = P4CGI::cgi()->param("FSPC") ;
&P4CGI::p4call(*P4,"files \"$dir\" $err2null") ;
while(<P4>) {
chomp ;
s/^.*\/(.*)\#(\d+) - (\w\w).*$/"$1" $2 $3/;
print "$_\n" ;
} ;
close *P4 ;
} ;
#
# That's all folks
#

Просмотреть файл

@ -0,0 +1,411 @@
#!/usr/bin/perl -w
# -*- perl -*-
use P4CGI ;
use strict ;
#
#################################################################
# CONFIGURATION INFORMATION
# All config info should be in P4CGI.pm
#
#################################################################
#
# P4 change browser
# View list of jobs
#
#################################################################
#######
# Parameters:
#
# LIST
# If defined, show a list, if not, show select dialogue
#
# JOBVIEW
# If defined, used as jobview
#
# FLDnnn
# These parameters for this script depends on the fileds defined in the
# jobspec. The parameters are named:
# FLDnnn
# Where nnn is the field number as defined in the jobspec
#
# MATCHTYPE
# Used with FLDnnn parameters and defines if all or any should match
#
######
###
### Get and parse jobspec
###
my %jobspec ;
&P4CGI::p4readform("jobspec -o",\%jobspec) ;
#
# Make a 2000.2 jobspec compatible with 2000.1 and earlier
#
if(exists $jobspec{"Values"}) {
foreach (split("\n",$jobspec{"Values"})) {
my ($fld,$value) = split(/\s+/,$_) ;
$jobspec{"Values-$fld"} = $value ;
} ;
}
#
# Get jpbspec fields
#
my %fields ; # Store name, type, len, and options by field number
{
my @tmp = split("\n",$jobspec{"Fields"}) ;
my $s ;
foreach $s (@tmp) {
my ($code,$name,$type,$len,$option) = split(/\s+/,$s) ;
$fields{$code} = [ $name, $type, $len, $option ] ;
}
}
###
### Build a selection forms for job list
###
sub buildSelection() {
## Get list of users (for later use for "user" field)
my @users ;
&P4CGI::p4call(\@users, "users" );
my @listOfUsers = sort { uc($a) cmp uc ($b) } map { /^(\S+).*> \((.+)\) .*$/ ; $1 ; } @users ;
my %userCvt = map { /^(\S+).*> \((.+)\) .*$/ ; ($1,$2) ; } @users ;
my $ulistSize = @listOfUsers ;
$ulistSize= 15 if $ulistSize > 15 ;
my @fieldPrompt ; # Prompt for each field
my @field ; # form entry for each field
my $code ; ## Loop over all fields (sorted by id)
foreach $code (sort keys %fields)
{
my ($name,$type,$len,$option) = @{$fields{$code}} ;
# Handle "Select" type field
if($type eq "select") {
my @set = split("/",$jobspec{"Values-$name"}) ;
my $size = scalar @set ;
if($size > 5) { $size = 5 } ;
push @field, &P4CGI::cgi()->scrolling_list(-name => "FLD".$code,
-values => \@set,
-size => $size,
-multiple => 'true') ;
push @fieldPrompt,"$name is one of" ;
next ;
}
# Date type field
if($type eq "date") {
my %values = (
1 => " One Day old",
2 => " Two Days old",
3 => "Three Days old",
4 => " Four Days old",
5 => " Five Days old",
6 => " Six Days old",
7 => " One Week old",
7*2 => " Two Weeks old",
7*2 => "Three Weeks old",
7*4 => " Four Weeks old",
7*5 => " Five Weeks old",
7*6 => " Six Weeks old",
7*7 => "Seven Weeks old",
7*8 => "Eight Weeks old",
7*9 => " Nine Weeks old",
7*10 => " 10 Weeks old",
7*11 => " 11 Weeks old",
7*12 => " 12 Weeks old",
7*16 => " 16 Weeks old",
7*20 => " 20 Weeks old",
7*26 => " 26 Weeks old",
7*40 => " 40 Weeks old",
7*52 => " 52 Weeks old") ;
my @values = sort { $a <=> $b } keys %values ;
push @field, join("\n",
(&P4CGI::cgi()->popup_menu(-name => "FLD".$code."cmp",
-default => 0,
-values => ["-",">",">=","<=","<"] ,
-labels => { "-"=>"- Ignore -",
">"=>"Less than",
">="=>"Less than or exactly",
"<="=>"More than or exactly",
"<"=>"More than" }),
&P4CGI::cgi()->popup_menu(-name => "FLD".$code,
-default => 0,
-values => \@values,
-labels => \%values))
) ;
push @fieldPrompt,"$name is" ;
next ;
}
# Type must be word, line or text. Compute some lengths for
# text field
$len = 256 if $len == 0 ;
my $displen = $len ;
$displen = 40 if $displen > 40 ;
my $textfield = &P4CGI::cgi()->textfield(-name => "FLD".$code,
-size => $displen,
-maxlength => $len) ;
# Field type word
if($type eq "word") {
if($code == 101) {
# Reserved field Job
push @fieldPrompt,"Job name is" ;
push @field, $textfield ;
next ;
}
else {
if($code == 103) {
# Rserved field User
push @fieldPrompt,"User is one of" ;
push @field, &P4CGI::cgi()->scrolling_list(-name => "FLD$code",
-values => \@listOfUsers,
-size => $ulistSize,
-multiple => 'true',
-labels => \%userCvt) ;
next ;
}
push @fieldPrompt,"$name is" ;
push @field, $textfield ;
next ;
}
}
# Field type line or text
if($type eq "line" or $type eq "text") {
push @fieldPrompt,"$name contains one of the words" ;
push @field, $textfield ;
next ;
}
} # end loop over fields
# Add field for match for "any" or "all" fields
push @fieldPrompt,"Select type of match" ;
push @field, &P4CGI::cgi()->popup_menu(-name => "MATCHTYPE",
-default => 0,
-values => ["all","any"] ,
-labels => { "all"=>"Match all fields above",
"any" =>"Match any field above"}) ; #
# Create table contents from fields
my @tmp ;
while(@field > 0) {
my $pr = shift @fieldPrompt ;
my $fld = shift @field ;
push @tmp,("<tr>",
"<td align=right valign=center>",$pr,":</td>",
"<td align=left valign=center><font face=fixed>",
$fld,
"</font></td></tr>") ;
} ;
# Return table and form
return
join("\n",
(&P4CGI::start_table("bgcolor=".&P4CGI::HDRFTR_BGCOLOR().
" align=center cellpadding=0 cellspacing=2"),
"<tr><td>\n",
&P4CGI::start_table("width=100% cellspacing=4"),
&P4CGI::table_row(-valign=>"center",
{-align=>"center",
-text =>
join("\n",
&P4CGI::cgi()->startform(-action => "jobList.cgi",
-method => "GET"),
"<font size=+1>Select jobs</font>")},
{-align=>"left",
-valign=>"top",
-text => join("\n",(&P4CGI::start_table(),
@tmp,
"</table>"))},
{-align=>"left",
-text => " "},
{-align=>"left",
-valign=>"bottom",
-width=>"1",
-text => &P4CGI::cgi()->submit(-name => "LIST",
-value => "List Jobs")
},
{ -valign=>"bottom",
-text => &P4CGI::cgi()->endform()
},
),
&P4CGI::end_table(),
"</tr></td>",
&P4CGI::end_table())) ;
} # end buildSelection()
unless(defined &P4CGI::cgi()->param("LIST"))
{
my $selection = &buildSelection() ;
my @legend ;
push @legend,&P4CGI::ahref("LIST=Y",
"MATCHTYPE=",
"List all jobs") ;
if(exists $fields{"102"}) { # Check that we have a status field (code 102)
my $name = $ { $fields{"102"}}[0] ;
if(exists $jobspec{"Values-$name"}) { # Check that we have the values
my @values = split('/',$jobspec{"Values-$name"}) ;
my $v ;
foreach $v (@values) {
push @legend,&P4CGI::ahref("FLD102=$v",
"LIST=Y",
"MATCHTYPE=",
"List jobs with $name=$v") ;
}
}
}
print
"",
&P4CGI::start_page("View job list",&P4CGI::ul_list(@legend)),
$selection ;
}
else {
# Do we have "JOBVIEW"?
my $jobview = &P4CGI::cgi()->param("JOBVIEW") ;
$jobview = "Yes" if defined $jobview;
my $jobviewDesc ;
if(defined $jobview) {
$jobviewDesc = "Where jobview is: <TT>$jobview</TT>" ;
}
# If not, build a job view
if(! defined $jobview) {
$jobview = "" ;
$jobviewDesc="" ;
# Get field parameters
my @selectParams = grep { /^FLD/ ; } P4CGI::cgi()->param ;
my %params ;
foreach (@selectParams) {
&P4CGI::bail("Invalid field parameter.") if (/[<>"&:;'`]/);
my $v = $_ ;
s/^FLD// ;
my @pars = &P4CGI::cgi()->param($v) ;
$params{$_} = \@pars ;
}
# Set match all/any
my $MATCHTYPE = &P4CGI::cgi()->param("MATCHTYPE") ;
$MATCHTYPE="all" unless defined $MATCHTYPE and $MATCHTYPE eq "any";
my $matchtype = "|" ;
my $matchtypeDesc = "or" ;
if($MATCHTYPE eq "all") {
$matchtype = "" ;
$matchtypeDesc = "and" ;
} ;
# Loop over field parameters
my $id ;
foreach $id (grep {/^\d+$/} keys %params) {
my $desc ;
next unless exists $fields{$id} ;
my ($name,$type,$len,$option) = @{$fields{$id}} ;
my @p = @{ $params{$id}} ;
if($type eq "text" or
$type eq "line") {
my @tmp = map { split ; } @p ;
@p = @tmp ;
} ;
if(@p > 0 and length($p[0]) > 0) {
my $thisItem ;
if($type eq "date") {
my @cmp = @{ $params{"${id}cmp"}} ;
my $cmp = shift @cmp ;
next if $cmp eq "-" ;
my $time = time()-(24*3600*$p[0]) ;
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($time);
$year = 1900+$year ;
$thisItem = sprintf("$name$cmp$year/%02.2d/%02.2d",$mon+1,$mday) ;
$desc .= "$thisItem" ;
}
else {
if(@p == 1) {
$thisItem = "$name=$p[0]" ;
$desc .= "$name is \"$p[0]\"" if $type eq "select" ;
$desc .= "$name contains \"$p[0]\""
if $type =~ /^(word|line|text)/ ;
}
else {
$thisItem = "($name=" . join("|$name=",@p) . ")" ;
$desc .= "$name is" if $type eq "select" ;
$desc .= "$name contains" if $type =~ /^(word|line|text)/ ;
$desc .= " one of" if @p > 2 ;
my $last = pop @p ;
$desc .= " \"". join('","',@p) . "\" or \"$last\"" ;
}
}
if(length($jobview) > 0) {
$jobview .= " $matchtype $thisItem" ;
$jobviewDesc .= "<br><font>$matchtypeDesc</font><br>\n$desc" ;
}
else {
$jobview = "$thisItem" ;
$jobviewDesc = $desc ;
}
}
} ;
} ;
&P4CGI::cgi()->delete("LIST") ;
my $legend = &P4CGI::ul_list("<b>Job name</b> -- see details of job",
"<b>User</b> -- Information about user",
&P4CGI::ahref("-url" => &P4CGI::cgi()->self_url(),
"New selection")) ;
print "", &P4CGI::start_page("View job list<br>$jobviewDesc",$legend) ;
&P4CGI::ERRLOG("jobView:\"$jobview\"") ;
my @tmp ;
$jobview = "-e \"$jobview\"" if length($jobview) > 0 ;
&P4CGI::p4call(\@tmp, "jobs -l $jobview" );
if(@tmp == 0) {
print
"<font color=red size=+1>No matching jobs found for:<br><tt>jobs -l $jobview</tt></font><hr>",
&buildSelection() ;
}
else {
print "<dl>\n" ;
while (@tmp > 0) {
my $l = shift @tmp ;
$l =~ /^(\S+) (on \S+ by) (\S+) (.*)/ and do {
my ($job,$date,$user,$status) = ($1,$2,$3,$4) ;
$status =~ s/\*(\S+)\*/Status: <tt>$1<\/tt>/ ;
my $SPACESTR = " " ;
my $xsp = "" ;
if(length($job) < length($SPACESTR)) {
$xsp = "<tt>" . substr($SPACESTR,length($job)) . "</tt>" ;
$xsp =~ s/ /&nbsp;/g ;
} ;
print
"<dt>",
&P4CGI::ahref("-url" => "jobView.cgi",
"JOB=$job",
"<tt>$job</tt>"),
"$xsp $date ",
&P4CGI::ahref("-url" => "userView.cgi",
"USER=$user",
$user),
" $status\n" ;
shift @tmp ;
print "<dd><pre>" ;
while(@tmp > 0) {
my $desc = shift @tmp ;
$desc =~ s/^\s+// ;
last if length($desc) == 0 ;
print "$desc\n" ;
}
print "</pre>" ;
}
}
print "</dl>\n" ;
print "<pre> ",join("\n ",@tmp),"</pre>" ;
}
} ;
print &P4CGI::end_page() ;
#
# That's all folks
#

Просмотреть файл

@ -0,0 +1,96 @@
#!/usr/bin/perl -w
# -*- perl -*-
use P4CGI ;
use strict ;
#
#################################################################
# CONFIGURATION INFORMATION
# All config info should be in the config file
#
#################################################################
#
# P4 view job
# View a job
#
#################################################################
# Get file spec argument
my $job = P4CGI::cgi()->param("JOB") ;
&P4CGI::bail("No job specified") unless defined $job ;
&P4CGI::bail("Invalid job.") if ($job =~ /[<>"&:;'`]/);
# Create title
print "", &P4CGI::start_page("Job $job","") ;
my @fields ;
my %fieldData ;
@fields = &P4CGI::p4readform("job -o $job",\%fieldData);
# Check that job exist
if($fieldData{"Description"} =~ /<enter description here>/) {
&P4CGI::signalError("Job $job does not exist") ;
}
# Fix user field
if(exists $fieldData{"User"}) {
$fieldData{"User"} = &P4CGI::ahref(-url => "userView.cgi",
"USER=$fieldData{User}",
$fieldData{"User"}) ;
}
# Fix description field
if(exists $fieldData{"Description"}) {
my $d = &P4CGI::fixSpecChar($fieldData{"Description"}) ;
$d =~ s/\n/<br>/g ;
$fieldData{"Description"} = "<tt>$d</tt>" ;
}
my @fixes ;
&P4CGI::p4call(\@fixes,"fixes -j $job") ;
if(@fixes > 0) {
push @fields,"Fixed by" ;
$fieldData{"Fixed by"} = join("<br>\n",
map {/change (\d+) on (\S+) by (\S+)\@(\S+)/ ;
my ($ch,$date,$user,$client) = ($1,$2,$3,$4) ;
$ch = &P4CGI::ahref(-url => "changeView.cgi",
"CH=$ch",
$ch) ;
$user = &P4CGI::ahref(-url => "userView.cgi",
"USER=$user",
$user) ;
$client = &P4CGI::ahref(-url => "clientView.cgi",
"CLIENT=$client",
$client) ;
"Change $ch on $date by $user\@$client" ; } @fixes ) ;
}
print
"",
&P4CGI::start_table("") ;
my $f ;
foreach $f (@fields) {
print &P4CGI::table_row({-align => "right",
-valign => "top",
-type => "th",
-text => $f},
$fieldData{$f}) ;
} ;
print &P4CGI::end_table("") ;
print &P4CGI::end_page();
#
# That's all folks
#

Просмотреть файл

@ -0,0 +1,296 @@
#!/usr/bin/perl -w
# -*- perl -*-
use P4CGI ;
use strict ;
#
#################################################################
# CONFIGURATION INFORMATION
# All config info should be in P4CGI.pm
#
#################################################################
#
# P4 label diff viewer
# View diff between two labels
#
#################################################################
# Get arguments
# Labels to diff
my $LABEL1 = P4CGI::cgi()->param("LABEL1") ;
my $LABEL2 = P4CGI::cgi()->param("LABEL2") ;
&P4CGI::error("No first label specified") unless defined $LABEL1 ;
&P4CGI::error("No second label specified") unless defined $LABEL2 ;
&P4CGI::bail("Invalid first label.") if ($LABEL1 =~ /[<>"&:;'`]/);
&P4CGI::bail("Invalid second label.") if ($LABEL2 =~ /[<>"&:;'`]/);
# defined if files that are the same in both labels
# should be listed
my $SHOWSAME = P4CGI::cgi()->param("SHOWSAME") ;
if(defined $SHOWSAME) { undef $SHOWSAME if $SHOWSAME ne "Y" ; } ;
# defined if files that are not the same in botha labels
# should be listed
my $SHOWNOTSAME = P4CGI::cgi()->param("SHOWNOTSAME") ;
if(defined $SHOWNOTSAME) { undef $SHOWNOTSAME if $SHOWNOTSAME ne "Y" ; } ;
# defined if files that exists only in one of the labels
# shold be displayed
my $SHOWDIFF = P4CGI::cgi()->param("SHOWDIFF") ;
if(defined $SHOWDIFF) { undef $SHOWDIFF if $SHOWDIFF ne "Y" ; } ;
sub compareFiles($$) {
my ($a,$b) = @_ ;
if(!defined $a) {
return 1 ; # In this context an undef value is higher than any other
}
if(!defined $b) {
return -1 ;
}
if(&P4CGI::IGNORE_CASE() eq "Yes") {
return uc($a) cmp uc($b) ;
}
else {
return $a cmp $b ;
} ;
}
#
# Start page
#
print
"",
&P4CGI::start_page("Diff between label<br> $LABEL1 and $LABEL2","") ;
#
# Get basic data for labels
#
my %label1Data ;
&P4CGI::p4readform("label -o $LABEL1",\%label1Data) ;
my %label2Data ;
my @fields = &P4CGI::p4readform("label -o $LABEL2",\%label2Data) ;
# Fix View field
{
$label1Data{"View"} = "<tt>$label1Data{View}</tt>" ;
$label2Data{"View"} = "<tt>$label2Data{View}</tt>" ;
}
#
# Print basic label data
#
print "", # Start table
&P4CGI::start_table(""),
&P4CGI::table_row(-type => "th",
"",
$LABEL1,
$LABEL2) ;
my $f ;
shift @fields ; # remove "Label" from fields (redundant)
# print label information
foreach $f (@fields) {
my $f1 = $label1Data{$f} ;
my $f2 = $label2Data{$f} ;
if($f1 eq $f2) {
$f1 = undef ;
}
else {
$f1 = {-align => "center",
-bgcolor=>&P4CGI::HDRFTR_BGCOLOR(),
-text =>$f1} ;
}
$f2 = {-align => "center",
-bgcolor=>&P4CGI::HDRFTR_BGCOLOR(),
-text =>$f2} ;
print "",&P4CGI::table_row({-align => "right",
-text => "<b>$f</b>"},
$f1,
$f2) ;
} ;
print "",
&P4CGI::end_table(),
"<hr>";
#
# Get files for labels
#
# Get files
my (@filesLabel1,@filesLabel2);
&P4CGI::p4call(\@filesLabel1, "files \"\@$LABEL1\"" );
&P4CGI::p4call(\@filesLabel2, "files \"\@$LABEL2\"" );
# Remove revision info and create file-to-rev maps
my (%fileRevLabel1,%fileRevLabel2) ;
map { s/\#(\d+).*// ; $fileRevLabel1{$_} = $1 } @filesLabel1 ;
map { s/\#(\d+).*// ; $fileRevLabel2{$_} = $1 } @filesLabel2 ;
# Sort files
{
my @tmp = @filesLabel1 ;
@filesLabel1 = sort { compareFiles($a,$b) ; } @tmp ;
@tmp = @filesLabel2 ;
@filesLabel2 = sort { compareFiles($a,$b) ; } @tmp ;
}
# Get some statistics
my $commonFound=0 ;
my $commonAndSameRev=0 ;
{
my $f ;
foreach $f (@filesLabel1) {
if(exists $fileRevLabel2{$f}) {
$commonFound++ ;
$commonAndSameRev++ if $fileRevLabel2{$f} == $fileRevLabel1{$f} ;
}
}
}
my ($nfiles1,$nfiles2) ;
$nfiles1 = @filesLabel1 ;
$nfiles2 = @filesLabel2 ;
my $fileslisted = "Yes" ;
print "",
&P4CGI::start_table("COLSPACING=0 CELLPADDING=0"),
&P4CGI::table_row({-type=>"th",
-align=>"right",
-text=>"$LABEL1:"}
,"$nfiles1 files"),
&P4CGI::table_row({-type=>"th",
-align=>"right",
-text=>"$LABEL2:"}
,"$nfiles2 files"),
&P4CGI::table_row("","$commonFound common files") ;
if($commonAndSameRev > 0) {
print "",&P4CGI::table_row("","$commonAndSameRev with same revision") ;
}
print "",
&P4CGI::end_table() ;
if($commonFound == 0) {
print
"<FONT SIZE=+2 COLOR=red>",
"The two labels has no files in common, comparsion aborted.</FONT>" ;
}
else {
if(defined $SHOWSAME and defined $SHOWNOTSAME and defined $SHOWDIFF) {
print "<B>Files:</B><br>\n" ;
}
elsif(!defined $SHOWSAME and !defined $SHOWNOTSAME and !defined $SHOWDIFF) {
print "No files listed!<br>\n" ;
$fileslisted = undef ;
}
else {
print "<B>Listed files are:<BR>\n" ;
defined $SHOWSAME and do {
print "<LI> Files not modified\n" ; } ;
defined $SHOWNOTSAME and do {
print "<LI> Modified files (different rev.)\n" ; } ;
defined $SHOWDIFF and do {
print "<LI> Files only in one of the labels $LABEL1 and $LABEL2\n" ; } ;
print "</B>\n" ;
} ;
#
# Start print list of files
#
if(defined $fileslisted) {
print
"",
&P4CGI::start_table("border "),
&P4CGI::table_row("-type","th",
"File",undef,"$LABEL1<br>Rev.",undef,"$LABEL2<br>Rev.") ;
my ($name1,$name2) ;
while(@filesLabel1 > 0 or @filesLabel2 > 0) {
$name1 = shift @filesLabel1 unless defined $name1 ;
$name2 = shift @filesLabel2 unless defined $name2 ;
my $rev1 = $fileRevLabel1{$name1} if defined $name1 ;
my $rev2 = $fileRevLabel2{$name2} if defined $name2 ;
my $cmp = compareFiles($name1,$name2) ;
if($cmp == 0) {
if($rev1 == $rev2 and defined $SHOWSAME) {
print &P4CGI::table_row(&P4CGI::ahref("-url",
"fileLogView.cgi",
"FSPC=$name1",
"$name1"),
undef,undef,undef,
{-text=>"$rev1",
-align=>"center"}) ;
}
if($rev1 != $rev2 and defined $SHOWNOTSAME) {
print &P4CGI::table_row(&P4CGI::ahref("-url","fileLogView.cgi",
"FSPC=$name1",
"$name1"),
{-text=>"$rev1",
-align=>"center"},
undef,
{-text=>&P4CGI::ahref("-url","fileDiffView.cgi",
"FSPC=$name1",
"REV=$rev1",
"REV2=$rev2",
"ACT=edit",
"<small>diff</small>"),
-align=>"center"},
{-text=>"$rev2",
-align=>"center"}) ;
}
$name1 = undef ;
$name2 = undef ;
next ;
}
if($cmp < 0) {
if(defined $SHOWDIFF) {
print &P4CGI::table_row(&P4CGI::ahref(-url => "fileLogView.cgi",
"FSPC=$name1",
"$name1"),
undef,
{-text => "$rev1",
-align => "center"},
undef,
{-text => "<small>not in label</small>",
-align => "center",
-bgcolor => "red"}) ;
}
$name1=undef ;
next ;
}
else {
if(defined $SHOWDIFF) {
print &P4CGI::table_row(&P4CGI::ahref("-url","fileLogView.cgi",
"FSPC=$name2",
"$name2"),
undef,
{-text => "<small>not in label</small>",
-align => "center",
-bgcolor => "red"},
undef,
{-text => "$rev2",
-align => "center"}) ;
}
$name2=undef ;
next ;
}
}
print
"",
&P4CGI::end_table() ;
}
}
print &P4CGI::end_page() ;
#
# That's all folks
#

Просмотреть файл

@ -0,0 +1,82 @@
#!/usr/bin/perl -w
# -*- perl -*-
use P4CGI ;
use strict ;
#
#################################################################
# CONFIGURATION INFORMATION
# All config info should be in P4CGI.pm
#
#################################################################
#
# List all labels
#
#################################################################
##
#
# Parameters:
#
# SORTBY defines sort order
# One of "NAME" and "DATE"
#
#
my $SORTBY = &P4CGI::cgi()->param("SORTBY") ;
$SORTBY = "NAME" unless defined $SORTBY and $SORTBY eq "DATE" ;
# Get list of all label
my @labels ;
&P4CGI::p4call(\@labels, "labels" );
map { /^Label (\S+)\s+(\S+)\s+'(.*)'/ ; $_ = [$1,$2,$3] ; } @labels ;
# Print header
my @legend = ("<b>label</b> -- view label info") ;
my @lab ;
if($SORTBY eq "DATE") {
@lab = sort { my @b = @$a ;
my @a = @$b ;
$a[1] cmp $b[1] ; } @labels ;
push @legend,&P4CGI::ahref(-url => "labelList.cgi",
"SORTBY=NAME",
"Sort list by name") ;
}
else {
@lab = sort { my @a = @$a ;
my @b = @$b ;
uc($a[0]) cmp uc($b[0]) ; } @labels ;
push @legend,&P4CGI::ahref(-url => "labelList.cgi",
"SORTBY=DATE",
"Sort list by date") ;
}
print "",
&P4CGI::start_page("List of labels",
&P4CGI::ul_list(@legend)) ;
print "",
scalar @labels," labels",
&P4CGI::start_table(""),
&P4CGI::table_header("Label/label info","Date","Desc.") ;
foreach (@lab) {
my ($name,$date,$desc) = @{$_} ;
my $lab =
print &P4CGI::table_row(-valign => "top",
&P4CGI::ahref(-url => "labelView.cgi",
"LABEL=$name",
$name),
$date,
$desc) ;
}
print
&P4CGI::end_table(),
&P4CGI::end_page() ;
#
# That's all folks
#

Просмотреть файл

@ -0,0 +1,212 @@
#!/usr/bin/perl -w
# -*- perl -*-
use P4CGI ;
use strict ;
#
#################################################################
# CONFIGURATION INFORMATION
# All config info should be in P4CGI.pm
#
#################################################################
#
# View labels
#
#################################################################
# Get label
my $label = P4CGI::cgi()->param("LABEL") ;
&P4CGI::bail("No label specified") unless defined $label ;
&P4CGI::bail("Invalid label.") if ($label =~ /[<>"&:;'`]/);
my $found ;
# Get list of all labels and also check that supplied label exists
my @labels ;
&P4CGI::p4call(\@labels, "labels" );
foreach (@labels) {
$_ =~ s/^Label (\S+).*$/$1/ ;
if($_ eq $label) {
$found = "Yes" ;
} ;
}
# Print header
print "",
&P4CGI::start_page("Label $label",
&P4CGI::ul_list("<b>owner</b> -- view user info",
"<b>view</b> -- View changes for view")) ;
&P4CGI::signalError("Label $label not in depot") unless $found ;
my @otherLabels ;
foreach (@labels) {
next if ($_ eq $label) ;
push @otherLabels,$_ ;
} ;
###
### "Sort" otherlabels after "closeness"
###
{
my $lab=uc($label) ;
my $len = length($lab) ;
my @labs ;
while($len > 3) {
my @tmp ;
my $l ;
$len-- ;
$lab = substr($lab,0,$len) ;
foreach $l (@otherLabels) {
if(uc(substr($l,0,$len)) eq $lab) {
push @labs,$l ;
}
else {
push @tmp,$l ;
}
}
@otherLabels = @tmp ;
} ;
@otherLabels = (@labs,@otherLabels) ;
}
# Get label info
print
"",
&P4CGI::start_table("") ;
my %values ;
my @fields = &P4CGI::p4readform("label -o \"$label\"",\%values) ;
# Fix description field
if(exists $values{"Description"}) {
my $d = $values{"Description"} ;
$values{"Description"} = "<pre>$d</pre>" ;
}
# Fix owner field
if (exists $values{"Owner"}) {
# Get real user names...
my %userCvt ;
{
my @users ;
&P4CGI::p4call(\@users, "users" );
%userCvt = map { /^(\S+).*> \((.+)\) .*$/ ; ($1,$2) ; } @users ;
}
my $u = $values{"Owner"} ;
if(exists $userCvt{$u}) {
$values{"Owner"} = &P4CGI::ahref(-url=>"userView.cgi",
"USER=$u",
"$u") . " (" . $userCvt{$u} . ")" ;
}
else {
$values{"Owner"} = "$u (Unknown user)" ;
}
}
# Fix view field
my $viewFSPC = $values{"View"} ;
my $view ;
foreach (split("\n",$values{"View"})) {
my $t = &P4CGI::ahref(-url => "depotTreeBrowser.cgi",
"FSPC=$_",
"<tt>$_</tt>") ;
if (defined $view) {
$view .= "<br>$t" ;
}
else {
$view .= "$t" ;
} ;
} ;
$values{"View"} = $view ;
print &P4CGI::start_table("") ;
my $f ;
foreach $f (@fields) {
print &P4CGI::table_row({-align => "right",
-valign => "top",
-type => "th",
-text => "$f"},
$values{$f}) ;
} ;
$viewFSPC =~ s/\n//ig ;
print
&P4CGI::table_row(undef,
&P4CGI::ul_list(&P4CGI::ahref(-url => "changeList.cgi",
"FSPC=$viewFSPC",
"EXLABEL=$label",
"List changes in label view not included in label"),
&P4CGI::ahref(-url => "changeList.cgi",
"LABEL=$label",
"View changes for label $label"),
&P4CGI::ahref(-url => "fileSearch.cgi",
"LABEL=$label",
"List files in label $label"))) ;
print &P4CGI::end_table() ;
print
"<hr>",
&P4CGI::cgi()->startform(-action => "labelDiffView.cgi" ,
-method => "GET"),
&P4CGI::cgi()->hidden(-name=>"LABEL1",
-value=>"$label"),
"Diff with label: ",
&P4CGI::cgi()->popup_menu(-name => "LABEL2",
-value => \@otherLabels),
"<br>Show files that: ",
&P4CGI::cgi()->checkbox(-name => "SHOWSAME",
-value => "Y",
-label => " are not modified"),
&P4CGI::cgi()->checkbox(-name => "SHOWNOTSAME",
-checked => "Y",
-value => "Y",
-label => " are modified"),
&P4CGI::cgi()->checkbox(-name => "SHOWDIFF",
-checked => "Y",
-value => "Y",
-label => " differ"),
&P4CGI::cgi()->submit(-name => "Go",
-value => "Go"),
&P4CGI::cgi()->endform() ;
print
"<hr>",
&P4CGI::cgi()->startform(-action => "changeList.cgi",
-method => "GET"),
&P4CGI::cgi()->hidden(-name=>"LABEL",
-value=>"$label"),
"View changes for label $label excluding label: ",
&P4CGI::cgi()->popup_menu(-name => "EXLABEL",
-value => \@otherLabels),
&P4CGI::cgi()->submit(-name => "Go",
-value => "Go"),
&P4CGI::cgi()->endform() ;
print
"<hr>",
&P4CGI::cgi()->startform(-action => "fileSearch.cgi",
-method => "GET"),
&P4CGI::cgi()->hidden(-name=>"LABEL",
-value=>"$label"),
&P4CGI::cgi()->submit(-name => "ignore",
-value => "Search in label for:"),
&P4CGI::cgi()->textfield(-name => "FSPC",
-default => "//...",
-size => 50,
-maxlength => 256),
&P4CGI::cgi()->endform() ;
print
"",
&P4CGI::end_page() ;
#
# That's all folks
#

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Двоичные данные
webtools/tinderbox2/src/bonsai_p4db/p4jdb/P4DirTree$1.class Executable file

Двоичный файл не отображается.

Двоичные данные
webtools/tinderbox2/src/bonsai_p4db/p4jdb/P4DirTree$2.class Executable file

Двоичный файл не отображается.

Двоичные данные
webtools/tinderbox2/src/bonsai_p4db/p4jdb/P4DirTree$3.class Executable file

Двоичный файл не отображается.

Двоичные данные
webtools/tinderbox2/src/bonsai_p4db/p4jdb/P4DirTree$Manager.class Executable file

Двоичный файл не отображается.

Двоичные данные
webtools/tinderbox2/src/bonsai_p4db/p4jdb/P4DirTree.class Executable file

Двоичный файл не отображается.

Просмотреть файл

@ -0,0 +1,262 @@
package p4jdb ;
import p4jdb.* ;
import java.applet.* ;
import java.net.* ;
import java.lang.System ;
import java.io.* ;
import java.lang.Throwable ;
import java.awt.* ;
import java.awt.event.* ;
import java.util.* ;
/**
* Displays a p4 depot graphically
*
*/
public class P4DirTree
{
/**
* Frame used to display data.
*/
public Frame frame_ ;
/**
* Parent Applet
*/
static public Applet applet ;
/**
* True if deleted files should be viewed
*/
static public boolean showDeleted = true ;
/**
* True if files should be viewed
*/
static public boolean showFiles = true ;
/**
* DataManager object required by TreeDisplay class
*/
private class Manager implements TreeDisplay.DataManager {
private Vector visible_ = new Vector();
private int lineHeight_ ;
/**
* Base object for tree (gotta be a folder)
*/
public P4Folder base_ ;
/**
* Constructor
*@param height Line height
*/
public Manager(int height) {
lineHeight_ = height ;
base_ = new P4Folder("",
"",
0) ;
}
/**
*@return Number of lines (items) to display
*/
public int getLines() {
if( visible_.size() == 0) {
updateVisible() ;
}
return visible_.size() ;
} ;
/**
* Get Data object by offset
*@param offset Offset of object to return
*@return Item at specified offset
*@throws IndexOutOfBoundsException if offset out of bounds
*/
public TreeDisplay.Data getItemAt(int offset)
throws java.lang.IndexOutOfBoundsException {
if( visible_.size() == 0) {
updateVisible() ;
}
return ((TreeDisplay.Data) visible_.elementAt(offset)) ;
}
/**
* Get line height
*@return line height in pixels
*/
public int getLineHeight() {
return lineHeight_ ;
} ;
/**
* Get indent value
*@return number of pixels to indent for each level
*/
public int indentValue() {
return lineHeight_ ;
}
/**
* Get background color
*@return background color
*/
public Color getBackground() { return Color.white ; } ;
public void prePaint()
{
markVisibleModified() ;
} ;
/**
* Update visible vector
*/
private void updateVisible() {
if( visible_.size() > 0) {
visible_.removeAllElements() ;
} ;
base_.addToVector(visible_) ;
} ;
/**
* Mark visible vector for update
*/
public void markVisibleModified() {
visible_.removeAllElements() ;
} ;
/**
* Refresh base from stream
*/
public void refresh() {
base_ = null ;
base_ = new P4Folder("",
"/",
0) ;
markVisibleModified() ;
} ;
} ;
Manager theManager_ ;
public TreeDisplay theTreeDisplay ;
/**
* Constructor
*@Param app Parent applet object
*/
public P4DirTree(Applet app) {
applet = app ;
initData() ;
} ;
/**
* Initialize data (from url)
*/
public void initData() {
theManager_ = new Manager(15) ;
}
/**
* Start to display (if initiated)
*/
public void start() {
// If frame already created, move it to top
if(frame_ != null) {
frame_.setVisible(true) ;
return ;
}
// Create frame
try {
frame_ = new Frame("P4DB Depot Directory Browser") ;
frame_.setSize(300,400) ;
frame_.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
frame_.dispose() ;
frame_ = null ;
} ;
}) ;
theTreeDisplay = new TreeDisplay(theManager_) ;
// Build "File" menu
Menu file = new Menu("File") ;
final String EXIT=("Exit") ;
file.add(EXIT) ;
file.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
if(ae.getActionCommand() == EXIT) {
frame_.dispose() ;
frame_ = null ;
}
}
}) ;
Menu view = new Menu("View") ;
final String COLLAPSE="Collapse all" ;
view.add(COLLAPSE) ;
final String SHOWDEL="Show deleted" ;
final String HIDEDEL="Hide deleted" ;
final MenuItem showHidedel = new MenuItem(HIDEDEL) ;
view.add(showHidedel) ;
final String REFRESH = "Refresh data from depot" ;
view.add(REFRESH) ;
view.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
// System.err.println(ae) ;
if(ae.getActionCommand() == COLLAPSE) {
frame_.setCursor(new Cursor(Cursor.WAIT_CURSOR));
theManager_.base_.setOpen(false) ;
theManager_.updateVisible() ;
theTreeDisplay.paint(theTreeDisplay.getGraphics()) ;
frame_.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
}
else if(ae.getActionCommand() == SHOWDEL) {
frame_.setCursor(new Cursor(Cursor.WAIT_CURSOR));
showDeleted = true ;
showHidedel.setLabel(HIDEDEL);
theManager_.updateVisible() ;
theTreeDisplay.paint(theTreeDisplay.getGraphics()) ;
frame_.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
}
else if(ae.getActionCommand() == HIDEDEL) {
frame_.setCursor(new Cursor(Cursor.WAIT_CURSOR));
showDeleted = false ;
showHidedel.setLabel(SHOWDEL);
theManager_.updateVisible() ;
theTreeDisplay.paint(theTreeDisplay.getGraphics()) ;
frame_.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
}
else if(ae.getActionCommand() == REFRESH) {
frame_.setCursor(new Cursor(Cursor.WAIT_CURSOR));
initData() ;
theTreeDisplay.setManager(theManager_) ;
frame_.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
}
}
}) ;
MenuBar mbar = new MenuBar() ;
mbar.add(file) ;
mbar.add(view) ;
frame_.setMenuBar(mbar) ;
frame_.add(theTreeDisplay,"Center") ;
frame_.setVisible(true) ;
frame_.paint(frame_.getGraphics()) ;
}
catch (IllegalArgumentException e) {
System.err.println("Ilegal argument: "+e.getMessage()) ;
} ;
}
}

Двоичные данные
webtools/tinderbox2/src/bonsai_p4db/p4jdb/P4DirTreeApplet$1.class Executable file

Двоичный файл не отображается.

Двоичные данные
webtools/tinderbox2/src/bonsai_p4db/p4jdb/P4DirTreeApplet.class Executable file

Двоичный файл не отображается.

Просмотреть файл

@ -0,0 +1,66 @@
package p4jdb ;
import p4jdb.TreeDisplay ;
import p4jdb.P4DirTree ;
import java.applet.*;
import java.awt.* ;
import java.awt.event.* ;
/**
* Display p4 depot
*/
public class P4DirTreeApplet extends Applet
{
P4DirTree theP4DirTree_ ;
/**
* init applet
*/
public void init() {
theP4DirTree_ = new P4DirTree(this) ;
setBackground(Color.white) ;
theP4DirTree_.initData() ;
final String buttonText = "Graphic Browser" ;
final String fontName = "SansSerif" ;
final Dimension windim = getSize() ;
int fontSize ;
{
FontMetrics fm = getFontMetrics(new Font(fontName,Font.BOLD,14)) ;
final int len = fm.stringWidth(buttonText) ;
final int height = fm.getHeight() ;
final int fs1 = (new Double((windim.width*13/len))).intValue() ;
final int fs2 = (new Double((windim.height*13/height))).intValue() ;
fontSize = fs1 ;
if(fs2 < fs1) {
fontSize = fs2 ;
}
}
Button butt = new Button(buttonText) ;
butt.setBackground(new Color(0xe0,0xe0,0xe0)) ;
butt.setForeground(Color.blue) ;
butt.setFont(new Font(fontName,Font.BOLD,fontSize)) ;
butt.setSize(windim) ;
add(butt) ;
butt.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
theP4DirTree_.start() ;
} ;
}) ;
}
public String[][] getParameterInfo() {
String[][] s = {
{"File", "String", "Name of data file"}} ;
return s ;
} ;
}

Двоичные данные
webtools/tinderbox2/src/bonsai_p4db/p4jdb/P4File$1.class Executable file

Двоичный файл не отображается.

Двоичные данные
webtools/tinderbox2/src/bonsai_p4db/p4jdb/P4File.class Executable file

Двоичный файл не отображается.

Просмотреть файл

@ -0,0 +1,130 @@
package p4jdb ;
import p4jdb.* ;
import java.lang.* ;
import java.util.* ;
import java.net.* ;
import java.applet.* ;
import java.awt.* ;
import java.awt.event.* ;
/**
* Represents a directory folder in the p4 depot.
*/
public class P4File implements TreeDisplay.Data {
/**
* Name and full path of directory
*/
private String name_,path_,urlPath_ ;
/**
* file revision
*/
private int rev_ ;
/**
* file status code
*/
public String status_ ;
/**
* "level" in directory tree
*/
private int level_ ;
public P4File(String name,
String path,
int rev,
int level,
String status)
{
name_ = name ;
path_ = path ;
urlPath_ = URLEncoder.encode(path_+"/"+name_) ;
rev_ = rev ;
level_ = level ;
status_ = status ;
}
/**
* Draw line info
*@param height Line height
*@param p Start point (lower right)
*@param g Graphics object to use
*@return width of object drawn (or 0 if no object)
*/
public int draw(int height, Point p, Graphics g)
{
final String name = name_ + "#" + rev_ ;
final FontMetrics fm = g.getFontMetrics() ;
final int width = fm.stringWidth(name) ;
g.setColor(Color.black) ;
g.drawString(name,p.x,p.y) ;
if(status_.equals("de")) {
g.setColor(Color.red) ;
final int ylevel = p.y - (fm.getHeight()/3) ;
g.drawLine(p.x,ylevel,
p.x+width,ylevel) ;
} ;
return width ;
}
/**
*@return level in tree (number of tics to indent)
*/
public int level()
{
return level_ ;
}
/**
* Invoked when the mouse has been clicked on an object.
*@param cp Component where object is drawn
*@param pt Point within component where mouse is clicked
*@param rpt Point within object (relative to zero position
* given in draw() metod
*/
public void mouseClicked(Component cp, Point pt, Point rpt)
{
final String HISTORY = "View file history" ;
final String VIEW = "View file" ;
final String VIEW_CHANGES = "View changes for file" ;
PopupMenu popup = new PopupMenu(path_+"/"+name_) ;
popup.add(HISTORY) ;
popup.add(VIEW) ;
popup.add(VIEW_CHANGES) ;
popup.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
AppletContext ac = P4DirTree.applet.getAppletContext() ;
URL url ;
try {
if(e.getActionCommand() == HISTORY)
url = new URL(P4DirTree.applet.getDocumentBase(),
"fileLogView.cgi?FSPC="+urlPath_) ;
else if (e.getActionCommand() == VIEW)
url = new URL(P4DirTree.applet.getDocumentBase(),
"fileViewer.cgi?FSPC="+urlPath_+"&REV="+rev_) ;
else // if (e.getActionCommand() == VIEW_CHANGES)
url = new URL(P4DirTree.applet.getDocumentBase(),
"changeList.cgi?FSPC="+urlPath_) ;
ac.showDocument(url) ;
}
catch (Throwable t) {
System.err.println("Exception: "+t.toString()) ;
}
}
}) ;
cp.add(popup) ;
popup.show(cp,pt.x,pt.y) ;
} ;
} ;

Двоичные данные
webtools/tinderbox2/src/bonsai_p4db/p4jdb/P4Folder$1.class Executable file

Двоичный файл не отображается.

Двоичные данные
webtools/tinderbox2/src/bonsai_p4db/p4jdb/P4Folder.class Executable file

Двоичный файл не отображается.

Просмотреть файл

@ -0,0 +1,295 @@
package p4jdb ;
import p4jdb.* ;
import java.lang.* ;
import java.util.* ;
import java.applet.* ;
import java.awt.* ;
import java.awt.event.* ;
import java.io.* ;
import java.net.* ;
/**
* Represents a directory folder in the p4 depot.
*/
public class P4Folder implements TreeDisplay.Data {
/**
* Name and full path of directory
*/
public String name_,path_,urlPath_;
/**
* Vector that contains the contents of the directory
* (other directories and files...)
*/
private Vector contents_ ;
/**
* true if directory "open", that is: if contents is displayed
*/
private boolean open_ ;
/**
* true of directory scanned
*/
private boolean scanned_ ;
/**
* "level" in directory tree
*/
private int level_ ;
/**
* X value for border between folder and name
*/
private int borderX_ ;
static private String helpText = "P4DB experimental java browser" ;
/**
* Constructor
*/
public P4Folder(String name,
String path,
int level)
{
level_ = level ;
name_ = name ;
path_ = path+"/"+name ;
urlPath_ = URLEncoder.encode(path_) ;
open_ = false ;
scanned_ = false ;
contents_ = new Vector() ;
if(level == 0) {
scan(null) ;
open_ = true ;
} ;
} ;
/**
* Scan
*/
public void scan(Component cp) {
if(cp != null)
cp.setCursor(new Cursor(Cursor.WAIT_CURSOR)) ;
try {
URL u = new URL(P4DirTree.applet.getDocumentBase(),
P4DirTree.applet.getParameter("File")+
"?CMD=DIRSCAN&FSPC="+urlPath_+"/"+"*") ;
URLConnection conn = u.openConnection() ;
InputStreamReader isr = new InputStreamReader(conn.getInputStream()) ;
BufferedReader in = new BufferedReader(isr);
StreamTokenizer tok = new StreamTokenizer(in) ;
int nxt ;
while((nxt = tok.nextToken()) != StreamTokenizer.TT_EOF) {
String type = tok.sval ;
tok.nextToken() ;
String name = tok.sval ;
if(type.equals("D")) {
contents_.addElement(new P4Folder(name,
path_,
level_+1)) ;
}
else {
tok.nextToken() ;
double rev = tok.nval ;
tok.nextToken() ;
String status = tok.sval ;
contents_.addElement(new P4File(name,
path_,
(new Double(rev)).intValue(),
level_+1,
status)) ;
}
}
scanned_ = true ;
}
catch (IOException e) {
System.err.println("IOEx:" + e) ;
}
catch (Throwable e) {
System.err.println(e.getMessage()) ;
} ;
if(cp != null)
cp.setCursor(new Cursor(Cursor.DEFAULT_CURSOR)) ;
}
/**
* Add folder entry to vector
*/
void addToVector(Vector v) {
v.addElement(this) ;
if(open_) {
Enumeration enum = contents_.elements() ;
while(enum.hasMoreElements()) {
Object o = enum.nextElement() ;
if(o instanceof P4Folder) {
((P4Folder) o).addToVector(v) ;
}
else {
if(o instanceof P4File) {
P4File f = ((P4File) o) ;
if(P4DirTree.showDeleted ||
!f.status_.equals("de"))
v.addElement(o) ;
}
else {
v.addElement(o) ;
}
}
} ;
} ;
}
/**
* Collapse/expand all entries
*/
void setOpen(boolean open) {
// System.err.println("setOpen("+open+"): "+name_) ; // DEBUG
open_ = open ;
Enumeration enum = contents_.elements() ;
while(enum.hasMoreElements()) {
Object o = enum.nextElement() ;
if(o instanceof P4Folder) {
((P4Folder) o).setOpen(open) ;
}
} ;
}
/**
* Draw line info
*@param height Line height
*@param p Start point (lower right)
*@param g Graphics object to use
*@return width of object drawn (or 0 if no object)
*/
public int draw(int height, Point p, Graphics g)
{
//final Color FLD_COLOR = Color.yellow ;
// Folder dimension
//final Dimension FLD_DIM = new Dimension((height*2)/3,height/2) ;
// Folder start point (upper left of folder "main"
// rectangle
if(level_ > 0) {
final Color FLD_COLOR = Color.yellow.brighter() ;
// Folder dimension
final Dimension FLD_DIM = new Dimension((height*2)/3,height/2) ;
// Folder start point (upper left of folder "main"
// rectangle
// ** Draw a "folder" **
g.setColor(FLD_COLOR) ; // Fill folder "main" rectangle
g.fillRect(p.x,p.y-FLD_DIM.height,
FLD_DIM.width,FLD_DIM.height) ;
g.setColor(Color.black) ; // Draw folder "main" outline
g.drawRect(p.x,p.y-FLD_DIM.height,
FLD_DIM.width,FLD_DIM.height) ;
g.setColor(FLD_COLOR) ; // Fill folder tab
g.fillRect(p.x+(FLD_DIM.width/2), p.y-2-FLD_DIM.height,
FLD_DIM.width/2,2) ;
g.setColor(Color.black) ; // Draw folder tab outline
g.drawRect(p.x+(FLD_DIM.width/2), p.y-2-FLD_DIM.height,
FLD_DIM.width/2,2) ;
// ** print string
borderX_ = FLD_DIM.width + 3 ;
g.drawString(name_,p.x+borderX_+1,p.y) ;
}
else {
// Draw "barrel"
final Color BARREL_COLOR = Color.gray.brighter() ;
final Dimension FLD_DIM = new Dimension(height,height/2) ;
final int yo = 2 ;
g.setColor(BARREL_COLOR) ;
g.fillRect(p.x,p.y-FLD_DIM.height-yo,
FLD_DIM.width,FLD_DIM.height) ;
g.setColor(Color.black) ; // Draw folder tab outline
g.drawRect(p.x,p.y-FLD_DIM.height-yo,
FLD_DIM.width,FLD_DIM.height) ;
g.setColor(BARREL_COLOR) ;
g.fillOval(p.x,p.y-((FLD_DIM.height*3)/2)-yo,
FLD_DIM.width,(FLD_DIM.height*2)/3) ;
g.setColor(BARREL_COLOR) ;
g.fillOval(p.x,p.y-1-yo,
FLD_DIM.width,(FLD_DIM.height*2)/3) ;
g.setColor(Color.black) ; // Draw folder tab outline
g.drawOval(p.x,p.y-((FLD_DIM.height*3)/2)-yo,
FLD_DIM.width,(FLD_DIM.height*2)/3) ;
g.drawArc(p.x,p.y-1-yo,
FLD_DIM.width,(FLD_DIM.height*2)/3,180,180) ;
borderX_ = FLD_DIM.width + 3 ;
g.setColor(Color.blue.brighter()) ;
g.drawString(helpText,p.x+borderX_+1,p.y) ;
}
return borderX_ + 1 + g.getFontMetrics().stringWidth(name_) ;
}
/**
*@return level in tree (number of tics to indent)
*/
public int level()
{
return level_ ;
}
/**
* Invoked when the mouse has been clicked on an object.
*@param cp Component where object is drawn
*@param pt Point within component where mouse is clicked
*@param rpt Point within object (relative to zero position
* given in draw() metod
*/
public void mouseClicked(Component cp, Point pt, Point rpt)
{
if(rpt.x < borderX_) {
// click on folder
open_ = !open_ ;
if(open_ && !scanned_) {
scan(cp) ;
helpText = "" ;
}
}
else {
// click on name
PopupMenu popup = new PopupMenu(path_) ;
final String VIEW_CHANGES = "View changes below this point" ;
final String BROWSE = "Browse this directory" ;
popup.add(VIEW_CHANGES) ;
popup.add(BROWSE) ;
popup.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
AppletContext ac = P4DirTree.applet.getAppletContext() ;
try {
if(e.getActionCommand() == VIEW_CHANGES) {
ac.showDocument(new
URL(P4DirTree.applet.getDocumentBase(),
"changeList.cgi?FSPC="+urlPath_+"/...&MAXCH=100")) ;
}
else if (e.getActionCommand() == BROWSE){
ac.showDocument(new
URL(P4DirTree.applet.getDocumentBase(),
"depotTreeBrowser.cgi?FSPC="+urlPath_)) ;
}
}
catch (Throwable t) {
System.err.println("Exception: "+t.getMessage()) ;
}
}
}) ;
cp.add(popup) ;
popup.show(cp,pt.x,pt.y) ;
}
} ;
} ;

Двоичные данные
webtools/tinderbox2/src/bonsai_p4db/p4jdb/TreeDisplay$1.class Executable file

Двоичный файл не отображается.

Двоичные данные
webtools/tinderbox2/src/bonsai_p4db/p4jdb/TreeDisplay$Data.class Executable file

Двоичный файл не отображается.

Двоичные данные
webtools/tinderbox2/src/bonsai_p4db/p4jdb/TreeDisplay$DataManager.class Executable file

Двоичный файл не отображается.

Двоичные данные
webtools/tinderbox2/src/bonsai_p4db/p4jdb/TreeDisplay$LineData.class Executable file

Двоичный файл не отображается.

Двоичные данные
webtools/tinderbox2/src/bonsai_p4db/p4jdb/TreeDisplay$MyPanel.class Executable file

Двоичный файл не отображается.

Двоичные данные
webtools/tinderbox2/src/bonsai_p4db/p4jdb/TreeDisplay.class Executable file

Двоичный файл не отображается.

Просмотреть файл

@ -0,0 +1,372 @@
package p4jdb ;
import java.awt.* ;
import java.awt.event.* ;
import java.util.* ;
/**
* Yet another Java object that displays a directory tree.
* The main differences, apart from that I wrote it myself (NIH ;^) )
* is that it is tested with large trees (>20k entries) and does not
* bother with images and other fancy stuff. The need for speed.....
* <br>
* The class defines two interfaces, <tt>TreeDisplay::Data</tt> and
* <tt>TreeDisplay::DataManager</tt>, that connects the display to the
* data. The constructor takes a <tt>TreeDisplay::DataManager</tt>
* object that provides an interface to <tt>TreeDisplay::Data</tt>
* objects. <br>
* <i>/Fredric</i><br>
* PS. It is also my first java ever so be gentle....
*/
public class TreeDisplay extends Panel implements AdjustmentListener {
/**
* Represents a data item displayed in the tree (typically a file)
* <br>
* The data for the object is displayed on a line
*/
public interface Data {
/**
* Draw a line representing a data object.
*@param height Line height
*@param p Start point (lower right)
*@param g Graphics object to use
*@return width of object drawn in pixels (or 0 if no object). The
* width is used to determine clickable area for the object.
*/
public int draw(int height, Point p, Graphics g) ;
/**
* Get level in tree
*@return level in tree (number of tics to indent)
*/
public int level() ;
/**
* This member is called when the mouse has been clicked on the
* line.
*@param cp Component where object is drawn
*@param pt Point within component where mouse is clicked
*@param rpt Point relative to position given in draw() metod
*/
public void mouseClicked(Component cp, Point pt, Point rpt) ;
} ;
/**
* Interface for an object that manages the data items (typically a file
* structure)
*/
public interface DataManager {
/**
* Used by <tt>TreeDisplay</tt> to get the total number of
* lines to display.
*@return Number of lines (items) to display
*/
public int getLines() ;
/**
* Get Data object by offset
*@param offset Offset of object to return
*@return Item at specified offset
*@throws IndexOutOfBoundsException if offset out of bounds
*/
public Data getItemAt(int offset)
throws java.lang.IndexOutOfBoundsException ;
/**
* Get line height. Current implementation assumes same height
* for all lines.
*@return line height in pixels
*/
public int getLineHeight() ;
/**
* Get indent value
*@return number of pixels to indent for each level in tree
*/
public int indentValue() ;
/**
* Get background color for panel
*@return background color
*/
public Color getBackground() ;
/**
* Called before repaint. The idea is to give the <tt>DataManager</tt>
* object a chance to prepare itself before data is painted.
*/
public void prePaint() ;
} ;
private DataManager theDataManager_ ;
/**
* Contains data for a line
*/
private class LineData {
/**
* Min and max x/y positions
*/
public int minY,maxY,minX,maxX ;
/**
* Data object
*/
public Data data ;
} ;
private Vector lineDataV_ = new Vector() ;
/**
* Internal class that represents a panel
*/
private class MyPanel extends Panel {
public Image offScreenImage ;
public void paint(Graphics graphics) {
if(offScreenImage == null) {
TreeDisplay.this.paint(TreeDisplay.this.getGraphics()) ;
}
graphics.drawImage(offScreenImage,0,0,this) ;
}
} ;
/**
* Graphic objects
*/
//private Scrollbar hadj_ ;
private Scrollbar vadj_ ;
private MyPanel panel_ ;
/**
* No. of top line in window
*/
private int firstLineNo_ ;
/**
* Constructor
*@param dataManager DataManager object
*/
public TreeDisplay(DataManager dataManager)
{
theDataManager_ = dataManager ;
firstLineNo_ = 0 ;
// Create graphic objects
panel_ = new MyPanel() ;
//hadj_ = new Scrollbar(Scrollbar.HORIZONTAL) ;
vadj_ = new Scrollbar(Scrollbar.VERTICAL) ;
// Re-direct mouseclicks to parent class
panel_.addMouseListener(new MouseAdapter()
{
public void mouseClicked(MouseEvent e) {
TreeDisplay.this.mouseClicked(e) ;
}
}) ;
// Make object listen to scrollbars
//hadj_.addAdjustmentListener(this) ;
vadj_.addAdjustmentListener(this) ;
// Define a layout
GridBagLayout gridbag = new GridBagLayout() ;
setLayout(gridbag) ;
GridBagConstraints c = new GridBagConstraints();
// Define layout for panel and add object
c.fill = GridBagConstraints.BOTH ;
c.weightx = 1;
c.weighty = 1;
c.gridwidth = GridBagConstraints.RELATIVE ;
c.gridheight = GridBagConstraints.RELATIVE ;
gridbag.setConstraints(panel_,c) ;
add(panel_) ;
// Define layout for vertical scrollbar and
// add object
c.weightx = 0;
c.weighty = 0;
c.gridwidth = GridBagConstraints.REMAINDER ;
c.gridheight = GridBagConstraints.RELATIVE ;
gridbag.setConstraints(vadj_,c) ;
add(vadj_) ;
// Define layout for horizontal scrollbar and
// add object
//c.gridwidth = GridBagConstraints.RELATIVE ;
//c.gridheight = GridBagConstraints.REMAINDER ;
//gridbag.setConstraints(hadj_,c) ;
//add(hadj_) ;
panel_.setBackground(theDataManager_.getBackground()) ;
} ;
/**
* <B>NOTE!</B> Should really be private, bug in java<br>
* handle mouse click
*/
public void mouseClicked(MouseEvent event) {
int y = event.getPoint().y ;
Enumeration e = lineDataV_.elements() ;
LineData ld;
while(e.hasMoreElements()) {
ld = ((LineData) e.nextElement()) ;
if((y >= ld.minY) && (y <= ld.maxY)) {
int x = event.getPoint().x ;
if((x >= ld.minX) && (x <= ld.maxX)) {
ld.data.mouseClicked(panel_,
new Point(x,y),
new Point(x-ld.minX,y-ld.minY)) ;
}
else {
break ;
} ;
theDataManager_.prePaint() ;
paint(getGraphics()) ;
break ;
}
}
} ;
/**
* Change manager object
*/
public void setManager(DataManager dataManager)
{
theDataManager_ = dataManager ;
paint(getGraphics()) ;
}
/**
* Called when Scrollbar object modified by user
*/
public void adjustmentValueChanged(AdjustmentEvent e)
{
firstLineNo_ = vadj_.getValue() ;
paint(getGraphics()) ;
} ;
/**
* re-paint window
*/
public void paint(Graphics graphics)
{
// Create a temp graphic object
final Dimension dim = panel_.getSize() ;
panel_.offScreenImage = createImage(dim.width,dim.height) ;
Graphics tmpGraphics = panel_.offScreenImage.getGraphics() ;
// Clear object
tmpGraphics.setColor(theDataManager_.getBackground());
tmpGraphics.fillRect(0,0,dim.width,dim.height) ;
// Compute lines displayed
final int visibleLines = dim.height/theDataManager_.getLineHeight() ;
// Adjust first line if neccesary
final int totLines = theDataManager_.getLines() ;
if(firstLineNo_ > totLines-visibleLines) {
firstLineNo_ = totLines-visibleLines ;
if(firstLineNo_ < 0) firstLineNo_ = 0 ;
}
// Adjust vertical scrollbar values
vadj_.setMinimum(0) ;
vadj_.setBlockIncrement(visibleLines) ;
vadj_.setVisibleAmount(visibleLines) ;
if((totLines-visibleLines)+1 > 0) {
vadj_.setMaximum(totLines) ;
}
else
vadj_.setMaximum(1) ;
vadj_.setValue(firstLineNo_) ;
// Clear displayed-line to data vector
lineDataV_.removeAllElements() ;
// Draw lines
try {
int line = 0 ;
Vector pointByLevel = new Vector() ;
int ypos = theDataManager_.getLineHeight() ;
int lastLevel = 0 ;
for(line = 0;
(line <= visibleLines) && (line+firstLineNo_ < totLines);
line++) {
LineData ld = new LineData() ;
ld.data = theDataManager_.getItemAt(line+firstLineNo_) ;
ld.minY = ypos - theDataManager_.getLineHeight() ;
ld.maxY = ypos ;
final int lineBot = ypos - (theDataManager_.getLineHeight()*2)/3 ;
tmpGraphics.setColor(new Color(0x40,0x40,0xff)) ;
// int i ;
int xp=0 ;
if(ld.data.level() > 0) {
if(pointByLevel.size() < ld.data.level()) {
pointByLevel.setSize(ld.data.level()+1) ;
for(int i=0;i< ld.data.level();i++) {
final int x = ((i*theDataManager_.indentValue()) +
theDataManager_.indentValue()/2) ;
pointByLevel.setElementAt(new Point(x,0),i) ;
}
}
Point p = ((Point) pointByLevel.elementAt(ld.data.level()-1)) ;
tmpGraphics.drawLine(p.x,p.y,
p.x,lineBot) ;
p.y = lineBot ;
tmpGraphics.drawLine(p.x,p.y,
p.x+theDataManager_.indentValue()/2,
p.y+(theDataManager_.getLineHeight()/4)) ;
}
Point startp = new Point(3+(ld.data.level())*
theDataManager_.indentValue(),
ypos) ;
if(pointByLevel.size() < ld.data.level()+1)
pointByLevel.setSize(ld.data.level()+1) ;
pointByLevel.setElementAt(new
Point(startp.x - 3 +
(theDataManager_.indentValue()/2),
startp.y),
ld.data.level()) ;
ld.minX = startp.x ;
ld.maxX = (startp.x +
ld.data.draw(theDataManager_.getLineHeight(),
startp,
tmpGraphics)) ;
lineDataV_.addElement(ld) ;
ypos += theDataManager_.getLineHeight() ;
lastLevel = ld.data.level() ;
}
line += firstLineNo_ ;
for(;lastLevel > 1 && line<theDataManager_.getLines();line++) {
Data data = theDataManager_.getItemAt(line) ;
if(data.level() < lastLevel) {
lastLevel = data.level() ;
}
if(lastLevel > 0 && data.level() == lastLevel) {
Point p = ((Point) pointByLevel.elementAt(lastLevel-1)) ;
tmpGraphics.setColor(new Color(0x40,0x40,0xff)) ;
tmpGraphics.drawLine(p.x,p.y,
p.x,dim.height) ;
}
}
}
catch(Throwable e) {
System.err.println("paint() throws:" + e) ;
e.printStackTrace() ;
tmpGraphics.setColor(Color.red) ;
tmpGraphics.drawString(e.getMessage(),10,10) ;
}
panel_.paint(panel_.getGraphics()) ;
}
} ;

Просмотреть файл

@ -0,0 +1,197 @@
#!/usr/bin/perl -w
# $Id: p4pr.perl,v 1.1 2006/01/27 03:52:54 kestesisme%yahoo.com Exp $
# Interpolate change information into a source listing of a p4 file.
# Takes a file name or depot filename, with #<ref> or @<change>.
# Contributed by Bob Sidebotham.
# Modified for use by P4DB by Fredric Fredricson
use P4CGI ;
use strict ;
# Simplify program name, if it is a path.
$0 =~ s#.*/##;
# Execute a command, keeping the output of the command in an array.
# Returns the array, unless an error occured, in which case the an
# exception is thrown (via die) with an appropriate message.
sub command {
my($command) = @_;
my @results ;
&P4CGI::p4call(\@results,$command) ;
if ($?) {
my($err) = ($? >> 8);
print STDERR @results;
die qq($0: "$command" exited with status $err.\n);
}
@results ;
}
# Fatal usage error
sub usage {
my($err) = @_;
die
"$0: $err\n" .
"usage: $0 <file> | <file>#<rev> | <file>\@<change>\n" .
" <file> may be a client file name or depot file name.\n";
}
# Default options
my $showauthor = 1;
my $showchange = 1;
my $showrev = 1;
# Undocumented options
if (@ARGV && $ARGV[0] =~ /^-/) {
$showchange = 0;
}
# Parse options
while (@ARGV && $ARGV[0] =~ /^-/) {
my $opt = shift;
if ($opt eq '-r') {
$showrev = 1; # Show revision numbers instead of changes.
} elsif ($opt eq '-c') {
$showchange = 1;
} else {
usage("invalid option $opt");
}
}
# Get file argument.
usage("file name expected") if !@ARGV;
usage("invalid argument") if @ARGV > 1;
my $file = shift;
my $tmpFile = $file;
# Handle # and @ notation (only for numeric changes and revisions).
my $change = $1 if $file =~ s/@(\d+)//;
my $head = $1 if $file =~ s/#(\d+)//;
# Check that the file specification maps to exactly one file.
my @list = command qq(files "$tmpFile");
if (@list > 1) {
die("$0: the specified file pattern maps to more than one file.\n");
}
# Check that the revision is not deleted.
if ($list[0] =~ /(.*)\#(\d+) - delete change/) {
die("$0: revision $1#$2 is deleted.\n") ;
} ;
# Get the fullname of the file and the history, all from
# the filelog for the file.
my ($fullname, @history) = command qq(filelog "$file");
chomp($fullname);
$fullname =~ s/#.*//;
my @fullname = split(m!/!, $fullname);
# Extract the revision to change number mapping. Also
# get the author of each revision, and for merged
# or copied revisions, the "branch name", which we
# use instead of an author.
my %change;
my %author ;
my $thisrev ;
my $headseen ;
for (@history) {
if (/^\.\.\. \#(\d+) change (\d+)\s+(\w+) .*? by (.*?)@/) {
# If a change number or revision is specified, then ignore
# later revisions.
next if $change && $change < $2;
next if $head && $head < $1;
last if $3 eq "delete" ; # Small bug fix by Fredric Fredricson
$change{$1} = $2;
$author{$1} = $4;
$head = $1 if !$head;
$thisrev = $1;
$headseen = 1;
} else {
# If we see a branch from, then we know that
# previous revisions did not contribute to the current
# revision. Don't do this, however, if we haven't seen
# the revision we've been requested to print, yet.
# We used to do this for copy from, but I think
# it's better not to.
next unless $headseen;
if (/^\.\.\. \.\.\. (copy|branch|merge) from (\/\/.*)#/) {
# If merged or copied from another part of the
# tree, then we use the first component of the
# name that is different, and call that the "branch"
# Further, we make the "author" be the name of the
# branch.
my($type) = $1;
my(@from) = split(m#/#, $2);
my $i ;
for ($i = 0; $i < @from; $i++) {
if ($from[$i] ne $fullname[$i]) {
$author{$thisrev} = $from[$i] if $from[$i];
last;
}
}
# If branched, we don't bother getting any more
# history. We treat this as starting with the branch.
last if $type eq 'branch';
}
}
}
# Get first revision, and list of remaining revisions
my ($base, @revs) = sort {$a <=> $b} keys %change;
# Get the contents of the base revision of the file,
# purely for the purposes of counting the lines.
my @text = command qq(print -q "$file\#$base");
# For each line in the file, set the change revision
# to be the base revision.
my @lines = ($base) x @text;
# For each revision from the base to the selected revision
# "apply" the diffs by manipulating the array of revision
# numbers. If lines are added, we add a corresponding
# set of entries with the revision number that added it.
# We ignore the actual revision text--that will be merged
# with the change information later.
my $rev ;
for $rev (@revs) {
my($r1) = $rev - 1;
# Apply the diffs in reverse order to maintain correctness
# of line numbers for each range as we apply it.
for (reverse command qq(diff2 "$file\#$r1" "$file\#$rev")) {
my( $la, $lb, $op, $ra, $rb ) = /(\d+),?(\d*)([acd])(\d+),?(\d*)/;
next unless defined($ra);
$lb = $la if ! $lb;
++$la if $op eq 'a';
$rb = $ra if ! $rb;
++$ra if $op eq 'd';
splice @lines, $la - 1, $lb - $la + 1, ($rev) x ($rb - $ra + 1);
}
}
# Get the text of the selected revision. The number of lines
# resulting from applying the diffs should equal the number of
# of lines in this revision.
my ($header, @text) = command qq(print "$file#$head");
if (@text != @lines) {
die("$0: internal error applying diffs - please contact the author\n")
}
# Print a pretty header. Note that the interpolated information
# at the beginning of the line is a multiple of 8 bytes (currently 24)
# so that the default tabbing of 8 characters works correctly.
my($fmt) = "%5s %15s %6s %4s %s\n";
my @fields = ("line", "author/branch", "change", "rev", $header);
printf($fmt, @fields);
printf("$fmt", map('-' x length($_), @fields));
# Interpolate the change author and number into the text.
my($line) = 1;
while (@text) {
my($rev) = shift(@lines);
printf($fmt, $line++, $author{$rev}, $change{$rev}, $rev, shift @text);
}

Просмотреть файл

@ -0,0 +1,289 @@
#!/usr/bin/perl -w
# -*- perl -*-
use P4CGI ;
use strict ;
#################################################################
#
#
# The great
#
# P 4 S U B M I T R A C E
#
# contest
#
#
#
# This is unpublished and unofficial and unsupported and untrusted
# and unbelivable non-proprietary source code of MYDATA automation AB
# Do whatever you want with it. We don't care.
#
# Send your comments, flames, fan email, threats, email bombs, spam etc to:
# fredric@mydata.se
#
# Troubleshooting guide:
# Apart from the usual problems with cgi's you might get in touble
# with the P4 protection system. I think you must have at least "list"
# access to the depot, but I have not tested this so.....
#
# Other than that: You're on your own buddy!
#
#################################################################
#
my $DEFAULT_LENGTH = 499 ; # Set default number of changes
#
my $changes = $DEFAULT_LENGTH ;
my %subsByUsr;
# Contains number of submits by user
my %userpoints;
# Contains "points" per user (actually, used to compute the
# "mean position" of all the submits found by user). This is used to
# evaluate users "speed".
my %ptsInLast10;
# Contains number of submits in the oldest ten percent. A little "extra"
# feature to make comments more interesting.
#
# Find out if mozilla (a plot to make the user feel he is always wrong)
#
my $browser = $ENV{"HTTP_USER_AGENT"} ;
my $bestViewed = "Netscape Navigator <!-- not $browser -->";
my $blink="B" ;
if(($browser =~ /mozilla/i) and not ($browser =~ /msie/i)) {
$bestViewed = "Microsoft Explorer <!-- not $browser -->" ;
$blink="BLINK" ;
}
my $replay = &P4CGI::cgi()->param("REPLAY") ;
$replay = undef unless defined $replay and $replay =~ /^\d+$/ ;
$replay = 0 unless defined $replay ;
#
# Read p4 repository
#
local *CHANGES ;
my $skip = $replay ;
my $ch = $changes + $replay ;
&P4CGI::p4call(*CHANGES,"changes -m $ch -s submitted") ;
my $tenPercent = $changes/10 ;
my $pos = 0 ;
my $lastUsr ;
my $firstUsr ;
my $leadChange ;
my $tmpch = $changes ;
while (<CHANGES>) {
unless(defined $leadChange) {
/^Change (\d+).*/ ;
$leadChange = $1 ;
};
next if $skip-- > 0 ;
$tmpch-- || do { last ; } ;
/(\w+)@/ || do { next ; } ;
$pos++ ;
$lastUsr = $1 ;
$firstUsr = $1 unless defined $firstUsr ;
if(!$subsByUsr{$1}) {
$subsByUsr{$1} = 1 ;
$userpoints{$1} = $pos ;
}
else {
$userpoints{$1} += $pos ;
$subsByUsr{$1}++ ;
}
if($tmpch < $tenPercent) {
if(defined $ptsInLast10{$1}) { $ptsInLast10{$1} += 1 ; }
else { $ptsInLast10{$1} = 1 ; } ;
}
}
my $total = $pos ;
close CHANGES;
my %userToName ;
local *F ;
&P4CGI::p4call(*F,"users") ;
while(<F>) {
/^(\w+).*>\s+\((.*)\)\s+acc/ || do { next ; } ;
$userToName{$1}=$2 ;
};
close(F) ;
##
## Write html code
##
#
# Get date and time
#
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
localtime(time());
my $date = sprintf("%d/%d-%4.4d %2.2d:%2.2d",
$mday,$mon+1,$year+1900,
$hour,$min) ;
my $replayUrl = "" ;
if($replay > 0) {
my $r = $replay-1 ;
&P4CGI::EXTRAHEADER(-Refresh => "4; URL=p4race.cgi?REPLAY=$r") ;
$replayUrl = "<blink><font align=center color=red size=+1>Replay offset $replay</font></blink><br>" . &P4CGI::ahref(-url=>"p4race.cgi",
"Abort Replay")
} else {
&P4CGI::EXTRAHEADER(-Refresh => "30; URL=p4race.cgi") ;
$replayUrl = &P4CGI::ahref("REPLAY=30",
"Replay the last 30 submits") ;
}
&P4CGI::SET_HELP_TARGET("P4Race") ;
print "",
&P4CGI::start_page("P4 submit race <br><small>$date</small>",
"Distance: $changes changes<br>$replayUrl") ;
#
# Compute a background color
#
srand($leadChange) ;
my $bc=(((((rand(0x10)*5)+0xB0) & 0xf0)*0x10000)+
((((rand(0x10)*5)+0xB0) & 0xf0)*0x100) +
(( (rand(0x10)*5)+0xB0) & 0xf0)) ;
my $lcolor=sprintf("%6.6X",$bc & 0xf0f0f0) ;
#
# Start building table
#
my $posInRace = 0;
my $prevUserPoints = 0;
my $usersAtSamePos = 1;
my $usr ;
my $table="first" ;
print "<P>",
&P4CGI::start_table("BORDER=10 ALIGN=CENTER BGCOLOR=$lcolor"),
&P4CGI::table_row(-type=>"th",
"Position",
"User",
"# of submits",
"Comment") ;
foreach $usr (sort { $subsByUsr{$b} <=> $subsByUsr{$a} } (keys %subsByUsr)){
#
# Compute weighted mean position for users submits
#
my $meanPos = 100*(1-($userpoints{$usr}/($subsByUsr{$usr}*$total))) ;
#
# Set a status message depending on mean pos
#
my $status ;
$status = "A LOSER" ;
$status = "Losing position fast" if $meanPos > 10 ;
$status = "Losing" if $meanPos > 25 ;
$status = "Losing slowly" if $meanPos > 33 ;
$status = "Almost keeping pace" if $meanPos > 43 ;
$status = "Hanging in there" if $meanPos > 47 ;
$status = "Almost advancing" if $meanPos > 53 ;
$status = "Advancing slowly" if $meanPos > 57 ;
$status = "Advancing" if $meanPos > 70 ;
$status = "Advancing fast" if $meanPos > 80 ;
$status = "A ROCKET!" if $meanPos > 90 ;
#
# Compute how many of users submits that are in the last 10%
# (== he will soon lose the points)
#
my $troublePts = 0 ;
# Contains percentage of points in last 10% of submits
if(defined $ptsInLast10{$usr}) {
$troublePts = ($ptsInLast10{$usr}*100)/$subsByUsr{$usr} ;
} ;
#
# Add an extra text if user has a lot of points in last 10%
#
my $and = " and" ;
$and = " but" if $meanPos > 43 ;
my $tmp = "" ;
$tmp = "$and in some trouble" if ($troublePts > 12) ;
$tmp = "$and in trouble" if ($troublePts > 15);
$tmp = "$and in <B>big</B> trouble" if ($troublePts > 20);
$tmp = "$and in <B><BIG>huge</BIG></B> trouble" if ($troublePts > 30);
$status .=$tmp ;
if($subsByUsr{$usr} != $prevUserPoints){
$posInRace = $posInRace + $usersAtSamePos;
$prevUserPoints = $subsByUsr{$usr};
$usersAtSamePos = 1;
$pos = $posInRace ;
} else {
$usersAtSamePos = $usersAtSamePos + 1;
$pos =" " ;
} ;
#
# Treat the first three special
#
$pos eq "1" && do {
$pos="<BIG><FONT COLOR=\"red\"><$blink>First</$blink></FONT></BIG>" ;
};
$pos eq "2" && do {
$pos="<BIG><FONT COLOR=\"blue\">Second</FONT></BIG>";
};
$pos eq "3" && do {
$pos="<BIG><FONT COLOR=\"blue\">Third</FONT></BIG>" ;
};
#
# End first table and start second if position is greater than 3
#
$posInRace ge "4" && ($table eq "first") && do {
print
&P4CGI::end_table(),
"\n<B>Followed by:</B>\n",
&P4CGI::start_table("BORDER=3 BGCOLOR=\"#E0E0E0\""),
&P4CGI::table_row(-type=>"th",
"Position",
"User",
"# of submits",
"Comment") ;
$table="second" ;
} ;
#
# Translate user to "real name", if available
#
my $user = $usr ;
if($userToName{$usr} && ($userToName{$usr} ne $usr)) {
$user = "$userToName{$usr}" ;
};
#
# Print table entry
#
my @bgcolor = () ;
push @bgcolor,("-bgcolor","\"#99ff99\"") if $usr eq $firstUsr;
$subsByUsr{$usr} = "<FONT COLOR=red>$subsByUsr{$usr}</FONT>" if $usr eq $lastUsr;
print &P4CGI::table_row({-align=>"center",
-text=>$pos},
$user,
{-align=>"center",
@bgcolor,
-text=>$subsByUsr{$usr}},
$status) ;
};
#
# Print page end
#
print "",
&P4CGI::end_table(),
"\n<br><br><SMALL>This page is best viewed with $bestViewed</SMALL>",
&P4CGI::end_page();

Просмотреть файл

@ -0,0 +1,109 @@
#!/usr/bin/perl -w
# -*- perl -*-
use P4CGI ;
use strict ;
#
#################################################################
# CONFIGURATION INFORMATION
# All config info should be in P4CGI.pm
#
#################################################################
#
# Search changes for pattern
#
#################################################################
my $FSPC = &P4CGI::cgi()->param("FSPC") ;
$FSPC = "//..." unless defined $FSPC ;
&P4CGI::bail("Invalid file spec.") if ($FSPC =~ /[<>"&:;'`]/);
my @legend ;
my $legend = "" ;
$legend = &P4CGI::ul_list(@legend) if @legend > 0 ;
&P4CGI::SET_HELP_TARGET("searchPattern") ;
print "", &P4CGI::start_page("Search Descriptions",$legend) ;
print "",
&P4CGI::start_table("bgcolor=".&P4CGI::HDRFTR_BGCOLOR()." align=center cellpadding=0 cellspacing=2"),
"<tr><td>\n" ;
sub prSelection($$$$ )
{
my $cgitarget = shift @_ ;
my $desc = shift @_ ;
my $fields = shift @_ ;
my $helpTarget = shift @_ ;
print "", &P4CGI::table_row(-valign=>"center",
{-align=>"center",
-text =>
join("\n",
&P4CGI::cgi()->startform(-action => $cgitarget,
-method => "GET"),
"<font size=+1>$desc</font>")},
{-align=>"left",
-valign=>"top",
-text => $fields},
{-align=>"left",
-text => " "},
{-align=>"left",
-valign=>"bottom",
-width=>"1",
-text => &P4CGI::cgi()->submit(-name => "ignore",
-value => "GO!")
},
{ -valign=>"bottom",
-text => &P4CGI::cgi()->endform()
},
) ;
} ;
print "", &P4CGI::start_table("width=100% cellspacing=4") ;
prSelection("changeList.cgi",
"Search for pattern<br>in change description",
join("\n",(&P4CGI::start_table(),
"<tr>",
"<td align=right valign=center>File spec:</td>",
"<td align=left valign=center><font face=fixed>",
&P4CGI::cgi()->textfield(-name => "FSPC",
-default => "//...",
-size => 50,
-maxlength => 256),
"</font></td></tr>",
"<td align=right valign=center>Pattern:</td>",
"<td align=left valign=center><font face=fixed>",
&P4CGI::cgi()->textfield(-name => "SEARCHDESC",
-default => "<pattern>",
-size => 50,
-maxlength => 256),
"</font></td></tr>",
"<td align=right valign=center>Invert search:</td>",
"<td align=left valign=center><font face=fixed>",
&P4CGI::cgi()->checkbox(-name => "SEARCH_INVERT",
-value => 1,
-label => " Search descriptions <B>NOT</B> including pattern"),
"</font></td></tr>",
"</table>")),
"searchPatt") ;
print &P4CGI::end_table() ;
print "</tr></td>",&P4CGI::end_table() ;
print
&P4CGI::end_page() ;
#
# That's all folks
#

Просмотреть файл

@ -0,0 +1,55 @@
#!/usr/bin/perl -w
# -*- perl -*-
use P4CGI ;
use strict ;
#
#################################################################
# CONFIGURATION INFORMATION
# All config info should be in P4CGI.pm
#
#################################################################
#
# P4 special file viewer for HTML, JPEG and GIF files
# View a "special" file
#
#################################################################
use viewConfig ;
$| = 1 ; # Turn output buffering off
# Get type arg
my $type = P4CGI::cgi()->param("TYPE") ;
&P4CGI::bail("No file type specified") unless defined $type ;
&P4CGI::bail("Invalid file type.") if ($type =~ /[<>"&:;'`]/);
# Get file spec argument
my $file = P4CGI::cgi()->param("FSPC") ;
&P4CGI::bail("No file specified") unless defined $file ;
&P4CGI::bail("Invalid file.") if ($file =~ /[<>"&:;'`]/);
my $revision = P4CGI::cgi()->param("REV") ;
$revision = "#$revision" if defined $revision ;
$revision="" unless defined $revision ;
&P4CGI::bail("Invalid revision.") unless ($revision =~ /^#?\d*$/);
my ($url,$desc,$content,$about) = @{$viewConfig::TypeData{$type}} ;
&P4CGI::bail("Undefined type code") unless defined $url ;
my $filename=$file ;
$filename =~ s/^.*\///;
print
"Content-Type: $content\n",
"Content-Disposition: filename=$filename\n",
"\n" ;
local *P4 ;
&P4CGI::p4call( *P4, "print -q \"$file$revision\"" );
while(<P4>) {
print ;
} ;
#
# That's all folks
#

Просмотреть файл

@ -0,0 +1,138 @@
#!/usr/bin/perl -w
# -*- perl -*-
use P4CGI ;
use strict ;
#
#################################################################
# CONFIGURATION INFORMATION
# All config info should be in P4CGI.pm
#
#################################################################
#
# P4 list all users
# List p4 users
#
#################################################################
my $GROUPSONLY = P4CGI::cgi()->param("GROUPSONLY") ;
$GROUPSONLY = "Y" if defined $GROUPSONLY;
sub weeksago($$$ ) {
my ($y,$m,$d) = @_ ;
$y -= 1900 ;
$m-- ;
my $_now = time() ;
my $_then = $_now ;
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
localtime($_then);
if(($y > $year) or
(($y == $year) and ($m > $mon)) or
(($y == $year) and ($m == $mon) and ($d > $mday))) {
return 0 ;
}
while(1) {
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
localtime($_then);
if(($y == $year) and ($m == $mon) and ($d == $mday)) {
return int(( $_now - $_then)/(3600*24*7)) ;
}
$_then -= 3600*24 ;
} ;
}
&P4CGI::SET_HELP_TARGET("userList") ;
# Get users
my @users ;
@users=&P4CGI::run_cmd("users" );
# Get groups
my @groups ;
@users=&P4CGI::run_cmd("groups" );
my $emailall ;
my $usertable = "" ;
unless(defined $GROUPSONLY) {
$usertable .= join("\n",("<B>",scalar(@users)," users:<br></B>",
&P4CGI::start_table("cellpadding=1"),
&P4CGI::table_header("User/view user",
"Name",
"e-mail address/send email",
"Last access"))) ;
my $userinfo ;
foreach $userinfo (sort { uc($a) cmp uc($b) } @users)
{
$userinfo =~ /(\w+)\s+\<(.*)\>\s+\((.*)\) accessed (\S+)/ and do {
my ($user,$email,$name,$lastaccess) = ($1,$2,$3,$4) ;
$user = &P4CGI::ahref(-url => "userView.cgi",
"USER=$user",
$user) ;
$email =~ /\w+\@\w+/ and do {
if(defined $emailall) {
$emailall .= ",$email" ;
} else {
$emailall = "mailto:$email" ;
} ;
$email = &P4CGI::ahref(-url => "mailto:$email",
$email) ;
} ;
my $weeksOld = "" ;
if($lastaccess =~ /(\d\d\d\d)\/(\d\d)\/(\d\d)/) {
$weeksOld = weeksago($1,$2,$3) ;
if($weeksOld > 10) {
$weeksOld = "<b>Not used for $weeksOld weeks!</b>" ;
}
else {
$weeksOld = "" ;
}
}
$usertable .= &P4CGI::table_row($user,
$name,
$email,
$lastaccess,
$weeksOld) ;
}
}
$usertable .= &P4CGI::end_table() ;
} ;
if(@groups > 0) {
my $g = @groups == 1?"group":"groups" ;
my $n = @groups ;
$usertable .= "<B>$n $g</B><br>" ;
$usertable .= &P4CGI::start_table("cellpadding=1") ;
$usertable .= &P4CGI::table_header("Group/view group");
foreach (@groups) {
$usertable .= &P4CGI::table_row(&P4CGI::ahref(-url => "groupView.cgi",
"GROUP=$_",
$_)) ;
}
$usertable .= &P4CGI::end_table() ;
}
my @legend ;
unless(defined $GROUPSONLY) {
push @legend ,("<b>user</b> -- see more info",
"<b>e-mail address</b> -- e-mail user",
&P4CGI::ahref(-url => $emailall,
"<b>Email all users</b>")) ;
} ;
push @legend,"<b>group</b> -- details about group" if @groups > 0 ;
unless(defined $GROUPSONLY) {
push @legend, &P4CGI::ahref("GROUPSONLY=Y",
"<b>Groups only</b>") ;
}
print "",
&P4CGI::start_page(defined $GROUPSONLY ? "P4 Groups":@groups > 0?"P4 Users and Groups":"P4 Users",
&P4CGI::ul_list(@legend)),
$usertable,
&P4CGI::end_page() ;
#
# That's all folks
#

Просмотреть файл

@ -0,0 +1,151 @@
#!/usr/bin/perl -Tw
# -*- perl -*-
use lib '.';
use P4CGI ;
use strict ;
#
#################################################################
# CONFIGURATION INFORMATION
# All config info should be in P4CGI.pm
#
#################################################################
#
# P4 list user
# List a p4 user
#
#################################################################
# Get parameter
my $user = P4CGI::cgi()->param("USER") ;
$user = P4CGI::extract_user($user);
# users may be specified with a client name,
# but do not look them up that way.
$user =~ s/\@.*$//;
unless(defined $user) {
&P4CGI::bail("No user specified!") ;
} ;
# List all users
my @userData = &P4CGI::run_cmd("users" );
my %userData = map { /^(\S+)/ ; ($1,1) ; } @userData ;
# Get user info
my %values ;
my @fields ;
if(exists $userData{$user}) {
@fields = &P4CGI::p4readform("user -o $user",\%values);
}
# Fix email
if(exists $values{"Email"}) {
my $em = &P4CGI::fixSpecChar($values{"Email"}) ;
$values{"Email"}=&P4CGI::ahref(-url => "mailto:$values{Email}",$em) ;
}
# Fix fullname
if(exists $values{"FullName"}) {
$values{"FullName"} = &P4CGI::fixSpecChar( $values{"FullName"}) ;
}
# Fix job view
if(exists $values{"JobView"}) {
my $v = $values{"JobView"} ;
$values{"JobView"} = &P4CGI::ahref(-url => "jobList.cgi",
"JOBVIEW=$v",
"LIST=Y",
$v) ;
}
# Fix group view
{
my @groups ;
@groups=&P4CGI::run_cmd("groups", $user) ;
if(@groups > 0) {
my $p = "In group" ;
if(@groups > 1) { $p .="s" ; } ;
push @fields,$p ;
$values{$p} = join(",", map { &P4CGI::ahref(-url => "groupView.cgi",
"GROUP=$_",
$_) ; } @groups) ;
}
}
print "",
&P4CGI::start_page("User $user",
&P4CGI::ul_list("<b>e-mail address</b> -- e-mail user",
"<b>JobView</b> -- list jobs for this view",
&P4CGI::ahref(-url => "clientList.cgi",
"USER=$user",
"List clients") .
" -- List clients owned by user $user",
&P4CGI::ahref(-url => "changeList.cgi",
"USER=$user",
"FSPC=//...",
"List changes by user") .
" -- List changes made by user $user",
&P4CGI::ahref(-url => "userList.cgi",
"List all users") .
" -- List all users and groups",
)) ;
unless(exists $userData{$user}) {
&P4CGI::signalError("User \"$user\" does not exist. ") ;
}
print
&P4CGI::start_table("") ;
my $f ;
foreach $f (@fields) {
print &P4CGI::table_row({-align => "right",
-type => "th",
-text => "$f"},
$values{$f}) ;
} ;
my $openfiles ;
&P4CGI::p4call(*P4, "opened -a" );
my $line=0 ;
while(<P4>) {
chomp ;
/ by $user\@/ and do {
$line++ ;
/^(.*\#\d+) - (\S+) .* by \w+\@(\S+)/ or do { &P4CGI::ERROR("Unable to parse line $line ($_)") ;
next ; } ;
my $file = $1 ;
my $reason = $2 ;
my $client = $3 ;
$client = &P4CGI::ahref(-url => "clientView.cgi",
"CLIENT=$client",
"<tt>$client</tt>") ;
$file =~ /(.*)\#(\d+)/ ;
if($reason ne "add") {
$file = &P4CGI::ahref(-url => "fileLogView.cgi",
"FSPC=$1",
"REV=$2",
"$file") ;
}
if(defined $openfiles) {
$openfiles .= "<br><tt>$file</tt> -&nbsp;<b>$reason</b>&nbsp;by&nbsp;client&nbsp;$client" ;
} else {
$openfiles = "<tt>$file</tt> -&nbsp;<b>$reason</b>&nbsp;by&nbsp;client&nbsp;$client" ;
} ;
} ;
} ;
if(defined $openfiles) {
print &P4CGI::table_row({-align => "right",
-type => "th",
-valign => "top",
-text => "Open&nbsp;files"},
"$openfiles") ;
} ;
print
&P4CGI::end_table(),
&P4CGI::end_page() ;
#
# That's all folks
#

Просмотреть файл

@ -0,0 +1,61 @@
#!/usr/bin/perl -w
# -*- perl -*-
package viewConfig ;
use strict ;
#
#
#################################################################
# Configuration file for special file viewer.
#################################################################
#
#
my %ExtensionToType ;
my %TypeData ;
BEGIN()
{
# Keys: file extension (in uppercase)
# value: A type code (must be unique)
%viewConfig::ExtensionToType =
(
HTML =>"HTML",
HTM =>"HTML",
GIF =>"GIF",
JPEG =>"JPEG",
JPG =>"JPEG",
DOC =>"WINWORD",
DOT =>"WINWORDT",
PPT =>"PWRPT",
RTF =>"RTF",
PDF =>"PDF",
) ;
# Special "about" url for html viewer
my $htmlAbout = &P4CGI::ahref(-url => "htmlFileView.cgi" ,
"TYPE=ABOUT",
"About the HTML viewer") ;
# Keys: Type code
# value: A referece to an array:
# [url for viewer,description of content, content type, optinal about]
%viewConfig::TypeData =
(
HTML =>["htmlFileView.cgi","html file using \"smart\" viewer and a browser","text/html",
$htmlAbout],
GIF =>["specialFileView.cgi" ,"gif image using browser","image/gif"],
JPEG =>["specialFileView.cgi" ,"jpeg image using browser","image/jpeg"],
WINWORD =>["specialFileView.cgi" ,"MS-Word document","application/msword"],
WINWORDT =>["specialFileView.cgi" ,"MS-Word template","application/msword"],
PWRTP =>["specialFileView.cgi" ,"MS-PowerPoint document","application/ppt"],
RTF =>["specialFileView.cgi" ,"RTF document","application/rtf"],
PDF =>["specialFileView.cgi" ,"PDF document","application/pdf"]
) ;
} ;
1;