Beispiel #1
0
        private Task<bool> RunSyncItem(Manifest.SyncItem f,
            bool verify, bool simulate,
            DownloadProgressChanged dpc, DownloadEnd de, DownloadMessage dm,
            CancellationTokenSource cts,
            string overrideDestination = null)
        {
            switch (f.type)
            {
                case "rsync":
                    RSyncDownloader dd = new RSyncDownloader(this);
                    dd.appPath = AppPath;
                    dd.tmpPath = TmpPath;
                    dd.VerifyChecksums = verify;
                    dd.Simulate = simulate;
                    return dd.Download(LatestManifest.rsyncUrl + "/" + f.name, f, RootPath,
                        dpc, de, dm, cts, overrideDestination);

                case "delete":
                    return Task<bool>.Run(() =>
                    {
                        if (f.name.EndsWith("/") && Directory.Exists(RootPath + "/" + f.name)) {
                            dm.Invoke("Deleting directory " + f.name);
                            Directory.Delete(RootPath + "/" + f.name, true);
                        } else if (File.Exists(RootPath + "/" + f.name)) {
                            dm.Invoke("Deleting file " + f.name);
                            File.Delete(RootPath + "/" + f.name);
                        }
                        return true;
                    });

                default:
                    return null;
            }
        }
Beispiel #2
0
        // Returns true if the file was changed in any way.
        public Task<bool> Download(string source, Manifest.SyncItem syncItem, string modPath,
            Catflap.Repository.DownloadProgressChanged dpc,
            Catflap.Repository.DownloadEnd de,
            Catflap.Repository.DownloadMessage dm,
            Catflap.Repository.DownloadVerifyChecksum dvc,
            CancellationTokenSource cts,
            string overrideDestination = null)
        {
            var ct = cts.Token;

            stdErr = "";

            return Task.Run<bool>(delegate() {
                currentRunWasChanged = false;
                var p = RunRSync(source, syncItem, modPath, dpc, dm, dvc, cts, overrideDestination);
                (Application.Current as App).TrackProcess(p);

                // Wait for the pid to appear.
                while (0 == p.Id && !p.HasExited);

                while (!p.HasExited)
                {
                    if (ct.IsCancellationRequested)
                    {
                        cancelled = true;
                        dm.Invoke("<cancelling (patience)>", true);

                        /* Try Ctrl+C first so we can catch --replace/partial transfers */
                        SIGTERM(p.Id);

                        /* Lets wait for a generous amount of time to wait for rsync to gracefully
                         * terminate. This can happen on slow disks.
                         */
                        p.WaitForExit(30000);

                        App.KillProcessAndChildren(p.Id);
                        p.WaitForExit();
                        ct.ThrowIfCancellationRequested();
                    }
                    else
                        Thread.Sleep(100);
                }
                p.WaitForExit();
                de.Invoke(p.ExitCode != 0, stdErr, bytesOnNetwork);

                return currentRunWasChanged;
            }, ct);
        }
