using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace Perforce.P4
{
///
/// Represents a Perforce server and connection.
///
public partial class Repository : IDisposable
{
///
/// Create a repository on the specified server.
///
/// The repository server.///
public Repository (Server server)
{
Server = server;
}
public Server Server {get; private set;}
private Connection _connection;
public Connection Connection
{
get
{
if (_connection == null)
{
_connection = new Connection(Server);
}
return _connection;
}
}
///
/// Return a list of FileSpecs of files in the depot that correspond
/// to the passed-in FileSpecs.
///
///
///
///
///
///
p4 help files
///
///
files -- List files in the depot
///
///
p4 files [ -a ] [ -A ] [ -m max ] file[revRange] ...
///
///
List details about specified files: depot file name, revision,
///
file, type, change action and changelist number of the current
///
head revision. If client syntax is used to specify the file
///
argument, the client view mapping is used to determine the
///
corresponding depot files.
///
///
By default, the head revision is listed. If the file argument
///
specifies a revision, then all files at that revision are listed.
///
If the file argument specifies a revision range, the highest revision
///
in the range is used for each file. For details about specifying
///
revisions, see 'p4 help revisions'.
///
///
The -a flag displays all revisions within the specific range, rather
///
than just the highest revision in the range.
///
///
The -A flag displays files in archive depots.
///
///
The -m flag limits files to the first 'max' number of files.
///
///
///
///
/// To get a maximum of 10 files from the repository:
///
///
/// Options opts = new Options(GetFilesCmdFlags.None, 10);
/// FileSpec fs = new FileSpec(new DepotPath("//depot/..."), null);
/// List lfs = new List();
/// lfs.Add(fs);
/// IList<FileSpec> files = _repository.getDepotFiles(lfs, opts);
///
///
///
///
public IList GetDepotFiles(IList filespecs, Options options)
{
P4.P4Command filesCmd = new P4Command(this, "files", true, FileSpec.ToStrings(filespecs));
P4.P4CommandResult r = filesCmd.Run(options);
if (r.Success != true)
{
P4Exception.Throw(r.ErrorList);
return null;
}
if ((r.TaggedOutput == null) || (r.TaggedOutput.Count <= 0))
{
return null;
}
List value = new List();
foreach (P4.TaggedObject obj in r.TaggedOutput)
{
string path = obj["depotFile"];
PathSpec ps = new DepotPath(path);
int rev = 0;
int.TryParse(obj["rev"], out rev);
FileSpec fs = new FileSpec(ps, new Revision(rev));
value.Add(fs);
}
return value;
}
///
/// Return a list of FileSpecs of files opened for specified changelists.
///
///
///
///
///
///
p4 help opened
///
///
opened -- List open files and display file status
///
///
p4 opened [-a -c changelist# -C client -u user -m max] [file ...]
///
///
Lists files currently opened in pending changelists, or, for
///
specified files, show whether they are currently opened or locked.
///
If the file specification is omitted, all files open in the current
///
client workspace are listed.
///
///
The -a flag lists opened files in all clients. By default, only
///
files opened by the current client are listed.
///
///
The -c changelist# flag lists files opened in the specified
///
changelist#.
///
///
The -C client flag lists files open in the specified client workspace.
///
///
The -u user flag lists files opened by the specified user.
///
///
The -m max flag limits output to the first 'max' number of files.
///
///
///
public IList GetOpenedFiles(IList filespecs, Options options)
{
P4.P4Command openedCmd = new P4Command(this, "opened", true, FileSpec.ToStrings(filespecs));
P4.P4CommandResult r = openedCmd.Run(options);
if (r.Success != true)
{
P4Exception.Throw(r.ErrorList);
return null;
}
if ((r.TaggedOutput == null) || (r.TaggedOutput.Count <= 0))
{
return null;
}
List value = new List();
DepotPath dps = null;
ClientPath cps = null;
int revision = 0;
Revision rev = new Revision(0);
Revision haveRev = new Revision(0);
StringEnum action = null;
int change = -1;
FileType type = null;
DateTime submittime = DateTime.MinValue;
string user = string.Empty;
string client = string.Empty;
foreach (P4.TaggedObject obj in r.TaggedOutput)
{
if (obj.ContainsKey("depotFile"))
{
dps = new DepotPath(obj["depotFile"]);
}
if (obj.ContainsKey("clientFile"))
{
cps = new ClientPath(obj["clientFile"]);
}
if (obj.ContainsKey("rev"))
{
int.TryParse(obj["rev"], out revision);
rev = new Revision(revision);
}
if (obj.ContainsKey("haveRev"))
{
int.TryParse(obj["haveRev"], out revision);
haveRev = new Revision(revision);
}
if (obj.ContainsKey("action"))
{
action = obj["action"];
}
if (obj.ContainsKey("change"))
{
int.TryParse(obj["change"], out change);
}
if (obj.ContainsKey("type"))
{
type = new FileType(obj["type"]);
}
if (obj.ContainsKey("user"))
{
user = obj["user"];
}
if (obj.ContainsKey("client"))
{
client = obj["client"];
}
File f = new File(dps, cps, rev, haveRev, change, action, type, submittime, user, client);
value.Add(f);
}
return value;
}
///
/// Use the p4 fstat command to get the file metadata for the files
/// matching the FileSpec.
///
///
///
///
///
///
p4 help fstat
///
///
fstat -- Dump file info
///
///
p4 fstat [-F filter -L -T fields -m max -r] [-c | -e changelist#]
///
[-Ox -Rx -Sx] file[rev] ...
///
///
Fstat lists information about files, one line per file. Fstat is
///
intended for use in Perforce API applications, where the output can
///
be accessed as variables, but its output is also suitable for parsing
///
from the client command output in scripts.
///
///
The fields that fstat displays are:
///
///
clientFile -- local path (host or Perforce syntax)
///
depotFile -- name in depot
///
movedFile -- name in depot of moved to/from file
///
path -- local path (host syntax)
///
isMapped -- set if mapped client file is synced
///
shelved -- set if file is shelved
///
headAction -- action at head rev, if in depot
///
headChange -- head rev changelist#, if in depot
///
headRev -- head rev #, if in depot
///
headType -- head rev type, if in depot
///
headTime -- head rev changelist time, if in depot
///
headModTime -- head rev mod time, if in depot
///
movedRev -- head rev # of moved file
///
haveRev -- rev had on client, if on client
///
desc -- change description
///
digest -- MD5 digest (fingerprint)
///
fileSize -- file size
///
action -- open action, if opened
///
type -- open type, if opened
///
actionOwner -- user who opened file, if opened
///
change -- open changelist#, if opened
///
resolved -- resolved integration records
///
unresolved -- unresolved integration records
///
reresolvable -- reresolvable integration records
///
otherOpen -- set if someone else has it open
///
otherOpen# -- list of user@client with file opened
///
otherLock -- set if someone else has it locked
///
otherLock# -- user@client with file locked
///
otherAction# -- open action, if opened by someone else
///
otherChange# -- changelist, if opened by someone else
///
ourLock -- set if this user/client has it locked
///
resolveAction# -- pending integration record action
///
resolveBaseFile# -- pending integration base file
///
resolveBaseRev# -- pending integration base rev
///
resolveFromFile# -- pending integration from file
///
resolveStartFromRev# -- pending integration from start rev
///
resolveEndFromRev# -- pending integration from end rev
///
///
The -F flag lists only files satisfying the filter expression. This
///
filter syntax is similar to the one used for 'jobs -e jobview' and is
///
used to evaluate the contents of the fields in the preceding list.
///
Filtering is case-sensitive.
///
///
Example: -Ol -F "fileSize > 1000000 & headType=text"
///
///
Note: filtering is not optimized with indexes for performance.
///
///
The -L flag can be used with multiple file arguments that are in
///
full depot syntax and include a valid revision number. When this
///
flag is used the arguments are processed together by building an
///
internal table similar to a label. This file list processing is
///
significantly faster than having to call the internal query engine
///
for each individual file argument. However, the file argument syntax
///
is strict and the command will not run if an error is encountered.
///
///
The -T fields flag returns only the specified fields. The field names
///
can be specified using a comma- or space-delimited list.
///
///
Example: -Ol -T "depotFile, fileSize"
///
///
The -m max flag limits output to the specified number of files.
///
///
The -r flag sorts the output in reverse order.
///
///
The -c changelist# flag displays files modified after the specified
///
changelist was submitted. This operation is much faster than using
///
a revision range on the affected files.
///
///
The -e changelist# flag lists files modified by the specified
///
changelist. When used with the -Ro flag, only pending changes are
///
considered, to ensure that files opened for add are included. This
///
option also displays the change description.
///
///
The -O options modify the output as follows:
///
///
-Of output all revisions for the given files (this
///
option suppresses other* and resolve* fields)
///
///
-Ol output a fileSize and digest field for each revision
///
(this may be expensive to compute)
///
///
-Op output the local file path in both Perforce syntax
///
(//client/) as 'clientFile' and host form as 'path'
///
///
-Or output pending integration record information for
///
files opened on the current client, or if used with
///
'-e <change> -Rs', on the shelved change
///
///
-Os exclude client-related data from output
///
///
The -R option limits output to specific files:
///
///
-Rc files mapped in the client view
///
-Rh files synced to the client workspace
///
-Rn files opened not at the head revision
///
-Ro files opened
///
-Rr files opened that have been resolved
///
-Rs files shelved (requires -e)
///
-Ru files opened that need resolving
///
///
The -S option changes the order of output:
///
///
-St sort by filetype
///
-Sd sort by date
///
-Sr sort by head revision
///
-Sh sort by have revision
///
-Ss sort by filesize
///
///
For compatibility, the following flags are also supported:
///
-C (-Rc) -H (-Rh) -W (-Ro) -P (-Op) -l (-Ol) -s (-Os).
///
///
///
public IList GetFileMetaData(Options options, params FileSpec[] filespecs)
{
string[] paths = FileSpec.ToEscapedStrings(filespecs);
P4.P4Command fstatCmd = new P4Command(this, "fstat", true, paths);
P4.P4CommandResult r = fstatCmd.Run(options);
if (r.Success != true)
{
P4Exception.Throw(r.ErrorList);
return null;
}
if ((r.TaggedOutput == null) || (r.TaggedOutput.Count <= 0))
{
return null;
}
List value = new List();
foreach (P4.TaggedObject obj in r.TaggedOutput)
{
FileMetaData fmd = new FileMetaData();
fmd.FromFstatCmdTaggedData(obj);
value.Add(fmd);
}
return value;
}
public IList GetFileMetaData(IList filespecs, Options options)
{
return GetFileMetaData(options, filespecs.ToArray());
}
///
/// Get the File objects associated with the passed-in FileSpec list.
///
///
///
///
///
///
p4 help files
///
///
files -- List files in the depot
///
///
p4 files [ -a ] [ -A ] [ -m max ] file[revRange] ...
///
///
List details about specified files: depot file name, revision,
///
file, type, change action and changelist number of the current
///
head revision. If client syntax is used to specify the file
///
argument, the client view mapping is used to determine the
///
corresponding depot files.
///
///
By default, the head revision is listed. If the file argument
///
specifies a revision, then all files at that revision are listed.
///
If the file argument specifies a revision range, the highest revision
///
in the range is used for each file. For details about specifying
///
revisions, see 'p4 help revisions'.
///
///
The -a flag displays all revisions within the specific range, rather
///
than just the highest revision in the range.
///
///
The -A flag displays files in archive depots.
///
///
The -m flag limits files to the first 'max' number of files.
///
///
///
public IList GetFiles(Options options, params FileSpec[] filespecs)
{
P4.P4Command fstatCmd = new P4Command(this, "files", true, FileSpec.ToStrings(filespecs));
P4.P4CommandResult r = fstatCmd.Run(options);
if (r.Success != true)
{
P4Exception.Throw(r.ErrorList);
return null;
}
if ((r.TaggedOutput == null) || (r.TaggedOutput.Count <= 0))
{
return null;
}
List value = new List();
foreach (P4.TaggedObject obj in r.TaggedOutput)
{
File val = new File();
val.ParseFilesCmdTaggedData(obj);
value.Add(val);
}
return value;
}
public IList GetFiles(IList filespecs, Options options)
{
return GetFiles(options, filespecs.ToArray());
}
///
/// List selected directory paths in the repository.
///
///
///
///
///
///
p4 help dirs
///
///
dirs -- List depot subdirectories
///
///
p4 dirs [-C -D -H] [-S stream] dir[revRange] ...
///
///
List directories that match the specified file pattern (dir).
///
This command does not support the recursive wildcard (...).
///
Use the * wildcard instead.
///
///
Perforce does not track directories individually. A path is treated
///
as a directory if there are any undeleted files with that path as a
///
prefix.
///
///
By default, all directories containing files are listed. If the dir
///
argument includes a revision range, only directories containing files
///
in the range are listed. For details about specifying file revisions,
///
see 'p4 help revisions'.
///
///
The -C flag lists only directories that fall within the current
///
client view.
///
///
The -D flag includes directories containing only deleted files.
///
///
The -H flag lists directories containing files synced to the current
///
client workspace.
///
///
The -S flag limits output to depot directories mapped in a stream's
///
client view.
///
///
///
public IList GetDepotDirs(Options options, params string[] dirs)
{
P4.P4Command dirsCmd = new P4Command(this, "dirs", false, dirs);
P4.P4CommandResult r = dirsCmd.Run(options);
if (r.Success != true)
{
P4Exception.Throw(r.ErrorList);
return null;
}
List value = new List();
foreach (P4.InfoLine l in r.InfoOutput)
{
value.Add(l.Info);
}
return value;
}
public IList GetDepotDirs(IList dirs, Options options)
{
return GetDepotDirs(options, dirs.ToArray());
}
///
/// Return the contents of the files identified by the passed-in file specs.
///
///
///
///
/// GetFileContents
///
///
p4 help print
///
///
print -- Write a depot file to standard output
///
///
p4 print [-a -o localFile -q] file[revRange] ...
///
///
Retrieve the contents of a depot file to the client's standard output.
///
The file is not synced. If file is specified using client syntax,
///
Perforce uses the client view to determine the corresponding depot
///
file.
///
///
By default, the head revision is printed. If the file argument
///
includes a revision, the specified revision is printed. If the
///
file argument has a revision range, then only files selected by
///
that revision range are printed, and the highest revision in the
///
range is printed. For details about revision specifiers, see 'p4
///
help revisions'.
///
///
The -a flag prints all revisions within the specified range, rather
///
than just the highest revision in the range.
///
///
The -o localFile flag redirects the output to the specified file on
///
the client filesystem.
///
///
The -q flag suppresses the initial line that displays the file name
///
and revision.
///
///
///
public IList GetFileContents(Options options, params FileSpec[] filespecs)
{
P4.P4Command printCmd = new P4Command(this, "print", true, FileSpec.ToEscapedStrings(filespecs));
P4.P4CommandResult r = printCmd.Run(options);
if (r.Success != true)
{
P4Exception.Throw(r.ErrorList);
return null;
}
IList value = new List();
if (r.TaggedOutput != null)
{
if ((options == null) ||
(options.ContainsKey("-q") == false))
{
foreach (P4.TaggedObject obj in r.TaggedOutput)
{
string path = string.Empty;
string rev = string.Empty;
if (obj.ContainsKey("depotFile"))
{
value.Add(obj["depotFile"]);
}
}
}
}
value.Add(r.TextOutput);
return value;
}
public IList GetFileContents(IList filespecs, Options options)
{
return GetFileContents(options, filespecs.ToArray());
}
///
/// Get the revision history data for the passed-in file specs.
///
///
/// See:
///
///
///
p4 help filelog
///
///
filelog -- List revision history of files
///
///
p4 filelog [-c changelist# -h -i -l -L -t -m maxRevs -s] file[revRange] ...
///
///
List the revision history of the specified files, from the most
///
recent revision to the first. If the file specification includes
///
a revision, the command lists revisions at or prior to the specified
///
revision. If the file specification includes a revision range,
///
the command lists only the specified revisions. See 'p4 help revisions'
///
for details.
///
///
The -c changelist# flag displays files submitted at the specified
///
changelist number.
///
///
The -i flag includes inherited file history. If a file was created by
///
branching (using 'p4 integrate'), filelog lists the revisions of the
///
file's ancestors up to the branch points that led to the specified
///
revision. File history inherited by renaming (using 'p4 move') is
///
always displayed regardless of whether -i is specified.
///
///
The -h flag displays file content history instead of file name
///
history. The list includes revisions of other files that were
///
branched or copied (using 'p4 integrate' and 'p4 resolve -at') to
///
the specified revision. Revisions that were replaced by copying
///
or branching are omitted, even if they are part of the history of
///
the specified revision.
///
///
The -t flag displays the time as well as the date.
///
///
The -l flag lists the full text of the changelist descriptions.
///
///
The -L flag lists the full text of the changelist descriptions,
///
truncated to 250 characters if longer.
///
///
The -m maxRevs displays at most 'maxRevs' revisions per file of
///
the file[rev] argument specified.
///
///
The -s flag displays a shortened form of filelog that omits
///
non-contributory integrations.
///
///
///
///
public IList GetFileHistory(Options options, params FileSpec[] filespecs)
{
P4.P4Command filesCmd = new P4Command(this, "filelog", true, FileSpec.ToEscapedStrings(filespecs));
P4.P4CommandResult r = filesCmd.Run(options);
if (r.Success != true)
{
P4Exception.Throw(r.ErrorList);
return null;
}
if ((r.TaggedOutput == null) || (r.TaggedOutput.Count <= 0))
{
return null;
}
IList value = new List();
foreach (P4.TaggedObject obj in r.TaggedOutput)
{
int idx = 0;
while (true)
{
string key = String.Format("rev{0}", idx);
int revision = -1;
if (obj.ContainsKey(key))
int.TryParse(obj[key], out revision);
else
break;
int changelistid = -1;
key = String.Format("change{0}", idx);
if (obj.ContainsKey(key))
int.TryParse(obj[key], out changelistid);
StringEnum action = "None";
key = String.Format("action{0}", idx);
if (obj.ContainsKey(key))
action = obj[key];
DateTime date = new DateTime();
long unixTime = 0;
key = String.Format("time{0}", idx);
if (obj.ContainsKey(key))
unixTime = Int64.Parse(obj[key]);
date = new DateTime(1970, 1, 1, 0, 0, 0, 0).AddSeconds(unixTime);
string username = null;
key = String.Format("user{0}", idx);
if (obj.ContainsKey(key))
username = obj[key];
string description = null;
key = String.Format("desc{0}", idx);
if (obj.ContainsKey(key))
description = obj[key];
string digest = null;
key = String.Format("digest{0}", idx);
if (obj.ContainsKey(key))
digest = obj[key];
long filesize = -1;
key = String.Format("fileSize{0}", idx);
if (obj.ContainsKey(key))
long.TryParse(obj[key], out filesize);
string clientname = null;
key = String.Format("client{0}", idx);
if (obj.ContainsKey(key))
clientname = obj[key];
PathSpec depotpath = new DepotPath(obj["depotFile"]);
FileType filetype = null;
key = String.Format("type{0}", idx);
if (obj.ContainsKey(key))
filetype = new FileType(obj[key]);
List integrationsummaries = new List();
int idx2 = 0;
key = String.Format("how{0},{1}", idx, idx2);
while (obj.ContainsKey(key))
{
string how = obj[key];
key = String.Format("file{0},{1}", idx, idx2);
string frompath = obj[key];
key = String.Format("srev{0},{1}", idx, idx2);
string srev = obj[key];
VersionSpec startrev = new Revision(-1);
if (srev.StartsWith("#h")
|
srev.StartsWith("#n"))
{
if (srev.Contains("#none"))
{
startrev = Revision.None;
}
if (srev.Contains("#have"))
{
startrev = Revision.Have;
}
if (srev.Contains("#head"))
{
startrev = Revision.Head;
}
}
else
{
srev = srev.Trim('#');
int rev = Convert.ToInt16(srev);
startrev = new Revision(rev);
}
key = String.Format("erev{0},{1}", idx, idx2);
string erev = obj[key];
VersionSpec endrev = new Revision(-1);
if (erev.StartsWith("#h")
|
erev.StartsWith("#n"))
{
if (erev.Contains("#none"))
{
endrev = Revision.None;
}
if (srev.Contains("#have"))
{
endrev = Revision.Have;
}
if (srev.Contains("#head"))
{
endrev = Revision.Head;
}
}
else
{
erev = erev.Trim('#');
int rev = Convert.ToInt16(erev);
endrev = new Revision(rev);
}
RevisionIntegrationSummary integrationsummary = new RevisionIntegrationSummary(
new FileSpec(new DepotPath(frompath),
new VersionRange(startrev, endrev)), how);
integrationsummaries.Add(integrationsummary);
idx2++;
key = String.Format("how{0},{1}", idx, idx2);
}
FileHistory fh = new FileHistory(revision, changelistid, action,
date, username, filetype, description, digest, filesize, depotpath, clientname, integrationsummaries);
value.Add(fh);
idx++;
}
}
return value;
}
public IList GetFileHistory(IList filespecs, Options options)
{
return GetFileHistory(options, filespecs.ToArray());
}
///
/// Get content and existence diff details for two depot files.
///
///
///
///
///
///
p4 help diff
///
///
diff -- Display diff of client file with depot file
///
///
p4 diff [-d<flags> -f -m max -s<flag> -t] [file[rev] ...]
///
///
On the client machine, diff a client file against the corresponding
///
revision in the depot. The file is compared only if the file is
///
opened for edit or a revision is provided. See 'p4 help revisions'
///
for details about specifying revisions.
///
///
If the file specification is omitted, all open files are diffed.
///
This option can be used to view pending changelists.
///
///
The -d<flags> modify the output as follows: -dn (RCS), -dc[n] (context),
///
-ds (summary), -du[n] (unified), -db (ignore whitespace changes),
///
-dw (ignore whitespace), -dl (ignore line endings). The optional
///
argument to -dc specifies number of context lines.
///
///
The -f flag diffs every file, regardless of whether they are opened
///
or the client has synced the specified revision. This option can be
///
used to verify the contents of the client workspace.
///
///
The -m max flag limits output to the first 'max' number of files,
///
unless the -s flag is used, in which case it is ignored.
///
///
The -s options lists the files that satisfy the following criteria:
///
///
-sa Opened files that differ from the revision
///
in the depot or are missing.
///
///
-sb Files that have been opened for integrate, resolved,
///
and subsequently modified.
///
///
-sd Unopened files that are missing on the client.
///
///
-se Unopened files that differ from the revision
///
in the depot.
///
///
-sl Every unopened file, along with the status of
///
'same, 'diff', or 'missing' as compared to the
///
corresponding revision in the depot.
///
///
-sr Opened files that do not differ from the revision in
///
the depot.
///
///
The -t flag forces 'p4 diff' to diff binary files.
///
///
If the environment variable $P4DIFF is set, the specified diff
///
program is launched in place of the default Perforce client diff.
///
The -d<flags> option can be used to pass arguments to the diff
///
program. Because the -s flag is only implemented internally, any
///
-d<flags> option used with the -s<flag> is ignored. To configure a
///
diff program for Unicode files, set the environment variable
///
$P4DIFFUNICODE. Specify the file's character set as the first
///
argument to the program.
///
///
///
public IList GetDepotFileDiffs(string filespecleft, string filespecright, Options options)
{
P4.P4Command GetDepotFileDiffs = new P4Command(this, "diff2", true, filespecleft, filespecright);
P4.P4CommandResult r = GetDepotFileDiffs.Run(options);
if (r.Success != true)
{
P4Exception.Throw(r.ErrorList);
return null;
}
if ((r.TaggedOutput == null) || (r.TaggedOutput.Count <= 0))
{
return null;
}
IList value = new List();
foreach (P4.TaggedObject obj in r.TaggedOutput)
{
DepotFileDiff val = new DepotFileDiff();
val.FromGetDepotFileDiffsCmdTaggedOutput(obj, _connection);
value.Add(val);
}
return value;
}
///
/// Return FileAnnotation objects for the listed FileSpecs.
///
///
///
///
///
///
p4 help annotate
///
///
annotate -- Print file lines and their revisions
///
///
p4 annotate [-aciIq -d<flags>] file[revRange] ...
///
///
Prints all lines of the specified files, indicating the revision that
///
introduced each line into the file.
///
///
If the file argument includes a revision, then only revisions up to
///
the specified revision are displayed. If the file argument has a
///
revision range, only revisions within that range are displayed. For
///
details about specifying revisions, see 'p4 help revisions'.
///
///
The -a flag includes both deleted files and lines no longer present
///
at the head revision. In the latter case, both the starting and ending
///
revision for each line is displayed.
///
///
The -c flag directs the annotate command to output changelist numbers
///
rather than revision numbers for each line.
///
///
The -d<flags> change the way whitespace and/or line endings are
///
treated: -db (ignore whitespace changes), -dw (ignore whitespace),
///
-dl (ignore line endings).
///
///
The -i flag follows branches. If a file was created by branching,
///
'p4 annotate' includes the revisions of the source file up to the
///
branch point, just as 'p4 filelog -i' does. If a file has history
///
prior to being created by branching (such as a file that was branched
///
on top of a deleted file), -i ignores those prior revisions and
///
follows the source. -i implies -c.
///
///
The -I flag follows all integrations into the file. If a line was
///
introduced into the file by a merge, the source of the merge is
///
displayed as the changelist that introduced the line. If the source
///
itself was the result of an integration, that source is used instead,
///
and so on. -I implies -c.
///
///
The -q flag suppresses the one-line header that is displayed by
///
default for each file.
///
///
///
public IList GetFileAnnotations(IList filespecs, Options options)
{
P4.P4Command annotateCmd = new P4Command(this, "annotate", true, FileSpec.ToStrings(filespecs));
P4.P4CommandResult r = annotateCmd.Run(options);
if (r.Success != true)
{
P4Exception.Throw(r.ErrorList);
return null;
}
if ((r.TaggedOutput == null) || (r.TaggedOutput.Count <= 0))
{
return null;
}
bool changelist = false;
string opts;
if (options != null)
{
opts = options.Keys.ToString();
if (opts.Contains("c"))
{ changelist = true; }
}
string dp = null;
string line = null;
int lower = -1;
int upper = -1;
IList value = new List();
//FileAnnotation fa = new FileAnnotation(new FileSpec(new DepotPath(dp), new VersionRange(lower, upper)), line);
foreach (P4.TaggedObject obj in r.TaggedOutput)
{
if (obj.ContainsKey("depotFile"))
{
dp = obj["depotFile"];
line = null;
lower = -1;
upper = -1;
continue;
}
if (obj.ContainsKey("lower"))
{
int l = -1;
int.TryParse(obj["lower"], out l);
lower = l;
}
if (obj.ContainsKey("upper"))
{
int u = -1;
int.TryParse(obj["upper"], out u);
upper = u;
}
if (obj.ContainsKey("data"))
{
line = obj["data"];
}
if (dp != null
&&
line != null
&&
lower != -1
&&
upper != -1)
{
FileSpec fs = new FileSpec();
if (changelist == true)
{
fs = new FileSpec(new DepotPath(dp), new VersionRange(new ChangelistIdVersion(lower), new ChangelistIdVersion(upper)));
}
else
{
fs = new FileSpec(new DepotPath(dp), new VersionRange(new Revision(lower), new Revision(upper)));
}
FileAnnotation fa = new FileAnnotation(fs, line);
value.Add(fa);
}
}
return value;
}
///
/// Tag depot files with the passed-in label.
///
///
///
///
///
///
///
p4 help tag
///
///
tag -- Tag files with a label
///
///
p4 tag [-d -n] -l label file[revRange] ...
///
///
Tag associates the named label with the file revisions specified by
///
the file argument. After file revisions are tagged with a label,
///
revision specifications of the form '@label' can be used to refer
///
to them.
///
///
If the file argument does not include a revision specification, the
///
head revisions is tagged. See 'p4 help revisions' for revision
///
specification options.
///
///
If the file argument includes a revision range specification, only
///
the files with revisions in that range are tagged. Files with more
///
than one revision in the range are tagged at the highest revision.
///
///
The -d deletes the association between the specified files and the
///
label, regardless of revision.
///
///
The -n flag previews the results of the operation.
///
///
Tag can be used with an existing label (see 'p4 help labels') or
///
with a new one. An existing label can be used only by its owner,
///
and only if it is unlocked. (See 'p4 help label').
///
///
To list the file revisions tagged with a label, use 'p4 files
///
@label'.
///
///
///
public IList TagFiles(IList filespecs, string labelid, Options options)
{
P4.P4Command tagCmd = new P4Command(this, "tag", true, FileSpec.ToStrings(filespecs));
options["-l"] = labelid;
P4.P4CommandResult r = tagCmd.Run(options);
if (r.Success != true)
{
P4Exception.Throw(r.ErrorList);
return null;
}
if ((r.TaggedOutput == null) || (r.TaggedOutput.Count <= 0))
{
return null;
}
IList value = new List();
foreach (P4.TaggedObject obj in r.TaggedOutput)
{
string revision = obj["rev"];
int rev = Convert.ToInt16(revision);
VersionSpec version = new Revision(rev);
DepotPath path = new DepotPath(obj["depotFile"]);
FileSpec fs = new FileSpec(path, version);
value.Add(fs);
}
return value;
}
///
/// List fixes affecting files and / or jobs and / or changelists.
///
///
///
///
///
///
p4 help fixes
///
///
fixes -- List jobs with fixes and the changelists that fix them
///
///
p4 fixes [-i -m max -c changelist# -j jobName] [file[revRange] ...]
///
///
'p4 fixes' list fixed jobs and the number of the changelist that
///
contains the fix.Fixes are associated with changelists using the
///
'p4 fix' command or by editing and submitting changelists.
///
///
The 'p4 fixes' command lists both submitted and pending changelists.
///
///
By default, 'p4 fixes' lists all fixes. This list can be limited
///
as follows: to list fixes for a specified job, use the -j jobName
///
flag. To list fixes for a specified changelist, use -c changelist#.
///
To list fixes that affect specified files, include the file argument.
///
The file pattern can include wildcards and revision specifiers. For
///
details about revision specifiers, see 'p4 help revisions'
///
///
The -i flag also includes any fixes made by changelists integrated
///
into the specified files.
///
///
The -m max flag limits output to the specified number of job
///
fixes.
///
///
///
public IList GetFixes(IList filespecs, Options options)
{
P4.P4Command fixesCmd = new P4Command(this, "fixes", true, FileSpec.ToStrings(filespecs));
P4.P4CommandResult r = fixesCmd.Run(options);
if (r.Success != true)
{
P4Exception.Throw(r.ErrorList);
return null;
}
if ((r.TaggedOutput == null) || (r.TaggedOutput.Count <= 0))
{
return null;
}
IList value = new List();
foreach (P4.TaggedObject obj in r.TaggedOutput)
{
value.Add(Fix.FromFixesCmdTaggedOutput(obj));
}
return value;
}
///
/// Get a list of matching lines in the passed-in file specs.
///
///
///
///
///
///
///
p4 help grep
///
///
grep -- Print lines matching a pattern
///
///
p4 grep [options] -e pattern file[revRange]...
///
///
options: -a -i -n -A <num> -B <num> -C <num> -t -s (-v|-l|-L) (-F|-G)
///
///
Searches files for lines that match the specified regular expression,
///
which can contain wildcards. The parser used by the Perforce server
///
is based on V8 regexp and might not be compatible with later parsers,
///
but the majority of functionality is available.
///
///
By default the head revision is searched. If the file argument includes
///
a revision specification, all corresponding revisions are searched.
///
If the file argument includes a revision range, only files in that
///
range are listed, and the highest revision in the range is searched.
///
For details about revision specifiers, see 'p4 help revisions'.
///
///
The -a flag searches all revisions within the specified range. By
///
default only the highest revision in the range is searched.
///
///
The -i flag causes the pattern matching to be case-insensitive. By
///
default, matching is case-sensitive.
///
///
The -n flag displays the matching line number after the file revision
///
number. By default, matches are displayed as revision#: <text>.
///
///
The -v flag displays files with non-matching lines.
///
///
The -F flag is used to interpret the pattern as a fixed string.
///
///
The -G flag is used to interpret the pattern as a regular expression,
///
which is the default behavior.
///
///
The -L flag displays the name of each selected file from which no
///
output would normally have been displayed. Scanning stops on the
///
first match.
///
///
The -l flag display the name of each selected file containing
///
matching text. Scanning stops on the first match.
///
///
The -s flag suppresses error messages that result from abandoning
///
files that have a maximum number of characters in a single line that
///
are greater than 4096. By default, an error is reported when grep
///
abandons such files.
///
///
The -t flag searches binary files. By default, only text files are
///
searched.
///
///
The -A <num> flag displays the specified number of lines of trailing
///
context after matching lines.
///
///
The -B <num> flag displays the specified number of lines of leading
///
context before matching lines.
///
///
The -C <num> flag displays the specified number of lines of output
///
context.
///
///
Regular expressions:
///
///
A regular expression is zero or more branches, separated by `|'. It
///
matches anything that matches one of the branches.
///
///
A branch is zero or more pieces, concatenated. It matches a match
///
for the first, followed by a match for the second, etc.
///
///
A piece is an atom possibly followed by `*', `+', or `?'. An atom
///
followed by `*' matches a sequence of 0 or more matches of the atom.
///
An atom followed by `+' matches a sequence of 1 or more matches of
///
the atom. An atom followed by `?' matches a match of the atom, or
///
the null string.
///
///
An atom is a regular expression in parentheses (matching a match for
///
the regular expression), a range (see below), `.' (matching any
///
single character), `^' (matching the null string at the beginning
///
of the input string), `$' (matching the null string at the end of
///
the input string), a `\' followed by a single character (matching
///
that character), or a single character with no other significance
///
(matching that character).
///
///
A range is a sequence of characters enclosed in `[]'. It normally
///
matches any single character from the sequence. If the sequence
///
begins with `^', it matches any single character not from the rest
///
of the sequence. If two characters in the sequence are separated by
///
`-', this is shorthand for the full list of ASCII characters between
///
them (e.g. `[0-9]' matches any decimal digit). To include a literal
///
`]' in the sequence, make it the first character (following a possible
///
`^'). To include a literal `-', make it the first or last character.
///
///
///
public IList GetFileLineMatches(IList filespecs, string pattern, Options options)
{
P4.P4Command grepCmd = new P4Command(this, "grep", true, FileSpec.ToStrings(filespecs));
options["-e"] = pattern;
P4.P4CommandResult r = grepCmd.Run(options);
if (r.Success != true)
{
P4Exception.Throw(r.ErrorList);
return null;
}
if ((r.TaggedOutput == null) || (r.TaggedOutput.Count <= 0))
{
return null;
}
IList value = new List();
foreach (P4.TaggedObject obj in r.TaggedOutput)
{
FileLineMatch val = new FileLineMatch();
val.ParseGrepCmdTaggedData(obj);
value.Add(val);
}
return value;
}
///
/// Get a list of submitted integrations for the passed-in file specs.
///
///
///
///
///
///
p4 help integrated
///
///
integrated -- List integrations that have been submitted
///
///
p4 integrated [-r] [-b branch] [file ...]
///
///
The p4 integrated command lists integrations that have been submitted.
///
To list unresolved integrations, use 'p4 resolve -n'. To list
///
resolved but unsubmitted integrations, use 'p4 resolved'.
///
///
If the -b branch flag is specified, only files integrated from the
///
source to target files in the branch view are listed. Qualified
///
files are listed, even if they were integrated without using the
///
branch view.
///
///
The -r flag reverses the mappings in the branch view, swapping the
///
target files and source files. The -b branch flag is required.
///
///
///
public IList GetSubmittedIntegrations(IList filespecs, Options options)
{
P4.P4Command integratedCmd = new P4Command(this, "integrated", true, FileSpec.ToStrings(filespecs));
P4.P4CommandResult r = integratedCmd.Run(options);
if (r.Success != true)
{
P4Exception.Throw(r.ErrorList);
return null;
}
if ((r.TaggedOutput == null) || (r.TaggedOutput.Count <= 0))
{
return null;
}
IList value = new List();
foreach (P4.TaggedObject obj in r.TaggedOutput)
{
FileIntegrationRecord val = new FileIntegrationRecord();
val.ParseIntegratedCmdTaggedData(obj);
value.Add(val);
}
return value;
}
///
/// Get a list of Perforce protection entries for the passed-in file specs
///
///
///
///
///
///
p4 help protects
///
///
protects -- Display protections defined for a specified user and path
///
///
p4 protects [-a | -g group | -u user] [-h host] [-m] [file ...]
///
///
'p4 protects' displays the lines from the protections table that
///
apply to the current user. The protections table is managed using
///
the 'p4 protect' command.
///
///
If the -a flag is specified, protection lines for all users are
///
displayed. If the -g group flag or -u user flag is specified,
///
protection lines for that group or user are displayed.
///
///
If the -h host flag is specified, the protection lines that apply
///
to the specified host (IP address) are displayed.
///
///
If the -m flag is given, a single word summary of the maximum
///
access level is reported. Note that this summary does not take
///
exclusions into account.
///
///
If the file argument is specified, protection lines that apply to
///
the specified files are displayed.
///
///
The -a/-g/-u flags require 'super' access granted by 'p4 protect'.
///
///
///
public IList GetProtectionEntries(IList filespecs, Options options)
{
P4.P4Command protectsCmd = new P4Command(this, "protects", true, FileSpec.ToStrings(filespecs));
P4.P4CommandResult r = protectsCmd.Run(options);
if (r.Success != true)
{
P4Exception.Throw(r.ErrorList);
return null;
}
if ((r.TaggedOutput == null) || (r.TaggedOutput.Count <= 0))
{
return null;
}
IList value = new List();
foreach (P4.TaggedObject obj in r.TaggedOutput)
{
StringEnum mode = obj["perm"];
StringEnum type = "User";
if (obj.ContainsKey("isgroup"))
{
type = "Group";
}
string name = obj["user"];
string host = obj["host"];
string path = obj["depotFile"];
ProtectionEntry pte = new ProtectionEntry(mode, type, name, host, path);
value.Add(pte);
}
return value;
}
///
/// List Perforce users assigned to review files.
///
///
///
///
///
///
p4 help reviews
///
///
reviews -- List the users who are subscribed to review files
///
///
p4 reviews [-c changelist#] [file ...]
///
///
'p4 reviews' lists all users who have subscribed to review the
///
specified files, the files in the specified changelist, or all files
///
(the default). To subscribe to review files, issue the 'p4 user'
///
command and edit the 'Reviews field'.
///
///
///
public IList GetReviewers (IList filespecs, Options options)
{
P4.P4Command reviewsCmd = new P4Command(this, "reviews", true, FileSpec.ToStrings(filespecs));
P4.P4CommandResult r = reviewsCmd.Run(options);
if (r.Success != true)
{
P4Exception.Throw(r.ErrorList);
return null;
}
if ((r.TaggedOutput == null) || (r.TaggedOutput.Count <= 0))
{
return null;
}
List value = new List();
foreach (P4.TaggedObject obj in r.TaggedOutput)
{
string id = obj["user"];
string fullname = obj["name"];
string password = string.Empty;
string emailaddress = obj["email"];
DateTime updated = DateTime.MinValue;
DateTime accessed = DateTime.MinValue;
string jobview = string.Empty;
List reviews = new List();
UserType type = UserType.Standard;
FormSpec spec = new FormSpec(null,null, null, null, null, null, null);
User user = new User(id, fullname, password, emailaddress, updated, accessed, jobview, reviews, type, spec);
value.Add(user);
}
return value;
}
///
/// Get a FormSpec of the specified form type.
///
///
///
///
///
///
p4 help spec
///
///
spec -- Edit spec definitions (unsupported)
///
///
p4 spec [-d -i -o] type
///
///
Edit any type of specification: branch, change, client, depot,
///
group, job, label, spec, stream, trigger, typemap, or user. Only
///
the comments and the formatting hints can be changed. Any fields
///
that you add during editing are discarded when the spec is saved.
///
///
'p4 jobspec' is equivalent to 'p4 spec job', and any custom spec
///
(include the job spec) can be deleted with 'p4 spec -d type'.
///
///
///
public FormSpec GetFormSpec(Options options, string spectype)
{
StringList cmdArgs = new StringList();
cmdArgs.Add(spectype);
P4.P4Command specCmd = new P4Command(this, "spec", true, cmdArgs);
P4.P4CommandResult r = specCmd.Run(options);
if (r.Success != true)
{
P4Exception.Throw(r.ErrorList);
return null;
}
if ((r.TaggedOutput == null) || (r.TaggedOutput.Count <= 0))
{
return null;
}
foreach (P4.TaggedObject obj in r.TaggedOutput)
{
FormSpec val = FormSpec.FromSpecCmdTaggedOutput(obj);
return val;
}
return null;
}
///
/// Get the repository's trigger table.
///
///
///
///
///
p4 help triggers
///
///
triggers -- Modify list of server triggers
///
///
p4 triggers
///
p4 triggers -o
///
p4 triggers -i
///
///
'p4 triggers' edits the table of triggers, which are used for
///
change submission validation, form validation, external authentication,
///
external job fix integration, and external archive integration.
///
///
Triggers are administrator-defined commands that the server runs
///
to perform the following:
///
///
Validate changelist submissions.
///
///
The server runs changelist triggers before the file transfer,
///
between file transfer and changelist commit, or after the commit
///
///
Validate shelve operations.
///
///
The server runs shelve triggers before files are shelved, after
///
files are shelved, or when shelved files have been discarded
///
(via shelve -d).
///
///
Manipulate and validate forms.
///
///
The server runs form-validating triggers between generating
///
and outputting the form, between inputting and parsing the
///
form, between parsing and saving the form, or when deleting
///
the form.
///
///
Authenticate or change a user password.
///
///
The server runs authentication triggers to either validate
///
a user password during login or when setting a new password.
///
///
Intercept job fix additions or deletions.
///
///
The server run fix triggers prior to adding or deleting a fix
///
between a job and changelist.
///
///
Access external archive files.
///
///
For files with the +X filetype modifier, the server runs an
///
archive trigger to read, write, or delete files in the archive.
///
///
The trigger form has a single entry 'Triggers', followed by any
///
number of trigger lines. Triggers are executed in the order listed
///
and if a trigger fails, subsequent triggers are not run. A trigger
///
succeeds if the executed command exits returning 0 and fails otherwise.
///
Normally the failure of a trigger prevents the operation from
///
completing, except for the commit triggers, which run after the
///
operation is complete.
///
///
Each trigger line contains a trigger name, a trigger type, a depot
///
file path pattern or form type, and a command to run.
///
///
Name: The name of the trigger. For change triggers, a run of the
///
same trigger name on contiguous lines is treated as a single
///
trigger so that multiple paths can be specified. Only the
///
command of the first such trigger line is used.
///
///
Type: When the trigger is to execute:
///
///
archive:
///
Execute an archive trigger for the server to access
///
any file with the +X filetype modifier.
///
///
auth-check:
///
service-check:
///
Execute an authentication check trigger to verify a
///
user's password against an external password manager
///
during login or when setting a new password.
///
///
auth-check-sso:
///
Facilitate a single sign-on user authentication. This
///
configuration requires two programs or scripts to run;
///
one on the client, the other on the server.
///
///
client:
///
Set the environment variable 'P4LOGINSSO' to point to
///
a script that can be executed to obtain the user's
///
credentials or other information that the server
///
trigger can verify. The client-side script must
///
write the message to the standard output
///
(max length 128K).
///
///
Example: P4LOGINSSO=/Users/joe/bin/runsso
///
///
The 'server address' can be optionally passed to the
///
client script by appending %serverAddress% to the
///
client command string, as in:
///
///
P4LOGINSSO="/Users/joe/bin/runsso %serverAddress%"
///
///
server:
///
Execute an authentication (sso) trigger that gets
///
this message from the standard input and returns an
///
exit status of 0 (for verified) or otherwise failed.
///
///
Example:
///
sso auth-check-sso auth "/secure/verify %user%"
///
///
The user must issue the 'p4 login' command, but no
///
password prompting is invoked. If the server
///
determines that the user is valid, they are issued a
///
Perforce ticket just as if they had logged in with a
///
password.
///
///
Pre-2007.2 clients cannot run a client-side single
///
sign-on. Specifying an 'auth-check' trigger as a backup
///
for a user to gain access will prompt the user for a
///
password if it's an older client or P4LOGINSSO has not
///
been configured.
///
///
Unlike passwords which are encrypted, the sso message is
///
sent to the server in clear text.
///
///
auth-set:
///
Execute an authentication set trigger to send a new
///
password to an external password manager.
///
///
change-submit:
///
Execute pre-submit trigger after changelist has been
///
created and files locked but prior to file transfer.
///
///
change-content:
///
Execute mid-submit trigger after file transfer but prior
///
to commit. Files can be accessed by the 'p4 diff2',
///
'p4 files', 'p4 fstat', and 'p4 print' commands using
///
the revision specification '@=change', where 'change' is
///
the pending changelist number passed as %changelist%.
///
///
change-commit:
///
Execute post-submit trigger after changelist commit.
///
///
fix-add:
///
Execute fix trigger prior to adding a fix. The special
///
variable %jobs% is available for expansion and must be
///
the last argument to the trigger as it expands to one
///
argument for each job listed on the 'p4 fix' command.
///
///
fix-delete:
///
Execute fix trigger prior to deleting a fix. The special
///
variable %jobs% is available for expansion and must be
///
the last argument to the trigger as it expands to one
///
argument for each job listed on the 'p4 fix -d' command.
///
///
form-out:
///
Execute form trigger on generation of form. Trigger may
///
modify form.
///
///
form-in:
///
Execute form trigger on input of form before its contents
///
are parsed and validated. Trigger may modify form.
///
///
form-save:
///
Execute form trigger prior to save of form after its
///
contents are parsed.
///
///
form-commit:
///
Execute form trigger after it has been committed, allowing
///
access to automatically generated fields (jobname, dates
///
etc). It cannot modify the form. This trigger for job
///
forms is run by 'p4 job' and 'p4 fix' (after the status
///
is updated), 'p4 change' (if the job is added or deleted)
///
and 'p4 submit' (if the job is associated with the change).
///
The 'form-commit' trigger has access to the new job name
///
created with 'p4 job', while the 'form-in' and 'form-save'
///
triggers are run before the job name is created. The
///
special variable %action% is available on the job
///
'form-commit' trigger command line, and is expanded when
///
the job is modified by a fix.
///
///
form-delete:
///
Execute form trigger prior to delete of form after its
///
contents are parsed.
///
///
shelve-submit:
///
Execute pre-shelve trigger after changelist has been
///
created but prior to file transfer.
///
///
shelve-commit:
///
Execute post-shelve trigger after files are shelved.
///
///
shelve-delete:
///
Execute shelve trigger prior to discarding shelved files.
///
///
Path: For change and submit triggers, a file pattern to match files
///
in the changelist. This file pattern can be an exclusion
///
mapping (-pattern), to exclude files. For form triggers, the
///
name of the form (branch, client, etc). For fix triggers
///
'fix' is required as the path value. For authentication
///
triggers, 'auth' is required as the path value. For archive
///
triggers, a file pattern to match the name of the file being
///
accessed in the archive. Note that, due to lazy copying when
///
branching files, the name of the file in the archive can not
///
be the same as the name of the file in the depot.
///
///
Command: The OS command to run for validation. If the command
///
contains spaces, enclose it in double quotes. The
///
following variables are expanded in the command string:
///
///
%client% -- the client issuing the command
///
%clienthost% -- the hostname of the client
///
%clientip% -- the IP address of the client
///
%serverhost% -- the hostname of the server
///
%serverip% -- the IP address of the server
///
%serverport% -- the IP address:port of the server
///
%serverroot% -- the value of the server's $P4ROOT
///
%user% -- the user issuing the command
///
///
%changelist% -- the changelist being submitted
///
%changeroot% -- the root path of files submitted
///
%oldchangelist% -- the pre-commit changelist number
///
///
(More information can be gathered about the
///
changelist being submitted by running
///
'p4 describe %changelist%'.)
///
///
%formfile% -- path to temp file containing form
///
%formname% -- the form's name (branch name, etc)
///
%formtype% -- the type of form (branch, etc)
///
%action% -- added/deleted/submitted on job form-commit
///
///
%jobs% -- list of job names for fix triggers
///
///
%op% -- read/write/delete for archive access
///
%file% -- name of archive file
///
%rev% -- revision of archive file
///
///
The command's standard input is empty for change, shelve,
///
fix, and auth triggers; it is the form contents for form
///
triggers; and it is the file content for the archive trigger.
///
///
If the command fails, the command's standard output (not
///
error output) is sent to the client as the text of a trigger
///
failure error message.
///
///
If the command succeeds, the command's standard output is
///
sent as an unadorned message to the client for all triggers
///
except archive triggers; for archive triggers, the command's
///
standard output is the file content.
///
///
The -o flag writes the trigger table to the standard output.
///
The user's editor is not invoked.
///
///
The -i flag reads the trigger table from the standard input.
///
The user's editor is not invoked.
///
///
'p4 triggers' requires 'super' access granted by 'p4 protect'.
///
///
///
public IList GetTriggerTable(Options options)
{
P4.P4Command triggersCmd = new P4Command(this, "triggers", true);
P4.P4CommandResult r = triggersCmd.Run(options);
if (r.Success != true)
{
P4Exception.Throw(r.ErrorList);
return null;
}
if ((r.TaggedOutput == null) || (r.TaggedOutput.Count <= 0))
{
return null;
}
List value = new List();
foreach (P4.TaggedObject obj in r.TaggedOutput)
{
System.Text.StringBuilder sb = new StringBuilder();
foreach (KeyValuePair key in obj)
{
sb.Remove(0, sb.Length);
sb.AppendLine((string.Format("{0} {1}", key.Key.ToString(), key.Value)));
string line = sb.ToString();
if (line.StartsWith("Triggers"))
{
line = line.Trim();
string[] entries = line.Split(' ');
string name = entries[1];
string ent = entries[2];
ent = ent.Replace("-","");
StringEnum type = ent;
string path = entries[3];
string command = entries[4] + " " + entries[5];
string ord = entries[0];
ord = ord.Remove(0, 8);
int order = 0;
order = Convert.ToInt16(ord);
Trigger trig = new Trigger(name, order, type, path, command);
value.Add(trig);
}
}
}
return value;
}
///
/// Get the repository's type map.
///
///
///
/// runs the command p4 typemap -o
///
///
///
p4 help typemap
///
///
typemap -- Edit the filename-to-filetype mapping table
///
///
p4 typemap
///
p4 typemap -o
///
p4 typemap -i
///
///
'p4 typemap' edits a name-to-type mapping table for 'p4 add', which
///
uses the table to assign a file's filetype based on its name.
///
///
The typemap form has a single field, 'TypeMap', followed by any
///
number of typemap lines. Each typemap line contains a filetype
///
and a depot file path pattern:
///
///
Filetype: See 'p4 help filetypes' for a list of valid filetypes.
///
///
Path: Names to be mapped to the filetype. The mapping is
///
a file pattern in depot syntax. When a user adds a file
///
matching this pattern, its default filetype is the
///
file type specified in the table. To exclude files from
///
the typemap, use exclusionary (-pattern) mappings.
///
To match all files anywhere in the depot hierarchy,
///
the pattern must begin with '//...'. To match files
///
with a specified suffix, use '//.../*.suffix' or
///
use '//....suffix' (four dots).
///
///
Later entries override earlier entries. If no matching entry is found
///
in the table, 'p4 add' determines the filetype by examining the file's
///
contents and execution permission bits.
///
///
The -o flag writes the typemap table to standard output. The user's
///
editor is not invoked.
///
///
The -i flag reads the typemap table from standard input. The user's
///
editor is not invoked.
///
///
'p4 typemap' requires 'admin' access, which is granted by 'p4 protect'.
///
///
///
public IList GetTypeMap()
{
P4.P4Command typemapCmd = new P4Command(this, "typemap", true, "-o");
P4.P4CommandResult r = typemapCmd.Run();
if (r.Success != true)
{
P4Exception.Throw(r.ErrorList);
return null;
}
if ((r.TaggedOutput == null) || (r.TaggedOutput.Count <= 0))
{
return null;
}
List value = new List();
foreach (P4.TaggedObject obj in r.TaggedOutput)
{
int ord = 0;
string key = String.Format("TypeMap{0}", ord);
while (obj.ContainsKey(key))
{
value.Add(new TypeMapEntry(obj[key]));
ord++;
key = String.Format("TypeMap{0}", ord);
}
return value;
}
return value;
}
//public string CreateSpec(List map)
//{
// StringBuilder val = new StringBuilder(map.Count * 256);
// val.AppendLine("TypeMap:");
// for (int idx = 0; idx < map.Count; idx++)
// {
// val.AppendLine(String.Format("/t{0}", map[idx].ToString()));
// }
// return base.ToString();
//}
///
/// Get the repository's protection table.
///
///
///
///
///
p4 help protect
///
///
protect -- Modify protections in the server namespace
///
///
p4 protect
///
p4 protect -o
///
p4 protect -i
///
///
'p4 protect' edits the protections table in a text form.
///
///
Each line in the table contains a protection mode, a group/user
///
indicator, the group/user name, client host ID and a depot file
///
path pattern. Users receive the highest privilege that is granted
///
on any line.
///
///
Note: remote depot are accessed using the pseudo-user 'remote'.
///
To control access from other servers that define your server as
///
a remote server, grant appropriate permissions to the 'remote' user.
///
///
Mode: The permission level or right being granted or denied.
///
Each permission level includes all the permissions above
///
it, except for 'review'. Each permission only includes
///
the specific right and no lesser rights. This approach
///
enables you to deny individual rights without having to
///
re-grant lesser rights. Modes prefixed by '=' are rights.
///
All other modes are permission levels.
///
///
Valid modes are:
///
///
list - users can see names but not contents of files;
///
users can see all non-file related metadata
///
(clients, users, changelists, jobs, etc.)
///
///
read - users can sync, diff, and print files
///
///
open - users can open files (add, edit. delete,
///
integrate)
///
///
write - users can submit open files
///
///
admin - permits those administrative commands and
///
command options that don't affect the server's
///
security.
///
///
super - access to all commands and command options.
///
///
review - permits access to the 'p4 review' command;
///
implies read access
///
///
=read - if this right is denied, users can't sync,
///
diff, or print files
///
///
=branch - if this right is denied, users are not
///
permitted to use files as a source
///
for 'p4 integrate'
///
///
=open = if this right is denied, users cannot open
///
files (add, edit, delete, integrate)
///
///
=write = if this right is denied, users cannot submit
///
open files
///
///
Group/User indicator: specifies the grantee is a group or user.
///
///
Name: A Perforce group or user name; can include wildcards.
///
///
Host: The IP address of a client host; can include wildcards.
///
///
Path: The part of the depot to which access is being granted
///
or denied. To deny access to a depot path, preface the
///
path with a "-" character. These exclusionary mappings
///
apply to all access levels, even if only one access
///
level is specified in the first field.
///
///
The -o flag writes the protection table to the standard output.
///
The user's editor is not invoked.
///
///
The -i flag reads the protection table from the standard input.
///
The user's editor is not invoked.
///
///
After protections are defined, 'p4 protect' requires 'super'
///
access.
///
///
///
public IList GetProtectionTable(Options options)
{
P4.P4Command protectCmd = new P4Command(this, "protect", true);
P4.P4CommandResult r = protectCmd.Run(options);
if (r.Success != true)
{
P4Exception.Throw(r.ErrorList);
return null;
}
if ((r.TaggedOutput == null) || (r.TaggedOutput.Count <= 0))
{
return null;
}
List value = new List();
foreach (P4.TaggedObject obj in r.TaggedOutput)
{
System.Text.StringBuilder sb = new StringBuilder();
foreach (KeyValuePair key in obj)
{
sb.Remove(0, sb.Length);
sb.AppendLine((string.Format("{0} {1}", key.Key.ToString(), key.Value)));
string line = sb.ToString();
if (line.StartsWith("Protections"))
{
line = line.Trim();
string[] entries = line.Split(' ');
StringEnum mode = entries[1];
StringEnum type = entries[2];
string grouporusername = entries[3];
string host = entries[4];
string path = entries[5];
ProtectionEntry pe = new ProtectionEntry(mode, type, grouporusername, host, path);
value.Add(pe);
}
}
}
return value;
}
///
/// Get the Perforce counters for this repository.
///
///
///
///
///
p4 help counters
///
///
counters -- Display list of known counters
///
///
p4 counters
///
///
Lists the counters in use by the server. The server
///
uses the following counters directly:
///
///
change Current change number
///
job Current job number
///
journal Current journal number
///
lastCheckpointAction Data about the last complete checkpoint
///
logger Event log index used by 'p4 logger'
///
traits Internal trait lot number used by 'p4 attribute'
///
upgrade Server database upgrade level
///
///
Other counters can be created by the 'p4 counter' or 'p4 review'
///
commands.
///
///
The names 'minClient', 'minClientMessage', 'monitor',
///
'security', and 'unicode' are reserved names: do not use them
///
as ordinary counters.
///
///
For general-purpose server configuration, see 'p4 help configure'.
///
///
///
public IList GetCounters(Options options)
{
P4.P4Command countersCmd = new P4Command(this, "counters", true);
P4.P4CommandResult r = countersCmd.Run(options);
if (r.Success != true)
{
P4Exception.Throw(r.ErrorList);
return null;
}
if ((r.TaggedOutput == null) || (r.TaggedOutput.Count <= 0))
{
return null;
}
IList val = new List();
foreach (P4.TaggedObject obj in r.TaggedOutput)
{
string name = obj["counter"];
string value = obj["value"];
Counter counter = new Counter(name, value);
val.Add(counter);
}
return val;
}
///
/// Get a named Perforce counter value from the repository.
///
///
///
///
///
///
p4 help counter
///
///
counter -- Display, set, or delete a counter
///
///
p4 counter name
///
p4 counter [-f] name value
///
p4 counter [-f] -d name
///
p4 counter [-f] -i name
///
///
The first form displays the value of the specified counter.
///
///
The second form sets the counter to the specified value.
///
///
The third form deletes the counter. This option usually has the
///
same effect as setting the counter to 0.
///
///
The -f flag sets or deletes counters used by Perforce, which are
///
listed by 'p4 help counters'. Important: Never set the 'change'
///
counter to a value that is lower than its current value.
///
///
The -i flag increments a counter by 1 and returns the new value.
///
This option is used instead of a value argument and can only be
///
used with numeric counters.
///
///
Counters can be assigned textual values as well as numeric ones,
///
despite the name 'counter'.
///
///
'p4 counter' requires 'review' access granted by 'p4 protect'.
///
The -f flag requires that the user be an operator or have 'super'
///
access.
///
///
///
public Counter GetCounter(String name, Options options)
{
P4.P4Command counterCmd = new P4.P4Command(_connection, "counter", true, name);
P4.P4CommandResult r = counterCmd.Run(options);
if (r.Success != true)
{
P4Exception.Throw(r.ErrorList);
return null;
}
if ((r.TaggedOutput == null) || (r.TaggedOutput.Count <= 0))
{
return null;
}
foreach (P4.TaggedObject obj in r.TaggedOutput)
{
string countername = obj["counter"];
string value = obj["value"];
Counter counter = new Counter(countername, value);
return counter;
}
return null;
}
///
/// Delete a Perforce counter from the repository.
///
///
///
///
///
///
p4 help counter
///
///
counter -- Display, set, or delete a counter
///
///
p4 counter name
///
p4 counter [-f] name value
///
p4 counter [-f] -d name
///
p4 counter [-f] -i name
///
///
The first form displays the value of the specified counter.
///
///
The second form sets the counter to the specified value.
///
///
The third form deletes the counter. This option usually has the
///
same effect as setting the counter to 0.
///
///
The -f flag sets or deletes counters used by Perforce, which are
///
listed by 'p4 help counters'. Important: Never set the 'change'
///
counter to a value that is lower than its current value.
///
///
The -i flag increments a counter by 1 and returns the new value.
///
This option is used instead of a value argument and can only be
///
used with numeric counters.
///
///
Counters can be assigned textual values as well as numeric ones,
///
despite the name 'counter'.
///
///
'p4 counter' requires 'review' access granted by 'p4 protect'.
///
The -f flag requires that the user be an operator or have 'super'
///
access.
///
///
///
public Object DeleteCounter(String name, Options options)
{
StringList cmdArgs = new StringList();
cmdArgs.Add("-f");
cmdArgs.Add("-d");
cmdArgs.Add(name);
P4.P4Command delcounterCmd = new P4Command(this, "counter", false, cmdArgs);
P4.P4CommandResult r = delcounterCmd.Run(options);
if (r.Success != true)
{
P4Exception.Throw(r.ErrorList);
return null;
}
return r.InfoOutput;
}
#region IDisposable Members
public void Dispose()
{
_connection.Dispose();
}
#endregion
}
}