コード例 #1
0
ファイル: FileSystemTree.cs プロジェクト: ivannp/cync
        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
                //
                // cync push c:/home/user/documents /user/documents
                //    Content of c:/home/user/documents goes into c:/home/user/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).

                // We need to figure out whether the destionation exists, and if so, what
                // is the destionation's type [file vs folder].

                dest = LexicalPath.Clean(dest);

                var item = context.Storage.GetItemInfo(dest);

                if (item != null)
                {
                    // The destination exists
                    if (!item.IsDir)
                    {
                        throw new PathException("The directory '" + src + "' cannot be copied - a file with the same name exists.");
                    }

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

                // 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
                    if (tt.Item2.Length > 0 && tt.Item2 != "/")
                    {
                        context.Storage.CreateDirectory(tt.Item2);
                    }

                    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));
                            _logger.Debug($"Queueing directory {ee} [target: '{destFullPath}']");
                        }
                        else
                        {
                            // A file - check size and timestamp
                            var fullDestPath = LexicalPath.Combine(tt.Item2, Path.GetFileName(ee));
                            var destItem     = context.Storage.GetItemInfo(fullDestPath);
                            var upload       = destItem == null || destItem.Size == null || fi.Length != destItem.Size || destItem.LastWriteTime == null || DateTime.Compare(destItem.LastWriteTime.Value, fi.LastWriteTime) < 0;
                            if (upload)
                            {
                                _logger.Debug($"Adding '{ee}' as '{fullDestPath}'");
                                context.Storage.Upload(ee, fullDestPath, finalizeLocal: false);
                                _logger.Debug($"Added '{ee}' as '{fullDestPath}'");
                            }
                            else
                            {
                                _logger.Debug($"Skipped '{ee}'. The repository file '{fullDestPath}' is newer or the same.");
                            }
                        }
                    }
                }
            }
        }
コード例 #2
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);
                }
            }
        }