public void SyncWithMaster(string masterDir, SyncOptions options, CancellationTokenSource cts) { var master = new Repository(masterDir, cts); if (cts.Token.IsCancellationRequested) { return; } var task = Task.Factory .StartNew(_ => PushTo(master, cts), cts) .ContinueWith(_ => PullFrom(master, options ?? SyncOptions.Default(), cts), TaskContinuationOptions.NotOnCanceled) .ContinueWith(_ => cts.Cancel()); task.Wait(); }
static void Main(string[] args) { InitalizeLog4Net(); string localDirPath = @"C:\Outils\FileTest\Local"; string masterDirPath = @"C:\Users\Laurent\Pictures\Photos LIGER\"; var filesEnumerator = new DirectoryInfo(localDirPath).EnumerateFiles("*", SearchOption.AllDirectories); int count = filesEnumerator.Count(); double totalLength = filesEnumerator.Sum(f => f.Length) / 1024.0 / 1024.0; Console.WriteLine("{0} fichiers. Taille totale : {1:0.00} Go, Taille moy. : {2:0.00} mo", count, totalLength / 1024, totalLength / count); CancellationTokenSource cts = new CancellationTokenSource(); var breakTask = Task.Factory.StartNew(() => { BreakExecution(cts); }, cts.Token); Repository syncDir = new Repository(localDirPath, cts); Console.WriteLine(); // on recommence, mais cette fois pour la synchro vers un autre repertoire cts = new CancellationTokenSource(); breakTask = Task.Factory.StartNew(() => { BreakExecution(cts); }, cts.Token); syncDir.SyncWithMaster(masterDirPath, new SyncOptions() { MaxLocalStorage = FileLength.FromGigaBytes(7) }, cts); //var doublons = syncDir.Map.Values // .GroupBy(ci => ci.Sha1String) // .Where(g => g.Count() > 1); //int totalDoublons = 0; //// affichage des doublons : //foreach (var group in doublons) //{ // foreach (var item in group) // { // Console.WriteLine("{0} : {1}", group.Key, item.FileName); // } // totalDoublons += group.Count(); // Console.WriteLine("-------- {0} doublons ---------", group.Count()); //} //Console.WriteLine("-------- {0} doublons au total ---------", totalDoublons); Console.WriteLine("Appuyer sur une touche pour fermer cette fenetre."); Console.Read(); }
private void PushTo(Repository other, CancellationTokenSource cts) { var newFiles = from info in Map.Values where other.Map.ContainsKey(info.FileName) == false select info; var modifiedFiles = from info in Map.Values from otherInfo in other.Map.Values where otherInfo.FileName == info.FileName && otherInfo.Sha1String != info.Sha1String && info.LastWriteTime > otherInfo.LastWriteTime select info; var filesToCopy = newFiles.Union(modifiedFiles); foreach (var f in filesToCopy) { if (cts.Token.IsCancellationRequested) { break; } other.CopyFrom(this, f); } }
private void PullFrom(Repository master, SyncOptions options, CancellationTokenSource cts) { var mapByHash = Map.Values.ToDictionary(ci => ci.Sha1String); var filesToCopy = master.Map.Values .OrderBy(ci => ci.LastWriteTime) .Reverse(); if (options.MaxLocalStorage != null) { long totalSize = 0; filesToCopy = filesToCopy .TakeWhile(ci => { totalSize += ci.Length; return totalSize < options.MaxLocalStorage; }); // purge des fichiers en trop pour le repo local var mapToCopy = filesToCopy.ToDictionary(f => f.FileName); int countDeleted = 0; foreach (var f in this.Map.Values) { if (mapToCopy.ContainsKey(f.FileName) == false) { // suppression du fichier File.Delete(Path.Combine(this.RootPath, f.FileName)); countDeleted++; } } _logger.InfoFormat("{0} fichiers supprimés pour respecter la taille max du repository : {1}", countDeleted, this.RootPath); } foreach (var f in filesToCopy) { if (cts.Token.IsCancellationRequested) { break; } if (!mapByHash.ContainsKey(f.Sha1String)) { this.CopyFrom(master, f); } } }
/// <summary> /// Copie atomique vers ce Repository /// </summary> private void CopyFrom(Repository otherRepo, CustomInfo f) { string srcPath = Path.Combine(otherRepo.RootPath, f.FileName); string destPath = Path.Combine(this.RootPath, f.FileName); File.Copy(srcPath, LocalTempFileName, true); Directory.CreateDirectory(Path.GetDirectoryName(destPath)); File.Move(LocalTempFileName, destPath); // ajout dans le repo local this.Map.GetOrAdd(f.FileName, f); }