bool FPerforceMarkForAddWorker::Execute(FPerforceSourceControlCommand& InCommand) { // Perforce will allow you to mark files for add that don't currently exist on disk // This goes against the workflow of our other SCC providers (such as SVN and Git), // so we manually check that the files exist before allowing this command to continue // This keeps the behavior consistent between SCC providers bool bHasMissingFiles = false; for(const FString& FileToAdd : InCommand.Files) { if(!IFileManager::Get().FileExists(*FileToAdd)) { bHasMissingFiles = true; InCommand.ErrorMessages.Add(FText::Format(LOCTEXT("Error_FailedToMarkFileForAdd_FileMissing", "Failed mark the file '{0}' for add. The file doesn't exist on disk."), FText::FromString(FileToAdd))); } } if(bHasMissingFiles) { InCommand.bCommandSuccessful = false; return false; } FScopedPerforceConnection ScopedConnection(InCommand); if (!InCommand.IsCanceled() && ScopedConnection.IsValid()) { FPerforceConnection& Connection = ScopedConnection.GetConnection(); TArray<FString> Parameters; FP4RecordSet Records; Parameters.Append(InCommand.Files); InCommand.bCommandSuccessful = Connection.RunCommand(TEXT("add"), Parameters, Records, InCommand.ErrorMessages, FOnIsCancelled::CreateRaw(&InCommand, &FPerforceSourceControlCommand::IsCanceled), InCommand.bConnectionDropped); ParseRecordSetForState(Records, OutResults); } return InCommand.bCommandSuccessful; }
bool FPerforceSyncWorker::Execute(FPerforceSourceControlCommand& InCommand) { FScopedPerforceConnection ScopedConnection(InCommand); if (!InCommand.IsCanceled() && ScopedConnection.IsValid()) { FPerforceConnection& Connection = ScopedConnection.GetConnection(); TArray<FString> Parameters; Parameters.Append(InCommand.Files); // check for directories and add '...' for(auto& FileName : Parameters) { if(FileName.EndsWith(TEXT("/"))) { FileName += TEXT("..."); } } FP4RecordSet Records; InCommand.bCommandSuccessful = Connection.RunCommand(TEXT("sync"), Parameters, Records, InCommand.ErrorMessages, FOnIsCancelled::CreateRaw(&InCommand, &FPerforceSourceControlCommand::IsCanceled), InCommand.bConnectionDropped); ParseSyncResults(Records, OutResults); RemoveRedundantErrors(InCommand, TEXT("file(s) up-to-date")); } return InCommand.bCommandSuccessful; }
bool FPerforceCheckOutWorker::Execute(FPerforceSourceControlCommand& InCommand) { FScopedPerforceConnection ScopedConnection(InCommand); if (!InCommand.IsCanceled() && ScopedConnection.IsValid()) { FPerforceConnection& Connection = ScopedConnection.GetConnection(); TArray<FString> Parameters; FPerforceSourceControlModule& PerforceSourceControl = FModuleManager::LoadModuleChecked<FPerforceSourceControlModule>("PerforceSourceControl"); FPerforceSourceControlSettings& Settings = PerforceSourceControl.AccessSettings(); if (Settings.GetChangelistNumber().IsEmpty() == false) { Parameters.Add(TEXT("-c")); Parameters.Add(Settings.GetChangelistNumber()); // Parameters.Add(FString::Printf(TEXT("-c %s"), *Settings.GetChangelistNumber())); } Parameters.Append(InCommand.Files); FP4RecordSet Records; InCommand.bCommandSuccessful = Connection.RunCommand(TEXT("edit"), Parameters, Records, InCommand.ErrorMessages, FOnIsCancelled::CreateRaw(&InCommand, &FPerforceSourceControlCommand::IsCanceled), InCommand.bConnectionDropped); ParseRecordSetForState(Records, OutResults); } return InCommand.bCommandSuccessful; }
bool FPerforceRevertWorker::Execute(FPerforceSourceControlCommand& InCommand) { FScopedPerforceConnection ScopedConnection(InCommand); if (!InCommand.IsCanceled() && ScopedConnection.IsValid()) { FPerforceConnection& Connection = ScopedConnection.GetConnection(); TArray<FString> Parameters; Parameters.Append(InCommand.Files); FP4RecordSet Records; InCommand.bCommandSuccessful = Connection.RunCommand(TEXT("revert"), Parameters, Records, InCommand.ErrorMessages, FOnIsCancelled::CreateRaw(&InCommand, &FPerforceSourceControlCommand::IsCanceled), InCommand.bConnectionDropped); ParseRecordSetForState(Records, OutResults); } return InCommand.bCommandSuccessful; }
bool FPerforceGetWorkspacesWorker::Execute(FPerforceSourceControlCommand& InCommand) { FScopedPerforceConnection ScopedConnection(InCommand); if (!InCommand.IsCanceled() && ScopedConnection.IsValid()) { FPerforceConnection& Connection = ScopedConnection.GetConnection(); TArray<FString> ClientSpecList; InCommand.bCommandSuccessful = Connection.GetWorkspaceList(InCommand.ConnectionInfo, FOnIsCancelled::CreateRaw(&InCommand, &FPerforceSourceControlCommand::IsCanceled), ClientSpecList, InCommand.ErrorMessages); check(InCommand.Operation->GetName() == GetName()); TSharedRef<FGetWorkspaces, ESPMode::ThreadSafe> Operation = StaticCastSharedRef<FGetWorkspaces>(InCommand.Operation); Operation->Results = ClientSpecList; } return InCommand.bCommandSuccessful; }
bool FPerforceConnectWorker::Execute(FPerforceSourceControlCommand& InCommand) { FScopedPerforceConnection ScopedConnection(InCommand); if (!InCommand.IsCanceled() && ScopedConnection.IsValid()) { FPerforceConnection& Connection = ScopedConnection.GetConnection(); TArray<FString> Parameters; FP4RecordSet Records; Parameters.Add(TEXT("-o")); Parameters.Add(InCommand.ConnectionInfo.Workspace); InCommand.bCommandSuccessful = Connection.RunCommand(TEXT("client"), Parameters, Records, InCommand.ErrorMessages, FOnIsCancelled::CreateRaw(&InCommand, &FPerforceSourceControlCommand::IsCanceled), InCommand.bConnectionDropped); // If there are error messages, user name is most likely invalid. Otherwise, make sure workspace actually // exists on server by checking if we have it's update date. InCommand.bCommandSuccessful &= InCommand.ErrorMessages.Num() == 0 && Records.Num() > 0 && Records[0].Contains(TEXT("Update")); if (!InCommand.bCommandSuccessful && InCommand.ErrorMessages.Num() == 0) { InCommand.ErrorMessages.Add(LOCTEXT("InvalidWorkspace", "Invalid workspace.")); } // check if we can actually work with this workspace if(InCommand.bCommandSuccessful) { FText Notification; InCommand.bCommandSuccessful = CheckWorkspaceRecordSet(Records, InCommand.ErrorMessages, Notification); if(!InCommand.bCommandSuccessful) { check(InCommand.Operation->GetName() == GetName()); TSharedRef<FConnect, ESPMode::ThreadSafe> Operation = StaticCastSharedRef<FConnect>(InCommand.Operation); Operation->SetErrorText(Notification); } } if(InCommand.bCommandSuccessful) { ParseRecordSet(Records, InCommand.InfoMessages); } } return InCommand.bCommandSuccessful; }
bool FPerforceUpdateStatusWorker::Execute(FPerforceSourceControlCommand& InCommand) { #if USE_P4_API FScopedPerforceConnection ScopedConnection(InCommand); if (!InCommand.IsCanceled() && ScopedConnection.IsValid()) { FPerforceConnection& Connection = ScopedConnection.GetConnection(); if(InCommand.Files.Num()) { // See http://www.perforce.com/perforce/doc.current/manuals/cmdref/p4_fstat.html // for full reference info on fstat command parameters... TArray<FString> Parameters; // We want to include integration record information: Parameters.Add(TEXT("-Or")); // Mandatory parameters (the list of files to stat): for (FString& File : InCommand.Files) { if (IFileManager::Get().DirectoryExists(*File)) { // If the file is a directory, do a recursive fstat on the contents File /= TEXT("..."); } Parameters.Add(File); } FP4RecordSet Records; InCommand.bCommandSuccessful = Connection.RunCommand(TEXT("fstat"), Parameters, Records, InCommand.ErrorMessages, FOnIsCancelled::CreateRaw(&InCommand, &FPerforceSourceControlCommand::IsCanceled), InCommand.bConnectionDropped); ParseUpdateStatusResults(Records, InCommand.ErrorMessages, OutStates); RemoveRedundantErrors(InCommand, TEXT(" - no such file(s).")); RemoveRedundantErrors(InCommand, TEXT("' is not under client's root '")); } else { InCommand.bCommandSuccessful = true; } // update using any special hints passed in via the operation check(InCommand.Operation->GetName() == GetName()); TSharedRef<FUpdateStatus, ESPMode::ThreadSafe> Operation = StaticCastSharedRef<FUpdateStatus>(InCommand.Operation); if(Operation->ShouldUpdateHistory()) { TArray<FString> Parameters; FP4RecordSet Records; // disregard non-contributory integrations Parameters.Add(TEXT("-s")); //include branching history Parameters.Add(TEXT("-i")); //include truncated change list descriptions Parameters.Add(TEXT("-L")); //include time stamps Parameters.Add(TEXT("-t")); //limit to last 100 changes Parameters.Add(TEXT("-m 100")); Parameters.Append(InCommand.Files); InCommand.bCommandSuccessful &= Connection.RunCommand(TEXT("filelog"), Parameters, Records, InCommand.ErrorMessages, FOnIsCancelled::CreateRaw(&InCommand, &FPerforceSourceControlCommand::IsCanceled), InCommand.bConnectionDropped); ParseHistoryResults(Records, OutStates, OutHistory); RemoveRedundantErrors(InCommand, TEXT(" - no such file(s).")); RemoveRedundantErrors(InCommand, TEXT(" - file(s) not on client")); RemoveRedundantErrors(InCommand, TEXT("' is not under client's root '")); } if(Operation->ShouldGetOpenedOnly()) { const FString ContentFolder = FPaths::ConvertRelativePathToFull(FPaths::RootDir()); const FString FileQuery = FString::Printf(TEXT("%s..."), *ContentFolder); TArray<FString> Parameters = InCommand.Files; Parameters.Add(FileQuery); FP4RecordSet Records; InCommand.bCommandSuccessful &= Connection.RunCommand(TEXT("opened"), Parameters, Records, InCommand.ErrorMessages, FOnIsCancelled::CreateRaw(&InCommand, &FPerforceSourceControlCommand::IsCanceled), InCommand.bConnectionDropped); ParseOpenedResults(Records, ANSI_TO_TCHAR(Connection.P4Client.GetClient().Text()), Connection.ClientRoot, OutStateMap); RemoveRedundantErrors(InCommand, TEXT(" - no such file(s).")); RemoveRedundantErrors(InCommand, TEXT("' is not under client's root '")); } if(Operation->ShouldUpdateModifiedState()) { TArray<FString> Parameters; FP4RecordSet Records; // Query for open files different than the versions stored in Perforce Parameters.Add(TEXT("-sa")); Parameters.Append(InCommand.Files); InCommand.bCommandSuccessful &= Connection.RunCommand(TEXT("diff"), Parameters, Records, InCommand.ErrorMessages, FOnIsCancelled::CreateRaw(&InCommand, &FPerforceSourceControlCommand::IsCanceled), InCommand.bConnectionDropped); // Parse the results and store them in the command ParseDiffResults(Records, OutModifiedFiles); RemoveRedundantErrors(InCommand, TEXT(" - no such file(s).")); RemoveRedundantErrors(InCommand, TEXT(" - file(s) not opened for edit")); RemoveRedundantErrors(InCommand, TEXT("' is not under client's root '")); } } #endif return InCommand.bCommandSuccessful; }
bool FPerforceCheckInWorker::Execute(FPerforceSourceControlCommand& InCommand) { FScopedPerforceConnection ScopedConnection(InCommand); if (!InCommand.IsCanceled() && ScopedConnection.IsValid()) { FPerforceConnection& Connection = ScopedConnection.GetConnection(); check(InCommand.Operation->GetName() == GetName()); TSharedRef<FCheckIn, ESPMode::ThreadSafe> Operation = StaticCastSharedRef<FCheckIn>(InCommand.Operation); int32 ChangeList = Connection.CreatePendingChangelist(Operation->GetDescription(), FOnIsCancelled::CreateRaw(&InCommand, &FPerforceSourceControlCommand::IsCanceled), InCommand.ErrorMessages); if (ChangeList > 0) { // Batch reopen into multiple commands, to avoid command line limits const int32 BatchedCount = 100; InCommand.bCommandSuccessful = true; for (int32 StartingIndex = 0; StartingIndex < InCommand.Files.Num() && InCommand.bCommandSuccessful; StartingIndex += BatchedCount) { FP4RecordSet Records; TArray< FString > ReopenParams; //Add changelist information to params ReopenParams.Insert(TEXT("-c"), 0); ReopenParams.Insert(FString::Printf(TEXT("%d"), ChangeList), 1); int32 NextIndex = FMath::Min(StartingIndex + BatchedCount, InCommand.Files.Num()); for (int32 FileIndex = StartingIndex; FileIndex < NextIndex; FileIndex++) { ReopenParams.Add(InCommand.Files[FileIndex]); } InCommand.bCommandSuccessful = Connection.RunCommand(TEXT("reopen"), ReopenParams, Records, InCommand.ErrorMessages, FOnIsCancelled::CreateRaw(&InCommand, &FPerforceSourceControlCommand::IsCanceled), InCommand.bConnectionDropped); } if (InCommand.bCommandSuccessful) { // Only submit if reopen was successful TArray<FString> SubmitParams; FP4RecordSet Records; SubmitParams.Insert(TEXT("-c"), 0); SubmitParams.Insert(FString::Printf(TEXT("%d"), ChangeList), 1); InCommand.bCommandSuccessful = Connection.RunCommand(TEXT("submit"), SubmitParams, Records, InCommand.ErrorMessages, FOnIsCancelled::CreateRaw(&InCommand, &FPerforceSourceControlCommand::IsCanceled), InCommand.bConnectionDropped); if (InCommand.ErrorMessages.Num() > 0) { InCommand.bCommandSuccessful = false; } if (InCommand.bCommandSuccessful) { // Remove any deleted files from status cache FPerforceSourceControlModule& PerforceSourceControl = FModuleManager::GetModuleChecked<FPerforceSourceControlModule>("PerforceSourceControl"); FPerforceSourceControlProvider& Provider = PerforceSourceControl.GetProvider(); TArray<TSharedRef<ISourceControlState, ESPMode::ThreadSafe>> States; Provider.GetState(InCommand.Files, States, EStateCacheUsage::Use); for (const auto& State : States) { if (State->IsDeleted()) { Provider.RemoveFileFromCache(State->GetFilename()); } } StaticCastSharedRef<FCheckIn>(InCommand.Operation)->SetSuccessMessage(ParseSubmitResults(Records)); for(auto Iter(InCommand.Files.CreateIterator()); Iter; Iter++) { OutResults.Add(*Iter, EPerforceState::ReadOnly); } } } } else { // Failed to create the changelist InCommand.bCommandSuccessful = false; } } return InCommand.bCommandSuccessful; }