[OpenSource] Sync - Tool für Dateisystem-Backups und -Synchronisierungen

    • VB.NET
    • .NET (FX) 4.5–4.8

    Es gibt 8 Antworten in diesem Thema. Der letzte Beitrag () ist von zn-gong.

      [OpenSource] Sync - Tool für Dateisystem-Backups und -Synchronisierungen

      Disclaimer
      Ich übernehme keine Haftung für irgendwelche Schäden, die im Zusammenhang mit diesem Programms entstehen können. Dabei spielt keine Rolle, was die Schäden hervorrief, ob unsachgemäße Verwendung, System-Inkompatiblitäten, Programmierfehler meinerseits, nachträglich vorgenommene Veränderungen, oder was auch immer. Ich garantiere lediglich, willentlich keinen Schad-Code implementiert zu haben.

      Was macht Sync
      Mit Sync kann man Datei-Ordner "spiegeln" - also bewirken, dass ihr Inhalt identisch ist.
      Man kann das auf sehr große Systeme anwenden, etwa um ein Daten-Backup aller User-Daten eines Systems auf eine externe Festplatte zu schubsen. Oder man synchronisiert sämtliche Programmier-Projekte zwischen Desktop und Laptop. Oder zum Rechner umziehen.
      Man auch kleine "Repositories" anlegen, mit nur ein paar Projekten darin, etwa auf einem Usb-Stick.

      Das Back-End: RoboCopy
      Das Back-End dahinter ist übrigens vergleichsweise einfach, es ist das zu Windows gehörende Kommandozeilen-Tool "RoboCopy", und mein Proggi erstellt vor allem ein paar Kommandozeilen, mit denen dieses Tool dann abgefahren wird.
      Also vom Prinzip her ist dieses ein weiteres "YARCGUI" - "Yet Another RoboCopy Graphical User Interface" - mit sehr anderem, auf "Repository" ausgerichteten Oberflächen-Konzept. Das andere YarcGui kann ja beliebige RoboCopy-Ausführungs-Pläne erstellen, und auch sowas ähnliches wie ein Repository (halt ohne mergen).
      Jdfs. bei mir bedeutet "Repository", dass man eine *.syn - Datei in einem Ordner liegen hat, in der die zu synchronisierenden Ordner gespiegelt werden sollen. Dabei kann ein Repository mehrere Clients unterstützen, also man legt fest:
      "Repository-BliBlaBlu wird auf Client1 mit C:\Progs\BliBlaBlu synchronisiert und auf Client2 mit D:\OllerKram\HupfHupf".
      Praktisch aussehen tut sowas so:

      Links das Repository - dort die Pfade sind relativ zum Repository-Folder - daher kürzer und v.a. ohne Laufwerk.
      Mittig der "Current Client" - das ist der aktuelle Rechner, dessen System synchronisiert werden kann. Der andere Client, "Client2" kann nicht bearbeitet werden, denn jenes Dateisystem liegt ja auf einem anneren Rechner.

      Die Sync-Operationen Push, Pull, Merge
      • Push erstellt im Repository den "Spiegel" des eigenen Systems. Alles abweichende wird entfernt, neu hinzugekommenes hinzugefügt, veraltetes überschrieben.
      • Pull ist derselbe Vorgang andersrum, also das Repository erstellt einen Spiegel im Client.
      • Merge ist modifiziertes Pull, als "Reparatur"-Funktion, wenn man was verdaddelt hat.
      Verdaddeln ist nämlich recht einfach: Etwa wenn Client1 pusht, und danach weiterarbeitet, und dann Client2 pullt, und dort auch weiterarbeietet - dann hat man einen Merge-Konflikt, denn unentscheidbar ist, welche Version nun die beste ist, oder ob beide Versionen je eigene Vor- und Nach-teile haben.
      In so einem Fall kann zB Client2 seinen neuesten Stand pushen, und Client1 pullt den nicht, sondern merget.
      Ein Merge ist ein Pull, nur werden dabei keine überflüssigen Dateien/Ordner gelöscht oder überschrieben. Sondern bei Namens-Gleichheit kriegt die Repository-Datei einen ".mergeConflict" - Dateinamens-Zusatz, bevor sie kopiert wird.
      Der User muss dann selbst zusehen, wie er den Konflikt im Einzelnen auflöst. Auf jeden Fall hat er nach einem Merge u.U. erhebliche Mengen neues Material in seinem System - zunächstmal unnützes Zeug, denn sein vorheriges System besteht ja vollkommen unangetastet weiter wie zuvor - das neue ist in keiner Weise in die System-Funktionalität integriert.

      Es ist auch bischen Sicherheit eingebaut, um Merge-Konflikte zu vermeiden. Zwei einfache Regeln:
      1. Es darf nur der Client pushen, der zuvor als letzter gepullt hat.
        Denn nur wer gepullt hat, hat die neueste Version vom Repository geladen.
      2. Andere Clients können nur pullen, wenn vorher gepusht wurde.
        Denn nur wenn sie gepusht wurde, liegt die neueste Version im Repository.
      Unproblematisch ist es für den Client, der mit pushen dran ist, auch öfter jeweils immer neuere Versionen zu pushen.
      Diese Regeln gewährleisten so leidlich, dass die neueste Version nur auf einem Client ist, und auf keinem anderen. Sie können allerdings nicht davor schützen, dass jmd. mit dem einen Client pullt, dann aber auf dem anderen Client weiter-arbeitet (s.o. - Merge-Konflikt)

      Getting Started
      1. ins Projekte-Verzeichnis entpacken, im VisualStudio öffnen und als Release kompilieren. Als Release ist wichtig, denn die Debug-Version lädt nur ein Test-Repository.
      2. die Empty.syn - Datei in einen Ordner zB auf die externe Festplatte kopieren (oder wo immer das Repository einzurichten ist) - und sinnig umbenennen.
      3. die Empty.syn mit Doppelklick öffnen. Da erscheint ein Dialog, über den man das Programm erstmal suchen muss, mit dem *.syn - Dateien in Zukunft zu öffnen sind - hier die Sync.Exe suchen, die man ja grad in 1) sich zurecht-kompiliert hat ;)
      4. Aussm Explorer vom Client die Ordner, die man synchronisieren möchte, auf den linken (noch leeren) Treeview ziehen. Dabei auch im weiteren nicht auf schon vorhandene Nodes droppen, sondern in die leere Fläche unter den Nodes.
        Das generiert sowohl im CurrentClient als auch im Repository einen Treeview, bei dem die kindlosen Knoten (die "Leafs") grün gekennzeichnet sind.
      5. Im Repository-Treeview kann man per KontextMenü Delete (Save Childs) nach Belieben Nicht-Leaf-Nodes entfernen - um die Ordner-Struktur des Repositories zu vereinfachen. Leafs-Nodes kann man übrigens gar nicht entfernen, denn ein Leaf im Repository-Tree bedeutet ja einen Kopier-Auftrag, und ist mit einem Client-Leaf verbunden.
      6. Im Client-Tree hingegen lautet das KontextMenü Delete Branch, und kann nicht nur einzelne Leafs weghauen, sondern entfernt gleich den ganzen Zweig (ggfs. auch mit mehreren Leafs). Denn ein Zweig ohne Blatt (Kopier-Auftrag) ergäbe zur Synchronisierung keinen Sinn.
      7. Jo, dann kann man erstmalig pushen, dass auch was drinne ist im Repository. Der erste Push dauert übrigens besonders lange (vlt. 5min/GByte). Wenn später nur geänderte Dateien kopiert werden gehts zackiger
      8. Nun kann man auch einen 2. Client anschließen ans Repository - also einen anderen Computer. Dazu zieht man von dessen Dateisystem Ordner aufs Repository - nun aber genau auf jeweils ein grün markiertes Leaf. Dadurch wird im Repository kein neuer Ordner generiert, sondern des neuen Clients Ordner verbindet sich mit dem bestehenden Repository-Leaf zu einem Kopier-Auftrag für diesen Client.
      9. Nochmal Bildle gucken: zB. Repository.Client12 (2) ist verbunden mit Client1.Client12 (2) und Client2.Client23 (2). Also auf verschiedenen PCs haben die Ordner durchaus verschiedene Namen - v.a. liegen sie meist wohl in unterschiedlichen Pfaden.

      Points of Interest-codetechnisch

      Bei dem Projekt entstand eine recht umfassende, leistungsfähige, flexible, resourcensparende Node-Infrastruktur:

      Kern ist die Node(Of TNode)-Class
      Wenn man das Bildle genau anschaut, erklärt sich glaub jeder ihrer 23 Member von selbst. Kurz zur Type-Property: die ist Datentyp NodeType - also nebenstehende Enumeration: TopLevel, Inner, Leaf - auch selbsterklärend, oder?
      Und die Tree-Property, die ist vom Typ Tree(Of TNode), und das ist eine weitere wesentliche Klasse: Dort kann man nämlich Member anlegen, die für alle Nodes eines Trees gleichermaßen relevant sind, zB eine SelectedNode-Property ist bereits drin. Aber ich hab in Tree-erbenden Klassen auch komplette KontextMenüs angelegt, und im RepTree noch zusätzlich zusätzlich die ganze Drag-n-Drop-Verarbeitung (Rep-Node/-Tree sind Viewmodel des Repository-Baums).

      Node(Of T) kümmert sich auch um Daten-Konsistenz: Etwa bei der InsertItem()-Überschreibung trägt ein Node sich selbst als Parent ein im zu insertenden ChildNode.
      Die Resourcen-Effizienz besteht v.a. darin, dass ein Node nur für Name und Parent wirklich ein individuelles Feld hinterlegt hat. Die anderen Sachen holt er sich immer gschwind vom Root-Node, welches ist der einzige Node, der einen wirklichen Verweis auf den Tree(of TNode) hat. ZB. der IsSelected-Property hinterliegt kein Boolean-Feld, sondern um Node.IsSelected zu ermitteln (oder zu setzen) rennt er intern von Parent zu Parent zum Root, holt sich den Tree, und wenn er selbst des Trees SelectedNode ist, dann ist IsSelected wohl True.

      MenuTree - eine Anwendung der Node-Infrastruktur
      Ich beerbe Node(Of TNode) ja 5 mal, um 1) SortedNode zu erhalten, 2) SyncNode mit Gemeinsamkeiten von 3) ClientNode und 4) RepNode, und letztere halt mit genau den Unterschiedlichkeiten.
      Und von 5) - MenuTree zeige ich mal die praktische Anwendung:

      VB.NET-Quellcode

      1. Public Class MainModel : Inherits MainModelBase(Of MainModel)
      2. Public Class Menu : Inherits MenuTree
      3. Public Shared _Load, _Save, _File, _Push, Pu_ll, _Merge As String
      4. Public Shared ExitNoSave As String = "E_xit Without Saving Changes", SyncOptions As String = "_Sync-Options"
      5. Public Sub New()
      6. SubMenu(_File, _Load, _Save, ExitNoSave)
      7. End Sub
      8. End Class
      9. Public WithEvents MainMenu As New Menu
      10. Private Sub MainMenu_Execute(sender As Object, e As ExecuteEventargs) Handles MainMenu.Execute
      11. Select Case e.ID
      12. Case Menu.ExitNoSave : WithoutEvents.Create(_MainWindow).Close() 'bypass _MainWindow_Closing()
      13. Case Menu._Load : Reload()
      14. Case Menu._Save : Save()
      15. Case Menu._Push : LaunchSync(SyncMode.Push)
      16. Case Menu.Pu_ll : LaunchSync(SyncMode.Pull)
      17. Case Menu._Merge : LaunchSync(SyncMode.Merge)
      18. Case Menu.SyncOptions : MessageBox.Show(My.Settings.SyncOptions, "Synchronisize-Options")
      19. End Select
      20. End Sub
      Also im Mainmodel eine eingeschachtelte kleine Klasse Menu (Zeilen #3 - #9), von MenuTree erbend, mit lauter Shared String-Membern.
      In Sub New der BasisKlasse (hier nicht gezeigt) werden per Reflection daraus MenuNodes gebastelt, an die Xaml ein Menü binden kann, Template dran und fertig - ein für allemal. (Xaml.Menu ist ja ein ItemsControl, und kann baumartige Strukturen anzeigen - prinzipiell wie Treeview).
      Jdfs. im oben gezeigten Menu.New(), zeile #7, wird zusätzlich die MenuTree-Methode SubMenu() aufgerufen, die die MenuNodes _Load, _Save, ExitNoSave zu SubMenuItem des _File-MenuItems macht:


      Ich kann also im Mainmodel das Menü gestalten und umbauen wie wolle, ohne am Xaml rumzufummeln.
      Und die vielen Shared Strings definieren einerseits die Beschriftungen der MenuItems, fungieren andererseits aber auch als ein Enum, anhand dessen ich in MainMenu_Execute() die Klickse den richtigen Methoden-Aufrufen zuordnen kann.
      Ja, soweit.

      Nu interessieren täte mich, ob ich der einzige bleibe, der dieses Tool nutzt, ob dem einen oder anderen meine Ausführungen was gebracht haben, oder ob mein Code jmd. ein bischen inspiriert hat.
      Und ggfs. auch Fragen, oder gar BugReports.
      Aber ich sage gleich: Es ist nicht idiotensicher. Wenn ihr den BilderOrdner des einen Clients mit den ProgrammierProjekten des anderen synchronisiert, sind hinterher entweder die Bilder weg oder die Programmier-Projekte ;(

      Edit: Lizenz: Beerware
      Dateien
      • Sync.zip

        (164,24 kB, 260 mal heruntergeladen, zuletzt: )

      Dieser Beitrag wurde bereits 7 mal editiert, zuletzt von „ErfinderDesRades“ ()

      Hallo,

      Darf man den Code weiter entwickeln, vornehmentlich für dem Internen Hausgebrauch, da währe dann eine integration mit der Herbrich-20 Software nicht schlecht.

      Aber kleine frage am radne? Nutzt du das Microsoft Sync Framework??

      LG, Herbrich
      Warum eigentlich das Rad neu erfinden? Es gibt doch zahlreiche Tools für das zentrale speichern von Dateien (Dropbox, OneDrive, OwnCloud, ...) und auch Tools zur Versionskontrolle wie Git (andere sind z.B. Mercurial oder TFS), welches vom Konzept her deinem System extrem ähnelt.

      nafets schrieb:

      Warum eigentlich das Rad neu erfinden?
      Schicksal ;)

      Im Ernst: Ja, es gibt viel ähnliches. Aber zB DropBox, OneDrive, OwnCloud - ich kenne die nicht, aber geht das nicht übers Internet? Würde das zB einen 20GByte-Sync-Auftrag verkraften?
      Versionskontrolle kenne ich nur Mercurial, und da musste ich immer jede popelige Datei einzeln angeben - das war mir sehr lästig, weil wenn ich progge, änder ich alle 10min was am Dateisystem. Und ich fand Mercurial auch sonst unintuitiv, also erst musste ich die Dateien festlegen, dann committen, dann pushen, dann pullen, dann restoren - also war mir sehr lästig.
      Und Sync ist auch keine Versionskontrolle, wo man jede verflossene Version wieder restaurieren kann. Es gibt nur einen Spiegel und basta. Der Spiegel kann halt paar MB klein sein auf einem USB, aber ebensogut zig GByte gross, und alle Account-Daten aller User eines PCs backuppen (dauert dann halt bischen).
      Windows-Ordner oder Program-Files zu syncen macht hingegen nicht so viel Sinn - es geht schon ums Sichern von User-Daten.
      Bei Cloud-Storage-Anbietern wie Dropbox haste automatische Synchronisation zwischen all deinen Geräten und eine Kopie in der Cloud, auf die du jederzeit von Überfall aus zugreifen kannst. Das finde ich für Dokumente sehr praktisch, da sie so sicher gespeichert und immer verfügbar sind.
      Für 20GB-Sachen bräuchtest du halt schon sehr lange - dafür sind solche Anbieter aber auch nicht wirklich geeignet, wenn du keine extrem schnelle Internetverbindung hast. Man könnte sich allerdings ein NAS besorgen und das als Cloud verwenden. Dann hast du die oben genannten Vorteile und kannst zu Hause auch extrem schnell Dateien austauschen.

      Da ich mit Mercurial noch nie gearbeitet habe kann ich nicht beurteilen, wie das ist. Bei Git ist es allerdings dank Visual Studio-Integration extrem einfach. Und für meine Projekte würde ich nichts anderes nutzen wollen. Ich könnte mir auch gut vorstellen, eine Art Versionskontrolle/automatische Backups von allen Änderungen zu nutzen.

      Was planst du denn an Features, welche die Nutzung vereinfachen sollen? Ich würde es jedenfalls nutzen, wenn es noch etwas ausgereifter wäre.
      Die Nutzung zu vereinfachen fällt mir grad nicht so viel ein: Man zieht die Ordner drauf, die man syncen will, und klickst "Push" - geht das noch einfacher?
      Tatsächlich zieht man ja nur alle Jubeljahre iwas drauf, normal doppelklickst man die längst eingerichtete .syn-Datei - "Push" - das wars ja schon.
      Du kannst dir auch eine Verknüpfung auf den Desktop legen, wenn die .syn - Datei zu suchen zu mühsam ist.
      Bei mir ists sogar noch mühsamer: Ich muss mich immer unter den Tisch bücken, um meine externe Festplatte ein-/aus-zustöpseln - wirklich! 8|
      Und wegen der Stöpselei mache ich auch keinen Dienst davon, der ständig im Hintergrund rumlungert und sowas.
      Servus,

      für Code nutze ich Visual Studio Online. Git ist aber auch gut.

      Dropbox hat IMHO eine Funktion das man im lokalen Netzwerk direkt synchronisieren kann und damit nicht erst alles übers Internet schieben muss. Wenn die Daten einmal online sind hat man auch direkt eine Versionskontrolle.
      Die deutsche Sprache ist Freeware, du kannst sie benutzen, ohne dafür zu bezahlen. Sie ist aber nicht Open Source, also darfst du sie nicht verändern, wie es dir gerade passt.
      @ErfinderDesRades
      Wegen der "Vereinfachung": Ich konnte mir dein Programm noch nicht genau ansehen, in deiner Erklärung klang es aber für mich ziemlich kompliziert. Trotzten fände ich es praktisch wenn es eine Funktion gäbe, bei der das Programm alle Aktionen selbstständig ausführt (bei jeder Änderung die entsprechende Datei aktualisieren -> FileSystemWatcher?).

      ErfinderDesRades schrieb:

      Edit: Lizenz: Beerware


      Hallo,

      Geile Lizenz, da bin ich sofort Dabei, alerdings dencke ich gerade auch über die "Weedware" lizenz nach. Oder Altanrativ "Dolphinware". Wo bei WeedWare ganz einfach zu erklähren ist, beinhaltet die Dolphinware Lizenz dann einfach "Schencke den Autor bei Gefallen ein Plüsch Delphin für seine Sammlung!" :D

      LG, Herbrich

      PS: Endschuldigung für den Offtopic aber nach dem ich mir die Wiki Seite gegeben habe konnte ich mir diesen kommi einfach nicht verkneifen. Warum programmieren wir bei vbp nicht absofort alle unsere Programme mit der Beerware Lizenz :D