bool FPerforceCopyWorker::Execute(class FPerforceSourceControlCommand& InCommand)
{
	FScopedPerforceConnection ScopedConnection(InCommand);
	if (!InCommand.IsCanceled() && ScopedConnection.IsValid())
	{
		FPerforceConnection& Connection = ScopedConnection.GetConnection();

		check(InCommand.Operation->GetName() == GetName());
		TSharedRef<FCopy, ESPMode::ThreadSafe> Operation = StaticCastSharedRef<FCopy>(InCommand.Operation);

		FString DestinationPath = FPaths::ConvertRelativePathToFull(Operation->GetDestination());

		TArray<FString> Parameters;
		Parameters.Append(InCommand.Files);
		Parameters.Add(DestinationPath);
		
		FP4RecordSet Records;
		InCommand.bCommandSuccessful = Connection.RunCommand(TEXT("integrate"), Parameters, Records, InCommand.ErrorMessages, FOnIsCancelled::CreateRaw(&InCommand, &FPerforceSourceControlCommand::IsCanceled), InCommand.bConnectionDropped);

		// We now need to do a p4 resolve.
		// This is because when we copy a file in the Editor, we first make the copy on disk before attempting to branch. This causes a conflict in P4's eyes.
		// We must do this to prevent the asset registry from picking up what it thinks is a newly-added file (which would be created by the p4 integrate command)
		// and then the package system getting very confused about where to save the now-duplicated assets.
		if(InCommand.bCommandSuccessful)
		{
			TArray<FString> ResolveParameters;
			ResolveParameters.Add(TEXT("-ay"));	// 'accept yours'
			ResolveParameters.Add(DestinationPath);
			InCommand.bCommandSuccessful = Connection.RunCommand(TEXT("resolve"), ResolveParameters, Records, InCommand.ErrorMessages, FOnIsCancelled::CreateRaw(&InCommand, &FPerforceSourceControlCommand::IsCanceled), InCommand.bConnectionDropped);
		}
	}
	return InCommand.bCommandSuccessful;
}
bool FSubversionCopyWorker::Execute(FSubversionSourceControlCommand& InCommand)
{
	check(InCommand.Operation->GetName() == GetName());
	TSharedRef<FCopy, ESPMode::ThreadSafe> Operation = StaticCastSharedRef<FCopy>(InCommand.Operation);

	FString Destination = FPaths::ConvertRelativePathToFull(Operation->GetDestination());

	// perform svn revert if the dest file already exists in the working copy (this is usually the case
	// as files that are copied in the editor are already marked for add when the package is created
	// in the new location)
	{
		TArray<FString> Files;
		Files.Add(Destination);

		InCommand.bCommandSuccessful = SubversionSourceControlUtils::RunCommand(TEXT("revert"), Files, TArray<FString>(), InCommand.InfoMessages, InCommand.ErrorMessages, InCommand.UserName);
	}

	// Now we need to move the file out of directory, copy then restore over the top, as SVN wont allow us 
	// to 'svn copy' over an existing file, even if it is not already added to the working copy.
	// This will be OK as far as the asset registry/directory watcher goes as it will just see the file being modified several times
	const FString TempFileName = FPaths::CreateTempFilename(*FPaths::GameLogDir(), TEXT("SVN-CopyTemp"), TEXT(".uasset"));
	const bool bReplace = true;
	const bool bEvenIfReadOnly = true;
	
	if (InCommand.bCommandSuccessful)
	{
		InCommand.bCommandSuccessful = IFileManager::Get().Move(*TempFileName, *Destination, bReplace, bEvenIfReadOnly);
	}

	// copy from source files to destination parameter
	if(InCommand.bCommandSuccessful)
	{
		TArray<FString> Files;
		Files.Append(InCommand.Files);
		Files.Add(Destination);

		TArray<FString> Parameters;
		// Add nonexistent/non-versioned parent directories too
		Parameters.Add(TEXT("--parents"));

		InCommand.bCommandSuccessful = SubversionSourceControlUtils::RunCommand(TEXT("copy"), Files, Parameters, InCommand.InfoMessages, InCommand.ErrorMessages, InCommand.UserName);
	}

	// now move the file back
	if (InCommand.bCommandSuccessful)
	{
		InCommand.bCommandSuccessful = IFileManager::Get().Move(*Destination, *TempFileName, bReplace, bEvenIfReadOnly);
	}

	// now update the status of our files
	{
		TArray<FXmlFile> ResultsXml;
		TArray<FString> StatusParameters;
		StatusParameters.Add(TEXT("--verbose"));
		StatusParameters.Add(TEXT("--show-updates"));

		// Get status of both source and destination files
		TArray<FString> StatusFiles;
		StatusFiles.Append(InCommand.Files);
		StatusFiles.Add(Destination);

		InCommand.bCommandSuccessful &= SubversionSourceControlUtils::RunCommand(TEXT("status"), StatusFiles, StatusParameters, ResultsXml, InCommand.ErrorMessages, InCommand.UserName);
		SubversionSourceControlUtils::ParseStatusResults(ResultsXml, InCommand.ErrorMessages, InCommand.UserName, InCommand.WorkingCopyRoot, OutStates);
	}

	return InCommand.bCommandSuccessful;
}