예제 #1
0
        private bool SyncResultedInError(ILfProject project,
                                         string syncResult, string errorString, ProcessingState.SendReceiveStates?newState = null)
        {
            var line = LfMergeBridgeServices.GetLineContaining(syncResult, errorString);

            if (!string.IsNullOrEmpty(line))
            {
                if (line.Contains("Exception"))
                {
                    IEnumerable <string> stackTrace = LfMergeBridgeServices.GetLineAndStackTraceContaining(syncResult, errorString);
                    Logger.Error(String.Join(Environment.NewLine, stackTrace));                       // We want entire stack trace logged as a single log entry, so don't use Logger.LogMany()
                }
                else
                {
                    Logger.Error(line);
                }
                if (newState.HasValue)
                {
                    if (newState.Value == ProcessingState.SendReceiveStates.HOLD)
                    {
                        // When going on hold, do so via the new PutOnHold() function so we record an error message
                        project.State.PutOnHold("Error during synchronize of {0}: {1}",
                                                project.ProjectCode, line);
                    }
                    else
                    {
                        project.State.SRState = newState.Value;
                    }
                }
                return(true);
            }
            return(false);
        }
예제 #2
0
        public static string GetPrefixedStringFromLfMergeBridgeOutput(string lfMergeBridgeOutput, string prefix)
        {
            if (string.IsNullOrEmpty(prefix) || string.IsNullOrEmpty(lfMergeBridgeOutput))
            {
                return(string.Empty);
            }
            string result = LfMergeBridgeServices.GetLineContaining(lfMergeBridgeOutput, prefix);

            if (result.StartsWith(prefix))
            {
                return(result.Substring(prefix.Length));
            }
            else
            {
                return(string.Empty);                // If the "prefix" wasn't actually a prefix, this wasn't the string we wanted.
            }
        }
예제 #3
0
        private bool CloneResultedInError(ILfProject project, string cloneResult,
                                          string errorString, bool isRecoverableError, ProcessingState.ErrorCodes errorCode)
        {
            var line = LfMergeBridgeServices.GetLineContaining(cloneResult, errorString);

            if (string.IsNullOrEmpty(line))
            {
                return(false);
            }

            var errorType = isRecoverableError ? "Recoverable error" : "Error";

            Logger.Error("{2} during initial clone of {0}: {1}", project.ProjectCode, line,
                         errorType);
            project.State.SetErrorState(isRecoverableError ? ProcessingState.SendReceiveStates.ERROR :
                                        ProcessingState.SendReceiveStates.HOLD, errorCode,
                                        "{2} during initial clone of {0}: {1}", project.ProjectCode, line, errorType);
            return(true);
        }
