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 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);

            // 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);
                            Application.Run(Context);

                            if (UpdateMonitor.IsUpdateAvailable && UpdateSpawn != null)
                            {
                                InstanceMutex.Close();
                                bool bLaunchUnstable = UpdateMonitor.RelaunchUnstable ?? bUnstable;
                                Utility.SpawnProcess(UpdateSpawn, "-restorestate" + (bLaunchUnstable ? " -unstable" : ""));
                            }
                        }
                    }
                    Telemetry.ActiveSink = PrevTelemetrySink;
                }
            }
        }
Exemple #2
0
        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);
                }

                Match Match = Regex.Match(NewSelectedProjectIdentifier, "//([^/]+)/");
                if (Match.Success)
                {
                    PerforceSpec Spec;
                    if (PerforceClient.TryGetDepotSpec(Match.Groups[1].Value, out Spec, Log) && Spec.GetField("Type") == "stream")
                    {
                        ErrorMessage = String.Format("Cannot use a legacy client ({0}) with a stream depot ({1}).", PerforceClient.ClientName, Match.Groups[1].Value);
                        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);
            }

            // Make sure the drive containing the project exists, to prevent other errors down the line
            string PathRoot = Path.GetPathRoot(NewSelectedFileName);

            if (!Directory.Exists(PathRoot))
            {
                ErrorMessage = String.Format("Path '{0}' is invalid", NewSelectedFileName);
                return(false);
            }

            // Read the initial config file
            LocalConfigFiles        = new List <KeyValuePair <string, DateTime> >();
            LatestProjectConfigFile = PerforceMonitor.ReadProjectConfigFile(PerforceClient, BranchClientPath, NewSelectedClientFileName, CacheFolder, LocalConfigFiles, Log);

            // Run any event hooks
            if (DeploymentSettings.OnDetectProjectSettings != null)
            {
                string Message;
                if (!DeploymentSettings.OnDetectProjectSettings(this, Log, out Message))
                {
                    ErrorMessage = Message;
                    return(false);
                }
            }

            // Succeed!
            ErrorMessage = null;
            return(true);
        }