예제 #1
0
        private bool AutoUpdateProject(Project p, bool notify = true)
        {
            LockProject(p.id);

              string dir = GetProjectDirectory(p);
              bool possibleCommit = false, rebaseStarted = false, success = false;
              ProcessReturn ret;

              try {
            if (!Directory.Exists(dir)) {
              if (!InitializeProject(p)) {
            return false;
              }
              return true;
            }

            if (GitWrapper.RebaseInProgress(dir)) {
              GitWrapper.Rebase(dir, "--abort");
            }

            ret = GitWrapper.Fetch(dir);
            if (ret.ReturnValue != 0) {
              if (ret.Output.Contains("Not a git")) {
            MessageBoxResult res = MessageBox.Show("Project " + p.name + " seems to be corrupted. Do you want SciGit to repair it?\r\n" +
              "You may want to back up your files first.", "Project corrupted", MessageBoxButton.YesNo);
            if (res == MessageBoxResult.Yes) {
              string gitDir = Path.Combine(dir, ".git");
              if (Directory.Exists(gitDir)) {
                Directory.Delete(gitDir, true);
              }
              if (!InitializeProject(p)) {
                return false;
              }
              ret = GitWrapper.Fetch(dir);
            } else {
              DisableAutoUpdates(p);
            }
              }
              if (ret.ReturnValue != 0) {
            return false;
              }
            }

            while (true) {
              // Reset commits until we get to something in common with FETCH_HEAD.
              ret = CheckReturn("merge-base", GitWrapper.MergeBase(dir, "HEAD", "FETCH_HEAD"));
              string baseCommit = ret.Stdout.Trim();
              GitWrapper.Reset(dir, baseCommit);

              // Make a temporary commit to facilitate merging.
              GitWrapper.AddAll(dir);
              ret = GitWrapper.Commit(dir, "tempCommit " + DateTime.Now);
              possibleCommit = true;

              ret = GitWrapper.Rebase(dir, "FETCH_HEAD");
              if (ret.Output.Contains("Permission denied")) {
            // One of the files is open.
            // If the return value isn't 0, there was a merge conflict on top of this (so abort the rebase)
            if (ret.ReturnValue == 0) {
              GitWrapper.Reset(dir, baseCommit);
            } else {
              rebaseStarted = true;
            }
            var match = Regex.Match(ret.Output, "error: unable to unlink old '(.*)' \\(Permission denied\\)");
            string file = "";
            if (match.Success) {
              file = " (" + match.Groups[1].Value + ")";
            }
            var resp = Util.ShowMessageBox("Project " + p.name + " cannot be updated, as one of the project files is currently open" + file + ".\n"
              + "Please save and close your changes before continuing.", "File Locked", MessageBoxButtons.RetryCancel);
            if (resp == DialogResult.Cancel) {
              DisableAutoUpdates(p);
              return false;
            }
            if (rebaseStarted) GitWrapper.Rebase(dir, "--abort");
              } else {
            break;
              }
            }

            if (ret.ReturnValue != 0) {
              rebaseStarted = true;
              if (ret.Output.Contains("CONFLICT")) {
            var resp = Util.ShowMessageBox("Merge conflict(s) were detected in project " + p.name + ". Would you like to resolve them now using the SciGit editor?\r\n" +
              "Please save any changes to open files before continuing.", "Auto-update: merge conflict", MessageBoxButtons.OKCancel);
            MergeResolver mr = null;
            Exception exception = null;
            if (resp == DialogResult.OK) {
              parent.Invoke(new Action(() => {
                try {
                  mr = new MergeResolver(p);
                  mr.ShowDialog();
                } catch (Exception e) {
                  if (mr != null) mr.Hide();
                  exception = e;
                }
              }));
            }
            if (exception != null) throw new Exception("", exception);

            if (mr == null || !mr.Saved) {
              DisableAutoUpdates(p);
              return false;
            } else {
              GitWrapper.AddAll(dir);
              ret = GitWrapper.Rebase(dir, "--continue");
              if (ret.ReturnValue != 0) {
                if (ret.Output.Contains("No changes")) {
                  // The temp commit was effectively ignored. Just skip it.
                  CheckReturn("rebase", GitWrapper.Rebase(dir, "--skip"));
                } else {
                  throw new Exception("rebase: " + ret.Output);
                }
              }
              success = true;
              rebaseStarted = false;
            }
              } else {
            throw new Exception("rebase: " + ret.Output);
              }
            } else {
              success = true;
              if (!ret.Output.Contains("up to date") && notify) {
            DispatchCallbacks(projectAutoUpdatedCallbacks, p);
              }
            }
              } catch (Exception e) {
            return false;
              } finally {
            if (rebaseStarted) GitWrapper.Rebase(dir, "--abort");
            if (possibleCommit) {
              // Reset commits until we get to something in common with FETCH_HEAD.
              ret = CheckReturn("merge-base", GitWrapper.MergeBase(dir, "HEAD", "FETCH_HEAD"));
              CheckReturn("reset", GitWrapper.Reset(dir, ret.Stdout.Trim()));
            }
            if (success) {
              lock (updatedProjects) {
            updatedProjects.RemoveAll(pr => pr.id == p.id);
              }
            }
            UnlockProject(p.id);
              }

              return success;
        }