Beispiel #3
0
        private Process RunRSync(String rsyncUrl, Manifest.SyncItem syncItem, string modPath,
            Catflap.Repository.DownloadProgressChanged dpc,
            Catflap.Repository.DownloadMessage dm,
            Catflap.Repository.DownloadVerifyChecksum dvc,
            CancellationTokenSource cts,
            string overrideDestination = null)
        {
            var targetFileName = syncItem.name;

            string targetDir = modPath + "\\" + Path.GetDirectoryName(targetFileName);
            Directory.CreateDirectory(targetDir);

            string rsyncTargetSpec =  overrideDestination != null ? overrideDestination :".";
            bool isDir = targetFileName.EndsWith("/");

            if (this.repository.Username != null)
                rsyncUrl = rsyncUrl.Replace("%user%", this.repository.Username);

            string va = rsyncFlags + " " + "\"" + rsyncUrl + "\"" + " " + "\"" + rsyncTargetSpec.ShellEscape() + "\"";

            if (VerifyChecksums) va += " " + rsyncFlagsVerify;
            if (!VerifyChecksums) va += " " + rsyncFlagsNoVerify;
            if (Simulate) va += " --dry-run";

            if (isDir) va += " " + rsyncFlagsDirectory;

            if (syncItem.ignoreExisting.GetValueOrDefault()) va += " --ignore-existing";

            // Only ever allow purge on directories, obviously.
            if (isDir && syncItem.purge.GetValueOrDefault()) va += " --delete-delay";

            if (syncItem.ignoreCase.GetValueOrDefault()) va += " --ignore-case";
            if (syncItem.fuzzy.GetValueOrDefault()) va += " --fuzzy";

            va += " \"--temp-dir=" + tmpPath.ShellEscape() + "\"";

            switch (syncItem.mode)
            {
                case "inplace":
                    va += " --inplace";
                    break;

                default: // "replace"
                    /* We cannot keep partials for ignore-existing .. */
                    if (!syncItem.ignoreExisting.GetValueOrDefault())
                        va += " --partial-dir=catflap.partials";

                    va += " --delay-updates";
                    break;
            }

            long thisFileTotalSize = 0;
            string thisFilename = targetFileName;

            dm.Invoke("(rsync) " + va);

            Process pProcess = new System.Diagnostics.Process();
            pProcess.StartInfo.FileName = appPath + "\\bin\\rsync.exe";
            pProcess.StartInfo.Arguments = va;
            pProcess.StartInfo.CreateNoWindow = true;
            pProcess.StartInfo.UseShellExecute = false;
            pProcess.StartInfo.RedirectStandardOutput = true;
            pProcess.StartInfo.RedirectStandardError = true;
            pProcess.StartInfo.RedirectStandardInput = true;
            pProcess.StartInfo.WorkingDirectory = targetDir;

            if (pProcess.StartInfo.EnvironmentVariables.ContainsKey("PATH"))
                pProcess.StartInfo.EnvironmentVariables.Remove("PATH");

            if (pProcess.StartInfo.EnvironmentVariables.ContainsKey("CYGWIN"))
                pProcess.StartInfo.EnvironmentVariables.Remove("CYGWIN");

            pProcess.StartInfo.EnvironmentVariables.Add("CYGWIN", "nodosfilewarning");

            if (this.repository.Password != null)
                pProcess.StartInfo.EnvironmentVariables.Add("RSYNC_PASSWORD", this.repository.Password);

            Console.WriteLine("VA = " + va);

            pProcess.OutputDataReceived += (s, ee) =>
            {
                if (ee.Data != null)
                {
                    /* Send everything to the log as-is. */
                    dm.Invoke("(stdout) " + ee.Data);

                    switch (ee.Data)
                    {
                        case "receiving file list ... ":
                        case "receiving incremental file list":
                            dm.Invoke("<receiving list>", true);
                            break;

                        default:
                            Match mr;

                            // Progress indicator
                            if ((mr = rxRsyncProgress.Match(ee.Data)).Success)
                            {
                                long bytesDone = long.Parse(mr.Groups[1].Value, CultureInfo.InvariantCulture);
                                int percentage = int.Parse(mr.Groups[2].Value, CultureInfo.InvariantCulture);
                                double rate = double.Parse(mr.Groups[3].Value, CultureInfo.InvariantCulture);
                                string rateDesc = mr.Groups[4].Value;
                                string eta = mr.Groups[5].Value;
                                string details = mr.Groups[6].Value;
                                if (details == null)
                                    details = "";
                                details = details.Trim();

                                if (rateDesc == "kB/s")
                                    rate *= 1024;
                                if (rateDesc == "MB/s")
                                    rate *= 1024 * 1024;

                                dpc.Invoke(cancelled ? "<cancelling>" : thisFilename, percentage, bytesDone, thisFileTotalSize, (int)rate, details);
                            }
                            else if ((mr = rxRsyncNewTransfer.Match(ee.Data)).Success)
                            {
                                string fname = mr.Groups[1].Value;
                                if (isDir)
                                    if (fname == "." || fname == "./")
                                        fname = targetFileName;
                                    else if (isDir)
                                        fname = targetFileName + fname;
                                    else
                                        fname = targetFileName;

                                thisFilename = fname;
                                // dm.Invoke(fname, true);
                            }

                            // transfer complete / hash
                            else if ((mr = rxRsyncNewFile.Match(ee.Data)).Success)
                            {
                                string flags = mr.Groups[1].Value;
                                thisFileTotalSize = long.Parse(mr.Groups[2].Value, CultureInfo.InvariantCulture);
                                //string fname = mr.Groups[3].Value;

                                // YXcstpogz
                                // X: update type (< > c .)
                                // Y: filetype (f d L D S)
                                // c: checksum, s: size, t: time,
                                var action = "";
                                switch (flags[0])
                                {
                                    case '*': action = "[deleting] "; break;
                                    case '<': action = "[sending] "; break;
                                    case '>': action = ""; break;
                                    case 'c': action = "[creating] "; break;
                                }

                                dm.Invoke(action + thisFilename, true);

                                if (!dvc.Invoke(thisFilename, mr.Groups[4].Value.ToLowerInvariant()))
                                {
                                    cts.Cancel();
                                }
                            }

                            // Literal data: xx
                            else if ((mr = rxRsyncLiteralData.Match(ee.Data)).Success)
                            {
                                if (mr.Groups[1].Value != "0")
                                    currentRunWasChanged = true;
                            }

                            // Total bytes received
                            else if ((mr = rxRsyncTotalBytesReceived.Match(ee.Data)).Success)
                            {
                                if (mr.Groups[1].Value != "0")
                                    bytesOnNetwork += long.Parse(mr.Groups[1].Value, CultureInfo.InvariantCulture);
                            }

                            // Total bytes sent
                            else if ((mr = rxRsyncTotalBytesSent.Match(ee.Data)).Success)
                            {
                                if (mr.Groups[1].Value != "0")
                                    bytesOnNetwork += long.Parse(mr.Groups[1].Value, CultureInfo.InvariantCulture);
                            }

                            break;

                    }
                }
            };
            pProcess.ErrorDataReceived += (s, ee) =>
            {
                if (ee.Data != null)
                {
                    stdErr += ee.Data + "\n";
                    dm.Invoke("ERROR: " + ee.Data);
                }
            };

            dm.Invoke("Verifying " + syncItem.name + " (checksumming/waiting for server)", true);

            pProcess.Start();
            pProcess.BeginOutputReadLine();
            pProcess.BeginErrorReadLine();

            // This eats "Password:"******"\n");

            return pProcess;
        }
Beispiel #4
0
 private async Task RunAction(Manifest.ManifestAction action)
 {
     Accent old = SetTheme(accentBusy);
     RefreshProgress(UIState.Busy);
     SetUIState(false);
     try
     {
         await action.Run(repository,
             action.passArguments ? App.mArgs : new string[] { });
     }
     catch (Exception ex)
     {
         MessageBox.Show(Text.t("run_error", ex.Message));
     }
     finally
     {
         SetUIState(true);
         SetTheme(old);
         RefreshProgress(UIState.OK);
     }
 }