public UpdateMonitor(PerforceConnection InPerforce, string InWatchPath) { Perforce = InPerforce; WatchPath = InWatchPath; QuitEvent = new ManualResetEvent(false); if(WatchPath != null) { WorkerThread = new Thread(() => PollForUpdates()); WorkerThread.Start(); } }
public static bool ShowModal(IWin32Window Owner, PerforceConnection DefaultConnection, string StreamName, string ProjectPath, out WorkspaceInfo WorkspaceInfo, TextWriter Log) { FindDefaultWorkspaceTask FindWorkspace = new FindDefaultWorkspaceTask(StreamName); string ErrorMessage; PerforceModalTask.Execute(Owner, DefaultConnection, FindWorkspace, "Finding workspace", "Finding default workspace, please wait...", Log, out ErrorMessage); AutomatedSyncWindow Window = new AutomatedSyncWindow(StreamName, ProjectPath, FindWorkspace.WorkspaceName, DefaultConnection, Log); if (Window.ShowDialog() == DialogResult.OK) { WorkspaceInfo = Window.SelectedWorkspaceInfo; return(true); } else { WorkspaceInfo = null; return(false); } }
public FindFoldersToCleanTask(PerforceConnection InPerforceClient, FolderToClean InRootFolderToClean, string InClientRootPath, IReadOnlyList<string> InSyncPaths, TextWriter InLog) { PerforceClient = InPerforceClient; ClientRootPath = InClientRootPath.TrimEnd('/') + "/"; SyncPaths = new List<string>(InSyncPaths); Log = InLog; RootFolderToClean = InRootFolderToClean; FinishedScan = new ManualResetEvent(true); foreach(string SyncPath in SyncPaths) { Debug.Assert(SyncPath.StartsWith(ClientRootPath)); if(SyncPath.StartsWith(ClientRootPath, StringComparison.InvariantCultureIgnoreCase)) { string[] Fragments = SyncPath.Substring(ClientRootPath.Length).Split('/'); FolderToClean SyncFolder = RootFolderToClean; for(int Idx = 0; Idx < Fragments.Length - 1; Idx++) { FolderToClean NextSyncFolder = SyncFolder.SubFolders.FirstOrDefault(x => x.Name.Equals(Fragments[Idx], StringComparison.InvariantCultureIgnoreCase)); if(NextSyncFolder == null) { NextSyncFolder = new FolderToClean(new DirectoryInfo(Path.Combine(SyncFolder.Directory.FullName, Fragments[Idx]))); SyncFolder.SubFolders.Add(NextSyncFolder); } SyncFolder = NextSyncFolder; } string Wildcard = Fragments[Fragments.Length - 1]; if(Wildcard == "...") { QueueFolderToPopulate(SyncFolder); } else if(SyncFolder.Directory.Exists) { SyncFolder.FilesToClean = SyncFolder.FilesToClean.Union(SyncFolder.Directory.GetFiles(Wildcard)).GroupBy(x => x.Name).Select(x => x.First()).ToList(); } } } }
public FindFoldersToCleanTask(PerforceConnection InPerforceClient, FolderToClean InRootFolderToClean, string InClientRootPath, IReadOnlyList <string> InSyncPaths, TextWriter InLog) { PerforceClient = InPerforceClient; ClientRootPath = InClientRootPath.TrimEnd('/') + "/"; SyncPaths = new List <string>(InSyncPaths); Log = InLog; RootFolderToClean = InRootFolderToClean; FinishedScan = new ManualResetEvent(true); foreach (string SyncPath in SyncPaths) { Debug.Assert(SyncPath.StartsWith(ClientRootPath)); if (SyncPath.StartsWith(ClientRootPath, StringComparison.InvariantCultureIgnoreCase)) { string[] Fragments = SyncPath.Substring(ClientRootPath.Length).Split('/'); FolderToClean SyncFolder = RootFolderToClean; for (int Idx = 0; Idx < Fragments.Length - 1; Idx++) { FolderToClean NextSyncFolder = SyncFolder.SubFolders.FirstOrDefault(x => x.Name.Equals(Fragments[Idx], StringComparison.InvariantCultureIgnoreCase)); if (NextSyncFolder == null) { NextSyncFolder = new FolderToClean(new DirectoryInfo(Path.Combine(SyncFolder.Directory.FullName, Fragments[Idx]))); SyncFolder.SubFolders.Add(NextSyncFolder); } SyncFolder = NextSyncFolder; } string Wildcard = Fragments[Fragments.Length - 1]; if (Wildcard == "...") { QueueFolderToPopulate(SyncFolder); } else if (SyncFolder.Directory.Exists) { SyncFolder.FilesToClean = SyncFolder.FilesToClean.Union(SyncFolder.Directory.GetFiles(Wildcard)).GroupBy(x => x.Name).Select(x => x.First()).ToList(); } } } }
public bool Run(PerforceConnection Perforce, TextWriter Log, out string ErrorMessage) { PerforceInfoRecord Info; if (!Perforce.Info(out Info, Log)) { ErrorMessage = "Unable to query Perforce info."; return(false); } List <PerforceClientRecord> Clients; if (!Perforce.FindClients(Info.UserName, out Clients, Log)) { ErrorMessage = "Unable to enumerate clients from Perforce"; return(false); } List <PerforceClientRecord> CandidateClients = new List <PerforceClientRecord>(); foreach (PerforceClientRecord Client in Clients) { if (Client.Host == null || Client.Host.Equals(Info.HostName, StringComparison.OrdinalIgnoreCase)) { if (Client.Stream != null && Client.Stream.Equals(StreamName, StringComparison.OrdinalIgnoreCase)) { CandidateClients.Add(Client); } } } if (CandidateClients.Count == 1) { WorkspaceName = CandidateClients[0].Name; } ErrorMessage = null; return(true); }
public bool Run(out string ErrorMessage) { // Get the server settings string ServerAndPort = SelectedProject.ServerAndPort; string UserName = SelectedProject.UserName; string ProjectFileName = null; if (SelectedProject.Type == UserSelectedProjectType.Local) { ProjectFileName = SelectedProject.LocalPath; } if (!PerforceModalTask.TryGetServerSettings(ProjectFileName, ref ServerAndPort, ref UserName, Log)) { ErrorMessage = "Unable to get Perforce server settings."; return(false); } // Create the connection PerforceConnection Perforce = new PerforceConnection(UserName, null, ServerAndPort); // Make sure we're logged in bool bLoggedIn; if (!Perforce.GetLoggedInState(out bLoggedIn, Log)) { ErrorMessage = "Error while checking login status."; return(false); } if (!bLoggedIn) { ErrorMessage = "User is not logged in to Perforce."; return(false); } // Execute like a regular task return(Run(Perforce, Log, out ErrorMessage)); }
public bool Run(out string ErrorMessage) { // Set the default login state to failed LoginResult = LoginResult.Failed; // Get the server settings if (!TryGetServerSettings(ProjectFileName, ref ServerAndPort, ref UserName, Log)) { ErrorMessage = "Unable to get Perforce server settings."; return(false); } // Create the connection PerforceConnection Perforce = new PerforceConnection(UserName, null, ServerAndPort); // If we've got a password, execute the login command if (Password != null) { string PasswordErrorMessage; LoginResult = Perforce.Login(Password, out PasswordErrorMessage, Log); if (LoginResult != LoginResult.Succeded) { ErrorMessage = String.Format("Unable to login: {0}", PasswordErrorMessage); return(false); } } // Check that we're logged in if (!Perforce.IsLoggedIn(Log)) { LoginResult = LoginResult.MissingPassword; ErrorMessage = "User is not logged in to Perforce."; return(false); } // Execute the inner task LoginResult = LoginResult.Succeded; return(InnerTask.Run(Perforce, Log, out ErrorMessage)); }
private ConnectWindow(PerforceConnection DefaultConnection, string ServerAndPortOverride, string UserNameOverride, TextWriter Log) { InitializeComponent(); this.DefaultConnection = DefaultConnection; this.Log = Log; if (!String.IsNullOrWhiteSpace(ServerAndPortOverride)) { this.ServerAndPortOverride = ServerAndPortOverride.Trim(); } if (!String.IsNullOrEmpty(UserNameOverride)) { this.UserNameOverride = UserNameOverride.Trim(); } ServerAndPortTextBox.CueBanner = DefaultConnection.ServerAndPort; ServerAndPortTextBox.Text = this.ServerAndPortOverride ?? DefaultConnection.ServerAndPort; UserNameTextBox.CueBanner = DefaultConnection.UserName; UserNameTextBox.Text = this.UserNameOverride ?? DefaultConnection.UserName; UseDefaultConnectionSettings.Checked = this.ServerAndPortOverride == null && this.UserNameOverride == null; UpdateEnabledControls(); }
public bool Run(PerforceConnection Perforce, TextWriter Log, out string ErrorMessage) { this.ServerAndPort = Perforce.ServerAndPort; this.UserName = Perforce.UserName; PerforceSpec Spec; if (!Perforce.TryGetClientSpec(WorkspaceName, out Spec, Log)) { ErrorMessage = String.Format("Unable to get info for client '{0}'", WorkspaceName); return(false); } string CurrentStreamName = Spec.GetField("Stream"); if (CurrentStreamName == null || CurrentStreamName != StreamName) { bRequiresStreamSwitch = true; bHasOpenFiles = Perforce.HasOpenFiles(Log); } ErrorMessage = null; return(true); }
private AutomatedSyncWindow(string StreamName, string ProjectPath, string WorkspaceName, PerforceConnection DefaultConnection, TextWriter Log) { this.StreamName = StreamName; this.DefaultConnection = DefaultConnection; this.Log = Log; InitializeComponent(); ActiveControl = WorkspaceNameTextBox; MinimumSize = Size; MaximumSize = new Size(32768, Size.Height); ProjectTextBox.Text = StreamName + ProjectPath; if (WorkspaceName != null) { WorkspaceNameTextBox.Text = WorkspaceName; WorkspaceNameTextBox.Select(WorkspaceNameTextBox.Text.Length, 0); } UpdateServerLabel(); UpdateOkButton(); }
bool TryGetStreamPrefix(PerforceConnection Perforce, string StreamName, TextWriter Log, out string StreamPrefix) { string CurrentStreamName = StreamName; for(;;) { PerforceSpec StreamSpec; if(!Perforce.TryGetStreamSpec(CurrentStreamName, out StreamSpec, Log)) { StreamPrefix = null; return false; } if(StreamSpec.GetField("Type") != "virtual") { StreamPrefix = CurrentStreamName; return true; } CurrentStreamName = StreamSpec.GetField("Parent"); } }
public FindChangesWorker(PerforceConnection Perforce, OnCompleteDelegate OnComplete) { this.Perforce = Perforce; this.MainThreadSyncContext = SynchronizationContext.Current; this.OnComplete = OnComplete; }
AutomationRequestOutput StartAutomatedSync(AutomationRequest Request, bool bForceSync) { ShowAndActivate(); BinaryReader Reader = new BinaryReader(new MemoryStream(Request.Input.Data)); string StreamName = Reader.ReadString(); string ProjectPath = Reader.ReadString(); AutomatedSyncWindow.WorkspaceInfo WorkspaceInfo; if (!AutomatedSyncWindow.ShowModal(this, StreamName, ProjectPath, out WorkspaceInfo, Log)) { return(new AutomationRequestOutput(AutomationRequestResult.Canceled)); } if (WorkspaceInfo.bRequiresStreamSwitch) { // Close any tab containing this window for (int ExistingTabIdx = 0; ExistingTabIdx < TabControl.GetTabCount(); ExistingTabIdx++) { WorkspaceControl ExistingWorkspace = TabControl.GetTabData(ExistingTabIdx) as WorkspaceControl; if (ExistingWorkspace != null && ExistingWorkspace.ClientName.Equals(WorkspaceInfo.WorkspaceName)) { TabControl.RemoveTab(ExistingTabIdx); break; } } // Switch the stream PerforceConnection Perforce = new PerforceConnection(WorkspaceInfo.UserName, WorkspaceInfo.WorkspaceName, WorkspaceInfo.ServerAndPort); if (!Perforce.SwitchStream(StreamName, Log)) { Log.WriteLine("Unable to switch stream"); return(new AutomationRequestOutput(AutomationRequestResult.Error)); } } UserSelectedProjectSettings SelectedProject = new UserSelectedProjectSettings(WorkspaceInfo.ServerAndPort, WorkspaceInfo.UserName, UserSelectedProjectType.Client, String.Format("//{0}{1}", WorkspaceInfo.WorkspaceName, ProjectPath), null); int TabIdx = TryOpenProject(SelectedProject, -1, OpenProjectOptions.None); if (TabIdx == -1) { Log.WriteLine("Unable to open project"); return(new AutomationRequestOutput(AutomationRequestResult.Error)); } WorkspaceControl Workspace = TabControl.GetTabData(TabIdx) as WorkspaceControl; if (Workspace == null) { Log.WriteLine("Workspace was unable to open"); return(new AutomationRequestOutput(AutomationRequestResult.Error)); } if (!bForceSync && Workspace.CanLaunchEditor()) { return(new AutomationRequestOutput(AutomationRequestResult.Ok, Encoding.UTF8.GetBytes(Workspace.SelectedFileName))); } Workspace.AddStartupCallback((Control, bCancel) => StartAutomatedSyncAfterStartup(Control, bCancel, Request)); return(null); }
public static bool ShowModal(IWin32Window Owner, UserSelectedProjectSettings Project, out DetectProjectSettingsTask NewDetectedProjectSettings, UserSettings Settings, string DataFolder, string CacheFolder, PerforceConnection DefaultConnection, TextWriter Log) { OpenProjectWindow Window = new OpenProjectWindow(Project, Settings, DataFolder, CacheFolder, DefaultConnection, Log); if (Window.ShowDialog(Owner) == DialogResult.OK) { NewDetectedProjectSettings = Window.DetectedProjectSettings; return(true); } else { NewDetectedProjectSettings = null; return(false); } }
private OpenProjectWindow(UserSelectedProjectSettings Project, UserSettings Settings, string DataFolder, string CacheFolder, PerforceConnection DefaultConnection, TextWriter Log) { InitializeComponent(); this.Settings = Settings; this.DetectedProjectSettings = null; this.DataFolder = DataFolder; this.CacheFolder = CacheFolder; this.DefaultConnection = DefaultConnection; this.Log = Log; if (Project == null) { LocalFileRadioBtn.Checked = true; } else { if (!String.IsNullOrWhiteSpace(Project.ServerAndPort)) { ServerAndPortOverride = Project.ServerAndPort; } if (!String.IsNullOrWhiteSpace(Project.UserName)) { UserNameOverride = Project.UserName; } if (Project.ClientPath != null && Project.ClientPath.StartsWith("//")) { int SlashIdx = Project.ClientPath.IndexOf('/', 2); if (SlashIdx != -1) { WorkspaceNameTextBox.Text = Project.ClientPath.Substring(2, SlashIdx - 2); WorkspacePathTextBox.Text = Project.ClientPath.Substring(SlashIdx); } } if (Project.LocalPath != null) { LocalFileTextBox.Text = Project.LocalPath; } if (Project.Type == UserSelectedProjectType.Client) { WorkspaceRadioBtn.Checked = true; } else { LocalFileRadioBtn.Checked = true; } } UpdateEnabledControls(); UpdateServerLabel(); UpdateWorkspacePathBrowseButton(); UpdateOkButton(); }
public bool Run(out string ErrorMessage) { PerforceConnection Perforce = new PerforceConnection(null, null, null); // Get the Perforce server info PerforceInfoRecord PerforceInfo; if (!Perforce.Info(out PerforceInfo, Log)) { ErrorMessage = String.Format("Couldn't get Perforce server info"); return(false); } if (String.IsNullOrEmpty(PerforceInfo.UserName)) { ErrorMessage = "Missing user name in call to p4 info"; return(false); } if (String.IsNullOrEmpty(PerforceInfo.HostName)) { ErrorMessage = "Missing host name in call to p4 info"; return(false); } ServerTimeZone = PerforceInfo.ServerTimeZone; // Find all the clients on this machine Log.WriteLine("Enumerating clients on local machine..."); List <PerforceClientRecord> Clients; if (!Perforce.FindClients(out Clients, Log)) { ErrorMessage = String.Format("Couldn't find any clients for this host."); return(false); } // Find any clients which are valid. If this is not exactly one, we should fail. List <PerforceConnection> CandidateClients = new List <PerforceConnection>(); foreach (PerforceClientRecord Client in Clients) { // Make sure the client is well formed if (!String.IsNullOrEmpty(Client.Name) && (!String.IsNullOrEmpty(Client.Host) || !String.IsNullOrEmpty(Client.Owner)) && !String.IsNullOrEmpty(Client.Root)) { // Require either a username or host name match if ((String.IsNullOrEmpty(Client.Host) || String.Compare(Client.Host, PerforceInfo.HostName, StringComparison.InvariantCultureIgnoreCase) == 0) && (String.IsNullOrEmpty(Client.Owner) || String.Compare(Client.Owner, PerforceInfo.UserName, StringComparison.InvariantCultureIgnoreCase) == 0)) { if (!Utility.SafeIsFileUnderDirectory(NewSelectedFileName, Client.Root)) { Log.WriteLine("Rejecting {0} due to root mismatch ({1})", Client.Name, Client.Root); continue; } PerforceConnection CandidateClient = new PerforceConnection(PerforceInfo.UserName, Client.Name, Perforce.ServerAndPort); bool bFileExists; if (!CandidateClient.FileExists(NewSelectedFileName, out bFileExists, Log) || !bFileExists) { Log.WriteLine("Rejecting {0} due to file not existing in workspace", Client.Name); continue; } List <PerforceFileRecord> Records; if (!CandidateClient.Stat(NewSelectedFileName, out Records, Log)) { Log.WriteLine("Rejecting {0} due to {1} not in depot", Client.Name, NewSelectedFileName); continue; } Records.RemoveAll(x => !x.IsMapped); if (Records.Count != 1) { Log.WriteLine("Rejecting {0} due to {1} matching records", Client.Name, Records.Count); continue; } Log.WriteLine("Found valid client {0}", Client.Name); CandidateClients.Add(CandidateClient); } } } // Check there's only one client if (CandidateClients.Count == 0) { ErrorMessage = String.Format("Couldn't find any Perforce workspace containing {0}.", NewSelectedFileName); return(false); } else if (CandidateClients.Count > 1) { ErrorMessage = String.Format("Found multiple workspaces containing {0}:\n\n{1}\n\nCannot determine which to use.", Path.GetFileName(NewSelectedFileName), String.Join("\n", CandidateClients.Select(x => x.ClientName))); return(false); } // Take the client we've chosen PerforceClient = CandidateClients[0]; // Get the client path for the project file if (!PerforceClient.ConvertToClientPath(NewSelectedFileName, out NewSelectedClientFileName, Log)) { ErrorMessage = String.Format("Couldn't get client path for {0}", NewSelectedFileName); return(false); } // Figure out where the engine is in relation to it for (int EndIdx = NewSelectedClientFileName.Length - 1;; EndIdx--) { if (EndIdx < 2) { ErrorMessage = String.Format("Could not find engine in Perforce relative to project path ({0})", NewSelectedClientFileName); return(false); } if (NewSelectedClientFileName[EndIdx] == '/') { bool bFileExists; if (!PerforceClient.FileExists(NewSelectedClientFileName.Substring(0, EndIdx) + "/Engine/Source/UE4Editor.target.cs", out bFileExists, Log)) { ErrorMessage = String.Format("Could not find engine in Perforce relative to project path ({0})", NewSelectedClientFileName); return(false); } else if (bFileExists) { BranchClientPath = NewSelectedClientFileName.Substring(0, EndIdx); break; } } } Log.WriteLine("Found branch root at {0}", BranchClientPath); // Get the local branch root if (!PerforceClient.ConvertToLocalPath(BranchClientPath + "/Engine/Source/UE4Editor.target.cs", out BaseEditorTargetPath, Log)) { ErrorMessage = String.Format("Couldn't get local path for editor target file"); return(false); } // Find the editor target for this project if (NewSelectedFileName.EndsWith(".uproject", StringComparison.InvariantCultureIgnoreCase)) { List <PerforceFileRecord> Files; if (PerforceClient.FindFiles(PerforceUtils.GetClientOrDepotDirectoryName(NewSelectedClientFileName) + "/Source/*Editor.Target.cs", out Files, Log) && Files.Count >= 1) { PerforceFileRecord File = Files.FirstOrDefault(x => x.Action == null || !x.Action.Contains("delete")); if (File == null) { Log.WriteLine("Couldn't find any non-deleted editor targets for this project."); } else { string DepotPath = File.DepotPath; NewProjectEditorTarget = Path.GetFileNameWithoutExtension(Path.GetFileNameWithoutExtension(DepotPath.Substring(DepotPath.LastIndexOf('/') + 1))); Log.WriteLine("Using {0} as editor target name (from {1})", NewProjectEditorTarget, Files[0]); } } else { Log.WriteLine("Couldn't find any editor targets for this project."); } } // Get a unique name for the project that's selected. For regular branches, this can be the depot path. For streams, we want to include the stream name to encode imports. if (PerforceClient.GetActiveStream(out StreamName, Log)) { string ExpectedPrefix = String.Format("//{0}/", PerforceClient.ClientName); if (!NewSelectedClientFileName.StartsWith(ExpectedPrefix, StringComparison.InvariantCultureIgnoreCase)) { ErrorMessage = String.Format("Unexpected client path; expected '{0}' to begin with '{1}'", NewSelectedClientFileName, ExpectedPrefix); return(false); } string StreamPrefix; if (!TryGetStreamPrefix(PerforceClient, StreamName, Log, out StreamPrefix)) { ErrorMessage = String.Format("Failed to get stream info for {0}", StreamName); return(false); } NewSelectedProjectIdentifier = String.Format("{0}/{1}", StreamPrefix, NewSelectedClientFileName.Substring(ExpectedPrefix.Length)); } else { if (!PerforceClient.ConvertToDepotPath(NewSelectedClientFileName, out NewSelectedProjectIdentifier, Log)) { ErrorMessage = String.Format("Couldn't get depot path for {0}", NewSelectedFileName); return(false); } } // Read the project logo if (NewSelectedFileName.EndsWith(".uproject", StringComparison.InvariantCultureIgnoreCase)) { string LogoFileName = Path.Combine(Path.GetDirectoryName(NewSelectedFileName), "Build", "UnrealGameSync.png"); if (File.Exists(LogoFileName)) { try { // Duplicate the image, otherwise we'll leave the file locked using (Image Image = Image.FromFile(LogoFileName)) { ProjectLogo = new Bitmap(Image); } } catch { ProjectLogo = null; } } } // Succeeed! ErrorMessage = null; return(true); }
public ProgramApplicationContext(PerforceConnection DefaultConnection, UpdateMonitor UpdateMonitor, string ApiUrl, string DataFolder, EventWaitHandle ActivateEvent, bool bRestoreState, string UpdateSpawn, string ProjectFileName, bool bUnstable, TimestampLogWriter Log) { this.DefaultConnection = DefaultConnection; this.UpdateMonitor = UpdateMonitor; this.ApiUrl = ApiUrl; this.DataFolder = DataFolder; this.CacheFolder = Path.Combine(DataFolder, "Cache"); this.bRestoreState = bRestoreState; this.UpdateSpawn = UpdateSpawn; this.bUnstable = bUnstable; this.Log = Log; // Create the directories Directory.CreateDirectory(DataFolder); Directory.CreateDirectory(CacheFolder); // Make sure a synchronization context is set. We spawn a bunch of threads (eg. UpdateMonitor) at startup, and need to make sure we can post messages // back to the main thread at any time. if (SynchronizationContext.Current == null) { SynchronizationContext.SetSynchronizationContext(new WindowsFormsSynchronizationContext()); } // Capture the main thread's synchronization context for callbacks MainThreadSynchronizationContext = WindowsFormsSynchronizationContext.Current; // Read the user's settings Settings = new UserSettings(Path.Combine(DataFolder, "UnrealGameSync.ini")); if (!String.IsNullOrEmpty(ProjectFileName)) { string FullProjectFileName = Path.GetFullPath(ProjectFileName); if (!Settings.OpenProjects.Any(x => x.LocalPath != null && String.Compare(x.LocalPath, FullProjectFileName, StringComparison.InvariantCultureIgnoreCase) == 0)) { Settings.OpenProjects.Add(new UserSelectedProjectSettings(null, null, UserSelectedProjectType.Local, null, FullProjectFileName)); } } // Update the settings to the latest version if (Settings.Version < UserSettingsVersion.Latest) { // Clear out the server settings for anything using the default server if (Settings.Version < UserSettingsVersion.DefaultServerSettings) { for (int Idx = 0; Idx < Settings.OpenProjects.Count; Idx++) { Settings.OpenProjects[Idx] = UpgradeSelectedProjectSettings(Settings.OpenProjects[Idx]); } for (int Idx = 0; Idx < Settings.RecentProjects.Count; Idx++) { Settings.RecentProjects[Idx] = UpgradeSelectedProjectSettings(Settings.RecentProjects[Idx]); } } // Save the new settings Settings.Version = UserSettingsVersion.Latest; Settings.Save(); } // Register the update listener UpdateMonitor.OnUpdateAvailable += OnUpdateAvailableCallback; // Create the activation listener ActivationListener = new ActivationListener(ActivateEvent); ActivationListener.Start(); ActivationListener.OnActivate += OnActivationListenerAsyncCallback; // Create the notification menu items NotifyMenu_OpenUnrealGameSync = new ToolStripMenuItem(); NotifyMenu_OpenUnrealGameSync.Name = nameof(NotifyMenu_OpenUnrealGameSync); NotifyMenu_OpenUnrealGameSync.Size = new Size(196, 22); NotifyMenu_OpenUnrealGameSync.Text = "Open UnrealGameSync"; NotifyMenu_OpenUnrealGameSync.Click += new EventHandler(NotifyMenu_OpenUnrealGameSync_Click); NotifyMenu_OpenUnrealGameSync.Font = new Font(NotifyMenu_OpenUnrealGameSync.Font, FontStyle.Bold); NotifyMenu_OpenUnrealGameSync_Separator = new ToolStripSeparator(); NotifyMenu_OpenUnrealGameSync_Separator.Name = nameof(NotifyMenu_OpenUnrealGameSync_Separator); NotifyMenu_OpenUnrealGameSync_Separator.Size = new Size(193, 6); NotifyMenu_SyncNow = new ToolStripMenuItem(); NotifyMenu_SyncNow.Name = nameof(NotifyMenu_SyncNow); NotifyMenu_SyncNow.Size = new Size(196, 22); NotifyMenu_SyncNow.Text = "Sync Now"; NotifyMenu_SyncNow.Click += new EventHandler(NotifyMenu_SyncNow_Click); NotifyMenu_LaunchEditor = new ToolStripMenuItem(); NotifyMenu_LaunchEditor.Name = nameof(NotifyMenu_LaunchEditor); NotifyMenu_LaunchEditor.Size = new Size(196, 22); NotifyMenu_LaunchEditor.Text = "Launch Editor"; NotifyMenu_LaunchEditor.Click += new EventHandler(NotifyMenu_LaunchEditor_Click); NotifyMenu_ExitSeparator = new ToolStripSeparator(); NotifyMenu_ExitSeparator.Name = nameof(NotifyMenu_ExitSeparator); NotifyMenu_ExitSeparator.Size = new Size(193, 6); NotifyMenu_Exit = new ToolStripMenuItem(); NotifyMenu_Exit.Name = nameof(NotifyMenu_Exit); NotifyMenu_Exit.Size = new Size(196, 22); NotifyMenu_Exit.Text = "Exit"; NotifyMenu_Exit.Click += new EventHandler(NotifyMenu_Exit_Click); // Create the notification menu NotifyMenu = new ContextMenuStrip(Components); NotifyMenu.Name = nameof(NotifyMenu); NotifyMenu.Size = new System.Drawing.Size(197, 104); NotifyMenu.SuspendLayout(); NotifyMenu.Items.Add(NotifyMenu_OpenUnrealGameSync); NotifyMenu.Items.Add(NotifyMenu_OpenUnrealGameSync_Separator); NotifyMenu.Items.Add(NotifyMenu_SyncNow); NotifyMenu.Items.Add(NotifyMenu_LaunchEditor); NotifyMenu.Items.Add(NotifyMenu_ExitSeparator); NotifyMenu.Items.Add(NotifyMenu_Exit); NotifyMenu.ResumeLayout(false); // Create the notification icon NotifyIcon = new NotifyIcon(Components); NotifyIcon.ContextMenuStrip = NotifyMenu; NotifyIcon.Icon = Properties.Resources.Icon; NotifyIcon.Text = "UnrealGameSync"; NotifyIcon.Visible = true; NotifyIcon.DoubleClick += new EventHandler(NotifyIcon_DoubleClick); NotifyIcon.MouseDown += new MouseEventHandler(NotifyIcon_MouseDown); // Find the initial list of projects to attempt to reopen List <DetectProjectSettingsTask> Tasks = new List <DetectProjectSettingsTask>(); foreach (UserSelectedProjectSettings OpenProject in Settings.OpenProjects) { BufferedTextWriter StartupLog = new BufferedTextWriter(); StartupLog.WriteLine("Detecting settings for {0}", OpenProject); StartupLogs.Add(StartupLog); Tasks.Add(new DetectProjectSettingsTask(OpenProject, DataFolder, CacheFolder, new TimestampLogWriter(new PrefixedTextWriter(" ", StartupLog)))); } // Detect settings for the project we want to open DetectStartupProjectSettingsTask = new DetectMultipleProjectSettingsTask(DefaultConnection, Tasks); DetectStartupProjectSettingsWindow = new ModalTaskWindow(DetectStartupProjectSettingsTask, "Opening Projects", "Opening projects, please wait...", FormStartPosition.CenterScreen); if (bRestoreState) { if (Settings.bWindowVisible) { DetectStartupProjectSettingsWindow.Show(); } } else { DetectStartupProjectSettingsWindow.Show(); DetectStartupProjectSettingsWindow.Activate(); } DetectStartupProjectSettingsWindow.Complete += OnDetectStartupProjectsComplete; }
private NewWorkspaceWindow(PerforceConnection Perforce, string ForceStream, string DefaultStream, PerforceInfoRecord Info, List <PerforceClientRecord> Clients, TextWriter Log) { InitializeComponent(); this.Perforce = Perforce; this.Info = Info; this.Clients = Clients; this.Log = Log; Dictionary <string, int> RootPathToCount = new Dictionary <string, int>(StringComparer.InvariantCultureIgnoreCase); foreach (PerforceClientRecord Client in Clients) { if (Client.Host == null || String.Compare(Client.Host, Info.HostName, StringComparison.InvariantCultureIgnoreCase) == 0) { if (!String.IsNullOrEmpty(Client.Root) && Client.Root != ".") { string ParentDir; try { ParentDir = Path.GetFullPath(Path.GetDirectoryName(Client.Root)); } catch { ParentDir = null; } if (ParentDir != null) { int Count; RootPathToCount.TryGetValue(ParentDir, out Count); RootPathToCount[ParentDir] = Count + 1; } } } } int RootPathMaxCount = 0; foreach (KeyValuePair <string, int> RootPathPair in RootPathToCount) { if (RootPathPair.Value > RootPathMaxCount) { DefaultRootPath = RootPathPair.Key; RootPathMaxCount = RootPathPair.Value; } } if (ForceStream != null) { StreamTextBox.Text = ForceStream; StreamTextBox.Enabled = false; } else { StreamTextBox.Text = DefaultStream ?? ""; StreamTextBox.Enabled = true; } StreamTextBox.SelectionStart = StreamTextBox.Text.Length; StreamTextBox.SelectionLength = 0; StreamTextBox.Focus(); StreamBrowseBtn.Enabled = (ForceStream == null); UpdateOkButton(); UpdateNameCueBanner(); UpdateRootDirCueBanner(); }
public bool Run(out string ErrorMessage) { PerforceConnection Perforce = new PerforceConnection(null, null, null); // Get the Perforce server info PerforceInfoRecord PerforceInfo; if(!Perforce.Info(out PerforceInfo, Log)) { ErrorMessage = String.Format("Couldn't get Perforce server info"); return false; } if(String.IsNullOrEmpty(PerforceInfo.UserName)) { ErrorMessage = "Missing user name in call to p4 info"; return false; } if(String.IsNullOrEmpty(PerforceInfo.HostName)) { ErrorMessage = "Missing host name in call to p4 info"; return false; } ServerTimeZone = PerforceInfo.ServerTimeZone; // Find all the clients on this machine Log.WriteLine("Enumerating clients on local machine..."); List<PerforceClientRecord> Clients; if(!Perforce.FindClients(out Clients, Log)) { ErrorMessage = String.Format("Couldn't find any clients for this host."); return false; } // Find any clients which are valid. If this is not exactly one, we should fail. List<PerforceConnection> CandidateClients = new List<PerforceConnection>(); foreach(PerforceClientRecord Client in Clients) { // Make sure the client is well formed if(!String.IsNullOrEmpty(Client.Name) && (!String.IsNullOrEmpty(Client.Host) || !String.IsNullOrEmpty(Client.Owner)) && !String.IsNullOrEmpty(Client.Root)) { // Require either a username or host name match if((String.IsNullOrEmpty(Client.Host) || String.Compare(Client.Host, PerforceInfo.HostName, StringComparison.InvariantCultureIgnoreCase) == 0) && (String.IsNullOrEmpty(Client.Owner) || String.Compare(Client.Owner, PerforceInfo.UserName, StringComparison.InvariantCultureIgnoreCase) == 0)) { if(!Utility.SafeIsFileUnderDirectory(NewSelectedFileName, Client.Root)) { Log.WriteLine("Rejecting {0} due to root mismatch ({1})", Client.Name, Client.Root); continue; } PerforceConnection CandidateClient = new PerforceConnection(PerforceInfo.UserName, Client.Name, Perforce.ServerAndPort); bool bFileExists; if(!CandidateClient.FileExists(NewSelectedFileName, out bFileExists, Log) || !bFileExists) { Log.WriteLine("Rejecting {0} due to file not existing in workspace", Client.Name); continue; } List<PerforceFileRecord> Records; if(!CandidateClient.Stat(NewSelectedFileName, out Records, Log)) { Log.WriteLine("Rejecting {0} due to {1} not in depot", Client.Name, NewSelectedFileName); continue; } Records.RemoveAll(x => !x.IsMapped); if(Records.Count != 1) { Log.WriteLine("Rejecting {0} due to {1} matching records", Client.Name, Records.Count); continue; } Log.WriteLine("Found valid client {0}", Client.Name); CandidateClients.Add(CandidateClient); } } } // Check there's only one client if(CandidateClients.Count == 0) { ErrorMessage = String.Format("Couldn't find any Perforce workspace containing {0}.", NewSelectedFileName); return false; } else if(CandidateClients.Count > 1) { ErrorMessage = String.Format("Found multiple workspaces containing {0}:\n\n{1}\n\nCannot determine which to use.", Path.GetFileName(NewSelectedFileName), String.Join("\n", CandidateClients.Select(x => x.ClientName))); return false; } // Take the client we've chosen PerforceClient = CandidateClients[0]; // Get the client path for the project file if(!PerforceClient.ConvertToClientPath(NewSelectedFileName, out NewSelectedClientFileName, Log)) { ErrorMessage = String.Format("Couldn't get client path for {0}", NewSelectedFileName); return false; } // Figure out where the engine is in relation to it for(int EndIdx = NewSelectedClientFileName.Length - 1;;EndIdx--) { if(EndIdx < 2) { ErrorMessage = String.Format("Could not find engine in Perforce relative to project path ({0})", NewSelectedClientFileName); return false; } if(NewSelectedClientFileName[EndIdx] == '/') { bool bFileExists; if(!PerforceClient.FileExists(NewSelectedClientFileName.Substring(0, EndIdx) + "/Engine/Source/UE4Editor.target.cs", out bFileExists, Log)) { ErrorMessage = String.Format("Could not find engine in Perforce relative to project path ({0})", NewSelectedClientFileName); return false; } else if(bFileExists) { BranchClientPath = NewSelectedClientFileName.Substring(0, EndIdx); break; } } } Log.WriteLine("Found branch root at {0}", BranchClientPath); // Get the local branch root if(!PerforceClient.ConvertToLocalPath(BranchClientPath + "/Engine/Source/UE4Editor.target.cs", out BaseEditorTargetPath, Log)) { ErrorMessage = String.Format("Couldn't get local path for editor target file"); return false; } // Find the editor target for this project if(NewSelectedFileName.EndsWith(".uproject", StringComparison.InvariantCultureIgnoreCase)) { List<PerforceFileRecord> Files; if(PerforceClient.FindFiles(PerforceUtils.GetClientOrDepotDirectoryName(NewSelectedClientFileName) + "/Source/*Editor.Target.cs", out Files, Log) && Files.Count >= 1) { PerforceFileRecord File = Files.FirstOrDefault(x => x.Action == null || !x.Action.Contains("delete")); if(File == null) { Log.WriteLine("Couldn't find any non-deleted editor targets for this project."); } else { string DepotPath = File.DepotPath; NewProjectEditorTarget = Path.GetFileNameWithoutExtension(Path.GetFileNameWithoutExtension(DepotPath.Substring(DepotPath.LastIndexOf('/') + 1))); Log.WriteLine("Using {0} as editor target name (from {1})", NewProjectEditorTarget, Files[0]); } } else { Log.WriteLine("Couldn't find any editor targets for this project."); } } // Get a unique name for the project that's selected. For regular branches, this can be the depot path. For streams, we want to include the stream name to encode imports. if(PerforceClient.GetActiveStream(out StreamName, Log)) { string ExpectedPrefix = String.Format("//{0}/", PerforceClient.ClientName); if(!NewSelectedClientFileName.StartsWith(ExpectedPrefix, StringComparison.InvariantCultureIgnoreCase)) { ErrorMessage = String.Format("Unexpected client path; expected '{0}' to begin with '{1}'", NewSelectedClientFileName, ExpectedPrefix); return false; } string StreamPrefix; if(!TryGetStreamPrefix(PerforceClient, StreamName, Log, out StreamPrefix)) { ErrorMessage = String.Format("Failed to get stream info for {0}", StreamName); return false; } NewSelectedProjectIdentifier = String.Format("{0}/{1}", StreamPrefix, NewSelectedClientFileName.Substring(ExpectedPrefix.Length)); } else { if(!PerforceClient.ConvertToDepotPath(NewSelectedClientFileName, out NewSelectedProjectIdentifier, Log)) { ErrorMessage = String.Format("Couldn't get depot path for {0}", NewSelectedFileName); return false; } } // Read the project logo if(NewSelectedFileName.EndsWith(".uproject", StringComparison.InvariantCultureIgnoreCase)) { string LogoFileName = Path.Combine(Path.GetDirectoryName(NewSelectedFileName), "Build", "UnrealGameSync.png"); if(File.Exists(LogoFileName)) { try { // Duplicate the image, otherwise we'll leave the file locked using(Image Image = Image.FromFile(LogoFileName)) { ProjectLogo = new Bitmap(Image); } } catch { ProjectLogo = null; } } } // Succeeed! ErrorMessage = null; return true; }
public QuietDetectProjectSettingsTask(PerforceConnection Perforce, DetectProjectSettingsTask Inner, TextWriter Log) { this.Perforce = Perforce; this.Inner = Inner; this.Log = Log; }
public Workspace(PerforceConnection InPerforce, string InLocalRootPath, string InSelectedLocalFileName, string InClientRootPath, string InSelectedClientFileName, int InInitialChangeNumber, int InLastBuiltChangeNumber, string InTelemetryProjectPath, TextWriter InLog) { Perforce = InPerforce; LocalRootPath = InLocalRootPath; SelectedLocalFileName = InSelectedLocalFileName; ClientRootPath = InClientRootPath; SelectedClientFileName = InSelectedClientFileName; CurrentChangeNumber = InInitialChangeNumber; PendingChangeNumber = InInitialChangeNumber; LastBuiltChangeNumber = InLastBuiltChangeNumber; TelemetryProjectPath = InTelemetryProjectPath; Log = InLog; List<string> SyncPaths = new List<string>(); if(SelectedClientFileName.EndsWith(".uproject", StringComparison.InvariantCultureIgnoreCase)) { SyncPaths.Add(ClientRootPath + "/*"); SyncPaths.Add(ClientRootPath + "/Engine/..."); SyncPaths.Add(PerforceUtils.GetClientOrDepotDirectoryName(SelectedClientFileName) + "/..."); } else { SyncPaths.Add(ClientRootPath + "/..."); } this.SyncPaths = SyncPaths.AsReadOnly(); ProjectConfigFile = ReadProjectConfigFile(InLocalRootPath, InSelectedLocalFileName, Log); }
static void InnerMain(Mutex InstanceMutex, EventWaitHandle ActivateEvent, string[] Args) { string ServerAndPort = null; string UserName = null; string BaseUpdatePath = null; Utility.ReadGlobalPerforceSettings(ref ServerAndPort, ref UserName, ref BaseUpdatePath); List <string> RemainingArgs = new List <string>(Args); string UpdateSpawn; ParseArgument(RemainingArgs, "-updatespawn=", out UpdateSpawn); string UpdatePath; ParseArgument(RemainingArgs, "-updatepath=", out UpdatePath); bool bRestoreState; ParseOption(RemainingArgs, "-restorestate", out bRestoreState); bool bUnstable; ParseOption(RemainingArgs, "-unstable", out bUnstable); string ProjectFileName; ParseArgument(RemainingArgs, "-project=", out ProjectFileName); string Uri; ParseArgument(RemainingArgs, "-uri=", out Uri); string UpdateConfigFile = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "AutoUpdate.ini"); MergeUpdateSettings(UpdateConfigFile, ref UpdatePath, ref UpdateSpawn); string SyncVersionFile = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "SyncVersion.txt"); if (File.Exists(SyncVersionFile)) { try { SyncVersion = File.ReadAllText(SyncVersionFile).Trim(); } catch (Exception) { SyncVersion = null; } } string DataFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "UnrealGameSync"); Directory.CreateDirectory(DataFolder); // Enable TLS 1.1 and 1.2. TLS 1.0 is now deprecated and not allowed by default in NET Core servers. ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12; // Create the log file using (TimestampLogWriter Log = new TimestampLogWriter(new BoundedLogWriter(Path.Combine(DataFolder, "UnrealGameSync.log")))) { Log.WriteLine("Application version: {0}", Assembly.GetExecutingAssembly().GetName().Version); Log.WriteLine("Started at {0}", DateTime.Now.ToString()); string SessionId = Guid.NewGuid().ToString(); Log.WriteLine("SessionId: {0}", SessionId); if (ServerAndPort == null || UserName == null) { Log.WriteLine("Missing server settings; finding defaults."); GetDefaultServerSettings(ref ServerAndPort, ref UserName, Log); Utility.SaveGlobalPerforceSettings(ServerAndPort, UserName, BaseUpdatePath); } using (BoundedLogWriter TelemetryLog = new BoundedLogWriter(Path.Combine(DataFolder, "Telemetry.log"))) { TelemetryLog.WriteLine("Creating telemetry sink for session {0}", SessionId); ITelemetrySink PrevTelemetrySink = Telemetry.ActiveSink; using (ITelemetrySink TelemetrySink = DeploymentSettings.CreateTelemetrySink(UserName, SessionId, TelemetryLog)) { Telemetry.ActiveSink = TelemetrySink; Telemetry.SendEvent("Startup", new { User = Environment.UserName, Machine = Environment.MachineName }); AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; PerforceConnection DefaultConnection = new PerforceConnection(UserName, null, ServerAndPort); using (UpdateMonitor UpdateMonitor = new UpdateMonitor(DefaultConnection, UpdatePath)) { ProgramApplicationContext Context = new ProgramApplicationContext(DefaultConnection, UpdateMonitor, DeploymentSettings.ApiUrl, DataFolder, ActivateEvent, bRestoreState, UpdateSpawn, ProjectFileName, bUnstable, Log, Uri); Application.Run(Context); if (UpdateMonitor.IsUpdateAvailable && UpdateSpawn != null) { InstanceMutex.Close(); bool bLaunchUnstable = UpdateMonitor.RelaunchUnstable ?? bUnstable; Utility.SpawnProcess(UpdateSpawn, "-restorestate" + (bLaunchUnstable ? " -unstable" : "")); } } } Telemetry.ActiveSink = PrevTelemetrySink; } } }
public bool Run(PerforceConnection Perforce, TextWriter Log, out string ErrorMessage) { // Get the perforce server settings PerforceInfoRecord PerforceInfo; if (!Perforce.Info(out PerforceInfo, Log)) { ErrorMessage = String.Format("Couldn't get Perforce server info"); return(false); } // Configure the time zone ServerTimeZone = PerforceInfo.ServerTimeZone; // If we're using the legacy path of specifying a file, figure out the workspace name now if (SelectedProject.Type == UserSelectedProjectType.Client) { // Get the client path NewSelectedClientFileName = SelectedProject.ClientPath; // Get the client name string ClientName; if (!PerforceUtils.TryGetClientName(NewSelectedClientFileName, out ClientName)) { ErrorMessage = String.Format("Couldn't get client name from {0}", NewSelectedClientFileName); return(false); } // Create the client PerforceClient = new PerforceConnection(Perforce.UserName, ClientName, Perforce.ServerAndPort); // Figure out the path on the client if (!PerforceClient.ConvertToLocalPath(NewSelectedClientFileName, out NewSelectedFileName, Log)) { ErrorMessage = String.Format("Couldn't get client path for {0}", NewSelectedFileName); return(false); } } else if (SelectedProject.Type == UserSelectedProjectType.Local) { // Use the path as the selected filename NewSelectedFileName = SelectedProject.LocalPath; // Make sure the project exists if (!File.Exists(SelectedProject.LocalPath)) { ErrorMessage = String.Format("{0} does not exist.", SelectedProject.LocalPath); return(false); } // Find all the clients on this machine Log.WriteLine("Enumerating clients on local machine..."); List <PerforceClientRecord> Clients; if (!Perforce.FindClients(out Clients, Log)) { ErrorMessage = String.Format("Couldn't find any clients for this host."); return(false); } // Find any clients which are valid. If this is not exactly one, we should fail. List <PerforceConnection> CandidateClients = new List <PerforceConnection>(); foreach (PerforceClientRecord Client in Clients) { // Make sure the client is well formed if (!String.IsNullOrEmpty(Client.Name) && (!String.IsNullOrEmpty(Client.Host) || !String.IsNullOrEmpty(Client.Owner)) && !String.IsNullOrEmpty(Client.Root)) { // Require either a username or host name match if ((String.IsNullOrEmpty(Client.Host) || String.Compare(Client.Host, PerforceInfo.HostName, StringComparison.InvariantCultureIgnoreCase) == 0) && (String.IsNullOrEmpty(Client.Owner) || String.Compare(Client.Owner, PerforceInfo.UserName, StringComparison.InvariantCultureIgnoreCase) == 0)) { if (!Utility.SafeIsFileUnderDirectory(NewSelectedFileName, Client.Root)) { Log.WriteLine("Rejecting {0} due to root mismatch ({1})", Client.Name, Client.Root); continue; } PerforceConnection CandidateClient = new PerforceConnection(PerforceInfo.UserName, Client.Name, Perforce.ServerAndPort); bool bFileExists; if (!CandidateClient.FileExists(NewSelectedFileName, out bFileExists, Log) || !bFileExists) { Log.WriteLine("Rejecting {0} due to file not existing in workspace", Client.Name); continue; } List <PerforceFileRecord> Records; if (!CandidateClient.Stat(NewSelectedFileName, out Records, Log)) { Log.WriteLine("Rejecting {0} due to {1} not in depot", Client.Name, NewSelectedFileName); continue; } Records.RemoveAll(x => !x.IsMapped); if (Records.Count == 0) { Log.WriteLine("Rejecting {0} due to {1} matching records", Client.Name, Records.Count); continue; } Log.WriteLine("Found valid client {0}", Client.Name); CandidateClients.Add(CandidateClient); } } } // Check there's only one client if (CandidateClients.Count == 0) { ErrorMessage = String.Format("Couldn't find any Perforce workspace containing {0}. Check your connection settings.", NewSelectedFileName); return(false); } else if (CandidateClients.Count > 1) { ErrorMessage = String.Format("Found multiple workspaces containing {0}:\n\n{1}\n\nCannot determine which to use.", Path.GetFileName(NewSelectedFileName), String.Join("\n", CandidateClients.Select(x => x.ClientName))); return(false); } // Take the client we've chosen PerforceClient = CandidateClients[0]; // Get the client path for the project file if (!PerforceClient.ConvertToClientPath(NewSelectedFileName, out NewSelectedClientFileName, Log)) { ErrorMessage = String.Format("Couldn't get client path for {0}", NewSelectedFileName); return(false); } } else { throw new InvalidDataException("Invalid selected project type"); } // Normalize the filename NewSelectedFileName = Path.GetFullPath(NewSelectedFileName).Replace('/', Path.DirectorySeparatorChar); // Make sure the path case is correct. This can cause UBT intermediates to be out of date if the case mismatches. NewSelectedFileName = Utility.GetPathWithCorrectCase(new FileInfo(NewSelectedFileName)); // Update the selected project with all the data we've found SelectedProject = new UserSelectedProjectSettings(Perforce.ServerAndPort, Perforce.UserName, SelectedProject.Type, NewSelectedClientFileName, NewSelectedFileName); // Figure out where the engine is in relation to it for (int EndIdx = NewSelectedClientFileName.Length - 1;; EndIdx--) { if (EndIdx < 2) { ErrorMessage = String.Format("Could not find engine in Perforce relative to project path ({0})", NewSelectedClientFileName); return(false); } if (NewSelectedClientFileName[EndIdx] == '/') { bool bFileExists; if (PerforceClient.FileExists(NewSelectedClientFileName.Substring(0, EndIdx) + "/Engine/Build/Build.version", out bFileExists, Log) && bFileExists) { BranchClientPath = NewSelectedClientFileName.Substring(0, EndIdx); break; } } } Log.WriteLine("Found branch root at {0}", BranchClientPath); // Get the local branch root string BuildVersionPath; if (!PerforceClient.ConvertToLocalPath(BranchClientPath + "/Engine/Build/Build.version", out BuildVersionPath, Log)) { ErrorMessage = String.Format("Couldn't get local path for Engine/Build/Build.version"); return(false); } BranchDirectoryName = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(BuildVersionPath), "..", "..")); // Find the editor target for this project if (NewSelectedFileName.EndsWith(".uproject", StringComparison.InvariantCultureIgnoreCase)) { List <PerforceFileRecord> Files; if (PerforceClient.FindFiles(PerforceUtils.GetClientOrDepotDirectoryName(NewSelectedClientFileName) + "/Source/*Editor.Target.cs", out Files, Log) && Files.Count >= 1) { PerforceFileRecord File = Files.FirstOrDefault(x => x.Action == null || !x.Action.Contains("delete")); if (File != null) { string DepotPath = File.DepotPath; NewProjectEditorTarget = Path.GetFileNameWithoutExtension(Path.GetFileNameWithoutExtension(DepotPath.Substring(DepotPath.LastIndexOf('/') + 1))); Log.WriteLine("Using {0} as editor target name (from {1})", NewProjectEditorTarget, Files[0]); } } if (NewProjectEditorTarget == null) { Log.WriteLine("Couldn't find any editor targets for this project."); } } // Get a unique name for the project that's selected. For regular branches, this can be the depot path. For streams, we want to include the stream name to encode imports. if (PerforceClient.GetActiveStream(out StreamName, Log)) { string ExpectedPrefix = String.Format("//{0}/", PerforceClient.ClientName); if (!NewSelectedClientFileName.StartsWith(ExpectedPrefix, StringComparison.InvariantCultureIgnoreCase)) { ErrorMessage = String.Format("Unexpected client path; expected '{0}' to begin with '{1}'", NewSelectedClientFileName, ExpectedPrefix); return(false); } string StreamPrefix; if (!TryGetStreamPrefix(PerforceClient, StreamName, Log, out StreamPrefix)) { ErrorMessage = String.Format("Failed to get stream info for {0}", StreamName); return(false); } NewSelectedProjectIdentifier = String.Format("{0}/{1}", StreamPrefix, NewSelectedClientFileName.Substring(ExpectedPrefix.Length)); } else { if (!PerforceClient.ConvertToDepotPath(NewSelectedClientFileName, out NewSelectedProjectIdentifier, Log)) { ErrorMessage = String.Format("Couldn't get depot path for {0}", NewSelectedFileName); return(false); } } // Read the project logo if (NewSelectedFileName.EndsWith(".uproject", StringComparison.InvariantCultureIgnoreCase)) { string LogoFileName = Path.Combine(Path.GetDirectoryName(NewSelectedFileName), "Build", "UnrealGameSync.png"); if (File.Exists(LogoFileName)) { try { // Duplicate the image, otherwise we'll leave the file locked using (Image Image = Image.FromFile(LogoFileName)) { ProjectLogo = new Bitmap(Image); } } catch { ProjectLogo = null; } } } // Figure out if it's an enterprise project List <string> ProjectLines; if (NewSelectedClientFileName.EndsWith(".uproject", StringComparison.InvariantCultureIgnoreCase) && PerforceClient.Print(NewSelectedClientFileName, out ProjectLines, Log)) { string Text = String.Join("\n", ProjectLines); bIsEnterpriseProject = Utility.IsEnterpriseProjectFromText(Text); } // Read the initial config file LocalConfigFiles = new List <KeyValuePair <string, DateTime> >(); LatestProjectConfigFile = PerforceMonitor.ReadProjectConfigFile(PerforceClient, BranchClientPath, NewSelectedClientFileName, LocalConfigFiles, Log); // Succeed! ErrorMessage = null; return(true); }
public PerforceModalTask(PerforceConnection Perforce, IPerforceModalTask InnerTask, TextWriter Log) { this.Perforce = Perforce; this.InnerTask = InnerTask; this.Log = Log; }
public DetectMultipleProjectSettingsTask(PerforceConnection DefaultConnection, IEnumerable <DetectProjectSettingsTask> Tasks) { this.DefaultConnection = DefaultConnection; this.Tasks = Tasks.ToArray(); }
public static void DoClean(PerforceConnection PerforceClient, string LocalRootPath, string ClientRootPath, IReadOnlyList<string> SyncPaths, TextWriter Log) { // Figure out which folders to clean FolderToClean RootFolderToClean = new FolderToClean(new DirectoryInfo(LocalRootPath)); using(FindFoldersToCleanTask QueryWorkspace = new FindFoldersToCleanTask(PerforceClient, RootFolderToClean, ClientRootPath, SyncPaths, Log)) { string ErrorMessage; if(!ModalTaskWindow.Execute(QueryWorkspace, "Clean Workspace", "Querying files in Perforce, please wait...", out ErrorMessage)) { if(!String.IsNullOrEmpty(ErrorMessage)) { MessageBox.Show(ErrorMessage); } return; } } // If there's nothing to delete, don't bother displaying the dialog at all if(RootFolderToClean.FilesToClean.Count == 0 && RootFolderToClean.SubFolders.Count == 0) { MessageBox.Show("You have no local files which are not in Perforce.", "Workspace Clean", MessageBoxButtons.OK); return; } // Populate the tree CleanWorkspaceWindow CleanWorkspace = new CleanWorkspaceWindow(RootFolderToClean); CleanWorkspace.ShowDialog(); }
public bool Run(PerforceConnection Perforce, TextWriter Log, out string ErrorMessage) { // Use the cached client path to the file if it's available; it's much quicker than trying to find the correct workspace. if (!String.IsNullOrEmpty(SelectedProject.ClientPath)) { // Get the client path NewSelectedClientFileName = SelectedProject.ClientPath; // Get the client name string ClientName; if (!PerforceUtils.TryGetClientName(NewSelectedClientFileName, out ClientName)) { ErrorMessage = String.Format("Couldn't get client name from {0}", NewSelectedClientFileName); return(false); } // Create the client PerforceClient = new PerforceConnection(Perforce.UserName, ClientName, Perforce.ServerAndPort); // Figure out the path on the client. Use the cached location if it's valid. if (SelectedProject.LocalPath != null && File.Exists(SelectedProject.LocalPath)) { NewSelectedFileName = SelectedProject.LocalPath; } else { if (!PerforceClient.ConvertToLocalPath(NewSelectedClientFileName, out NewSelectedFileName, Log)) { ErrorMessage = String.Format("Couldn't get client path for {0}", NewSelectedClientFileName); return(false); } } } else { // Get the perforce server settings PerforceInfoRecord PerforceInfo; if (!Perforce.Info(out PerforceInfo, Log)) { ErrorMessage = String.Format("Couldn't get Perforce server info"); return(false); } // Use the path as the selected filename NewSelectedFileName = SelectedProject.LocalPath; // Make sure the project exists if (!File.Exists(SelectedProject.LocalPath)) { ErrorMessage = String.Format("{0} does not exist.", SelectedProject.LocalPath); return(false); } // Find all the clients for this user Log.WriteLine("Enumerating clients for {0}...", PerforceInfo.UserName); List <PerforceClientRecord> Clients; if (!Perforce.FindClients(PerforceInfo.UserName, out Clients, Log)) { ErrorMessage = String.Format("Couldn't find any clients for this host."); return(false); } List <PerforceConnection> CandidateClients = FilterClients(Clients, Perforce.ServerAndPort, PerforceInfo.HostName, PerforceInfo.UserName); if (CandidateClients.Count == 0) { // Search through all workspaces. We may find a suitable workspace which is for any user. Log.WriteLine("Enumerating shared clients..."); if (!Perforce.FindClients("", out Clients, Log)) { ErrorMessage = "Failed to enumerate clients."; return(false); } // Filter this list of clients CandidateClients = FilterClients(Clients, Perforce.ServerAndPort, PerforceInfo.HostName, PerforceInfo.UserName); // If we still couldn't find any, fail. if (CandidateClients.Count == 0) { ErrorMessage = String.Format("Couldn't find any Perforce workspace containing {0}. Check your connection settings.", NewSelectedFileName); return(false); } } // Check there's only one client if (CandidateClients.Count > 1) { ErrorMessage = String.Format("Found multiple workspaces containing {0}:\n\n{1}\n\nCannot determine which to use.", Path.GetFileName(NewSelectedFileName), String.Join("\n", CandidateClients.Select(x => x.ClientName))); return(false); } // Take the client we've chosen PerforceClient = CandidateClients[0]; // Get the client path for the project file if (!PerforceClient.ConvertToClientPath(NewSelectedFileName, out NewSelectedClientFileName, Log)) { ErrorMessage = String.Format("Couldn't get client path for {0}", NewSelectedFileName); return(false); } } // Normalize the filename NewSelectedFileName = Path.GetFullPath(NewSelectedFileName).Replace('/', Path.DirectorySeparatorChar); // Make sure the path case is correct. This can cause UBT intermediates to be out of date if the case mismatches. NewSelectedFileName = Utility.GetPathWithCorrectCase(new FileInfo(NewSelectedFileName)); // Update the selected project with all the data we've found SelectedProject = new UserSelectedProjectSettings(SelectedProject.ServerAndPort, SelectedProject.UserName, SelectedProject.Type, NewSelectedClientFileName, NewSelectedFileName); // Figure out where the engine is in relation to it int EndIdx = NewSelectedClientFileName.Length - 1; if (EndIdx != -1 && NewSelectedClientFileName.EndsWith(".uproject", StringComparison.InvariantCultureIgnoreCase)) { EndIdx = NewSelectedClientFileName.LastIndexOf('/') - 1; } for (;; EndIdx--) { if (EndIdx < 2) { ErrorMessage = String.Format("Could not find engine in Perforce relative to project path ({0})", NewSelectedClientFileName); return(false); } if (NewSelectedClientFileName[EndIdx] == '/') { List <PerforceFileRecord> FileRecords; if (PerforceClient.Stat(NewSelectedClientFileName.Substring(0, EndIdx) + "/Engine/Build/Build.version", out FileRecords, Log) && FileRecords.Count > 0) { if (FileRecords[0].ClientPath == null) { ErrorMessage = String.Format("Missing client path for {0}", FileRecords[0].DepotPath); return(false); } BranchClientPath = NewSelectedClientFileName.Substring(0, EndIdx); BranchDirectoryName = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(FileRecords[0].ClientPath), "..", "..")); break; } } } Log.WriteLine("Found branch root at {0}", BranchClientPath); // Find the editor target for this project if (NewSelectedFileName.EndsWith(".uproject", StringComparison.InvariantCultureIgnoreCase)) { List <PerforceFileRecord> Files; if (PerforceClient.FindFiles(PerforceUtils.GetClientOrDepotDirectoryName(NewSelectedClientFileName) + "/Source/*Editor.Target.cs", out Files, Log) && Files.Count >= 1) { string DepotPath = Files[0].DepotPath; NewProjectEditorTarget = Path.GetFileNameWithoutExtension(Path.GetFileNameWithoutExtension(DepotPath.Substring(DepotPath.LastIndexOf('/') + 1))); Log.WriteLine("Using {0} as editor target name (from {1})", NewProjectEditorTarget, Files[0]); } if (NewProjectEditorTarget == null) { Log.WriteLine("Couldn't find any editor targets for this project."); } } // Get a unique name for the project that's selected. For regular branches, this can be the depot path. For streams, we want to include the stream name to encode imports. if (PerforceClient.GetActiveStream(out StreamName, Log)) { string ExpectedPrefix = String.Format("//{0}/", PerforceClient.ClientName); if (!NewSelectedClientFileName.StartsWith(ExpectedPrefix, StringComparison.InvariantCultureIgnoreCase)) { ErrorMessage = String.Format("Unexpected client path; expected '{0}' to begin with '{1}'", NewSelectedClientFileName, ExpectedPrefix); return(false); } string StreamPrefix; if (!TryGetStreamPrefix(PerforceClient, StreamName, Log, out StreamPrefix)) { ErrorMessage = String.Format("Failed to get stream info for {0}", StreamName); return(false); } NewSelectedProjectIdentifier = String.Format("{0}/{1}", StreamPrefix, NewSelectedClientFileName.Substring(ExpectedPrefix.Length)); } else { if (!PerforceClient.ConvertToDepotPath(NewSelectedClientFileName, out NewSelectedProjectIdentifier, Log)) { ErrorMessage = String.Format("Couldn't get depot path for {0}", NewSelectedFileName); return(false); } } // Read the project logo if (NewSelectedFileName.EndsWith(".uproject", StringComparison.InvariantCultureIgnoreCase)) { string LogoFileName = Path.Combine(Path.GetDirectoryName(NewSelectedFileName), "Build", "UnrealGameSync.png"); if (File.Exists(LogoFileName)) { try { // Duplicate the image, otherwise we'll leave the file locked using (Image Image = Image.FromFile(LogoFileName)) { ProjectLogo = new Bitmap(Image); } } catch { ProjectLogo = null; } } } // Figure out if it's an enterprise project. Use the synced version if we have it. if (NewSelectedClientFileName.EndsWith(".uproject", StringComparison.InvariantCultureIgnoreCase)) { string Text; if (File.Exists(NewSelectedFileName)) { Text = File.ReadAllText(NewSelectedFileName); } else { List <string> ProjectLines; if (!PerforceClient.Print(NewSelectedClientFileName, out ProjectLines, Log)) { ErrorMessage = String.Format("Unable to get contents of {0}", NewSelectedClientFileName); return(false); } Text = String.Join("\n", ProjectLines); } bIsEnterpriseProject = Utility.IsEnterpriseProjectFromText(Text); } // Read the initial config file LocalConfigFiles = new List <KeyValuePair <string, DateTime> >(); LatestProjectConfigFile = PerforceMonitor.ReadProjectConfigFile(PerforceClient, BranchClientPath, NewSelectedClientFileName, CacheFolder, LocalConfigFiles, Log); // Succeed! ErrorMessage = null; return(true); }
static void InnerMain(Mutex InstanceMutex, EventWaitHandle ActivateEvent, string[] Args) { string ServerAndPort = null; string UserName = null; string UpdatePath = null; Utility.ReadGlobalPerforceSettings(ref ServerAndPort, ref UserName, ref UpdatePath); List <string> RemainingArgs = new List <string>(Args); string UpdateSpawn; ParseArgument(RemainingArgs, "-updatespawn=", out UpdateSpawn); bool bRestoreState; ParseOption(RemainingArgs, "-restorestate", out bRestoreState); bool bUnstable; ParseOption(RemainingArgs, "-unstable", out bUnstable); string ProjectFileName; ParseArgument(RemainingArgs, "-project=", out ProjectFileName); string UpdateConfigFile = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "AutoUpdate.ini"); MergeUpdateSettings(UpdateConfigFile, ref UpdatePath, ref UpdateSpawn); string SyncVersionFile = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "SyncVersion.txt"); if (File.Exists(SyncVersionFile)) { try { SyncVersion = File.ReadAllText(SyncVersionFile).Trim(); } catch (Exception) { SyncVersion = null; } } string DataFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "UnrealGameSync"); Directory.CreateDirectory(DataFolder); using (TelemetryWriter Telemetry = new TelemetryWriter(DeploymentSettings.ApiUrl, Path.Combine(DataFolder, "Telemetry.log"))) { AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; // Create the log file using (TimestampLogWriter Log = new TimestampLogWriter(new BoundedLogWriter(Path.Combine(DataFolder, "UnrealGameSync.log")))) { Log.WriteLine("Application version: {0}", Assembly.GetExecutingAssembly().GetName().Version); Log.WriteLine("Started at {0}", DateTime.Now.ToString()); if (ServerAndPort == null || UserName == null) { Log.WriteLine("Missing server settings; finding defaults."); GetDefaultServerSettings(ref ServerAndPort, ref UserName, Log); Utility.SaveGlobalPerforceSettings(ServerAndPort, UserName, UpdatePath); } PerforceConnection DefaultConnection = new PerforceConnection(UserName, null, ServerAndPort); using (UpdateMonitor UpdateMonitor = new UpdateMonitor(DefaultConnection, UpdatePath)) { ProgramApplicationContext Context = new ProgramApplicationContext(DefaultConnection, UpdateMonitor, DeploymentSettings.ApiUrl, DataFolder, ActivateEvent, bRestoreState, UpdateSpawn, ProjectFileName, bUnstable, Log); Application.Run(Context); if (UpdateMonitor.IsUpdateAvailable && UpdateSpawn != null) { InstanceMutex.Close(); bool bLaunchUnstable = UpdateMonitor.RelaunchUnstable ?? bUnstable; Utility.SpawnProcess(UpdateSpawn, "-restorestate" + (bLaunchUnstable? " -unstable" : "")); } } } } }