コード例 #1
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,
                                    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, 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("<cancelando (paciência!)>", 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(20000);

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

                return currentRunWasChanged;
            }, ct));
        }
コード例 #2
0
        private Process RunRSync(String rsyncUrl, Manifest.SyncItem syncItem, string modPath,
                                 Catflap.Repository.DownloadProgressChanged dpc, Catflap.Repository.DownloadMessage dm, 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 + "\\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;
                            if (rateDesc == "kB/s")
                            {
                                rate *= 1024;
                            }
                            if (rateDesc == "MB/s")
                            {
                                rate *= 1024 * 1024;
                            }

                            dpc.Invoke(cancelled ? "<cancelando>" : thisFilename, percentage, bytesDone, thisFileTotalSize, (int)rate);
                        }

                        // new file
                        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;
                            //if (isDir)
                            if (fname == "." || fname == "./")
                            {
                                fname = targetFileName;
                            }
                            else if (isDir)
                            {
                                fname = targetFileName + fname;
                            }
                            else
                            {
                                fname = targetFileName;
                            }

                            // 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;
                            }

                            /*var typeStr = "";
                             * switch (flags[1])
                             * {
                             *  case 'f': typeStr = "file"; break;
                             *  case 'd': typeStr = "directory"; break;
                             * }*/

                            thisFilename = action + " " + fname;
                            var flagStr = flags.Substring(2).Replace(".", "").Replace("+", "").Trim();
                            if (flagStr != "")
                            {
                                thisFilename += " [" + flagStr + "]";
                            }

                            dm.Invoke(thisFilename, true);
                        }


                        // 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";
                    Console.WriteLine("STDERR: " + ee.Data);
                    dm.Invoke("ERRO: " + ee.Data);
                }
            };

            dm.Invoke("Verificando " + syncItem.name + " (checksumming/esperando o server)", true);

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

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

            return(pProcess);
        }