예제 #2
0
        public bool UpdateProject(Project p, Window window, BackgroundWorker worker, bool progress = true)
        {
            LockProject(p.id);

              string dir = GetProjectDirectory(p);
              bool possibleCommit = false, rebaseStarted = false, success = false;
              ProcessReturn ret;

              try {
            if (worker.CancellationPending) return false;

            if (!Directory.Exists(dir)) {
              worker.ReportProgress(progress ? 25 : -1, "Repairing project...");
              MessageBoxResult result = MessageBox.Show("Project " + p.name + " does not exist. Would you like to re-create it?",
                                                    "Project does not exist", MessageBoxButton.YesNo);
              if (result == MessageBoxResult.Yes) {
            if (!InitializeProject(p)) {
              ShowError(window, "Could not obtain project from the SciGit servers. Please try again later.");
            } else {
              worker.ReportProgress(progress ? 100 : -1, "Repair and update successful.");
              return true;
            }
              }
              return false;
            }

            if (GitWrapper.RebaseInProgress(dir)) {
              GitWrapper.Rebase(dir, "--abort");
            }
            if (worker.CancellationPending) return false;

            worker.ReportProgress(progress ? 25 : -1, "Checking for updates...");
            ret = GitWrapper.Fetch(dir);
            worker.ReportProgress(-1, ret.Output);
            if (ret.ReturnValue != 0) {
              if (ret.Output.Contains("Not a git")) {
            MessageBoxResult res = MessageBox.Show("Project " + p.name + " seems to be corrupted. Do you want SciGit to repair it?\r\n" +
              "You may want to back up your files first.", "Project corrupted", MessageBoxButton.YesNo);
            if (res == MessageBoxResult.Yes) {
              string gitDir = Path.Combine(dir, ".git");
              if (Directory.Exists(gitDir)) {
                Directory.Delete(gitDir, true);
              }
              worker.ReportProgress(progress ? 30 : -1, "Repairing project...");
              if (!InitializeProject(p)) {
                ShowError(window, "Could not obtain project from the SciGit servers. Please try again later.");
                return false;
              }
              worker.ReportProgress(progress ? 35 : -1, "Checking for updates...");
              ret = GitWrapper.Fetch(dir);
              worker.ReportProgress(-1, ret.Output);
            } else {
              return false;
            }
              }
              if (ret.ReturnValue != 0) {
            ShowError(window, "Could not connect to the SciGit servers. Please try again later.");
            return false;
              }
            }

            while (true) {
              if (worker.CancellationPending) return false;

              // Reset commits until we get to something in common with FETCH_HEAD.
              ret = CheckReturn("merge-base", GitWrapper.MergeBase(dir, "HEAD", "FETCH_HEAD"), worker);
              string baseCommit = ret.Stdout.Trim();
              GitWrapper.Reset(dir, baseCommit);

              if (worker.CancellationPending) return false;

              // Make a temporary commit to facilitate merging.
              GitWrapper.AddAll(dir);
              worker.ReportProgress(-1, "Creating temporary commit...");
              ret = GitWrapper.Commit(dir, "tempCommit " + DateTime.Now);
              possibleCommit = true;
              worker.ReportProgress(-1, ret.Output);

              if (worker.CancellationPending) return false;

              worker.ReportProgress(progress ? 50 : -1, "Merging...");
              ret = GitWrapper.Rebase(dir, "FETCH_HEAD");
              worker.ReportProgress(-1, ret.Output);
              if (ret.Output.Contains("Permission denied")) {
            // One of the files is open.
            // If the return value isn't 0, there was a merge conflict on top of this (so abort the rebase)
            if (ret.ReturnValue == 0) {
              GitWrapper.Reset(dir, baseCommit);
            } else {
              rebaseStarted = true;
            }
            var match = Regex.Match(ret.Output, "error: unable to unlink old '(.*)' \\(Permission denied\\)");
            string file = "";
            if (match.Success) {
              file = "(" + match.Groups[1].Value + ") ";
            }
            var resp = MessageBox.Show("One of the project files is currently open " + file + "and cannot be edited. "
              + "Please save and close your changes before continuing.", "File Locked", MessageBoxButton.OKCancel);
            if (resp == MessageBoxResult.Cancel) {
              return false;
            }
            if (rebaseStarted) GitWrapper.Rebase(dir, "--abort");
              } else {
            break;
              }
            }

            if (ret.ReturnValue != 0) {
              rebaseStarted = true;
              if (worker.CancellationPending) return false;
              if (ret.Output.Contains("CONFLICT")) {
            MessageBoxResult resp = MessageBoxResult.Cancel;
            window.Dispatcher.Invoke(
              new Action(() => resp = MessageBox.Show(window, "Merge conflict(s) were detected. Would you like to resolve them now using the SciGit editor?\r\n" +
              "Please save any changes to open files before continuing.", "Merge Conflict", MessageBoxButton.OKCancel)));
            MergeResolver mr = null;
            Exception exception = null;
            if (resp == MessageBoxResult.OK) {
              window.Dispatcher.Invoke(new Action(() => {
                try {
                  mr = new MergeResolver(p);
                  mr.ShowDialog();
                } catch (Exception e) {
                  if (mr != null) mr.Hide();
                  exception = e;
                }
              }));
            }
            if (exception != null) throw new Exception("", exception);

            if (resp != MessageBoxResult.No && (mr == null || !mr.Saved)) {
              // Cancel the process here.
              return false;
            } else {
              GitWrapper.AddAll(dir);
              worker.ReportProgress(progress ? 75 : -1, "Continuing merge...");
              ret = GitWrapper.Rebase(dir, "--continue");
              worker.ReportProgress(-1, ret.Output);
              if (ret.ReturnValue != 0) {
                if (ret.Output.Contains("No changes")) {
                  // The temp commit was effectively ignored. Just skip it.
                  CheckReturn("rebase", GitWrapper.Rebase(dir, "--skip"), worker);
                } else {
                  throw new Exception("rebase: " + ret.Output);
                }
              }
              worker.ReportProgress(progress ? 100 : -1, "Merge successful.");
              success = true;
              rebaseStarted = false;
            }
              } else {
            throw new Exception("rebase: " + ret.Output);
              }
            } else {
              worker.ReportProgress(progress ? 100 : -1, ret.Output.Contains("up to date") ? "No changes." : "Changes merged without conflict.");
              success = true;
              if (progress && !ret.Output.Contains("up to date")) {
            var result = MessageBox.Show("Project " + p.name + " was successfully updated. Would you like to view the changes?",
                "Project updated", MessageBoxButton.YesNo);
            if (result == MessageBoxResult.Yes) {
              window.Dispatcher.Invoke(new Action(() => {
                var ph = new ProjectHistory(p, "HEAD");
                ph.Show();
              }));
            }
              }
            }
              } catch (Exception e) {
            throw new Exception("", e);
              } finally {
            if (rebaseStarted) GitWrapper.Rebase(dir, "--abort");
            if (possibleCommit) {
              // Reset commits until we get to something in common with FETCH_HEAD.
              ret = CheckReturn("merge-base", GitWrapper.MergeBase(dir, "HEAD", "FETCH_HEAD"), worker);
              CheckReturn("reset", GitWrapper.Reset(dir, ret.Stdout.Trim()), worker);
            }
            if (success) {
              lock (noAutoUpdateProjects) {
            noAutoUpdateProjects.Remove(p.id);
              }
              lock (updatedProjects) {
            updatedProjects.RemoveAll(pr => pr.id == p.id);
              }
            }
            UnlockProject(p.id);
              }

              return success;
        }