예제 #4
0
        /// <summary>
        /// Ensures a Send/Receive project from Language Depot is properly
        /// cloned into the WebWork directory for LfMerge.Core.
        /// A project will be cloned if:
        /// 1) The LfMerge state file doesn't exist OR
        /// 2) The current LfMerge state is ProcessingState.SendReceiveStates.CLONING OR
        /// 3) The project directory is empty
        /// </summary>
        /// <param name="project">LF Project.</param>
        protected override void DoRun(ILfProject project)
        {
            try
            {
                // Check if an initial clone needs to be performed
                if (File.Exists(Settings.GetStateFileName(project.ProjectCode)) &&
                    project.State.SRState != ProcessingState.SendReceiveStates.CLONING &&
                    File.Exists(project.FwDataPath))
                {
                    return;
                }
                var cloneLocation = project.ProjectDir;
                if (RepoAlreadyExists(cloneLocation))
                {
                    Logger.Notice("Repairing clone of project {0}", project.ProjectCode);
                }
                else
                {
                    Logger.Notice("Initial clone for project {0}", project.ProjectCode);
                }
                project.State.SRState = ProcessingState.SendReceiveStates.CLONING;

                string cloneResult;
                if (!CloneRepo(project, cloneLocation, out cloneResult))
                {
                    Logger.Error(cloneResult);
                    return;
                }

                if (CloneResultedInError(project, cloneResult, "clone is not a FLEx project", true, ProcessingState.ErrorCodes.NoFlexProject) ||
                    CloneResultedInError(project, cloneResult, "new repository with no commits", true, ProcessingState.ErrorCodes.EmptyProject) ||
                    CloneResultedInError(project, cloneResult, "clone has higher model", true, ProcessingState.ErrorCodes.ProjectTooNew) ||
                    CloneResultedInError(project, cloneResult, "LfMergeBridge starting S/R handler from directory", false, ProcessingState.ErrorCodes.Unspecified))
                {
                    return;
                }

                string line = LfMergeBridgeServices.GetLineContaining(cloneResult, "no such branch");
                if (!string.IsNullOrEmpty(line))
                {
                    const string modelString = "Highest available model '";
                    var          index       = line.IndexOf(modelString, StringComparison.Ordinal);
                    if (index < 0)
                    {
                        ReportNoSuchBranchFailure(project, cloneLocation, cloneResult, line, ProcessingState.ErrorCodes.UnspecifiedBranchError);
                        return;
                    }

                    var cloneModelVersion = line.Substring(index + modelString.Length, 7);
                    if (int.Parse(cloneModelVersion) < int.Parse(MagicStrings.MinimalModelVersion))
                    {
                        ReportNoSuchBranchFailure(project, cloneLocation, cloneResult, line, ProcessingState.ErrorCodes.ProjectTooOld);
                        Logger.Error("Error during initial clone of '{0}': " +
                                     "clone model version '{1}' less than minimal supported model version '{2}'.",
                                     project.ProjectCode, cloneModelVersion, MagicStrings.MinimalModelVersion);
                        return;
                    }
                    Logger.Info(line);
                    ChorusHelper.SetModelVersion(cloneModelVersion);
                }
                else
                {
                    ChorusHelper.SetModelVersion(FdoCache.ModelVersion);
                    line = LfMergeBridgeServices.GetLineContaining(cloneResult,
                                                                   "new clone created on branch");
                    Require.That(!string.IsNullOrEmpty(line),
                                 "Looks like the clone was not successful, but we didn't get an understandable error");

                    // verify clone path
                    GetActualClonePath(cloneLocation, line);

                    if (MongoProjectHasUserDataOrHasBeenSynced())
                    {
                        // If the local Mercurial repo was deleted but the Mongo database is still there,
                        // then there might be data in Mongo that we still need, in which case we should NOT
                        // skip the syncing step. So do nothing, so that we'll fall through to the SYNCING state.
                    }
                    else
                    {
                        InitialTransferToMongoAfterClone(project);
                        Logger.Notice("Initial clone completed; setting state to CLONED");
                        project.State.SRState = ProcessingState.SendReceiveStates.CLONED;
                    }
                }
            }
            catch (Exception e)
            {
                switch (e.GetType().Name)
                {
                case "ArgumentOutOfRangeException":
                    if (e.Message == "Cannot update to any branch.")
                    {
                        project.State.SetErrorState(ProcessingState.SendReceiveStates.ERROR,
                                                    ProcessingState.ErrorCodes.UnspecifiedBranchError,
                                                    "Error during initial clone of {0}: {1}", project.ProjectCode, e);
                        return;
                    }

                    break;

                case "RepositoryAuthorizationException":
                    Logger.Error("Initial clone of {0}: authorization exception", project.ProjectCode);
                    project.State.SetErrorState(ProcessingState.SendReceiveStates.ERROR,
                                                ProcessingState.ErrorCodes.Unauthorized,
                                                "Error during initial clone of {0}: authorization exception from remote repository",
                                                project.ProjectCode);
                    return;
                }

                Logger.Error("Got {0} exception trying to clone {1}: {2}", e.GetType(),
                             project.ProjectCode, e.Message);
                throw;
            }
        }
