using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; namespace Perforce.P4 { /// <summary> /// Represents a Perforce server and connection. /// </summary> public partial class Repository : IDisposable { /// <summary> /// Create a repository on the specified server. /// </summary> /// <param name="server">The repository server.</param> public Repository (Server server) { Server = server; } /// <summary> /// Represents a specific Perforce server. /// </summary> public Server Server {get; private set;} private Connection _connection; /// <summary> /// Represents the logical connection between a specific Perforce Server /// instance and a specific client application. /// </summary> public Connection Connection { get { if (_connection == null) { _connection = new Connection(Server); } return _connection; } } /// <summary> /// Return a list of FileSpecs of files in the depot that correspond /// to the passed-in FileSpecs. /// </summary> /// <param name="filespecs"></param> /// <param name="options"></param> /// <returns></returns> /// <remarks> /// <br/><b>p4 help files</b> /// <br/> /// <br/> files -- List files in the depot /// <br/> /// <br/> p4 files [ -a ] [ -A ] [ -e ] [ -m max ] file[revRange] ... /// <br/> p4 files -U unloadfile ... /// <br/> /// <br/> List details about specified files: depot file name, revision, /// <br/> file, type, change action and changelist number of the current /// <br/> head revision. If client syntax is used to specify the file /// <br/> argument, the client view mapping is used to determine the /// <br/> corresponding depot files. /// <br/> /// <br/> By default, the head revision is listed. If the file argument /// <br/> specifies a revision, then all files at that revision are listed. /// <br/> If the file argument specifies a revision range, the highest revision /// <br/> in the range is used for each file. For details about specifying /// <br/> revisions, see 'p4 help revisions'. /// <br/> /// <br/> The -a flag displays all revisions within the specific range, rather /// <br/> than just the highest revision in the range. /// <br/> /// <br/> The -A flag displays files in archive depots. /// <br/> /// <br/> The -e flag displays files with an action of anything other than /// <br/> deleted, purged or archived. Typically this revision is always /// <br/> available to sync or integrate from. /// <br/> /// <br/> The -m flag limits files to the first 'max' number of files. /// <br/> /// <br/> The -U option displays files in the unload depot (see 'p4 help /// <br/> unload' for more information about the unload depot). /// <br/> /// </remarks> /// <example> /// To get a maximum of 10 files from the repository: /// <code> /// /// GetDepotFilesCmdOptions opts = /// new GetDepotFilesCmdOptions(GetDepotFilesCmdFlags.None, 10); /// FileSpec fs = new FileSpec(new DepotPath("//depot/..."), null); /// List<FileSpec> lfs = new List<FileSpec>(); /// lfs.Add(fs); /// IList<FileSpec> files = Repository.GetDepotFiles(lfs, opts); /// /// </code> /// </example> /// <seealso cref="GetDepotFilesCmdFlags"/> public IList<FileSpec> GetDepotFiles(IList<FileSpec> 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<FileSpec> value = new List<FileSpec>(); 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; } /// <summary> /// Return a list of Files opened by users / clients. /// </summary> /// <param name="filespecs"></param> /// <param name="options"></param> /// <returns></returns> /// <remarks> /// <br/><b>p4 help opened</b> /// <br/> /// <br/> opened -- List open files and display file status /// <br/> /// <br/> p4 opened [-a -c changelist# -C client -u user -m max -s] [file ...] /// <br/> p4 opened [-a -x -m max ] [file ...] /// <br/> /// <br/> Lists files currently opened in pending changelists, or, for /// <br/> specified files, show whether they are currently opened or locked. /// <br/> If the file specification is omitted, all files open in the current /// <br/> client workspace are listed. /// <br/> /// <br/> Files in shelved changelists are not displayed by this command. To /// <br/> display shelved changelists, see 'p4 changes -s shelved'; to display /// <br/> the files in those shelved changelists, see 'p4 describe -s -S'. /// <br/> /// <br/> The -a flag lists opened files in all clients. By default, only /// <br/> files opened by the current client are listed. /// <br/> /// <br/> The -c changelist# flag lists files opened in the specified /// <br/> changelist#. /// <br/> /// <br/> The -C client flag lists files open in the specified client workspace. /// <br/> /// <br/> The -u user flag lists files opened by the specified user. /// <br/> /// <br/> The -m max flag limits output to the first 'max' number of files. /// <br/> /// <br/> The -s option produces 'short' and optimized output when used with /// <br/> the -a (all clients) option. For large repositories '-a' can take /// <br/> a long time when compared to '-as'. /// <br/> /// <br/> The -x option lists files that are opened 'exclusive'. This option /// <br/> only applies to a distributed installation where global tracking of /// <br/> these file types is necessary across servers. The -x option implies /// <br/> the -a option. /// <br/> /// </remarks> /// <example> /// To get a maximum of 10 opened files from the repository, opened by /// user fred, opened with any client: /// <code> /// /// FileSpec fs = new FileSpec(new DepotPath("//..."), null); /// /// List<FileSpec> lfs = new List<FileSpec>(); /// lfs.Add(fs); /// /// // null for changelist and client options /// GetOpenedFilesOptions opts = /// new GetOpenedFilesOptions(GetOpenedFilesCmdFlags.AllClients, /// null, null, "fred", 10); /// /// IList<File> target = Repository.GetOpenedFiles(lfs, opts); /// </code> /// </example> /// <seealso cref="GetOpenedFilesCmdFlags"/> public IList<File> GetOpenedFiles(IList<FileSpec> 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<File> value = new List<File>(); DepotPath dps = null; ClientPath cps = null; int revision = 0; Revision rev = new Revision(0); Revision haveRev = new Revision(0); StringEnum<FileAction> 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; } /// <summary> /// Use the p4 fstat command to get the file metadata for the files /// matching the FileSpec. /// </summary> /// <param name="filespecs"></param> /// <param name="options"></param> /// <returns></returns> /// <remarks> /// <br/><b>p4 help fstat</b> /// <br/> /// <br/> fstat -- Dump file info /// <br/> /// <br/> p4 fstat [-F filter -L -T fields -m max -r] [-c | -e changelist#] /// <br/> [-Ox -Rx -Sx] file[rev] ... /// <br/> /// <br/> Fstat lists information about files, one line per file. Fstat is /// <br/> intended for use in Perforce API applications, where the output can /// <br/> be accessed as variables, but its output is also suitable for parsing /// <br/> from the client command output in scripts. /// <br/> /// <br/> The fields that fstat displays are: /// <br/> /// <br/> attr-<name> -- attribute value for <name> /// <br/> attrProp-<name> -- set if attribute <name> is propagating /// <br/> clientFile -- local path (host or Perforce syntax) /// <br/> depotFile -- name in depot /// <br/> movedFile -- name in depot of moved to/from file /// <br/> path -- local path (host syntax) /// <br/> isMapped -- set if mapped client file is synced /// <br/> shelved -- set if file is shelved /// <br/> headAction -- action at head rev, if in depot /// <br/> headChange -- head rev changelist#, if in depot /// <br/> headRev -- head rev #, if in depot /// <br/> headType -- head rev type, if in depot /// <br/> headCharset -- head charset, for unicode type /// <br/> headTime -- head rev changelist time, if in depot /// <br/> headModTime -- head rev mod time, if in depot /// <br/> movedRev -- head rev # of moved file /// <br/> haveRev -- rev had on client, if on client /// <br/> desc -- change description /// <br/> digest -- MD5 digest (fingerprint) /// <br/> fileSize -- file size /// <br/> action -- open action, if opened /// <br/> type -- open type, if opened /// <br/> charset -- open charset, for unicode type /// <br/> actionOwner -- user who opened file, if opened /// <br/> change -- open changelist#, if opened /// <br/> resolved -- resolved integration records /// <br/> unresolved -- unresolved integration records /// <br/> reresolvable -- reresolvable integration records /// <br/> otherOpen -- set if someone else has it open /// <br/> otherOpen# -- list of user@client with file opened /// <br/> otherLock -- set if someone else has it locked /// <br/> otherLock# -- user@client with file locked /// <br/> otherAction# -- open action, if opened by someone else /// <br/> otherChange# -- changelist, if opened by someone else /// <br/> openattr-<name> -- attribute value for <name> /// <br/> openattrProp-<name> -- set if attribute <name> is propagating /// <br/> ourLock -- set if this user/client has it locked /// <br/> resolveAction# -- pending integration record action /// <br/> resolveBaseFile# -- pending integration base file /// <br/> resolveBaseRev# -- pending integration base rev /// <br/> resolveFromFile# -- pending integration from file /// <br/> resolveStartFromRev# -- pending integration from start rev /// <br/> resolveEndFromRev# -- pending integration from end rev /// <br/> totalFileCount -- total no. of files, if sorted /// <br/> /// <br/> The -A <pattern> flag restricts displayed attributes to those /// <br/> that match 'pattern'. /// <br/> /// <br/> The -F flag lists only files satisfying the filter expression. This /// <br/> filter syntax is similar to the one used for 'jobs -e jobview' and is /// <br/> used to evaluate the contents of the fields in the preceding list. /// <br/> Filtering is case-sensitive. /// <br/> /// <br/> Example: -Ol -F "fileSize > 1000000 & headType=text" /// <br/> /// <br/> Note: filtering is not optimized with indexes for performance. /// <br/> /// <br/> The -L flag can be used with multiple file arguments that are in /// <br/> full depot syntax and include a valid revision number. When this /// <br/> flag is used the arguments are processed together by building an /// <br/> internal table similar to a label. This file list processing is /// <br/> significantly faster than having to call the internal query engine /// <br/> for each individual file argument. However, the file argument syntax /// <br/> is strict and the command will not run if an error is encountered. /// <br/> /// <br/> The -T fields flag returns only the specified fields. The field names /// <br/> can be specified using a comma- or space-delimited list. /// <br/> /// <br/> Example: -Ol -T "depotFile, fileSize" /// <br/> /// <br/> The -m max flag limits output to the specified number of files. /// <br/> /// <br/> The -r flag sorts the output in reverse order. /// <br/> /// <br/> The -c changelist# flag displays files modified after the specified /// <br/> changelist was submitted. This operation is much faster than using /// <br/> a revision range on the affected files. /// <br/> /// <br/> The -e changelist# flag lists files modified by the specified /// <br/> changelist. When used with the -Ro flag, only pending changes are /// <br/> considered, to ensure that files opened for add are included. This /// <br/> option also displays the change description. /// <br/> /// <br/> The -O options modify the output as follows: /// <br/> /// <br/> -Oa output attributes set by 'p4 attribute'. /// <br/> /// <br/> -Od output the digest of the attribute. /// <br/> /// <br/> -Oe output attribute values encoded as hex /// <br/> /// <br/> -Of output all revisions for the given files (this /// <br/> option suppresses other* and resolve* fields) /// <br/> /// <br/> -Ol output a fileSize and digest field for each revision /// <br/> (this may be expensive to compute) /// <br/> /// <br/> -Op output the local file path in both Perforce syntax /// <br/> (//client/) as 'clientFile' and host form as 'path' /// <br/> /// <br/> -Or output pending integration record information for /// <br/> files opened on the current client, or if used with /// <br/> '-e <change> -Rs', on the shelved change /// <br/> /// <br/> -Os exclude client-related data from output /// <br/> /// <br/> The -R option limits output to specific files: /// <br/> /// <br/> -Rc files mapped in the client view /// <br/> -Rh files synced to the client workspace /// <br/> -Rn files opened not at the head revision /// <br/> -Ro files opened /// <br/> -Rr files opened that have been resolved /// <br/> -Rs files shelved (requires -e) /// <br/> -Ru files opened that need resolving /// <br/> /// <br/> The -S option changes the order of output: /// <br/> /// <br/> -St sort by filetype /// <br/> -Sd sort by date /// <br/> -Sr sort by head revision /// <br/> -Sh sort by have revision /// <br/> -Ss sort by filesize /// <br/> /// <br/> The -U flag displays information about unload files in the unload /// <br/> depot (see 'p4 help unload'). /// <br/> /// <br/> For compatibility, the following flags are also supported: /// <br/> -C (-Rc) -H (-Rh) -W (-Ro) -P (-Op) -l (-Ol) -s (-Os). /// <br/> /// <br/> /// </remarks> /// <example> /// To get FileMetaData for //depot/ReadMe.txt: /// <code> /// /// FileSpec fs = new FileSpec(new DepotPath("//depot/MyCode/ReadMe.txt"), null); /// /// GetFileMetaDataCmdOptions opts = /// new GetFileMetaDataCmdOptions(GetFileMetadataCmdFlags.None, /// null, null, 0, null, null, null); /// /// IList<FileMetaData> target = Repository.GetFileMetaData(opts, fs); /// </code> /// To get FileMetaData for files in the depot that need resolving: /// <code> /// /// FileSpec fs = new FileSpec(new DepotPath("//..."), null); /// /// GetFileMetaDataCmdOptions opts = /// new GetFileMetaDataCmdOptions(GetFileMetadataCmdFlags.NeedsResolve, /// null, null, 0, null, null, null); /// /// IList<FileMetaData> target = Repository.GetFileMetaData(opts, fs); /// </code> /// To get FileMetaData for files in the depot that are over a specific file /// size and of file type, text: /// <code> /// /// FileSpec fs = new FileSpec(new DepotPath("//..."), null); /// /// GetFileMetaDataCmdOptions opts = /// new GetFileMetaDataCmdOptions(GetFileMetadataCmdFlags.None, /// "fileSize > 1000000 & headType=text", null, 0, null, null, null); /// /// IList<FileMetaData> target = Repository.GetFileMetaData(opts, fs); /// </code> /// To get FileMetaData for files in the depot that have been modified at or /// after changelist 20345 and are mapped to the client view: /// <code> /// /// FileSpec fs = new FileSpec(new DepotPath("//..."), null); /// /// GetFileMetaDataCmdOptions opts = /// new GetFileMetaDataCmdOptions(GetFileMetadataCmdFlags.ClientMapped, /// null, null, 20345, null, null, null); /// /// IList<FileMetaData> target = Repository.GetFileMetaData(opts, fs); /// </code> /// To get FileMetaData for files in the depot including attributes which match /// the pattern "tested": /// <code> /// /// FileSpec fs = new FileSpec(new DepotPath("//..."), null); /// /// GetFileMetaDataCmdOptions opts = /// new GetFileMetaDataCmdOptions(GetFileMetadataCmdFlags.Attributes, /// null, null, 0, null, null, "tested"); /// /// IList<FileMetaData> target = Repository.GetFileMetaData(opts, fs); /// </code> /// </example> /// <seealso cref="GetFileMetadataCmdFlags"/> public IList<FileMetaData> 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<FileMetaData> value = new List<FileMetaData>(); foreach (P4.TaggedObject obj in r.TaggedOutput) { if ((obj.Count <=2) && (obj.ContainsKey("desc"))) { // hack, but this not really a file, it's just a // the description of the change if -e option is // specified, so skip it continue; } FileMetaData fmd = new FileMetaData(); fmd.FromFstatCmdTaggedData(obj); value.Add(fmd); } return value; } /// <summary> /// Use the p4 fstat command to get the file metadata for the files /// matching the FileSpec. /// </summary> /// <param name="filespecs"></param> /// <param name="options"></param> /// <returns></returns> /// <remarks> /// <br/><b>p4 help fstat</b> /// <br/> /// <br/> fstat -- Dump file info /// <br/> /// <br/> p4 fstat [-F filter -L -T fields -m max -r] [-c | -e changelist#] /// <br/> [-Ox -Rx -Sx] file[rev] ... /// <br/> /// <br/> Fstat lists information about files, one line per file. Fstat is /// <br/> intended for use in Perforce API applications, where the output can /// <br/> be accessed as variables, but its output is also suitable for parsing /// <br/> from the client command output in scripts. /// <br/> /// <br/> The fields that fstat displays are: /// <br/> /// <br/> attr-<name> -- attribute value for <name> /// <br/> attrProp-<name> -- set if attribute <name> is propagating /// <br/> clientFile -- local path (host or Perforce syntax) /// <br/> depotFile -- name in depot /// <br/> movedFile -- name in depot of moved to/from file /// <br/> path -- local path (host syntax) /// <br/> isMapped -- set if mapped client file is synced /// <br/> shelved -- set if file is shelved /// <br/> headAction -- action at head rev, if in depot /// <br/> headChange -- head rev changelist#, if in depot /// <br/> headRev -- head rev #, if in depot /// <br/> headType -- head rev type, if in depot /// <br/> headCharset -- head charset, for unicode type /// <br/> headTime -- head rev changelist time, if in depot /// <br/> headModTime -- head rev mod time, if in depot /// <br/> movedRev -- head rev # of moved file /// <br/> haveRev -- rev had on client, if on client /// <br/> desc -- change description /// <br/> digest -- MD5 digest (fingerprint) /// <br/> fileSize -- file size /// <br/> action -- open action, if opened /// <br/> type -- open type, if opened /// <br/> charset -- open charset, for unicode type /// <br/> actionOwner -- user who opened file, if opened /// <br/> change -- open changelist#, if opened /// <br/> resolved -- resolved integration records /// <br/> unresolved -- unresolved integration records /// <br/> reresolvable -- reresolvable integration records /// <br/> otherOpen -- set if someone else has it open /// <br/> otherOpen# -- list of user@client with file opened /// <br/> otherLock -- set if someone else has it locked /// <br/> otherLock# -- user@client with file locked /// <br/> otherAction# -- open action, if opened by someone else /// <br/> otherChange# -- changelist, if opened by someone else /// <br/> openattr-<name> -- attribute value for <name> /// <br/> openattrProp-<name> -- set if attribute <name> is propagating /// <br/> ourLock -- set if this user/client has it locked /// <br/> resolveAction# -- pending integration record action /// <br/> resolveBaseFile# -- pending integration base file /// <br/> resolveBaseRev# -- pending integration base rev /// <br/> resolveFromFile# -- pending integration from file /// <br/> resolveStartFromRev# -- pending integration from start rev /// <br/> resolveEndFromRev# -- pending integration from end rev /// <br/> totalFileCount -- total no. of files, if sorted /// <br/> /// <br/> The -A <pattern> flag restricts displayed attributes to those /// <br/> that match 'pattern'. /// <br/> /// <br/> The -F flag lists only files satisfying the filter expression. This /// <br/> filter syntax is similar to the one used for 'jobs -e jobview' and is /// <br/> used to evaluate the contents of the fields in the preceding list. /// <br/> Filtering is case-sensitive. /// <br/> /// <br/> Example: -Ol -F "fileSize > 1000000 & headType=text" /// <br/> /// <br/> Note: filtering is not optimized with indexes for performance. /// <br/> /// <br/> The -L flag can be used with multiple file arguments that are in /// <br/> full depot syntax and include a valid revision number. When this /// <br/> flag is used the arguments are processed together by building an /// <br/> internal table similar to a label. This file list processing is /// <br/> significantly faster than having to call the internal query engine /// <br/> for each individual file argument. However, the file argument syntax /// <br/> is strict and the command will not run if an error is encountered. /// <br/> /// <br/> The -T fields flag returns only the specified fields. The field names /// <br/> can be specified using a comma- or space-delimited list. /// <br/> /// <br/> Example: -Ol -T "depotFile, fileSize" /// <br/> /// <br/> The -m max flag limits output to the specified number of files. /// <br/> /// <br/> The -r flag sorts the output in reverse order. /// <br/> /// <br/> The -c changelist# flag displays files modified after the specified /// <br/> changelist was submitted. This operation is much faster than using /// <br/> a revision range on the affected files. /// <br/> /// <br/> The -e changelist# flag lists files modified by the specified /// <br/> changelist. When used with the -Ro flag, only pending changes are /// <br/> considered, to ensure that files opened for add are included. This /// <br/> option also displays the change description. /// <br/> /// <br/> The -O options modify the output as follows: /// <br/> /// <br/> -Oa output attributes set by 'p4 attribute'. /// <br/> /// <br/> -Od output the digest of the attribute. /// <br/> /// <br/> -Oe output attribute values encoded as hex /// <br/> /// <br/> -Of output all revisions for the given files (this /// <br/> option suppresses other* and resolve* fields) /// <br/> /// <br/> -Ol output a fileSize and digest field for each revision /// <br/> (this may be expensive to compute) /// <br/> /// <br/> -Op output the local file path in both Perforce syntax /// <br/> (//client/) as 'clientFile' and host form as 'path' /// <br/> /// <br/> -Or output pending integration record information for /// <br/> files opened on the current client, or if used with /// <br/> '-e <change> -Rs', on the shelved change /// <br/> /// <br/> -Os exclude client-related data from output /// <br/> /// <br/> The -R option limits output to specific files: /// <br/> /// <br/> -Rc files mapped in the client view /// <br/> -Rh files synced to the client workspace /// <br/> -Rn files opened not at the head revision /// <br/> -Ro files opened /// <br/> -Rr files opened that have been resolved /// <br/> -Rs files shelved (requires -e) /// <br/> -Ru files opened that need resolving /// <br/> /// <br/> The -S option changes the order of output: /// <br/> /// <br/> -St sort by filetype /// <br/> -Sd sort by date /// <br/> -Sr sort by head revision /// <br/> -Sh sort by have revision /// <br/> -Ss sort by filesize /// <br/> /// <br/> The -U flag displays information about unload files in the unload /// <br/> depot (see 'p4 help unload'). /// <br/> /// <br/> For compatibility, the following flags are also supported: /// <br/> -C (-Rc) -H (-Rh) -W (-Ro) -P (-Op) -l (-Ol) -s (-Os). /// <br/> /// <br/> /// </remarks> /// <example> /// To get FileMetaData for //depot/ReadMe.txt: /// <code> /// /// FileSpec fs = new FileSpec(new DepotPath("//depot/MyCode/ReadMe.txt"), null); /// IList<FileSpec> lfs = new List<FileSpec>(); /// lfs.Add(fs); /// /// GetFileMetaDataCmdOptions opts = /// new GetFileMetaDataCmdOptions(GetFileMetadataCmdFlags.None, /// null, null, 0, null, null, null); /// /// IList<FileMetaData> target = Repository.GetFileMetaData(lfs, opts); /// </code> /// To get FileMetaData for files in the depot that need resolving: /// <code> /// /// FileSpec fs = new FileSpec(new DepotPath("//..."), null); /// IList<FileSpec> lfs = new List<FileSpec>(); /// lfs.Add(fs); /// /// GetFileMetaDataCmdOptions opts = /// new GetFileMetaDataCmdOptions(GetFileMetadataCmdFlags.NeedsResolve, /// null, null, 0, null, null, null); /// /// IList<FileMetaData> target = Repository.GetFileMetaData(lfs, opts); /// </code> /// To get FileMetaData for files in the depot that are over a specific file /// size and of file type, text: /// <code> /// /// FileSpec fs = new FileSpec(new DepotPath("//..."), null); /// IList<FileSpec> lfs = new List<FileSpec>(); /// lfs.Add(fs); /// /// GetFileMetaDataCmdOptions opts = /// new GetFileMetaDataCmdOptions(GetFileMetadataCmdFlags.None, /// "fileSize > 1000000 & headType=text", null, 0, null, null, null); /// /// IList<FileMetaData> target = Repository.GetFileMetaData(lfs, opts); /// </code> /// To get FileMetaData for files in the depot that have been modified at or /// after changelist 20345 and are mapped to the client view: /// <code> /// /// FileSpec fs = new FileSpec(new DepotPath("//..."), null); /// IList<FileSpec> lfs = new List<FileSpec>(); /// lfs.Add(fs); /// /// GetFileMetaDataCmdOptions opts = /// new GetFileMetaDataCmdOptions(GetFileMetadataCmdFlags.ClientMapped, /// null, null, 20345, null, null, null); /// /// IList<FileMetaData> target = Repository.GetFileMetaData(lfs, opts); /// </code> /// To get FileMetaData for files in the depot including attributes which match /// the pattern "tested": /// <code> /// /// FileSpec fs = new FileSpec(new DepotPath("//..."), null); /// IList<FileSpec> lfs = new List<FileSpec>(); /// lfs.Add(fs); /// /// GetFileMetaDataCmdOptions opts = /// new GetFileMetaDataCmdOptions(GetFileMetadataCmdFlags.Attributes, /// null, null, 0, null, null, "tested"); /// /// IList<FileMetaData> target = Repository.GetFileMetaData(lfs, opts); /// </code> /// </example> /// <seealso cref="GetFileMetadataCmdFlags"/> public IList<FileMetaData> GetFileMetaData(IList<FileSpec> filespecs, Options options) { return GetFileMetaData(options, filespecs.ToArray()); } /// <summary> /// Return a list of Files in the depot that correspond to the passed-in /// FileSpecs. /// </summary> /// <remarks> /// <br/><b>p4 help files</b> /// <br/> /// <br/> files -- List files in the depot /// <br/> /// <br/> p4 files [ -a ] [ -A ] [ -e ] [ -m max ] file[revRange] ... /// <br/> p4 files -U unloadfile ... /// <br/> /// <br/> List details about specified files: depot file name, revision, /// <br/> file, type, change action and changelist number of the current /// <br/> head revision. If client syntax is used to specify the file /// <br/> argument, the client view mapping is used to determine the /// <br/> corresponding depot files. /// <br/> /// <br/> By default, the head revision is listed. If the file argument /// <br/> specifies a revision, then all files at that revision are listed. /// <br/> If the file argument specifies a revision range, the highest revision /// <br/> in the range is used for each file. For details about specifying /// <br/> revisions, see 'p4 help revisions'. /// <br/> /// <br/> The -a flag displays all revisions within the specific range, rather /// <br/> than just the highest revision in the range. /// <br/> /// <br/> The -A flag displays files in archive depots. /// <br/> /// <br/> The -e flag displays files with an action of anything other than /// <br/> deleted, purged or archived. Typically this revision is always /// <br/> available to sync or integrate from. /// <br/> /// <br/> The -m flag limits files to the first 'max' number of files. /// <br/> /// <br/> The -U option displays files in the unload depot (see 'p4 help unload' /// <br/> for more information about the unload depot). /// <br/> /// <br/> /// </remarks> /// <example> /// To get Files in local depot //depot/...: /// <code> /// GetDepotFilesCmdOptions opts = /// new GetDepotFilesCmdOptions(GetDepotFilesCmdFlags.None, 0); /// /// FileSpec fs = new FileSpec(new DepotPath("//depot/..."), null); /// /// IList<File> target = Repository.GetFiles(opts, fs); /// </code> /// To get Files in unload depot //Unloaded/...: /// <code> /// GetDepotFilesCmdOptions opts = /// new GetDepotFilesCmdOptions(GetDepotFilesCmdFlags.InUnloadDepot, 0); /// /// FileSpec fs = new FileSpec(new DepotPath("//Unloaded/..."), null); /// /// IList<File> target = Repository.GetFiles(opts, fs); /// </code> /// </example> /// <seealso cref="GetDepotFilesCmdFlags"/> public IList<File> 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<File> value = new List<File>(); foreach (P4.TaggedObject obj in r.TaggedOutput) { File val = new File(); val.ParseFilesCmdTaggedData(obj); value.Add(val); } return value; } /// <summary> /// Return a list of Files in the depot that correspond to the passed-in /// FileSpecs. /// </summary> /// <remarks> /// <br/><b>p4 help files</b> /// <br/> /// <br/> files -- List files in the depot /// <br/> /// <br/> p4 files [ -a ] [ -A ] [ -e ] [ -m max ] file[revRange] ... /// <br/> p4 files -U unloadfile ... /// <br/> /// <br/> List details about specified files: depot file name, revision, /// <br/> file, type, change action and changelist number of the current /// <br/> head revision. If client syntax is used to specify the file /// <br/> argument, the client view mapping is used to determine the /// <br/> corresponding depot files. /// <br/> /// <br/> By default, the head revision is listed. If the file argument /// <br/> specifies a revision, then all files at that revision are listed. /// <br/> If the file argument specifies a revision range, the highest revision /// <br/> in the range is used for each file. For details about specifying /// <br/> revisions, see 'p4 help revisions'. /// <br/> /// <br/> The -a flag displays all revisions within the specific range, rather /// <br/> than just the highest revision in the range. /// <br/> /// <br/> The -A flag displays files in archive depots. /// <br/> /// <br/> The -e flag displays files with an action of anything other than /// <br/> deleted, purged or archived. Typically this revision is always /// <br/> available to sync or integrate from. /// <br/> /// <br/> The -m flag limits files to the first 'max' number of files. /// <br/> /// <br/> The -U option displays files in the unload depot (see 'p4 help unload' /// <br/> for more information about the unload depot). /// <br/> /// <br/> /// </remarks> /// <example> /// To get Files in local depot //depot/...: /// <code> /// FileSpec fs = new FileSpec(new DepotPath("//depot/..."), null); /// IList<FileSpec> lfs = new List<FileSpec>(); /// lfs.Add(fs); /// /// GetDepotFilesCmdOptions opts = /// new GetDepotFilesCmdOptions(GetDepotFilesCmdFlags.None, 0); /// /// IList<File> target = Repository.GetFiles(lfs, opts); /// </code> /// To get Files in unload depot //Unloaded/...: /// <code> /// FileSpec fs = new FileSpec(new DepotPath("//Unloaded/..."), null); /// IList<FileSpec> lfs = new List<FileSpec>(); /// lfs.Add(fs); /// /// GetDepotFilesCmdOptions opts = /// new GetDepotFilesCmdOptions(GetDepotFilesCmdFlags.InUnloadDepot, 0); /// /// IList<File> target = Repository.GetFiles(lfs, opts); /// </code> /// </example> /// <seealso cref="GetDepotFilesCmdFlags"/> public IList<File> GetFiles(IList<FileSpec> filespecs, Options options) { return GetFiles(options, filespecs.ToArray()); } /// <summary> /// List selected directory paths in the repository. /// </summary> /// <param name="dirs"></param> /// <param name="options"></param> /// <returns></returns> /// <remarks> /// <br/><b>p4 help dirs</b> /// <br/> /// <br/> dirs -- List depot subdirectories /// <br/> /// <br/> p4 dirs [-C -D -H] [-S stream] dir[revRange] ... /// <br/> /// <br/> List directories that match the specified file pattern (dir). /// <br/> This command does not support the recursive wildcard (...). /// <br/> Use the * wildcard instead. /// <br/> /// <br/> Perforce does not track directories individually. A path is treated /// <br/> as a directory if there are any undeleted files with that path as a /// <br/> prefix. /// <br/> /// <br/> By default, all directories containing files are listed. If the dir /// <br/> argument includes a revision range, only directories containing files /// <br/> in the range are listed. For details about specifying file revisions, /// <br/> see 'p4 help revisions'. /// <br/> /// <br/> The -C flag lists only directories that fall within the current /// <br/> client view. /// <br/> /// <br/> The -D flag includes directories containing only deleted files. /// <br/> /// <br/> The -H flag lists directories containing files synced to the current /// <br/> client workspace. /// <br/> /// <br/> The -S flag limits output to depot directories mapped in a stream's /// <br/> client view. /// <br/> /// <br/> /// </remarks> /// <example> /// To get dirs on the server that fall within the current client view: /// <code> /// GetDepotDirsCmdOptions opts = /// new GetDepotDirsCmdOptions(GetDepotDirsCmdFlags.CurrentClientOnly, null); /// /// IList<String> target = Repository.GetDepotDirs(opts, "//* ); /// </code> /// To get dirs on the server that contain files synced to the current /// client workspace: /// <code> /// GetDepotDirsCmdOptions opts = /// new GetDepotDirsCmdOptions(GetDepotDirsCmdFlags.SyncedDirs, null); /// /// IList<String> target = Repository.GetDepotDirs(opts, "//* ); /// </code> /// To get dirs on the server that fall under the path //depot/main/: /// <code> /// GetDepotDirsCmdOptions opts = /// new GetDepotDirsCmdOptions(GetDepotDirsCmdFlags.None, null); /// /// IList<String> target = Repository.GetDepotDirs(opts, "//depot/main/* ); /// </code> /// </example> /// <seealso cref="GetDepotDirsCmdFlags"/> public IList<String> 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<String> value = new List<String>(); foreach (P4.P4ClientInfoMessage l in r.InfoOutput) { value.Add(l.Message); } return value; } /// <summary> /// List selected directory paths in the repository. /// </summary> /// <param name="dirs"></param> /// <param name="options"></param> /// <returns></returns> /// <remarks> /// <br/><b>p4 help dirs</b> /// <br/> /// <br/> dirs -- List depot subdirectories /// <br/> /// <br/> p4 dirs [-C -D -H] [-S stream] dir[revRange] ... /// <br/> /// <br/> List directories that match the specified file pattern (dir). /// <br/> This command does not support the recursive wildcard (...). /// <br/> Use the * wildcard instead. /// <br/> /// <br/> Perforce does not track directories individually. A path is treated /// <br/> as a directory if there are any undeleted files with that path as a /// <br/> prefix. /// <br/> /// <br/> By default, all directories containing files are listed. If the dir /// <br/> argument includes a revision range, only directories containing files /// <br/> in the range are listed. For details about specifying file revisions, /// <br/> see 'p4 help revisions'. /// <br/> /// <br/> The -C flag lists only directories that fall within the current /// <br/> client view. /// <br/> /// <br/> The -D flag includes directories containing only deleted files. /// <br/> /// <br/> The -H flag lists directories containing files synced to the current /// <br/> client workspace. /// <br/> /// <br/> The -S flag limits output to depot directories mapped in a stream's /// <br/> client view. /// <br/> /// <br/> /// </remarks> /// <example> /// To get dirs on the server that fall within the current client view: /// <code> /// GetDepotDirsCmdOptions opts = /// new GetDepotDirsCmdOptions(GetDepotDirsCmdFlags.CurrentClientOnly, null); /// /// IList<String> dirs = new List<String>() /// dirs.Add("//*"); /// /// IList<String> target = Repository.GetDepotDirs(dirs, opts); /// </code> /// To get dirs on the server that contain files synced to the current /// client workspace: /// <code> /// GetDepotDirsCmdOptions opts = /// new GetDepotDirsCmdOptions(GetDepotDirsCmdFlags.SyncedDirs, null); /// /// IList<String> dirs = new List<String>() /// dirs.Add("//*"); /// /// IList<String> target = Repository.GetDepotDirs(dirs, opts); /// </code> /// To get dirs on the server that fall under the path //depot/main/: /// <code> /// GetDepotDirsCmdOptions opts = /// new GetDepotDirsCmdOptions(GetDepotDirsCmdFlags.None, null); /// /// IList<String> dirs = new List<String>() /// dirs.Add("//depot/main/*"); /// /// IList<String> target = Repository.GetDepotDirs(dirs, opts); /// </code> /// </example> /// <seealso cref="GetDepotDirsCmdFlags"/> public IList<String> GetDepotDirs(IList<String> dirs, Options options) { return GetDepotDirs(options, dirs.ToArray()); } /// <summary> /// Return the contents of the files identified by the passed-in file specs. /// </summary> /// <param name="filespecs"></param> /// <param name="options"></param> /// <returns></returns> /// GetFileContents /// <remarks> /// <br/><b>p4 help print</b> /// <br/> /// <br/> print -- Write a depot file to standard output /// <br/> /// <br/> p4 print [-a -o localFile -q] file[revRange] ... /// <br/> /// <br/> Retrieve the contents of a depot file to the client's standard output. /// <br/> The file is not synced. If file is specified using client syntax, /// <br/> Perforce uses the client view to determine the corresponding depot /// <br/> file. /// <br/> /// <br/> By default, the head revision is printed. If the file argument /// <br/> includes a revision, the specified revision is printed. If the /// <br/> file argument has a revision range, then only files selected by /// <br/> that revision range are printed, and the highest revision in the /// <br/> range is printed. For details about revision specifiers, see 'p4 /// <br/> help revisions'. /// <br/> /// <br/> The -a flag prints all revisions within the specified range, rather /// <br/> than just the highest revision in the range. /// <br/> /// <br/> The -o localFile flag redirects the output to the specified file on /// <br/> the client filesystem. /// <br/> /// <br/> The -q flag suppresses the initial line that displays the file name /// <br/> and revision. /// <br/> /// <br/> /// </remarks> /// <example> /// To get the contents of the file //depot/MyCode/README.txt: /// <code> /// GetFileContentsCmdOptions opts = /// new GetFileContentsCmdOptions(GetFileContentsCmdFlags.None, null); /// /// FileSpec filespec = /// new FileSpec(new DepotPath("//depot/MyCode/README.txt"), null); /// /// IList<String> target = Repository.GetFileContents(opts, filespec); /// </code> /// To get the contents of the file //depot/MyCode/README.txt redirecting the /// contents to local file C:\Doc\README.txt and supressing the file name /// and revision line: /// <code> /// GetFileContentsCmdOptions opts = /// new GetFileContentsCmdOptions(GetFileContentsCmdFlags.Suppress, /// "C:\\Doc\\README.txt"); /// /// FileSpec filespec = /// new FileSpec(new DepotPath("//depot/MyCode/README.txt"), null); /// /// IList<String> target = Repository.GetFileContents(opts, filespec); /// </code> /// </example> /// <seealso cref="GetFileContentsCmdFlags"/> public IList<string> 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<string> value = new List<string>(); 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; } /// <summary> /// Return the contents of the files identified by the passed-in file specs. /// </summary> /// <param name="filespecs"></param> /// <param name="options"></param> /// <returns></returns> /// GetFileContents /// <remarks> /// <br/><b>p4 help print</b> /// <br/> /// <br/> print -- Write a depot file to standard output /// <br/> /// <br/> p4 print [-a -o localFile -q] file[revRange] ... /// <br/> /// <br/> Retrieve the contents of a depot file to the client's standard output. /// <br/> The file is not synced. If file is specified using client syntax, /// <br/> Perforce uses the client view to determine the corresponding depot /// <br/> file. /// <br/> /// <br/> By default, the head revision is printed. If the file argument /// <br/> includes a revision, the specified revision is printed. If the /// <br/> file argument has a revision range, then only files selected by /// <br/> that revision range are printed, and the highest revision in the /// <br/> range is printed. For details about revision specifiers, see 'p4 /// <br/> help revisions'. /// <br/> /// <br/> The -a flag prints all revisions within the specified range, rather /// <br/> than just the highest revision in the range. /// <br/> /// <br/> The -o localFile flag redirects the output to the specified file on /// <br/> the client filesystem. /// <br/> /// <br/> The -q flag suppresses the initial line that displays the file name /// <br/> and revision. /// <br/> /// <br/> /// </remarks> /// <example> /// To get the contents of the file //depot/MyCode/README.txt: /// <code> /// GetFileContentsCmdOptions opts = /// new GetFileContentsCmdOptions(GetFileContentsCmdFlags.None, null); /// /// FileSpec filespec = /// new FileSpec(new DepotPath("//depot/MyCode/README.txt"), null); /// IList<FileSpec> filespecs = new List<FileSpec>(); /// filespecs.Add(filespec); /// /// IList<String> target = Repository.GetFileContents(filespecs, opts); /// </code> /// To get the contents of the file //depot/MyCode/README.txt redirecting the /// contents to local file C:\Doc\README.txt and supressing the file name /// and revision line: /// <code> /// GetFileContentsCmdOptions opts = /// new GetFileContentsCmdOptions(GetFileContentsCmdFlags.Suppress, /// "C:\\Doc\\README.txt"); /// /// FileSpec filespec = /// new FileSpec(new DepotPath("//depot/MyCode/README.txt"), null); /// IList<FileSpec> filespecs = new List<FileSpec>(); /// filespecs.Add(filespec); /// /// IList<String> target = Repository.GetFileContents(filespecs, opts); /// </code> /// </example> /// <seealso cref="GetFileContentsCmdFlags"/> public IList<string> GetFileContents(IList<FileSpec> filespecs, Options options) { return GetFileContents(options, filespecs.ToArray()); } /// <summary> /// Return the contents of the files identified by the passed-in file specs. /// </summary> /// <param name="filespecs"></param> /// <param name="options"></param> /// <returns></returns> /// GetFileContentsEx /// <remarks> /// <br/><b>p4 help print</b> /// <br/> /// <br/> print -- Write a depot file to standard output /// <br/> /// <br/> p4 print [-a -o localFile -q] file[revRange] ... /// <br/> /// <br/> Retrieve the contents of a depot file to the client's standard output. /// <br/> The file is not synced. If file is specified using client syntax, /// <br/> Perforce uses the client view to determine the corresponding depot /// <br/> file. /// <br/> /// <br/> By default, the head revision is printed. If the file argument /// <br/> includes a revision, the specified revision is printed. If the /// <br/> file argument has a revision range, then only files selected by /// <br/> that revision range are printed, and the highest revision in the /// <br/> range is printed. For details about revision specifiers, see 'p4 /// <br/> help revisions'. /// <br/> /// <br/> The -a flag prints all revisions within the specified range, rather /// <br/> than just the highest revision in the range. /// <br/> /// <br/> The -o localFile flag redirects the output to the specified file on /// <br/> the client filesystem. /// <br/> /// <br/> The -q flag suppresses the initial line that displays the file name /// <br/> and revision. /// <br/> /// <br/> /// </remarks> /// <example> /// To get the contents of the file //depot/MyCode/README.txt: /// <code> /// GetFileContentsCmdOptions opts = /// new GetFileContentsCmdOptions(GetFileContentsCmdFlags.None, null); /// /// FileSpec filespec = /// new FileSpec(new DepotPath("//depot/MyCode/README.txt"), null); /// /// IList<String> target = Repository.GetFileContents(opts, filespec); /// </code> /// To get the contents of the file //depot/MyCode/README.txt redirecting the /// contents to local file C:\Doc\README.txt and supressing the file name /// and revision line: /// <code> /// GetFileContentsCmdOptions opts = /// new GetFileContentsCmdOptions(GetFileContentsCmdFlags.Suppress, /// "C:\\Doc\\README.txt"); /// /// FileSpec filespec = /// new FileSpec(new DepotPath("//depot/MyCode/README.txt"), null); /// /// IList<String> target = Repository.GetFileContents(opts, filespec); /// </code> /// </example> /// <seealso cref="GetFileContentsCmdFlags"/> public IList<object> GetFileContentsEx(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<object> value = new List<object>(); if (r.TaggedOutput != null) { if ((options == null) || (options.ContainsKey("-q") == false)) { foreach (P4.TaggedObject obj in r.TaggedOutput) { string path = string.Empty; string revStr = string.Empty; int rev = -1; if (obj.ContainsKey("depotFile")) { string s = obj["depotFile"]; int idx = s.LastIndexOf('#'); if (idx > 0) { path = s.Substring(0, idx); revStr = s.Substring(idx + 1); int.TryParse(revStr, out rev); } else { path = s; } if (rev >= 0) { value.Add(FileSpec.DepotSpec(path, rev)); } else { value.Add(FileSpec.DepotSpec(path)); } } } } } if (r.BinaryOutput != null) { value.Add(r.BinaryOutput); } else { value.Add(r.TextOutput); } return value; } /// <summary> /// Return the contents of the files identified by the passed-in file specs. /// </summary> /// <param name="filespecs"></param> /// <param name="options"></param> /// <returns></returns> /// GetFileContentsEx /// <remarks> /// <br/><b>p4 help print</b> /// <br/> /// <br/> print -- Write a depot file to standard output /// <br/> /// <br/> p4 print [-a -o localFile -q] file[revRange] ... /// <br/> /// <br/> Retrieve the contents of a depot file to the client's standard output. /// <br/> The file is not synced. If file is specified using client syntax, /// <br/> Perforce uses the client view to determine the corresponding depot /// <br/> file. /// <br/> /// <br/> By default, the head revision is printed. If the file argument /// <br/> includes a revision, the specified revision is printed. If the /// <br/> file argument has a revision range, then only files selected by /// <br/> that revision range are printed, and the highest revision in the /// <br/> range is printed. For details about revision specifiers, see 'p4 /// <br/> help revisions'. /// <br/> /// <br/> The -a flag prints all revisions within the specified range, rather /// <br/> than just the highest revision in the range. /// <br/> /// <br/> The -o localFile flag redirects the output to the specified file on /// <br/> the client filesystem. /// <br/> /// <br/> The -q flag suppresses the initial line that displays the file name /// <br/> and revision. /// <br/> /// <br/> /// </remarks> /// <example> /// To get the contents of the file //depot/MyCode/README.txt: /// <code> /// GetFileContentsCmdOptions opts = /// new GetFileContentsCmdOptions(GetFileContentsCmdFlags.None, null); /// /// FileSpec filespec = /// new FileSpec(new DepotPath("//depot/MyCode/README.txt"), null); /// IList<FileSpec> filespecs = new List<FileSpec>(); /// filespecs.Add(filespec); /// /// IList<String> target = Repository.GetFileContents(filespecs, opts); /// </code> /// To get the contents of the file //depot/MyCode/README.txt redirecting the /// contents to local file C:\Doc\README.txt and supressing the file name /// and revision line: /// <code> /// GetFileContentsCmdOptions opts = /// new GetFileContentsCmdOptions(GetFileContentsCmdFlags.Suppress, /// "C:\\Doc\\README.txt"); /// /// FileSpec filespec = /// new FileSpec(new DepotPath("//depot/MyCode/README.txt"), null); /// IList<FileSpec> filespecs = new List<FileSpec>(); /// filespecs.Add(filespec); /// /// IList<String> target = Repository.GetFileContents(filespecs, opts); /// </code> /// </example> /// <seealso cref="GetFileContentsCmdFlags"/> public IList<object> GetFileContentsEx(IList<FileSpec> filespecs, Options options) { return GetFileContentsEx(options, filespecs.ToArray()); } /// <summary> /// Get the revision history data for the passed-in file specs. /// </summary> /// <param name="filespecs"></param> /// <param name="options"></param> /// <returns></returns> /// <remarks> /// <br/><b>p4 help filelog</b> /// <br/> /// <br/> filelog -- List revision history of files /// <br/> /// <br/> p4 filelog [-c changelist# -h -i -l -L -t -m maxRevs -s] file[revRange] ... /// <br/> /// <br/> List the revision history of the specified files, from the most /// <br/> recent revision to the first. If the file specification includes /// <br/> a revision, the command lists revisions at or prior to the specified /// <br/> revision. If the file specification includes a revision range, /// <br/> the command lists only the specified revisions. See 'p4 help revisions' /// <br/> for details. /// <br/> /// <br/> The -c changelist# flag displays files submitted at the specified /// <br/> changelist number. /// <br/> /// <br/> The -i flag includes inherited file history. If a file was created by /// <br/> branching (using 'p4 integrate'), filelog lists the revisions of the /// <br/> file's ancestors up to the branch points that led to the specified /// <br/> revision. File history inherited by renaming (using 'p4 move') is /// <br/> always displayed regardless of whether -i is specified. /// <br/> /// <br/> The -h flag displays file content history instead of file name /// <br/> history. The list includes revisions of other files that were /// <br/> branched or copied (using 'p4 integrate' and 'p4 resolve -at') to /// <br/> the specified revision. Revisions that were replaced by copying /// <br/> or branching are omitted, even if they are part of the history of /// <br/> the specified revision. /// <br/> /// <br/> The -t flag displays the time as well as the date. /// <br/> /// <br/> The -l flag lists the full text of the changelist descriptions. /// <br/> /// <br/> The -L flag lists the full text of the changelist descriptions, /// <br/> truncated to 250 characters if longer. /// <br/> /// <br/> The -m maxRevs displays at most 'maxRevs' revisions per file of /// <br/> the file[rev] argument specified. /// <br/> /// <br/> The -s flag displays a shortened form of filelog that omits /// <br/> non-contributory integrations. /// <br/> /// <br/> /// </remarks> /// <example> /// To get the file history of the file //depot/MyCode/README.txt /// submitted at change 43578 and showing the full changelist description: /// <code> /// GetFileHistoryCmdOptions opts = /// new GetFileHistoryCmdOptions(GetFileHistoryCmdFlags.FullDescription /// 43578, 0); /// /// FileSpec filespec = /// new FileSpec(new DepotPath("//depot/MyCode/README.txt"), null); /// /// IList<String> target = Repository.GetFileHistory(opts, filespec); /// </code> /// To get the file history of the file //depot/MyCode/README.txt /// showing both time and date for the 10 latest revisions: /// <code> /// GetFileHistoryCmdOptions opts = /// new GetFileHistoryCmdOptions(GetFileHistoryCmdFlags.Time, /// 0, 10) /// /// FileSpec filespec = /// new FileSpec(new DepotPath("//depot/MyCode/README.txt"), null); /// /// IList<String> target = Repository.GetFileHistory(opts, filespec); /// </code> /// </example> /// <seealso cref="FileLogCmdFlags"/> /// <seealso cref="GetFileHistoryCmdFlags"/> public IList<FileHistory> 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<FileHistory> value = new List<FileHistory>(); bool dst_mismatch = false; string offset = string.Empty; if (Server != null && Server.Metadata != null) { offset = Server.Metadata.DateTimeOffset; dst_mismatch = FormBase.DSTMismatch(Server.Metadata); } 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<FileAction> 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]); DateTime UTC = FormBase.ConvertUnixTime(unixTime); DateTime GMT = new DateTime(UTC.Year, UTC.Month, UTC.Day, UTC.Hour, UTC.Minute, UTC.Second, DateTimeKind.Unspecified); date = FormBase.ConvertFromUTC(GMT, offset, dst_mismatch); 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<RevisionIntegrationSummary> integrationsummaries = new List<RevisionIntegrationSummary>(); 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; } /// <summary> /// Get the revision history data for the passed-in file specs. /// </summary> /// <param name="filespecs"></param> /// <param name="options"></param> /// <returns></returns> /// <remarks> /// <br/><b>p4 help filelog</b> /// <br/> /// <br/> filelog -- List revision history of files /// <br/> /// <br/> p4 filelog [-c changelist# -h -i -l -L -t -m maxRevs -s] file[revRange] ... /// <br/> /// <br/> List the revision history of the specified files, from the most /// <br/> recent revision to the first. If the file specification includes /// <br/> a revision, the command lists revisions at or prior to the specified /// <br/> revision. If the file specification includes a revision range, /// <br/> the command lists only the specified revisions. See 'p4 help revisions' /// <br/> for details. /// <br/> /// <br/> The -c changelist# flag displays files submitted at the specified /// <br/> changelist number. /// <br/> /// <br/> The -i flag includes inherited file history. If a file was created by /// <br/> branching (using 'p4 integrate'), filelog lists the revisions of the /// <br/> file's ancestors up to the branch points that led to the specified /// <br/> revision. File history inherited by renaming (using 'p4 move') is /// <br/> always displayed regardless of whether -i is specified. /// <br/> /// <br/> The -h flag displays file content history instead of file name /// <br/> history. The list includes revisions of other files that were /// <br/> branched or copied (using 'p4 integrate' and 'p4 resolve -at') to /// <br/> the specified revision. Revisions that were replaced by copying /// <br/> or branching are omitted, even if they are part of the history of /// <br/> the specified revision. /// <br/> /// <br/> The -t flag displays the time as well as the date. /// <br/> /// <br/> The -l flag lists the full text of the changelist descriptions. /// <br/> /// <br/> The -L flag lists the full text of the changelist descriptions, /// <br/> truncated to 250 characters if longer. /// <br/> /// <br/> The -m maxRevs displays at most 'maxRevs' revisions per file of /// <br/> the file[rev] argument specified. /// <br/> /// <br/> The -s flag displays a shortened form of filelog that omits /// <br/> non-contributory integrations. /// <br/> /// <br/> /// </remarks> /// <example> /// To get the file history of the file //depot/MyCode/README.txt /// submitted at change 43578 and showing the full changelist description: /// <code> /// GetFileHistoryCmdOptions opts = /// new GetFileHistoryCmdOptions(GetFileHistoryCmdFlags.FullDescription /// 43578, 0); /// /// FileSpec filespec = /// new FileSpec(new DepotPath("//depot/MyCode/README.txt"), null); /// IList<FileSpec> filespecs = new List<FileSpec>(); /// filespecs.Add(filespec); /// /// IList<String> target = Repository.GetFileHistory(filespecs, opts); /// </code> /// To get the file history of the file //depot/MyCode/README.txt /// showing both time and date for the 10 latest revisions: /// <code> /// GetFileHistoryCmdOptions opts = /// new GetFileHistoryCmdOptions(GetFileHistoryCmdFlags.Time, /// 0, 10) /// /// FileSpec filespec = /// new FileSpec(new DepotPath("//depot/MyCode/README.txt"), null); /// IList<FileSpec> filespecs = new List<FileSpec>(); /// filespecs.Add(filespec); /// /// IList<String> target = Repository.GetFileHistory(filespecs, opts); /// </code> /// </example> /// <seealso cref="FileLogCmdFlags"/> /// <seealso cref="GetFileHistoryCmdFlags"/> public IList<FileHistory> GetFileHistory(IList<FileSpec> filespecs, Options options) { return GetFileHistory(options, filespecs.ToArray()); } /// <summary> /// Get content and existence diff details for two depot files. /// </summary> /// <param name="filespecleft"></param> /// <param name="filespecright"></param> /// <param name="options"></param> /// <returns></returns> /// <remarks> /// <br/><b>p4 help diff2</b> /// <br/> /// <br/> diff2 -- Compare one set of depot files to another /// <br/> /// <br/> p4 diff2 [options] fromFile[rev] toFile[rev] /// <br/> p4 diff2 [options] -b branch [[fromFile[rev]] toFile[rev]] /// <br/> p4 diff2 [options] -S stream [-P parent] [[fromFile[rev]] toFile[rev]] /// <br/> /// <br/> options: -d<flags>> -Od -q -t -u /// <br/> /// <br/> 'p4 diff2' runs on the server to compare one set of depot files (the /// <br/> 'source') to another (the 'target'). Source and target file sets /// <br/> can be specified on the 'p4 diff2' command line or through a branch /// <br/> view. /// <br/> /// <br/> With a branch view, fromFile and toFile are optional; fromFile limits /// <br/> the scope of the source file set, and toFile limits the scope of the /// <br/> target. If only one file argument is given, it is assumed to be /// <br/> toFile. /// <br/> /// <br/> fromFile and toFile can include revision specifiers; by default, the /// <br/> head revisions are diffed. See 'p4 help revisions' for details /// <br/> about specifying file revisions. /// <br/> /// <br/> 'p4 diff2' precedes each diffed file pair with a header line of the /// <br/> following form: /// <br/> /// <br/> ==== source#rev (type) - target#rev (type) ==== summary /// <br/> /// <br/> A source or target file shown as '<none>' means there is no file /// <br/> at the specified name or revision to pair with its counterpart. /// <br/> The summary status is one of the following: 'identical' means file /// <br/> contents and types are identical, 'types' means file contents are /// <br/> identical but the types are different, and 'content' means file /// <br/> contents are different. /// <br/> /// <br/> The -b flag makes 'p4 diff2' use a user-defined branch view. (See /// <br/> 'p4 help branch'.) The left side of the branch view is the source /// <br/> and the right side is the target. /// <br/> /// <br/> The -S flag makes 'p4 diff2' use a generated branch view that maps /// <br/> a stream (or its underlying real stream) to its parent. -P can be /// <br/> used to generate the branch view using a parent stream other than /// <br/> the stream's actual parent. /// <br/> /// <br/> The -d<flags> modify the output of diffs as follows: /// <br/> /// <br/> -dn (RCS) /// <br/> -dc[n] (context) /// <br/> -ds (summary) /// <br/> -du[n] (unified) /// <br/> -db (ignore whitespace changes) /// <br/> -dw (ignore whitespace) /// <br/> -dl (ignore line endings). /// <br/> /// <br/> The optional argument to -dc/-du specifies number of context lines. /// <br/> /// <br/> The -Od flag limits output to files that differ. /// <br/> /// <br/> The -q omits files that have identical content and types and /// <br/> suppresses the actual diff for all files. /// <br/> /// <br/> The -t flag forces 'p4 diff2' to diff binary files. /// <br/> /// <br/> The -u flag uses the GNU diff -u format and displays only files /// <br/> that differ. The file names and dates are in Perforce syntax, but /// <br/> the output can be used by the patch program. /// <br/> /// <br/> /// </remarks> /// <example> /// To get the depot file diffs between //depot/main/Program.cs and /// //depot/rel/Program.cs and ignore whitespace changes: /// <code> /// GetDepotFileDiffsCmdOptions opts = /// new GetDepotFileDiffsCmdOptions(GetDepotFileDiffsCmdFlags.IgnoreWhitespaceChanges, /// 0, 0, null,null,null); /// /// IList<DepotFileDiff> target = /// Repository.GetDepotFileDiffs(//depot/main/Program.cs, /// //depot/rel/Program.cs, opts); /// </code> /// To get the depot files that differ between all files under //depot/main/... and /// //depot/rel/... and display in GNU format only listing files that differ: /// <code> /// GetDepotFileDiffsCmdOptions opts = /// new GetDepotFileDiffsCmdOptions(GetDepotFileDiffsCmdFlags.GNU, /// 0, 0, null,null,null); /// /// IList<DepotFileDiff> target = /// Repository.GetDepotFileDiffs(//depot/main/..., //depot/rel/..., opts); /// </code> /// </example> /// <seealso cref="GetDepotFileDiffsCmdFlags"/> public IList<DepotFileDiff> 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<DepotFileDiff> value = new List<DepotFileDiff>(); foreach (P4.TaggedObject obj in r.TaggedOutput) { DepotFileDiff val = new DepotFileDiff(); val.FromGetDepotFileDiffsCmdTaggedOutput(obj, _connection, options); value.Add(val); } return value; } /// <summary> /// Return FileAnnotation objects for the listed FileSpecs. /// </summary> /// <param name="filespecs"></param> /// <param name="options"></param> /// <returns></returns> /// <remarks> /// <br/><b>p4 help annotate</b> /// <br/> /// <br/> annotate -- Print file lines and their revisions /// <br/> /// <br/> p4 annotate [-aciIq -d<flags>] file[revRange] ... /// <br/> /// <br/> Prints all lines of the specified files, indicating the revision that /// <br/> introduced each line into the file. /// <br/> /// <br/> If the file argument includes a revision, then only revisions up to /// <br/> the specified revision are displayed. If the file argument has a /// <br/> revision range, only revisions within that range are displayed. For /// <br/> details about specifying revisions, see 'p4 help revisions'. /// <br/> /// <br/> The -a flag includes both deleted files and lines no longer present /// <br/> at the head revision. In the latter case, both the starting and ending /// <br/> revision for each line is displayed. /// <br/> /// <br/> The -c flag directs the annotate command to output changelist numbers /// <br/> rather than revision numbers for each line. /// <br/> /// <br/> The -d<flags> change the way whitespace and/or line endings are /// <br/> treated: -db (ignore whitespace changes), -dw (ignore whitespace), /// <br/> -dl (ignore line endings). /// <br/> /// <br/> The -i flag follows branches. If a file was created by branching, /// <br/> 'p4 annotate' includes the revisions of the source file up to the /// <br/> branch point, just as 'p4 filelog -i' does. If a file has history /// <br/> prior to being created by branching (such as a file that was branched /// <br/> on top of a deleted file), -i ignores those prior revisions and /// <br/> follows the source. -i implies -c. /// <br/> /// <br/> The -I flag follows all integrations into the file. If a line was /// <br/> introduced into the file by a merge, the source of the merge is /// <br/> displayed as the changelist that introduced the line. If the source /// <br/> itself was the result of an integration, that source is used instead, /// <br/> and so on. -I implies -c. /// <br/> /// <br/> The -q flag suppresses the one-line header that is displayed by /// <br/> default for each file. /// <br/> /// <br/> /// </remarks> /// <example> /// To get the file annotations of the file //depot/MyCode/README.txt: /// <code> /// GetFileAnnotationsCmdOptions opts = /// new GetFileAnnotationsCmdOptions(GetFileAnnotationsCmdFlags.None, null); /// /// FileSpec filespec = /// new FileSpec(new DepotPath("//depot/MyCode/README.txt"), null); /// IList<FileSpec> filespecs = new List<FileSpec>(); /// filespecs.Add(filespec); /// /// IList<FileAnnotation> target = Repository.GetFileAnnotations(filespecs, opts); /// </code> /// To get the file annotations of the file //depot/MyCode/README.txt redirecting the /// contents to local file C:\Doc\README.txt and supressing the one-line header: /// <code> /// GetFileAnnotationsCmdOptions opts = /// new GetFileAnnotationsCmdOptions(GetFileAnnotationsCmdFlags.Suppress, /// "C:\\Doc\\README.txt"); /// /// FileSpec filespec = /// new FileSpec(new DepotPath("//depot/MyCode/README.txt"), null); /// IList<FileSpec> filespecs = new List<FileSpec>(); /// filespecs.Add(filespec); /// /// IList<FileAnnotation> target = Repository.GetFileAnnotations(filespecs, opts); /// </code> /// </example> /// <seealso cref="GetFileAnnotationsCmdFlags"/> public IList<FileAnnotation> GetFileAnnotations(IList<FileSpec> 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<FileAnnotation> value = new List<FileAnnotation>(); 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; } /// <summary> /// Tag depot files with the passed-in label. /// </summary> /// <param name="filespecs"></param> /// <param name="labelid"></param> /// <param name="options"></param> /// <returns></returns> /// <remarks> /// <br/><b>p4 help tag</b> /// <br/> /// <br/> tag -- Tag files with a label /// <br/> /// <br/> p4 tag [-d -n] -l label file[revRange] ... /// <br/> /// <br/> Tag associates the named label with the file revisions specified by /// <br/> the file argument. After file revisions are tagged with a label, /// <br/> revision specifications of the form '@label' can be used to refer /// <br/> to them. /// <br/> /// <br/> If the file argument does not include a revision specification, the /// <br/> head revisions is tagged. See 'p4 help revisions' for revision /// <br/> specification options. /// <br/> /// <br/> If the file argument includes a revision range specification, only /// <br/> the files with revisions in that range are tagged. Files with more /// <br/> than one revision in the range are tagged at the highest revision. /// <br/> /// <br/> The -d deletes the association between the specified files and the /// <br/> label, regardless of revision. /// <br/> /// <br/> The -n flag previews the results of the operation. /// <br/> /// <br/> Tag can be used with an existing label (see 'p4 help labels') or /// <br/> with a new one. An existing label can be used only by its owner, /// <br/> and only if it is unlocked. (See 'p4 help label'). /// <br/> /// <br/> To list the file revisions tagged with a label, use 'p4 files /// <br/> @label'. /// <br/> /// <br/> /// </remarks> /// <example> /// To tag the file //depot/MyCode/README.txt with build_label: /// <code> /// TagCmdOptions opts = /// new TagCmdOptions(TagFilesCmdFlags.None, null); /// /// FileSpec filespec = /// new FileSpec(new DepotPath("//depot/MyCode/README.txt"), null); /// IList<FileSpec> filespecs = new List<FileSpec>(); /// filespecs.Add(filespec); /// /// IList<FileSpec> target = /// Repository.TagFiles(filespecs, "build_label", opts); /// </code> /// To remove the association between the file //depot/MyCode/README.txt /// and build_label: /// <code> /// TagCmdOptions opts = /// new TagCmdOptions(TagFilesCmdFlags.Delete, null); /// /// FileSpec filespec = /// new FileSpec(new DepotPath("//depot/MyCode/README.txt"), null); /// IList<FileSpec> filespecs = new List<FileSpec>(); /// filespecs.Add(filespec); /// /// IList<FileSpec> target = /// Repository.TagFiles(filespecs, "build_label", opts); /// </code> /// To get a preview list of the files that would be tagged in path /// //depot/main/src with build_label: /// <code> /// TagCmdOptions opts = /// new TagCmdOptions(TagFilesCmdFlags.ListOnly, null); /// /// FileSpec filespec = /// new FileSpec(new DepotPath("//depot/main/src/..."), null); /// IList<FileSpec> filespecs = new List<FileSpec>(); /// filespecs.Add(filespec); /// /// IList<FileSpec> target = /// Repository.TagFiles(filespecs, "build_label", opts); /// </code> /// </example> /// <seealso cref="TagFilesCmdFlags"/> public IList<FileSpec> TagFiles(IList<FileSpec> 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<FileSpec> value = new List<FileSpec>(); 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; } /// <summary> /// List fixes affecting files and / or jobs and / or changelists. /// </summary> /// <param name="filespecs"></param> /// <param name="options"></param> /// <returns></returns> /// <remarks> /// <br/><b>p4 help fixes</b> /// <br/> /// <br/> fixes -- List jobs with fixes and the changelists that fix them /// <br/> /// <br/> p4 fixes [-i -m max -c changelist# -j jobName] [file[revRange] ...] /// <br/> /// <br/> 'p4 fixes' list fixed jobs and the number of the changelist that /// <br/> contains the fix.Fixes are associated with changelists using the /// <br/> 'p4 fix' command or by editing and submitting changelists. /// <br/> /// <br/> The 'p4 fixes' command lists both submitted and pending changelists. /// <br/> /// <br/> By default, 'p4 fixes' lists all fixes. This list can be limited /// <br/> as follows: to list fixes for a specified job, use the -j jobName /// <br/> flag. To list fixes for a specified changelist, use -c changelist#. /// <br/> To list fixes that affect specified files, include the file argument. /// <br/> The file pattern can include wildcards and revision specifiers. For /// <br/> details about revision specifiers, see 'p4 help revisions' /// <br/> /// <br/> The -i flag also includes any fixes made by changelists integrated /// <br/> into the specified files. /// <br/> /// <br/> The -m max flag limits output to the specified number of job /// <br/> fixes. /// <br/> /// <br/> /// </remarks> /// <example> /// To list the fixes related to job000001: /// <code> /// GetFixesCmdOptions opts = /// new GetFixesCmdOptions(GetFixesCmdFlags.None, 0, "job000001", 0); /// /// FileSpec filespec = /// new FileSpec(new DepotPath("//..."), null); /// IList<FileSpec> filespecs = new List<FileSpec>(); /// filespecs.Add(filespec); /// /// IList<Fix> target = Repository.GetFixes(filespecs, opts); /// </code> /// To list the fixes related to changelist 47921: /// <code> /// GetFixesCmdOptions opts = /// new GetFixesCmdOptions(GetFixesCmdFlags.None, 47921, null, 0); /// /// FileSpec filespec = /// new FileSpec(new DepotPath("//..."), null); /// IList<FileSpec> filespecs = new List<FileSpec>(); /// filespecs.Add(filespec); /// /// IList<Fix> target = Repository.GetFixes(filespecs, opts); /// </code> /// To list the fixes related to path //depot/rel/src that occurred /// between 2014/1/1 and 2014/1/31: /// <code> /// GetFixesCmdOptions opts = /// new GetFixesCmdOptions(GetFixesCmdFlags.None, 0, null, 0); /// /// VersionRange vr = new VersionRange(new DateTimeVersion(new DateTime(2014, 1, 1)), /// new DateTimeVersion(new DateTime(2014, 1, 31))); /// /// FileSpec filespec = /// new FileSpec(new DepotPath("//..."), vr); /// IList<FileSpec> filespecs = new List<FileSpec>(); /// filespecs.Add(filespec); /// /// IList<Fix> target = Repository.GetFixes(filespecs, opts); /// </code> /// </example> /// <seealso cref="GetFixesCmdFlags"/> public IList<Fix> GetFixes(IList<FileSpec> 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<Fix> value = new List<Fix>(); foreach (P4.TaggedObject obj in r.TaggedOutput) { bool dst_mismatch = false; string offset = string.Empty; if (Server != null && Server.Metadata != null) { offset = Server.Metadata.DateTimeOffset; dst_mismatch = FormBase.DSTMismatch(Server.Metadata); } value.Add(Fix.FromFixesCmdTaggedOutput(obj,offset,dst_mismatch)); } return value; } /// <summary> /// Get a list of matching lines in the passed-in file specs. /// </summary> /// <param name="filespecs"></param> /// <param name="pattern"></param> /// <param name="options"></param> /// <returns></returns> /// <remarks> /// <br/><b>p4 help grep</b> /// <br/> /// <br/> grep -- Print lines matching a pattern /// <br/> /// <br/> p4 grep [options] -e pattern file[revRange]... /// <br/> /// <br/> options: -a -i -n -A <num> -B <num> -C <num> -t -s (-v|-l|-L) (-F|-G) /// <br/> /// <br/> Searches files for lines that match the specified regular expression, /// <br/> which can contain wildcards. The parser used by the Perforce server /// <br/> is based on V8 regexp and might not be compatible with later parsers, /// <br/> but the majority of functionality is available. /// <br/> /// <br/> By default the head revision is searched. If the file argument includes /// <br/> a revision specification, all corresponding revisions are searched. /// <br/> If the file argument includes a revision range, only files in that /// <br/> range are listed, and the highest revision in the range is searched. /// <br/> For details about revision specifiers, see 'p4 help revisions'. /// <br/> /// <br/> The -a flag searches all revisions within the specified range. By /// <br/> default only the highest revision in the range is searched. /// <br/> /// <br/> The -i flag causes the pattern matching to be case-insensitive. By /// <br/> default, matching is case-sensitive. /// <br/> /// <br/> The -n flag displays the matching line number after the file revision /// <br/> number. By default, matches are displayed as revision#: <text>. /// <br/> /// <br/> The -v flag displays files with non-matching lines. /// <br/> /// <br/> The -F flag is used to interpret the pattern as a fixed string. /// <br/> /// <br/> The -G flag is used to interpret the pattern as a regular expression, /// <br/> which is the default behavior. /// <br/> /// <br/> The -L flag displays the name of each selected file from which no /// <br/> output would normally have been displayed. Scanning stops on the /// <br/> first match. /// <br/> /// <br/> The -l flag display the name of each selected file containing /// <br/> matching text. Scanning stops on the first match. /// <br/> /// <br/> The -s flag suppresses error messages that result from abandoning /// <br/> files that have a maximum number of characters in a single line that /// <br/> are greater than 4096. By default, an error is reported when grep /// <br/> abandons such files. /// <br/> /// <br/> The -t flag searches binary files. By default, only text files are /// <br/> searched. /// <br/> /// <br/> The -A <num> flag displays the specified number of lines of trailing /// <br/> context after matching lines. /// <br/> /// <br/> The -B <num> flag displays the specified number of lines of leading /// <br/> context before matching lines. /// <br/> /// <br/> The -C <num> flag displays the specified number of lines of output /// <br/> context. /// <br/> /// <br/> Regular expressions: /// <br/> /// <br/> A regular expression is zero or more branches, separated by `|'. It /// <br/> matches anything that matches one of the branches. /// <br/> /// <br/> A branch is zero or more pieces, concatenated. It matches a match /// <br/> for the first, followed by a match for the second, etc. /// <br/> /// <br/> A piece is an atom possibly followed by `*', `+', or `?'. An atom /// <br/> followed by `*' matches a sequence of 0 or more matches of the atom. /// <br/> An atom followed by `+' matches a sequence of 1 or more matches of /// <br/> the atom. An atom followed by `?' matches a match of the atom, or /// <br/> the null string. /// <br/> /// <br/> An atom is a regular expression in parentheses (matching a match for /// <br/> the regular expression), a range (see below), `.' (matching any /// <br/> single character), `^' (matching the null string at the beginning /// <br/> of the input string), `$' (matching the null string at the end of /// <br/> the input string), a `\' followed by a single character (matching /// <br/> that character), or a single character with no other significance /// <br/> (matching that character). /// <br/> /// <br/> A range is a sequence of characters enclosed in `[]'. It normally /// <br/> matches any single character from the sequence. If the sequence /// <br/> begins with `^', it matches any single character not from the rest /// <br/> of the sequence. If two characters in the sequence are separated by /// <br/> `-', this is shorthand for the full list of ASCII characters between /// <br/> them (e.g. `[0-9]' matches any decimal digit). To include a literal /// <br/> `]' in the sequence, make it the first character (following a possible /// <br/> `^'). To include a literal `-', make it the first or last character. /// <br/> /// <br/> /// </remarks> /// <example> /// To get the file line matches for the pattern "OpenConnection" in the /// file //depot/main/Program.cs with case-insensitive search: /// <code> /// GetFileLineMatchesCmdOptions opts = /// new GetFileLineMatchesCmdOptions(GetFileLineMatchesCmdFlags.CaseInsensitive, /// 0, 0, 0); /// /// FileSpec filespec = /// new FileSpec(new DepotPath("//depot/main/Program.cs"), null); /// IList<FileSpec> filespecs = new List<FileSpec>(); /// filespecs.Add(filespec); /// /// IList<FileLineMatch> target = /// Repository.GetFileLineMatches(filespecs, "OpenConnection" opts); /// </code> /// To get the file line matches for the pattern "OpenConnection" in the /// file //depot/main/Program.cs showing 2 lines before and after the found /// pattern and showing line numbers: /// <code> /// GetFileLineMatchesCmdOptions opts = /// new GetFileLineMatchesCmdOptions(GetFileLineMatchesCmdFlags.IncludeLineNumbers, /// 2, 2, 0); /// /// FileSpec filespec = /// new FileSpec(new DepotPath("//depot/main/Program.cs"), null); /// IList<FileSpec> filespecs = new List<FileSpec>(); /// filespecs.Add(filespec); /// /// IList<FileLineMatch> target = /// Repository.GetFileLineMatches(filespecs, "OpenConnection" opts); /// </code> /// </example> /// <seealso cref="GetFileLineMatchesCmdFlags"/> public IList<FileLineMatch> GetFileLineMatches(IList<FileSpec> 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<FileLineMatch> value = new List<FileLineMatch>(); foreach (P4.TaggedObject obj in r.TaggedOutput) { FileLineMatch val = new FileLineMatch(); val.ParseGrepCmdTaggedData(obj); value.Add(val); } return value; } /// <summary> /// Get a list of submitted integrations for the passed-in file specs. /// </summary> /// <param name="filespecs"></param> /// <param name="options"></param> /// <returns></returns> /// <remarks> /// <br/><b>p4 help integrated</b> /// <br/> /// <br/> integrated -- List integrations that have been submitted /// <br/> /// <br/> p4 integrated [-r] [-b branch] [file ...] /// <br/> /// <br/> The p4 integrated command lists integrations that have been submitted. /// <br/> To list unresolved integrations, use 'p4 resolve -n'. To list /// <br/> resolved but unsubmitted integrations, use 'p4 resolved'. /// <br/> /// <br/> If the -b branch flag is specified, only files integrated from the /// <br/> source to target files in the branch view are listed. Qualified /// <br/> files are listed, even if they were integrated without using the /// <br/> branch view. /// <br/> /// <br/> The -r flag reverses the mappings in the branch view, swapping the /// <br/> target files and source files. The -b branch flag is required. /// <br/> /// <br/> /// </remarks> /// <example> /// To get the file intergration records for the path //depot/rel defined /// by branch specification main_to_rel: /// <code> /// GetSubmittedIntegrationsCmdOptions opts = /// new GetSubmittedIntegrationsCmdOptions(GetSubmittedIntegrationsCmdFlags.None, /// "main_to_rel"); /// /// FileSpec filespec = /// new FileSpec(new DepotPath("//depot/rel/..."), null); /// IList<FileSpec> filespecs = new List<FileSpec>(); /// filespecs.Add(filespec); /// /// IList<FileIntegrationRecord> target = /// Repository.GetSubmittedIntegrations(filespecs, opts); /// </code> /// To get the file intergration records for the path //depot/main defined /// by branch specification main_to_rel in reverse direction: /// <code> /// GetSubmittedIntegrationsCmdOptions opts = /// new GetSubmittedIntegrationsCmdOptions(GetSubmittedIntegrationsCmdFlags.ReverseMappings, /// "main_to_rel"); /// /// FileSpec filespec = /// new FileSpec(new DepotPath("//depot/rel/..."), null); /// IList<FileSpec> filespecs = new List<FileSpec>(); /// filespecs.Add(filespec); /// /// IList<FileIntegrationRecord> target = /// Repository.GetSubmittedIntegrations(filespecs, opts); /// </code> /// </example> /// <seealso cref="GetSubmittedIntegrationsCmdFlags"/> public IList<FileIntegrationRecord> GetSubmittedIntegrations(IList<FileSpec> 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<FileIntegrationRecord> value = new List<FileIntegrationRecord>(); foreach (P4.TaggedObject obj in r.TaggedOutput) { FileIntegrationRecord val = new FileIntegrationRecord(); val.ParseIntegratedCmdTaggedData(obj); value.Add(val); } return value; } /// <summary> /// Get a list of Perforce protection entries for the passed-in file specs /// </summary> /// <param name="filespecs"></param> /// <param name="options"></param> /// <returns></returns> /// <remarks> /// <br/><b>p4 help protects</b> /// <br/> /// <br/> protects -- Display protections defined for a specified user and path /// <br/> /// <br/> p4 protects [-a | -g group | -u user] [-h host] [-m] [file ...] /// <br/> /// <br/> 'p4 protects' displays the lines from the protections table that /// <br/> apply to the current user. The protections table is managed using /// <br/> the 'p4 protect' command. /// <br/> /// <br/> If the -a flag is specified, protection lines for all users are /// <br/> displayed. If the -g group flag or -u user flag is specified, /// <br/> protection lines for that group or user are displayed. /// <br/> /// <br/> If the -h host flag is specified, the protection lines that apply /// <br/> to the specified host (IP address) are displayed. /// <br/> /// <br/> If the -m flag is given, a single word summary of the maximum /// <br/> access level is reported. Note that this summary does not take /// <br/> exclusions into account. /// <br/> /// <br/> If the file argument is specified, protection lines that apply to /// <br/> the specified files are displayed. /// <br/> /// <br/> The -a/-g/-u flags require 'super' access granted by 'p4 protect'. /// <br/> /// <br/> /// </remarks> /// <example> /// To get the protections for the user tim for the entire server: /// <code> /// GetProtectionEntriesCmdOptions opts = /// new GetProtectionEntriesCmdOptions(GetProtectionEntriesCmdFlags.None, /// null, "tim", null); /// /// FileSpec filespec = /// new FileSpec(new DepotPath("//..."), null); /// IList<FileSpec> filespecs = new List<FileSpec>(); /// filespecs.Add(filespec); /// /// IList<ProtectionEntry> target = /// Repository.GetProtectionEntries(filespecs, opts); /// </code> /// To get the protections summary for the group development tim for the entire server /// when connecting from IP address 10.24.4.6: /// <code> /// GetProtectionEntriesCmdOptions opts = /// new GetProtectionEntriesCmdOptions(GetProtectionEntriesCmdFlags.AccessSummary, /// "development", null, "10.24.4.6"); /// /// FileSpec filespec = /// new FileSpec(new DepotPath("//..."), null); /// IList<FileSpec> filespecs = new List<FileSpec>(); /// filespecs.Add(filespec); /// /// IList<ProtectionEntry> target = /// Repository.GetProtectionEntries(filespecs, opts); /// </code> /// </example> /// <seealso cref="GetProtectionEntriesCmdFlags"/> public IList<ProtectionEntry> GetProtectionEntries(IList<FileSpec> 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<ProtectionEntry> value = new List<ProtectionEntry>(); foreach (P4.TaggedObject obj in r.TaggedOutput) { StringEnum<ProtectionMode> mode = obj["perm"]; StringEnum<EntryType> 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; } /// <summary> /// List Perforce users assigned to review files. /// </summary> /// <param name="filespecs"></param> /// <param name="options"></param> /// <returns></returns> /// <remarks> /// <br/><b>p4 help reviews</b> /// <br/> /// <br/> reviews -- List the users who are subscribed to review files /// <br/> /// <br/> p4 reviews [-c changelist#] [file ...] /// <br/> /// <br/> 'p4 reviews' lists all users who have subscribed to review the /// <br/> specified files, the files in the specified changelist, or all files /// <br/> (the default). To subscribe to review files, issue the 'p4 user' /// <br/> command and edit the 'Reviews field'. /// <br/> /// <br/> /// </remarks> /// <example> /// To get the list of users who are reviewing submits to //depot/main/src: /// <code> /// GetReviewersCmdOptions opts = /// new GetReviewersCmdOptions(GetReviewersCmdFlags.None, 0); /// /// FileSpec filespec = /// new FileSpec(new DepotPath("//depot/main/src/..."), null); /// IList<FileSpec> filespecs = new List<FileSpec>(); /// filespecs.Add(filespec); /// /// IList<ProtectionEntry> target = /// Repository.GetProtectionEntries(filespecs, opts); /// </code> /// To get the list of users who are reviewing submitted changelist 83476: /// <code> /// GetReviewersCmdOptions opts = /// new GetReviewersCmdOptions(GetReviewersCmdFlags.None, 83476); /// /// FileSpec filespec = /// new FileSpec(new DepotPath("//..."), null); /// IList<FileSpec> filespecs = new List<FileSpec>(); /// filespecs.Add(filespec); /// /// IList<ProtectionEntry> target = /// Repository.GetProtectionEntries(filespecs, opts); /// </code> /// </example> /// <seealso cref="GetProtectionEntriesCmdFlags"/> public IList<User> GetReviewers(IList<FileSpec> 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<User> value = new List<User>(); 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<string> reviews = new List<string>(); 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; } /// <summary> /// Get a FormSpec of the specified form type. /// </summary> /// <param name="spectype"></param> /// <param name="options"></param> /// <returns></returns> /// <remarks> /// <br/><b>p4 help spec</b> /// <br/> /// <br/> spec -- Edit spec definitions (unsupported) /// <br/> /// <br/> p4 spec [-d -i -o] type /// <br/> /// <br/> Edit any type of specification: branch, change, client, depot, /// <br/> group, job, label, spec, stream, trigger, typemap, or user. Only /// <br/> the comments and the formatting hints can be changed. Any fields /// <br/> that you add during editing are discarded when the spec is saved. /// <br/> /// <br/> 'p4 jobspec' is equivalent to 'p4 spec job', and any custom spec /// <br/> (include the job spec) can be deleted with 'p4 spec -d type'. /// <br/> /// <br/> /// </remarks> /// <example> /// To get the FormSpec for changelist: /// <code> /// Options ops = new Options(); /// ops["-o"] = null; /// /// FormSpec target = Repository.GetFormSpec(ops, "change"); /// </code> /// To get the FormSpec for client: /// <code> /// Options ops = new Options(); /// ops["-o"] = null; /// /// FormSpec target = Repository.GetFormSpec(ops, "clinet"); /// </code> /// To get the FormSpec for user: /// <code> /// Options ops = new Options(); /// ops["-o"] = null; /// /// FormSpec target = Repository.GetFormSpec(ops, "user"); /// </code> /// </example> 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; } /// <summary> /// Get the repository's trigger table. /// </summary> /// <param name="options"></param> /// <returns></returns> /// <remarks> /// <br/><b>p4 help triggers</b> /// <br/> /// <br/> triggers -- Modify list of server triggers /// <br/> /// <br/> p4 triggers /// <br/> p4 triggers -o /// <br/> p4 triggers -i /// <br/> /// <br/> 'p4 triggers' edits the table of triggers, which are used for /// <br/> change submission validation, form validation, external authentication, /// <br/> external job fix integration, and external archive integration. /// <br/> /// <br/> Triggers are administrator-defined commands that the server runs /// <br/> to perform the following: /// <br/> /// <br/> Validate changelist submissions. /// <br/> /// <br/> The server runs changelist triggers before the file transfer, /// <br/> between file transfer and changelist commit, or after the commit /// <br/> /// <br/> Validate shelve operations. /// <br/> /// <br/> The server runs shelve triggers before files are shelved, after /// <br/> files are shelved, or when shelved files have been discarded /// <br/> (via shelve -d). /// <br/> /// <br/> Manipulate and validate forms. /// <br/> /// <br/> The server runs form-validating triggers between generating /// <br/> and outputting the form, between inputting and parsing the /// <br/> form, between parsing and saving the form, or when deleting /// <br/> the form. /// <br/> /// <br/> Authenticate or change a user password. /// <br/> /// <br/> The server runs authentication triggers to either validate /// <br/> a user password during login or when setting a new password. /// <br/> /// <br/> Intercept job fix additions or deletions. /// <br/> /// <br/> The server run fix triggers prior to adding or deleting a fix /// <br/> between a job and changelist. /// <br/> /// <br/> Access external archive files. /// <br/> /// <br/> For files with the +X filetype modifier, the server runs an /// <br/> archive trigger to read, write, or delete files in the archive. /// <br/> /// <br/> Command execution policy. /// <br/> /// <br/> Command triggers can be specified to run before and after /// <br/> processing of user requests. Pre-execution triggers can /// <br/> prevent the command from running. /// <br/> /// <br/> The trigger form has a single entry 'Triggers', followed by any /// <br/> number of trigger lines. Triggers are executed in the order listed /// <br/> and if a trigger fails, subsequent triggers are not run. A trigger /// <br/> succeeds if the executed command exits returning 0 and fails otherwise. /// <br/> Normally the failure of a trigger prevents the operation from /// <br/> completing, except for the commit triggers, which run after the /// <br/> operation is complete. /// <br/> /// <br/> Each trigger line contains a trigger name, a trigger type, a depot /// <br/> file path pattern or form type, and a command to run. /// <br/> /// <br/> Name: The name of the trigger. For change triggers, a run of the /// <br/> same trigger name on contiguous lines is treated as a single /// <br/> trigger so that multiple paths can be specified. Only the /// <br/> command of the first such trigger line is used. /// <br/> /// <br/> Type: When the trigger is to execute: /// <br/> /// <br/> archive: /// <br/> Execute an archive trigger for the server to access /// <br/> any file with the +X filetype modifier. /// <br/> /// <br/> auth-check: /// <br/> service-check: /// <br/> Execute an authentication check trigger to verify a /// <br/> user's password against an external password manager /// <br/> during login or when setting a new password. /// <br/> /// <br/> auth-check-sso: /// <br/> Facilitate a single sign-on user authentication. This /// <br/> configuration requires two programs or scripts to run; /// <br/> one on the client, the other on the server. /// <br/> /// <br/> client: /// <br/> Set the environment variable 'P4LOGINSSO' to point to /// <br/> a script that can be executed to obtain the user's /// <br/> credentials or other information that the server /// <br/> trigger can verify. The client-side script must /// <br/> write the message to the standard output /// <br/> (max length 128K). /// <br/> /// <br/> Example: P4LOGINSSO=/Users/joe/bin/runsso /// <br/> /// <br/> The 'server address' can be optionally passed to the /// <br/> client script by appending %serverAddress% to the /// <br/> client command string, as in: /// <br/> /// <br/> P4LOGINSSO="/Users/joe/bin/runsso %serverAddress%" /// <br/> /// <br/> server: /// <br/> Execute an authentication (sso) trigger that gets /// <br/> this message from the standard input and returns an /// <br/> exit status of 0 (for verified) or otherwise failed. /// <br/> /// <br/> Example: /// <br/> sso auth-check-sso auth "/secure/verify %user%" /// <br/> /// <br/> The user must issue the 'p4 login' command, but no /// <br/> password prompting is invoked. If the server /// <br/> determines that the user is valid, they are issued a /// <br/> Perforce ticket just as if they had logged in with a /// <br/> password. /// <br/> /// <br/> Pre-2007.2 clients cannot run a client-side single /// <br/> sign-on. Specifying an 'auth-check' trigger as a backup /// <br/> for a user to gain access will prompt the user for a /// <br/> password if it's an older client or P4LOGINSSO has not /// <br/> been configured. /// <br/> /// <br/> Unlike passwords which are encrypted, the sso message is /// <br/> sent to the server in clear text. /// <br/> /// <br/> auth-set: /// <br/> Execute an authentication set trigger to send a new /// <br/> password to an external password manager. /// <br/> /// <br/> change-submit: /// <br/> Execute pre-submit trigger after changelist has been /// <br/> created and files locked but prior to file transfer. /// <br/> /// <br/> change-content: /// <br/> Execute mid-submit trigger after file transfer but prior /// <br/> to commit. Files can be accessed by the 'p4 diff2', /// <br/> 'p4 files', 'p4 fstat', and 'p4 print' commands using /// <br/> the revision specification '@=change', where 'change' is /// <br/> the pending changelist number passed as %changelist%. /// <br/> /// <br/> change-commit: /// <br/> Execute post-submit trigger after changelist commit. /// <br/> /// <br/> change-failed: /// <br/> Executes only if the changelist commit failed. /// <br/> Note that this trigger only fires on errors /// <br/> occurring after a commit process has started. It does /// <br/> not fire for early usage errors, or due to errors from /// <br/> the submit form. In short, if an edge-* or change-* /// <br/> trigger could have run, then the change-failed trigger /// <br/> will fire if that commit fails. /// <br/> /// <br/> command: /// <br/> Execute pre/post trigger when users run commands. /// <br/> /// <br/> edge-submit: /// <br/> Execute pre-submit trigger on Edge Server after changelist /// <br/> has been created but prior to file transfer. /// <br/> /// <br/> edge-content: /// <br/> Execute mid-submit trigger on Edge Server after file /// <br/> transfer but prior to beginning submit on Commit Server. /// <br/> /// <br/> fix-add: /// <br/> Execute fix trigger prior to adding a fix. The special /// <br/> variable %jobs% is available for expansion and must be /// <br/> the last argument to the trigger as it expands to one /// <br/> argument for each job listed on the 'p4 fix' command. /// <br/> /// <br/> fix-delete: /// <br/> Execute fix trigger prior to deleting a fix. The special /// <br/> variable %jobs% is available for expansion and must be /// <br/> the last argument to the trigger as it expands to one /// <br/> argument for each job listed on the 'p4 fix -d' command. /// <br/> /// <br/> form-out: /// <br/> Execute form trigger on generation of form. Trigger may /// <br/> modify form. /// <br/> /// <br/> form-in: /// <br/> Execute form trigger on input of form before its contents /// <br/> are parsed and validated. Trigger may modify form. /// <br/> /// <br/> form-save: /// <br/> Execute form trigger prior to save of form after its /// <br/> contents are parsed. /// <br/> /// <br/> form-commit: /// <br/> Execute form trigger after it has been committed, allowing /// <br/> access to automatically generated fields (jobname, dates /// <br/> etc). It cannot modify the form. This trigger for job /// <br/> forms is run by 'p4 job' and 'p4 fix' (after the status /// <br/> is updated), 'p4 change' (if the job is added or deleted) /// <br/> and 'p4 submit' (if the job is associated with the change). /// <br/> The 'form-commit' trigger has access to the new job name /// <br/> created with 'p4 job', while the 'form-in' and 'form-save' /// <br/> triggers are run before the job name is created. The /// <br/> special variable %action% is available on the job /// <br/> 'form-commit' trigger command line, and is expanded when /// <br/> the job is modified by a fix. /// <br/> /// <br/> form-delete: /// <br/> Execute form trigger prior to delete of form after its /// <br/> contents are parsed. /// <br/> /// <br/> shelve-submit: /// <br/> Execute pre-shelve trigger after changelist has been /// <br/> created but prior to file transfer. /// <br/> /// <br/> shelve-commit: /// <br/> Execute post-shelve trigger after files are shelved. /// <br/> /// <br/> shelve-delete: /// <br/> Execute shelve trigger prior to discarding shelved files. /// <br/> /// <br/> Path: For change and submit triggers, a file pattern to match files /// <br/> in the changelist. This file pattern can be an exclusion /// <br/> mapping (-pattern), to exclude files. For form triggers, the /// <br/> name of the form (branch, client, etc). For fix triggers /// <br/> 'fix' is required as the path value. For authentication /// <br/> triggers, 'auth' is required as the path value. For archive /// <br/> triggers, a file pattern to match the name of the file being /// <br/> accessed in the archive. Note that, due to lazy copying when /// <br/> branching files, the name of the file in the archive can not /// <br/> be the same as the name of the file in the depot. /// <br/> /// <br/> Command: The OS command to run for validation. If the command /// <br/> contains spaces, enclose it in double quotes. The /// <br/> following variables are expanded in the command string. /// <br/> Use of the triggers.io configurable with a value greater than /// <br/> zero is recommended, as some vars may be empty or contain /// <br/> shell metacharacters. /// <br/> /// <br/> %//depot/trigger.exe% -- depot paths within %vars% /// <br/> are filled with the path to a temporary file containing /// <br/> the referenced file's contents. Only standard and stream /// <br/> depot files whose contents is available are valid. /// <br/> %argc% -- number of command arguments /// <br/> %args% -- command argument string /// <br/> %client% -- the client issuing the command /// <br/> %clientcwd% -- client current working directory /// <br/> %clienthost% -- the hostname of the client /// <br/> %clientip% -- the IP address of the client /// <br/> %clientprog% -- the program name of the client /// <br/> %clientversion% -- the version of the client /// <br/> %command% -- name of command being run /// <br/> %groups% -- list of groups user is a member of /// <br/> %intermediateService% -- presence of a Broker/Proxy/etc /// <br/> %maxErrorSeverity% -- highest error seen for this cmd /// <br/> %maxErrorText% -- text and errno for highest error /// <br/> %maxLockTime% -- user-specified override of group value /// <br/> %maxResults% -- user-specified override of group value /// <br/> %maxScanRows% -- user-specified override of group value /// <br/> %quote% -- double quote character /// <br/> %serverhost% -- the hostname of the server /// <br/> %serverid% -- the value of the server's server.id /// <br/> %serverip% -- the IP address of the server /// <br/> %servername% -- the value of the server's $P4NAME /// <br/> %serverpid% -- the PID of the server /// <br/> %serverport% -- the IP address:port of the server /// <br/> preceded by the transport prefix, /// <br/> if needed (i.e. P4PORT) /// <br/> %serverroot% -- the value of the server's $P4ROOT /// <br/> %serverservices% -- the services provided by the server /// <br/> %serverVersion% -- the server's version string /// <br/> %terminated% -- if the command was forced to quit early /// <br/> %termReason% -- reason for early termination /// <br/> %triggerMeta_action% -- command to execute by trigger /// <br/> %triggerMeta_depotFile% -- third field in trigger def. /// <br/> %triggerMeta_name% -- name from trigger definition /// <br/> %triggerMeta_trigger% -- second field in trigger definition /// <br/> %user% -- the user issuing the command /// <br/> /// <br/> %changelist% -- the changelist being submitted /// <br/> %changeroot% -- the root path of files submitted /// <br/> %oldchangelist% -- the pre-commit changelist number /// <br/> /// <br/> (More information can be gathered about the /// <br/> changelist being submitted by running /// <br/> 'p4 describe %changelist%'.) /// <br/> /// <br/> %formfile% -- path to temp file containing form /// <br/> %formname% -- the form's name (branch name, etc) /// <br/> %formtype% -- the type of form (branch, etc) /// <br/> %action% -- added/deleted/submitted on job form-commit /// <br/> /// <br/> %jobs% -- list of job names for fix triggers /// <br/> /// <br/> %op% -- read/write/delete for archive access /// <br/> %file% -- name of archive file /// <br/> %rev% -- revision of archive file /// <br/> /// <br/> If the command was sent via a proxy, broker, or replica: /// <br/> %peerhost% -- the hostname of the proxy/broker/replica /// <br/> %peerip% -- the IP address of the proxy/broker/replica /// <br/> If the command was sent directly, %peerhost% and /// <br/> %peerip% match %clienthost% and %clientip%. /// <br/> /// <br/> For a change-* trigger in a distributed installation, /// <br/> %submitserverid% -- the server.id where submit was run /// <br/> /// <br/> Note that not all variables are available for every /// <br/> trigger type. E.g. argc and argv only show up for /// <br/> pre-user-$cmd and change-submit (and so on), but not for /// <br/> post-user-$cmd or change-commit. /// <br/> /// <br/> The command's standard input depends on the value of the /// <br/> triggers.io configurable. When it is set to zero, stdin is /// <br/> empty for change, shelve, fix, command, and auth triggers, it /// <br/> is the file content for the archive trigger. When triggers.io /// <br/> is set to 1, (except for archive triggers,) stdin is a textual /// <br/> dictionary containing connection information that the trigger. /// <br/> must read. /// <br/> /// <br/> If the command fails, the command's standard output (not /// <br/> error output) is sent to the client as the text of a trigger /// <br/> failure error message. /// <br/> /// <br/> If the command succeeds, the command's standard output is /// <br/> sent as an unadorned message to the client for all triggers /// <br/> except archive triggers; for archive triggers, the command's /// <br/> standard output is the file content. /// <br/> /// <br/> The -o flag writes the trigger table to the standard output. /// <br/> The user's editor is not invoked. /// <br/> /// <br/> The -i flag reads the trigger table from the standard input. /// <br/> The user's editor is not invoked. /// <br/> /// <br/> 'p4 triggers' requires 'super' access granted by 'p4 protect'. /// <br/> /// <br/> /// </remarks> /// <example> /// To get the trigger table: /// <code> /// GetTriggerTableCmdOptions opts = /// new GetTriggerTableCmdOptions(GetTriggerTableCmdFlags.Output); /// /// IList<Trigger> target = Repository.GetTriggerTable(opts); /// </code> /// </example> /// <seealso cref="GetTriggerTableCmdFlags"/> public IList<Trigger> 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<Trigger> value = new List<Trigger>(); foreach (P4.TaggedObject obj in r.TaggedOutput) { System.Text.StringBuilder sb = new StringBuilder(); foreach (KeyValuePair<string, string> 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<TriggerType> 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; } /// <summary> /// Get the repository's type map. /// </summary> /// <returns></returns> /// <remarks> /// runs the command p4 typemap -o /// </remarks> /// <remarks> /// <br/><b>p4 help typemap</b> /// <br/> /// <br/> typemap -- Edit the filename-to-filetype mapping table /// <br/> /// <br/> p4 typemap /// <br/> p4 typemap -o /// <br/> p4 typemap -i /// <br/> /// <br/> 'p4 typemap' edits a name-to-type mapping table for 'p4 add', which /// <br/> uses the table to assign a file's filetype based on its name. /// <br/> /// <br/> The typemap form has a single field, 'TypeMap', followed by any /// <br/> number of typemap lines. Each typemap line contains a filetype /// <br/> and a depot file path pattern: /// <br/> /// <br/> Filetype: See 'p4 help filetypes' for a list of valid filetypes. /// <br/> /// <br/> Path: Names to be mapped to the filetype. The mapping is /// <br/> a file pattern in depot syntax. When a user adds a file /// <br/> matching this pattern, its default filetype is the /// <br/> file type specified in the table. To exclude files from /// <br/> the typemap, use exclusionary (-pattern) mappings. /// <br/> To match all files anywhere in the depot hierarchy, /// <br/> the pattern must begin with '//...'. To match files /// <br/> with a specified suffix, use '//.../*.suffix' or /// <br/> use '//....suffix' (four dots). /// <br/> /// <br/> Later entries override earlier entries. If no matching entry is found /// <br/> in the table, 'p4 add' determines the filetype by examining the file's /// <br/> contents and execution permission bits. /// <br/> /// <br/> The -o flag writes the typemap table to standard output. The user's /// <br/> editor is not invoked. /// <br/> /// <br/> The -i flag reads the typemap table from standard input. The user's /// <br/> editor is not invoked. /// <br/> /// <br/> 'p4 typemap' requires 'admin' access, which is granted by 'p4 protect'. /// <br/> /// <br/> /// </remarks> /// <example> /// To get the typemap table: /// <code> /// IList<TypeMapEntry> target = Repository.GetTypeMap(); /// </code> /// </example> public IList<TypeMapEntry> 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<TypeMapEntry> value = new List<TypeMapEntry>(); 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; } /// <summary> /// Get the repository's protection table. /// </summary> /// <param name="options"></param> /// <returns></returns> /// <remarks> /// <br/><b>p4 help protect</b> /// <br/> /// <br/> protect -- Modify protections in the server namespace /// <br/> /// <br/> p4 protect /// <br/> p4 protect -o /// <br/> p4 protect -i /// <br/> /// <br/> 'p4 protect' edits the protections table in a text form. /// <br/> /// <br/> Each line in the table contains a protection mode, a group/user /// <br/> indicator, the group/user name, client host ID and a depot file /// <br/> path pattern. Users receive the highest privilege that is granted /// <br/> on any line. /// <br/> /// <br/> Note: remote depot are accessed using the pseudo-user 'remote'. /// <br/> To control access from other servers that define your server as /// <br/> a remote server, grant appropriate permissions to the 'remote' user. /// <br/> /// <br/> Mode: The permission level or right being granted or denied. /// <br/> Each permission level includes all the permissions above /// <br/> it, except for 'review'. Each permission only includes /// <br/> the specific right and no lesser rights. This approach /// <br/> enables you to deny individual rights without having to /// <br/> re-grant lesser rights. Modes prefixed by '=' are rights. /// <br/> All other modes are permission levels. /// <br/> /// <br/> Valid modes are: /// <br/> /// <br/> list - users can see names but not contents of files; /// <br/> users can see all non-file related metadata /// <br/> (clients, users, changelists, jobs, etc.) /// <br/> /// <br/> read - users can sync, diff, and print files /// <br/> /// <br/> open - users can open files (add, edit. delete, /// <br/> integrate) /// <br/> /// <br/> write - users can submit open files /// <br/> /// <br/> admin - permits those administrative commands and /// <br/> command options that don't affect the server's /// <br/> security. /// <br/> /// <br/> super - access to all commands and command options. /// <br/> /// <br/> review - permits access to the 'p4 review' command; /// <br/> implies read access /// <br/> /// <br/> =read - if this right is denied, users can't sync, /// <br/> diff, or print files /// <br/> /// <br/> =branch - if this right is denied, users are not /// <br/> permitted to use files as a source /// <br/> for 'p4 integrate' /// <br/> /// <br/> =open = if this right is denied, users cannot open /// <br/> files (add, edit, delete, integrate) /// <br/> /// <br/> =write = if this right is denied, users cannot submit /// <br/> open files /// <br/> /// <br/> Group/User indicator: specifies the grantee is a group or user. /// <br/> /// <br/> Name: A Perforce group or user name; can include wildcards. /// <br/> /// <br/> Host: The IP address of a client host; can include wildcards. /// <br/> /// <br/> Path: The part of the depot to which access is being granted /// <br/> or denied. To deny access to a depot path, preface the /// <br/> path with a "-" character. These exclusionary mappings /// <br/> apply to all access levels, even if only one access /// <br/> level is specified in the first field. /// <br/> /// <br/> The -o flag writes the protection table to the standard output. /// <br/> The user's editor is not invoked. /// <br/> /// <br/> The -i flag reads the protection table from the standard input. /// <br/> The user's editor is not invoked. /// <br/> /// <br/> After protections are defined, 'p4 protect' requires 'super' /// <br/> access. /// <br/> /// <br/> /// </remarks> /// <example> /// To get the protections table: /// <code> /// GetProtectionTableCmdOptions opts = /// new GetProtectionTableCmdOptions(GetProtectionTableCmdFlags.Output); /// /// IList<ProtectionEntry> target = Repository.GetProtectionTable(opts); /// </code> /// </example> /// <seealso cref="GetProtectionTableCmdFlags"/> public IList<ProtectionEntry> 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<ProtectionEntry> value = new List<ProtectionEntry>(); foreach (P4.TaggedObject obj in r.TaggedOutput) { System.Text.StringBuilder sb = new StringBuilder(); foreach (KeyValuePair<string, string> 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<ProtectionMode> mode = entries[1]; StringEnum<EntryType> 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; } /// <summary> /// Get the Perforce counters for this repository. /// </summary> /// <param name="options"></param> /// <returns></returns> /// <remarks> /// <br/><b>p4 help counters</b> /// <br/> /// <br/> counters -- Display list of known counters /// <br/> /// <br/> p4 counters [-e nameFilter -m max] /// <br/> /// <br/> Lists the counters in use by the server. The server /// <br/> uses the following counters directly: /// <br/> /// <br/> change Current change number /// <br/> job Current job number /// <br/> journal Current journal number /// <br/> lastCheckpointAction Data about the last complete checkpoint /// <br/> logger Event log index used by 'p4 logger' /// <br/> traits Internal trait lot number used by 'p4 attribute' /// <br/> upgrade Server database upgrade level /// <br/> /// <br/> The -e nameFilter flag lists counters with a name that matches /// <br/> the nameFilter pattern, for example: -e 'mycounter-*'. /// <br/> /// <br/> The -m max flag limits the output to the first 'max' counters. /// <br/> /// <br/> The names 'minClient', 'minClientMessage', 'monitor', /// <br/> 'security', and 'unicode' are reserved names: do not use them /// <br/> as ordinary counters. /// <br/> /// <br/> For general-purpose server configuration, see 'p4 help configure'. /// <br/> /// <br/> /// </remarks> /// <example> /// To get the counters on the server: /// <code> /// IList<Counter> target = Repository.GetCounters(null); /// </code> /// To get the counters on the server that start with the name "build_": /// <code> /// Options opts = new Options(); /// opts["-e"] = "build_*"; /// IList<Counter> target = Repository.GetCounters(opts); /// </code> /// </example> public IList<Counter> 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<Counter> val = new List<Counter>(); 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; } /// <summary> /// Get a named Perforce counter value from the repository. /// </summary> /// <param name="name"></param> /// <param name="options"></param> /// <returns></returns> /// <remarks> /// <br/><b>p4 help counter</b> /// <br/> /// <br/> counter -- Display, set, or delete a counter /// <br/> /// <br/> p4 counter name /// <br/> p4 counter [-f] name value /// <br/> p4 counter [-f] -d name /// <br/> p4 counter [-f] -i name /// <br/> p4 counter [-f] -m [ pair list ] /// <br/> /// <br/> The first form displays the value of the specified counter. /// <br/> /// <br/> The second form sets the counter to the specified value. /// <br/> /// <br/> The third form deletes the counter. This option usually has the /// <br/> same effect as setting the counter to 0. /// <br/> /// <br/> The -f flag sets or deletes counters used by Perforce, which are /// <br/> listed by 'p4 help counters'. Important: Never set the 'change' /// <br/> counter to a value that is lower than its current value. /// <br/> /// <br/> The -i flag increments a counter by 1 and returns the new value. /// <br/> This option is used instead of a value argument and can only be /// <br/> used with numeric counters. /// <br/> /// <br/> The fifth form allows multiple operations in one command. /// <br/> With this, the list is pairs of arguments. Each pair is either /// <br/> counter value or '-' counter. To set a counter use a name and value. /// <br/> To delete a counter use a '-' followed by the name. /// <br/> Counters can be assigned textual values as well as numeric ones, /// <br/> despite the name 'counter'. /// <br/> /// <br/> Counters can be assigned textual values as well as numeric ones, /// <br/> despite the name 'counter'. /// <br/> /// <br/> 'p4 counter' requires 'review' access granted by 'p4 protect'. /// <br/> The -f flag requires that the user be an operator or have 'super' /// <br/> access. /// <br/> /// <br/> /// </remarks> /// <example> /// To get the job counter: /// <code> /// Counter target = Repository.GetCounter("job", null); /// </code> /// To get the change counter: /// <code> /// Counter target = Repository.GetCounter("change", null); /// </code> /// To get the journal counter: /// <code> /// Counter target = Repository.GetCounter("journal", null); /// </code> /// </example> 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; } /// <summary> /// Delete a Perforce counter from the repository. /// </summary> /// <param name="name"></param> /// <param name="options"></param> /// <returns></returns> /// <remarks> /// <br/><b>p4 help counter</b> /// <br/> /// <br/> counter -- Display, set, or delete a counter /// <br/> /// <br/> p4 counter name /// <br/> p4 counter [-f] name value /// <br/> p4 counter [-f] -d name /// <br/> p4 counter [-f] -i name /// <br/> p4 counter [-f] -m [ pair list ] /// <br/> /// <br/> The first form displays the value of the specified counter. /// <br/> /// <br/> The second form sets the counter to the specified value. /// <br/> /// <br/> The third form deletes the counter. This option usually has the /// <br/> same effect as setting the counter to 0. /// <br/> /// <br/> The -f flag sets or deletes counters used by Perforce, which are /// <br/> listed by 'p4 help counters'. Important: Never set the 'change' /// <br/> counter to a value that is lower than its current value. /// <br/> /// <br/> The -i flag increments a counter by 1 and returns the new value. /// <br/> This option is used instead of a value argument and can only be /// <br/> used with numeric counters. /// <br/> /// <br/> The fifth form allows multiple operations in one command. /// <br/> With this, the list is pairs of arguments. Each pair is either /// <br/> counter value or '-' counter. To set a counter use a name and value. /// <br/> To delete a counter use a '-' followed by the name. /// <br/> Counters can be assigned textual values as well as numeric ones, /// <br/> despite the name 'counter'. /// <br/> /// <br/> 'p4 counter' requires 'review' access granted by 'p4 protect'. /// <br/> The -f flag requires that the user be an operator or have 'super' /// <br/> access. /// <br/> /// <br/> /// </remarks> /// <example> /// To delete a counter named test: /// <code> /// Counter target = Repository.DeleteCounter("test", null); /// </code> /// To delete a counter named build using -f with a user with /// super access: /// <code> /// Options opts = new Options(); /// opts["-f"] = null; /// Counter target = Repository.DeleteCounter("build", opts); /// </code> /// </example> public Object DeleteCounter(String name, Options options) { if (options==null) { options = new Options(); } options["-d"] = null; P4.P4Command Cmd = new P4Command(this, "counter", false, name); P4.P4CommandResult r = Cmd.Run(options); if (r.Success != true) { P4Exception.Throw(r.ErrorList); return null; } return r.InfoOutput; } #region IDisposable Members public void Dispose() { _connection.Dispose(); } #endregion } }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#1 | 18970 | rtande |
Merging //guest/perforce_software/p4connect/main/src/... to //rtande/p4connect/main/src/... |
||
//guest/perforce_software/p4connect/main/src/P4Bridge/p4api.net/Repository.cs | |||||
#1 | 16209 | Norman Morse | Move entire source tree into "main" branch so workshop code will act correctly. | ||
//guest/perforce_software/p4connect/src/P4Bridge/p4api.net/Repository.cs | |||||
#2 | 12135 | Norman Morse |
Integrate dev branch changes into main. This code is the basiis of the 2.7 BETA release which provides Unity 5 compatibility |
||
#1 | 10940 | Norman Morse |
Inital Workshop release of P4Connect. Released under BSD-2 license |