diff --git a/BackupEssentials/Backup/BackupReport.cs b/BackupEssentials/Backup/BackupReport.cs new file mode 100644 index 0000000..5c1986f --- /dev/null +++ b/BackupEssentials/Backup/BackupReport.cs @@ -0,0 +1,81 @@ +using BackupEssentials.Backup.IO; +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace BackupEssentials.Backup{ + class BackupReport{ + private readonly string _plain; + private string _parsed; + + public string Report { + get { + if (_parsed == null){ + StringBuilder build = new StringBuilder(16+(int)Math.Floor(_plain.Length*1.5D)); + + foreach(string line in SplitByLine(_plain)){ + if (line.Length == 0)continue; + + if (line[0] == 'I')build.Append(line.Substring(1)).Append(Environment.NewLine); + else if (line[0] == 'A' && line.Length > 3)build.Append(GetFullNameAction(line[1])).Append(' ').Append(GetFullNameType(line[2])).Append(' ').Append(line.Substring(3)).Append(Environment.NewLine); + } + + _parsed = build.ToString(); + } + + return _parsed; + } + } + + private BackupReport(string report){ + this._plain = report; + } + + public override string ToString(){ + return Report; + } + + public class Builder{ + private StringBuilder Build = new StringBuilder(256); + + public void Add(IOAction action, IOType type, string path){ + Build.Append('A').Append(GetShortName(action)).Append(GetShortName(type)).Append(path).Append(Environment.NewLine); + } + + public void Add(string message){ + Build.Append('I').Append(message).Append(Environment.NewLine); + } + + public BackupReport Finish(){ + return new BackupReport(Build.ToString()); + } + } + + private static char GetShortName(IOAction action){ + return action == IOAction.Create ? 'C' : action == IOAction.Delete ? 'D' : action == IOAction.Replace ? 'R' : '?'; + } + + private static string GetFullNameAction(char key){ + return key == 'C' ? "Added" : key == 'D' ? "Deleted" : key == 'R' ? "Updated" : "(unknown action)"; + } + + private static char GetShortName(IOType type){ + return type == IOType.File ? 'F' : type == IOType.Directory ? 'D' : '?'; + } + + private static string GetFullNameType(char key){ + return key == 'F' ? "File" : key == 'D' ? "Folder" : "(unknown type)"; + } + + private static IEnumerable<string> SplitByLine(string str){ + using(StringReader reader = new StringReader(str)){ + string line; + + while((line = reader.ReadLine()) != null){ + yield return line; + } + } + } + } +} diff --git a/BackupEssentials/Backup/BackupRunner.cs b/BackupEssentials/Backup/BackupRunner.cs index df0ed35..c6df9c7 100644 --- a/BackupEssentials/Backup/BackupRunner.cs +++ b/BackupEssentials/Backup/BackupRunner.cs @@ -1,10 +1,13 @@ -using BackupEssentials.Utils; +using BackupEssentials.Backup.IO; +using BackupEssentials.Utils; using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; +using System.Globalization; using System.IO; using System.Linq; +using System.Text; namespace BackupEssentials.Backup{ public class BackupRunner{ @@ -101,6 +104,19 @@ namespace BackupEssentials.Backup{ int totalActions = actions.Count, attempts = 10; string path; + BackupReport.Builder reportBuilder = new BackupReport.Builder(); + reportBuilder.Add("= Preparing backup ="); + reportBuilder.Add("Source: "+src); + reportBuilder.Add("Destination: "+destFolder); + reportBuilder.Add("Date: "+DateTime.Now.ToString("d")+" "+DateTime.Now.ToString("t")); + reportBuilder.Add(""); + reportBuilder.Add("= Files and folders ="); + reportBuilder.Add("Added: "+actions.Count((entry) => entry.Action == IOAction.Create)); + reportBuilder.Add("Updated: "+actions.Count((entry) => entry.Action == IOAction.Replace)); + reportBuilder.Add("Deleted: "+actions.Count((entry) => entry.Action == IOAction.Delete)); + reportBuilder.Add(""); + reportBuilder.Add("= Starting backup ="); + while(actions.Count > 0 && --attempts > 0){ for(int index = 0; index < actions.Count; index++){ IOActionEntry entry = actions[index]; @@ -129,7 +145,7 @@ namespace BackupEssentials.Backup{ } indexesToRemove.Add(index-indexesToRemove.Count); // goes from 0 to actions.Count, removing each index will move the structure - Debug.WriteLine("Finished: "+entry.ToString()); + reportBuilder.Add(entry.Action,entry.Type,entry.RelativePath); worker.ReportProgress((int)Math.Ceiling(((totalActions-actions.Count+indexesToRemove.Count)*100D)/totalActions)); if (worker.CancellationPending)break; @@ -139,22 +155,25 @@ namespace BackupEssentials.Backup{ // TODO handle special exceptions (security etc) } - if (worker.CancellationPending)throw new Exception("Backup canceled."); + if (worker.CancellationPending){ + reportBuilder.Add("= Backup canceled ="); + e.Result = reportBuilder.Finish(); + throw new Exception("Backup canceled."); + } } foreach(int index in indexesToRemove)actions.RemoveAt(index); indexesToRemove.Clear(); } - if (attempts == 0)throw new Exception("Backup failed: ran out of attempts."); - } + if (attempts == 0){ + reportBuilder.Add("= Backup failed (out of attempts) ="); + e.Result = reportBuilder.Finish(); + throw new Exception("Backup failed: ran out of attempts."); + } - private enum IOType{ - None, File, Directory - } - - private enum IOAction{ - None, Create, Replace, Delete + reportBuilder.Add("= Backup finished ="); + e.Result = reportBuilder.Finish(); } private class IOEntry{ diff --git a/BackupEssentials/Backup/IO/IOAction.cs b/BackupEssentials/Backup/IO/IOAction.cs new file mode 100644 index 0000000..165f8df --- /dev/null +++ b/BackupEssentials/Backup/IO/IOAction.cs @@ -0,0 +1,5 @@ +namespace BackupEssentials.Backup.IO{ + enum IOAction{ + None, Create, Replace, Delete + } +} diff --git a/BackupEssentials/Backup/IO/IOType.cs b/BackupEssentials/Backup/IO/IOType.cs new file mode 100644 index 0000000..be2e6b3 --- /dev/null +++ b/BackupEssentials/Backup/IO/IOType.cs @@ -0,0 +1,5 @@ +namespace BackupEssentials.Backup.IO{ + enum IOType{ + None, File, Directory + } +} diff --git a/BackupEssentials/BackupEssentials.csproj b/BackupEssentials/BackupEssentials.csproj index e480164..2f73f49 100644 --- a/BackupEssentials/BackupEssentials.csproj +++ b/BackupEssentials/BackupEssentials.csproj @@ -83,9 +83,12 @@ <DependentUpon>BackupWindow.xaml</DependentUpon> </Compile> <Compile Include="Backup\BackupLocation.cs" /> + <Compile Include="Backup\BackupReport.cs" /> <Compile Include="Backup\BackupRunner.cs" /> <Compile Include="Backup\DataStorage.cs" /> <Compile Include="Backup\ExplorerIntegration.cs" /> + <Compile Include="Backup\IO\IOAction.cs" /> + <Compile Include="Backup\IO\IOType.cs" /> <Compile Include="Pages\About.xaml.cs"> <DependentUpon>About.xaml</DependentUpon> </Compile> diff --git a/BackupEssentials/BackupWindow.xaml.cs b/BackupEssentials/BackupWindow.xaml.cs index 4d40110..cdee0c4 100644 --- a/BackupEssentials/BackupWindow.xaml.cs +++ b/BackupEssentials/BackupWindow.xaml.cs @@ -10,6 +10,7 @@ namespace BackupEssentials{ public partial class BackupWindow : Window{ private BackupRunner Runner; private int ActionCount; + private BackupReport Report; private DispatcherTimer CloseTimer; public BackupWindow(BackupRunner runner){ @@ -48,6 +49,9 @@ namespace BackupEssentials{ Runner = null; ButtonShowReport.IsEnabled = true; ButtonEnd.Content = "Close"; + Report = e.Result as BackupReport; + + Debug.WriteLine(Report.Report); if (e.Error != null){ LabelInfo.Content = e.Error.Message;