예제 #5
0
        protected override void DoRun(ILfProject project)
        {
            using (MainClass.Container.BeginLifetimeScope())
            {
                var transferAction = GetAction(ActionNames.TransferMongoToLcm);
                transferAction.Run(project);

                int entriesAdded = 0, entriesModified = 0, entriesDeleted = 0;
                // Need to (safely) cast to TransferMongoToLcmAction to get the entry counts
                var transferMongoToLcmAction = transferAction as TransferMongoToLcmAction;
                if (transferMongoToLcmAction != null)
                {
                    entriesAdded    = transferMongoToLcmAction.EntryCounts.Added;
                    entriesModified = transferMongoToLcmAction.EntryCounts.Modified;
                    entriesDeleted  = transferMongoToLcmAction.EntryCounts.Deleted;
                }

                Logger.Debug("About to dispose FW project {0}", project.ProjectCode);
                LanguageForgeProject.DisposeFwProject(project);
                Logger.Debug("Successfully disposed FW project {0}", project.ProjectCode);

                Logger.Notice("Syncing");
                string commitMessage = LfMergeBridgeServices.FormatCommitMessageForLfMerge(entriesAdded, entriesModified, entriesDeleted);
                if (commitMessage == null)                         // Shouldn't happen, but be careful anyway
                {
                    commitMessage = "Language Forge Send/Receive"; // Desperate fallback
                }
                var chorusHelper = MainClass.Container.Resolve <ChorusHelper>();

                // Call into LF Bridge to do the work.
                string syncResult;
                var    options = new Dictionary <string, string>
                {
                    { "fullPathToProject", project.ProjectDir },
                    { "fwdataFilename", project.FwDataPath },
                    { "fdoDataModelVersion", LcmCache.ModelVersion.ToString() },
                    { "languageDepotRepoName", "Language Depot" },
                    { "languageDepotRepoUri", chorusHelper.GetSyncUri(project) },
                    { "commitMessage", commitMessage }
                };

                try {
                    if (!LfMergeBridge.LfMergeBridge.Execute("Language_Forge_Send_Receive", Progress,
                                                             options, out syncResult))
                    {
                        Logger.Error(syncResult);
                        return;
                    }
                } catch (System.FormatException e) {
                    if (e.StackTrace.Contains("System.Int32.Parse"))
                    {
                        ChorusHelper.SetModelVersion(MagicStrings.MinimalModelVersionForNewBranchFormat);
                        return;
                    }
                    else
                    {
                        throw;
                    }
                }

                const string cannotCommitCurrentBranch = "Cannot commit to current branch '";
                var          line = LfMergeBridgeServices.GetLineContaining(syncResult, cannotCommitCurrentBranch);
                if (!string.IsNullOrEmpty(line))
                {
                    var index = line.IndexOf(cannotCommitCurrentBranch, StringComparison.Ordinal);
                    Require.That(index >= 0);

                    var modelVersion = int.Parse(line.Substring(index + cannotCommitCurrentBranch.Length, 7));
                    if (modelVersion > MagicStrings.MaximalModelVersion)
                    {
                        // Chorus changed model versions to 75#####.xxxxxxx where xxxxxxx is the old-style model version
                        modelVersion = int.Parse(line.Substring(index + cannotCommitCurrentBranch.Length + 8, 7));
                    }
                    if (modelVersion < MagicStrings.MinimalModelVersion)
                    {
                        SyncResultedInError(project, syncResult, cannotCommitCurrentBranch,
                                            ProcessingState.SendReceiveStates.HOLD);
                        Logger.Error("Error during sync of '{0}': " +
                                     "clone model version '{1}' less than minimal supported model version '{2}'.",
                                     project.ProjectCode, modelVersion, MagicStrings.MinimalModelVersion);
                        return;
                    }
                    ChorusHelper.SetModelVersion(modelVersion);
                    return;
                }

                const string pulledHigherModel = "pulled a higher model '";
                line = LfMergeBridgeServices.GetLineContaining(syncResult, pulledHigherModel);
                if (!string.IsNullOrEmpty(line))
                {
                    var index = line.IndexOf(pulledHigherModel, StringComparison.Ordinal);
                    Require.That(index >= 0);

                    var modelVersion = int.Parse(line.Substring(index + pulledHigherModel.Length, 7));
                    ChorusHelper.SetModelVersion(modelVersion);

                    // The .hg branch has a higher model version than the .fwdata file. We allow
                    // data migrations and try again.
                    Logger.Notice("Allow data migration for project '{0}' to migrate to model version '{1}'",
                                  project.ProjectCode, modelVersion);
                    FwProject.AllowDataMigration = true;

                    return;
                }

                if (SyncResultedInError(project, syncResult,
                                        "Cannot create a repository at this point in LF development.",
                                        ProcessingState.SendReceiveStates.HOLD) ||
                    // REVIEW: should we set the state to HOLD if we don't have previous commits?
                    SyncResultedInError(project, syncResult, "Cannot do first commit.",
                                        ProcessingState.SendReceiveStates.HOLD) ||
                    SyncResultedInError(project, syncResult, "Sync failure:"))
                {
                    return;
                }

                line = LfMergeBridgeServices.GetLineContaining(syncResult, "No changes from others");
                if (!string.IsNullOrEmpty(line))
                {
                    Logger.Notice(line);
                    // We still need to transfer back to Mongo to delete any entries marked for deletion
                }
                else
                {
                    // LfMergeBridge has code to detect when we got changes from others. However,
                    // that code never executes because it does a pull before calling synchronizer.SyncNow()
                    // so that syncResults.DidGetChangesFromOthers never gets set. It doesn't
                    // matter to us because we always do a transfer to mongodb.
                    line = LfMergeBridgeServices.GetLineContaining(syncResult, "Received changes from others");
                    if (string.IsNullOrEmpty(line))
                    {
                        // Hmm. Bad news. Must have been some kind of problem down there.
                        Logger.Error("Unhandled sync failure. Result we got was: {0}", syncResult);
                        return;
                    }
                    Logger.Notice(line);
                }

                IAction transferLcmToMongoAction = GetAction(ActionNames.TransferLcmToMongo);
                if (transferLcmToMongoAction == null)
                {
                    Logger.Error("Failed to run TransferLcmToMongo action: GetAction returned null");
                    return;
                }
                transferLcmToMongoAction.Run(project);
            }
        }