示例#1
0
        public void Push(ref Context context, string src, string dest)
        {
            bool srcEndsWithSeparator = OSPath.IsPathSeparator(src.Last());

            // src is a local file system path, thus, use the Path and the OSPath classes
            src = Path.GetFullPath(OSPath.Clean(src));

            FileAttributes fa = File.GetAttributes(src);
            Queue <Tuple <string, string> > queue = new Queue <Tuple <string, string> >();

            if ((fa & FileAttributes.Directory) == FileAttributes.Directory)
            {
                // src is a folder, let's define the desired behaviour, following
                // the design of rsync:
                //
                // cync push c:/home/user/documents/ /user/documents
                //    Content of c:/home/user/documents goes into /user/documents
                //
                // cync push c:/home/user/documents /user/documents
                //    Content of c:/home/user/documents goes into /user/documents/documents
                //
                // Notice the difference caused by the presence/lack of the final
                // directory separator (slash in the above example) in the source
                // (documents/ vs just documents).

                if (srcEndsWithSeparator)
                {
                    string fullDestPath = dest;
                    queue.Enqueue(Tuple.Create(src, fullDestPath));
                    context.InfoWriteLine($"Queueing directory '{src}' [target: '{fullDestPath}']");
                }
                else
                {
                    string fullDestPath = LexicalPath.Combine(dest, Path.GetFileName(src));
                    queue.Enqueue(Tuple.Create(src, fullDestPath));
                    context.InfoWriteLine($"Queueing directory '{src}' [target: '{fullDestPath}']");
                }

                // Compute total size
                var sizeQueue = new Queue <string>(queue.Select(t => t.Item1).ToList());
                var totalSize = 0L;
                while (sizeQueue.Count > 0)
                {
                    var path = sizeQueue.Dequeue();
                    foreach (var ee in Directory.EnumerateFileSystemEntries(path))
                    {
                        FileInfo fi = new FileInfo(ee);
                        if ((fi.Attributes & FileAttributes.Directory) == FileAttributes.Directory)
                        {
                            sizeQueue.Enqueue(ee);
                        }
                        else
                        {
                            totalSize += fi.Length;
                        }
                    }
                }

                var progress       = new ProgressBar(totalSize, flush: true);
                var processedBytes = 0L;

                // Process the queue
                while (queue.Count > 0)
                {
                    var tt = queue.Dequeue();

                    // Process all directory entries. Files are added to the repo directly,
                    // sub directories are queued for further processing.
                    var entries = Directory.EnumerateFileSystemEntries(tt.Item1);

                    // Create the path if it doesn't exist
                    Dir curDestDir = Dir.Open(ref context, LexicalPath.GetDirectoryName(tt.Item2), true);
                    if (tt.Item2.Length > 0 && tt.Item2 != "/")
                    {
                        string destPath = LexicalPath.GetFileName(tt.Item2);
                        if (!curDestDir.HasEntry(destPath))
                        {
                            curDestDir.AddDir(destPath, tt.Item1);
                        }
                        curDestDir.ChangeDirDown(destPath);
                    }

                    foreach (var ee in entries)
                    {
                        FileInfo fi = new FileInfo(ee);
                        if ((fi.Attributes & FileAttributes.Directory) == FileAttributes.Directory)
                        {
                            // Enque the directory for later processing
                            var destFullPath = LexicalPath.Combine(tt.Item2, Path.GetFileName(ee));
                            queue.Enqueue(Tuple.Create(ee, destFullPath));
                            context.InfoWriteLine($"Queueing directory '{ee}' [target: '{destFullPath}']");
                        }
                        else
                        {
                            if (!context.Verbose)
                            {
                                progress.Text = $"Processing '{ee}'";
                                progress.Update(processedBytes);
                            }

                            // A file - copy it
                            var added = curDestDir.PushFile(ee, Path.GetFileName(ee), false);
                            if (added)
                            {
                                context.InfoWriteLine($"Added '{ee}' as '{LexicalPath.Combine(tt.Item2, Path.GetFileName(ee))}'");
                            }
                            else
                            {
                                context.InfoWriteLine($"Skipped '{ee}'. The repository file '{LexicalPath.Combine(tt.Item2, Path.GetFileName(ee))}' is newer or the same.");
                            }

                            processedBytes += fi.Length;
                        }
                    }
                }

                if (!context.Verbose)
                {
                    progress.Text = "";
                    progress.Update(processedBytes);
                }
            }
        }