Perforce Api - How to command “get revision [chang

2019-08-04 08:11发布

问题:

I would like to implement the Perforce command "Get Revision [Changelist Number]" using the Perforce .NET API (C#). I currently have code that will "Get Latest Revision", but I need to modify it to get a specific changelist.

To sync the data with a changelist number, what should I do?

Source

// --------Connenct----------------
Perforce.P4.Server server = new Perforce.P4.Server(
    new Perforce.P4.ServerAddress("127.0.0.1:9999"));
Perforce.P4.Repository rep = new Perforce.P4.Repository(server);
Perforce.P4.Connection con = rep.Connection;

con.UserName = m_P4ID;
string password = m_P4PASS;

Perforce.P4.Options opconnect = new Perforce.P4.Options();
opconnect.Add("-p", password);
con.Connect(opconnect);

if (con.Credential == null)
    con.Login(password);

//----------Download----------
string clientPath = @"C:\P4V\";
string ws_client = clientPath;
Perforce.P4.Client client = new Perforce.P4.Client();
client.Name = ws_client;
client.Initialize(con);

con.CommandTimeout = new TimeSpan(0);
IList<Perforce.P4.FileSpec> fileList = client.SyncFiles(new Perforce.P4.Options());

//----------Disconnect------------
con.Disconnect();
con.Dispose();

Edit: Attempt 1

Perforce.P4.DepotPath depot = new Perforce.P4.DepotPath("//P4V//");
Perforce.P4.LocalPath local = new Perforce.P4.LocalPath(ws_client);
Perforce.P4.FileSpec fs = new Perforce.P4.FileSpec(depot, null, local,
    Perforce.P4.VersionSpec.Head);

IList<Perforce.P4.FileSpec> listFiles = new List<Perforce.P4.FileSpec>();
listFiles.Add(fs);
IList<Perforce.P4.FileSpec> foundFiles = rep.GetDepotFiles(listFiles,
    new Perforce.P4.Options(1234)); // 1234 = Changelist number

client.SyncFiles(foundFiles, null);

Error Message

Usage: files/print [-o localFile -q] files...Invalid option: -c.

I do not know the problem of any argument.

Or there will not be related to this reference source?

Edit 2

I tried to solve this problem. However, it does not solve the problem yet.

Perforce.P4.Changelist changelist = rep.GetChangelist(1234);
IList<Perforce.P4.FileMetaData> fileMeta = changelist.Files;

In this case, I could get only the files in the changelist. I would like to synchronize all files of the client at the moment of changelist 1234.

回答1:

SyncFiles takes an optional FileSpec arg. You can specify a file path and a revision specifier with that FileSpec arg. Here are the relevant docs:

FileSpec object docs

SyncFiles method docs

You don't need to run GetDepotFiles() to get the FileSpec object; you can just create one directly as shown in the FileSpec object docs. The error you are getting with GetDepotFiles() is because it expects the change number to be specified as part of the FileSpec object passed into as the first argument to GetDepotFiles().

To expand further, GetDepotFiles() calls the 'p4 files' command when it talks to Perforce. new Perforce.P4.Options(1234) generates an option of '-c 1234' which 'p4 files' doesn't accept. That's why the error message is 'Usage: files/print [-o localFile -q] files...Invalid option: -c.'



回答2:

I struggled with the same problem as well. Finally based on Matt's answer I got it working. Please see simple example below.

        using (Connection con = rep.Connection)
        {
            //setting up client object with viewmap
            Client client = new Client();
            client.Name = "p4apinet_solution_builder_sample_application_client";
            client.OwnerName = "p4username";
            client.Root = "c:\\clientRootPath";
            client.Options = ClientOption.AllWrite;
            client.LineEnd = LineEnd.Local;
            client.SubmitOptions = new ClientSubmitOptions(false, SubmitType.RevertUnchanged);
            client.ViewMap = new ViewMap();
            client.ViewMap.Add("//depotpath/to/your/file.txt", "//" + client.Name + "/clientpath/to/your/file.txt", MapType.Include);

            //connecting to p4 and creating client on p4 server
            Options options = new Options();
            options["Password"] = "p4password";
            con.UserName = "p4username";
            con.Client = new Client();
            con.Connect(options);
            con.Client = rep.CreateClient(client);

            //syncing all files (in this case 1) defined in client's viewmap to the changelist level of 12345
            Options syncFlags = new Options(SyncFilesCmdFlags.Force, 100);
            VersionSpec changeListLevel = new ChangelistIdVersion(12345);
            List<FileSpec> filesToBeSynced = con.Client.ViewMap.Select<MapEntry, FileSpec>(me => new FileSpec(me.Left, changeListLevel)).ToList();
            IList<FileSpec> results = con.Client.SyncFiles(filesToBeSynced, syncFlags);
        }


回答3:

The following code should allow you to sync a depot to a particular revision (changelist number).

string uri = "...";
string user = "...";
string workspace = "...";
string pass = "..."; 
int id = 12345; // the actual changelist number
string depotPath = "//depot/foo/main/...";
int maxItemsToSync = 10000;

Server server = new Server(new ServerAddress(uri));
Repository rep = new Repository(server);

server = new Server(new ServerAddress(uri));
rep = new Repository(server);
Connection con = rep.Connection;
con.UserName = user;
con.Client = new Client();
con.Client.Name = workspace;

// connect
bool connected = con.Connect(null);
if (connected)
{
    try
    {
        // attempt a login
        Perforce.P4.Credential cred = con.Login(pass);
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
        con.Disconnect();
        connected = false;
    }

    if (connected)
    {
        // get p4 info and show successful connection
        ServerMetaData info = rep.GetServerMetaData(null);
        Console.WriteLine("CONNECTED TO " + info.Address.Uri);
        Console.WriteLine("");

        try
        {
            Options opts = new Options();

            // uncomment below lines to only get a preview of the sync w/o updating the workspace
            //SyncFilesCmdOptions syncOpts = new SyncFilesCmdOptions(SyncFilesCmdFlags.Preview, maxItemsToSync);
            SyncFilesCmdOptions syncOpts = new SyncFilesCmdOptions(SyncFilesCmdFlags.None, maxItemsToSync);

            VersionSpec version = new ChangelistIdVersion(id);
            PathSpec path = new DepotPath(depotPath);
            FileSpec depotFile = new FileSpec(path, version);

            IList<FileSpec> syncedFiles = rep.Connection.Client.SyncFiles(syncOpts, depotFile);
            //foreach (var file in syncedFiles)
            //{
            //    Console.WriteLine(file.ToString());
            //}
            Console.WriteLine($"{syncedFiles.Count} files got synced!");
        }
        catch (Exception ex)
        {
            Console.WriteLine("");
            Console.WriteLine(ex.Message);
            Console.WriteLine("");
        }
        finally
        {
            con.Disconnect();
        }
    }
}

If you are looking for other ways to build the file spec, like for example sync only a specific list of files to "head", etc, visit this link and search for "Building a FileSpec"