Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/duplicati/duplicati.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKenneth Skovhede <kenneth@hexad.dk>2013-06-29 13:41:53 +0400
committerKenneth Skovhede <kenneth@hexad.dk>2013-06-29 14:16:30 +0400
commit2bf912a0af64942bc43106f3b9a7c8763150de2f (patch)
treef2544cc102ee82aa9a0daf53c4fefea0aab0ea2b /Duplicati
parent1a507fde23bd42c0034efa61280491fed263b9c8 (diff)
Rewrote the filter system to distinguish between match and result, which allows filter combinations
Diffstat (limited to 'Duplicati')
-rw-r--r--Duplicati/CommandLine/Program.cs25
-rw-r--r--Duplicati/Library/Main/Database/LocalDatabase.cs2
-rw-r--r--Duplicati/Library/Main/Database/LocalListChangesDatabase.cs2
-rw-r--r--Duplicati/Library/Main/Database/LocalRestoreDatabase.cs2
-rw-r--r--Duplicati/Library/Main/Operation/BackupHandler.cs10
-rw-r--r--Duplicati/Library/Main/Operation/ListChangesHandler.cs6
-rw-r--r--Duplicati/Library/Main/Operation/ListControlFilesHandler.cs4
-rw-r--r--Duplicati/Library/Main/Operation/ListFilesHandler.cs32
-rw-r--r--Duplicati/Library/Main/Operation/RecreateDatabaseHandler.cs2
-rw-r--r--Duplicati/Library/Main/Operation/RestoreControlFilesHandler.cs4
-rw-r--r--Duplicati/Library/Main/Operation/RestoreHandler.cs30
-rw-r--r--Duplicati/Library/Utility/CompositeFilterExpression.cs52
-rw-r--r--Duplicati/Library/Utility/Duplicati.Library.Utility.csproj2
-rw-r--r--Duplicati/Library/Utility/FilterExpression.cs76
-rw-r--r--Duplicati/Library/Utility/IFilter.cs3
-rw-r--r--Duplicati/Library/Utility/JoinedFilterExpression.cs56
-rw-r--r--Duplicati/Library/Utility/Utility.cs10
17 files changed, 175 insertions, 143 deletions
diff --git a/Duplicati/CommandLine/Program.cs b/Duplicati/CommandLine/Program.cs
index f6730364c..018a06dfa 100644
--- a/Duplicati/CommandLine/Program.cs
+++ b/Duplicati/CommandLine/Program.cs
@@ -28,20 +28,31 @@ namespace Duplicati.CommandLine
{
private class FilterCollector
{
- private List<KeyValuePair<bool, Library.Utility.IFilter>> m_filters = new List<KeyValuePair<bool, Library.Utility.IFilter>>();
- private Library.Utility.CompositeFilterExpression Filter { get { return new Library.Utility.CompositeFilterExpression(m_filters, true); } }
+ private List<Library.Utility.IFilter> m_filters = new List<Library.Utility.IFilter>();
+ private Library.Utility.IFilter Filter
+ {
+ get
+ {
+ if (m_filters.Count == 0)
+ return new Library.Utility.FilterExpression();
+ else if (m_filters.Count == 1)
+ return m_filters[0];
+ else
+ return m_filters.Aggregate((a,b) => Library.Utility.JoinedFilterExpression.Join(a, b));
+ }
+ }
private Dictionary<string, string> DoExtractOptions(List<string> args, Func<string, string, bool> callbackHandler = null)
{
return Library.Utility.CommandLineParser.ExtractOptions(args, (key, value) => {
if (key.Equals("include", StringComparison.InvariantCultureIgnoreCase))
{
- m_filters.Add(new KeyValuePair<bool, Library.Utility.IFilter>(true, new Library.Utility.FilterExpression(new string[] { value })));
+ m_filters.Add(new Library.Utility.FilterExpression(value, true));
return false;
}
else if (key.Equals("exclude", StringComparison.InvariantCultureIgnoreCase))
{
- m_filters.Add(new KeyValuePair<bool, Library.Utility.IFilter>(false, new Library.Utility.FilterExpression(new string[] { value })));
+ m_filters.Add(new Library.Utility.FilterExpression(value, false));
return false;
}
@@ -52,11 +63,11 @@ namespace Duplicati.CommandLine
});
}
- public static Tuple<Dictionary<string, string>, Library.Utility.CompositeFilterExpression> ExtractOptions(List<string> args, Func<string, string, bool> callbackHandler = null)
+ public static Tuple<Dictionary<string, string>, Library.Utility.IFilter> ExtractOptions(List<string> args, Func<string, string, bool> callbackHandler = null)
{
var fc = new FilterCollector();
var opts = fc.DoExtractOptions(args, callbackHandler);
- return new Tuple<Dictionary<string, string>, Library.Utility.CompositeFilterExpression>(opts, fc.Filter);
+ return new Tuple<Dictionary<string, string>, Library.Utility.IFilter>(opts, fc.Filter);
}
}
@@ -233,7 +244,7 @@ namespace Duplicati.CommandLine
}
}
- private static bool ReadOptionsFromFile(string filename, ref Library.Utility.CompositeFilterExpression filter, List<string> cargs, Dictionary<string, string> options)
+ private static bool ReadOptionsFromFile(string filename, ref Library.Utility.IFilter filter, List<string> cargs, Dictionary<string, string> options)
{
try
{
diff --git a/Duplicati/Library/Main/Database/LocalDatabase.cs b/Duplicati/Library/Main/Database/LocalDatabase.cs
index 510f29f36..8f9397b49 100644
--- a/Duplicati/Library/Main/Database/LocalDatabase.cs
+++ b/Duplicati/Library/Main/Database/LocalDatabase.cs
@@ -755,7 +755,7 @@ namespace Duplicati.Library.Main.Database
while(rd.Read())
{
var p = rd.GetValue(0).ToString();
- if (filter.Matches(p))
+ if(Library.Utility.FilterExpression.Matches(filter, p, true))
{
cmd.SetParameterValue(0, p);
cmd.ExecuteNonQuery();
diff --git a/Duplicati/Library/Main/Database/LocalListChangesDatabase.cs b/Duplicati/Library/Main/Database/LocalListChangesDatabase.cs
index 9188fb594..8da011c96 100644
--- a/Duplicati/Library/Main/Database/LocalListChangesDatabase.cs
+++ b/Duplicati/Library/Main/Database/LocalListChangesDatabase.cs
@@ -175,7 +175,7 @@ namespace Duplicati.Library.Main.Database
while (rd.Read())
{
rd.GetValues(values);
- if (values[0] != null && values[0] != DBNull.Value && filter.Matches(values[0].ToString()))
+ if (values[0] != null && values[0] != DBNull.Value && Library.Utility.FilterExpression.Matches(filter, values[0].ToString(), true))
{
cmd2.SetParameterValue(0, values[0]);
cmd2.SetParameterValue(1, values[1]);
diff --git a/Duplicati/Library/Main/Database/LocalRestoreDatabase.cs b/Duplicati/Library/Main/Database/LocalRestoreDatabase.cs
index a084eb7db..3b8f8d85a 100644
--- a/Duplicati/Library/Main/Database/LocalRestoreDatabase.cs
+++ b/Duplicati/Library/Main/Database/LocalRestoreDatabase.cs
@@ -117,7 +117,7 @@ namespace Duplicati.Library.Main.Database
while (rd.Read())
{
rd.GetValues(values);
- if (values[0] != null && values[0] != DBNull.Value && filter.Matches(values[0].ToString()))
+ if (values[0] != null && values[0] != DBNull.Value && Library.Utility.FilterExpression.Matches(filter, values[0].ToString(), true))
{
cmd2.SetParameterValue(0, values[0]);
cmd2.SetParameterValue(1, values[1]);
diff --git a/Duplicati/Library/Main/Operation/BackupHandler.cs b/Duplicati/Library/Main/Operation/BackupHandler.cs
index 6f5609248..8abd9d3a9 100644
--- a/Duplicati/Library/Main/Operation/BackupHandler.cs
+++ b/Duplicati/Library/Main/Operation/BackupHandler.cs
@@ -100,11 +100,7 @@ namespace Duplicati.Library.Main.Operation
m_database.VerifyConsistency(null);
// If there is no filter, we set an empty filter to simplify the code
// If there is a filter, we make sure that fall-through includes the entry
- m_filter =
- filter == null ?
- (Library.Utility.IFilter)new Library.Utility.CompositeFilterExpression(null, true)
- :
- (Library.Utility.IFilter)new Library.Utility.CompositeFilterExpression(((Library.Utility.CompositeFilterExpression)filter).Filters, true);
+ m_filter = filter ?? new Library.Utility.FilterExpression();
var lastVolumeSize = -1L;
m_backendLogFlushTimer = DateTime.Now.Add(FLUSH_TIMESPAN);
@@ -159,8 +155,8 @@ namespace Duplicati.Library.Main.Operation
m_result.AddVerboseMessage("Excluding path due to attribute filter {0}", path);
return false;
}
-
- if (!m_filter.Matches(path))
+
+ if (!Library.Utility.FilterExpression.Matches(m_filter, path, true))
{
m_result.AddVerboseMessage("Excluding path due to filter {0}", path);
return false;
diff --git a/Duplicati/Library/Main/Operation/ListChangesHandler.cs b/Duplicati/Library/Main/Operation/ListChangesHandler.cs
index 10131858e..8ab42fb29 100644
--- a/Duplicati/Library/Main/Operation/ListChangesHandler.cs
+++ b/Duplicati/Library/Main/Operation/ListChangesHandler.cs
@@ -56,7 +56,7 @@ namespace Duplicati.Library.Main.Operation
public void Run(string baseVersion, string compareVersion, IEnumerable<string> filterstrings = null, Library.Utility.IFilter compositefilter = null)
{
- var filter = ListFilesHandler.CombineFilters(new Library.Utility.FilterExpression(filterstrings), compositefilter);
+ var filter = Library.Utility.JoinedFilterExpression.Join(new Library.Utility.FilterExpression(filterstrings), compositefilter);
var useLocalDb = !m_options.NoLocalDb && System.IO.File.Exists(m_options.Dbpath);
baseVersion = string.IsNullOrEmpty(baseVersion) ? "0" : baseVersion;
@@ -130,13 +130,13 @@ namespace Duplicati.Library.Main.Operation
using(var tmpfile = backend.Get(baseFile.File.Name, baseFile.File.Size, null))
using(var rd = new Volumes.FilesetVolumeReader(RestoreHandler.GetCompressionModule(baseFile.File.Name), tmpfile, m_options))
foreach(var f in rd.Files)
- if (filter == null || filter.Empty || filter.Matches(f.Path))
+ if (Library.Utility.FilterExpression.Matches(filter, f.Path, true))
storageKeeper.AddElement(f.Path, f.Hash, f.Metahash, f.Size, conv(f.Type), false);
using(var tmpfile = backend.Get(compareFile.File.Name, compareFile.File.Size, null))
using(var rd = new Volumes.FilesetVolumeReader(RestoreHandler.GetCompressionModule(compareFile.File.Name), tmpfile, m_options))
foreach(var f in rd.Files)
- if (filter == null || filter.Empty || filter.Matches(f.Path))
+ if (Library.Utility.FilterExpression.Matches(filter, f.Path, true))
storageKeeper.AddElement(f.Path, f.Hash, f.Metahash, f.Size, conv(f.Type), true);
}
diff --git a/Duplicati/Library/Main/Operation/ListControlFilesHandler.cs b/Duplicati/Library/Main/Operation/ListControlFilesHandler.cs
index 803bbb35a..92af18267 100644
--- a/Duplicati/Library/Main/Operation/ListControlFilesHandler.cs
+++ b/Duplicati/Library/Main/Operation/ListControlFilesHandler.cs
@@ -42,7 +42,7 @@ namespace Duplicati.Library.Main.Operation
{
m_result.SetDatabase(db);
- var filter = ListFilesHandler.CombineFilters(filterstrings, compositefilter);
+ var filter = Library.Utility.JoinedFilterExpression.Join(new Library.Utility.FilterExpression(filterstrings), compositefilter);
try
{
@@ -67,7 +67,7 @@ namespace Duplicati.Library.Main.Operation
using (var tmpfile = backend.Get(file.Name, size, hash))
using (var tmp = new Volumes.FilesetVolumeReader(RestoreHandler.GetCompressionModule(file.Name), tmpfile, m_options))
foreach (var cf in tmp.ControlFiles)
- if (filter.Matches(cf.Key))
+ if (Library.Utility.FilterExpression.Matches(filter, cf.Key, true))
files.Add(new ListResultFile(cf.Key, null));
m_result.SetResult(new Library.Interface.IListResultFileset[] { new ListResultFileset(fileversion.Key, fileversion.Value.Time, -1, -1) }, files);
diff --git a/Duplicati/Library/Main/Operation/ListFilesHandler.cs b/Duplicati/Library/Main/Operation/ListFilesHandler.cs
index 6dc2c137a..711737505 100644
--- a/Duplicati/Library/Main/Operation/ListFilesHandler.cs
+++ b/Duplicati/Library/Main/Operation/ListFilesHandler.cs
@@ -21,10 +21,8 @@ namespace Duplicati.Library.Main.Operation
public void Run(IEnumerable<string> filterstrings = null, Library.Utility.IFilter compositefilter = null)
{
var parsedfilter = new Library.Utility.FilterExpression(filterstrings);
-
var simpleList = !(parsedfilter.Type == Library.Utility.FilterType.Simple || m_options.AllVersions);
-
- var filter = CombineFilters(parsedfilter, compositefilter);
+ var filter = Library.Utility.JoinedFilterExpression.Join(parsedfilter, compositefilter);
//Use a speedy local query
if (!m_options.NoLocalDb && System.IO.File.Exists(m_options.Dbpath))
@@ -79,7 +77,7 @@ namespace Duplicati.Library.Main.Operation
m_result.SetResult(
numberSeq.Take(1),
(from n in rd.Files
- where filter.Matches(n.Path)
+ where Library.Utility.FilterExpression.Matches(filter, n.Path, true)
orderby n.Path
select new ListResultFile(n.Path, new long[] { n.Size }))
.ToArray()
@@ -90,7 +88,7 @@ namespace Duplicati.Library.Main.Operation
else
{
res = rd.Files
- .Where(x => filter.Matches(x.Path))
+ .Where(x => Library.Utility.FilterExpression.Matches(filter, x.Path, true))
.ToDictionary(
x => x.Path,
y =>
@@ -108,7 +106,7 @@ namespace Duplicati.Library.Main.Operation
using(var tmpfile = backend.Get(flentry.Value.File.Name, -1, null))
using (var rd = new Volumes.FilesetVolumeReader(flentry.Value.CompressionModule, tmpfile, m_options))
{
- foreach(var p in from n in rd.Files where filter.Matches(n.Path) select n)
+ foreach(var p in from n in rd.Files where Library.Utility.FilterExpression.Matches(filter, n.Path, true) select n)
{
List<long> lst;
if (!res.TryGetValue(p.Path, out lst))
@@ -151,26 +149,6 @@ namespace Duplicati.Library.Main.Operation
public static IEnumerable<Library.Interface.IListResultFileset> CreateResultSequence(IEnumerable<KeyValuePair<long, Volumes.IParsedVolume>> filteredList)
{
return (from n in filteredList select (Library.Interface.IListResultFileset)(new ListResultFileset(n.Key, n.Value.Time.ToLocalTime(), -1, -1))).ToArray();
- }
-
- public static Library.Utility.IFilter CombineFilters(IEnumerable<string> filterstrings, Library.Utility.IFilter compositefilter)
- {
- return CombineFilters(new Library.Utility.FilterExpression(filterstrings), compositefilter);
- }
-
- public static Library.Utility.IFilter CombineFilters(Library.Utility.IFilter parsedfilter, Library.Utility.IFilter compositefilter)
- {
- Library.Utility.IFilter filter = parsedfilter;
- if (compositefilter != null && !compositefilter.Empty)
- filter = new Library.Utility.CompositeFilterExpression(
- ((Library.Utility.CompositeFilterExpression)compositefilter).Filters
- .Union(new KeyValuePair<bool, Library.Utility.IFilter>[] {
- new KeyValuePair<bool, Duplicati.Library.Utility.IFilter>(true, parsedfilter)
- }),
- false
- );
-
- return filter;
- }
+ }
}
}
diff --git a/Duplicati/Library/Main/Operation/RecreateDatabaseHandler.cs b/Duplicati/Library/Main/Operation/RecreateDatabaseHandler.cs
index 5f082d48f..f07e8e609 100644
--- a/Duplicati/Library/Main/Operation/RecreateDatabaseHandler.cs
+++ b/Duplicati/Library/Main/Operation/RecreateDatabaseHandler.cs
@@ -170,7 +170,7 @@ namespace Duplicati.Library.Main.Operation
// Create timestamped operations based on the file timestamp
backupdb.CreateFileset(volumeIds[entry.Name], parsed.Time, tr);
using (var filelistreader = new FilesetVolumeReader(parsed.CompressionModule, tmpfile, m_options))
- foreach (var fe in filelistreader.Files.Where(x => filter == null || filter.Matches(x.Path)))
+ foreach (var fe in filelistreader.Files.Where(x => Library.Utility.FilterExpression.Matches(filter, x.Path, true)))
{
if (fe.Type == FilelistEntryType.Folder)
{
diff --git a/Duplicati/Library/Main/Operation/RestoreControlFilesHandler.cs b/Duplicati/Library/Main/Operation/RestoreControlFilesHandler.cs
index bc8a5b36f..412642a23 100644
--- a/Duplicati/Library/Main/Operation/RestoreControlFilesHandler.cs
+++ b/Duplicati/Library/Main/Operation/RestoreControlFilesHandler.cs
@@ -31,7 +31,7 @@ namespace Duplicati.Library.Main.Operation
{
m_result.SetDatabase(db);
- var filter = ListFilesHandler.CombineFilters(filterstrings, compositefilter);
+ var filter = Library.Utility.JoinedFilterExpression.Join(new Library.Utility.FilterExpression(filterstrings), compositefilter);
try
{
@@ -56,7 +56,7 @@ namespace Duplicati.Library.Main.Operation
using (var tmpfile = backend.Get(file.Name, size, hash))
using (var tmp = new Volumes.FilesetVolumeReader(RestoreHandler.GetCompressionModule(file.Name), tmpfile, m_options))
foreach (var cf in tmp.ControlFiles)
- if (filter.Matches(cf.Key))
+ if (Library.Utility.FilterExpression.Matches(filter, cf.Key, true))
{
var targetpath = System.IO.Path.Combine(m_options.Restorepath, cf.Key);
using (var ts = System.IO.File.Create(targetpath))
diff --git a/Duplicati/Library/Main/Operation/RestoreHandler.cs b/Duplicati/Library/Main/Operation/RestoreHandler.cs
index a8784b778..1f6b064aa 100644
--- a/Duplicati/Library/Main/Operation/RestoreHandler.cs
+++ b/Duplicati/Library/Main/Operation/RestoreHandler.cs
@@ -76,34 +76,8 @@ namespace Duplicati.Library.Main.Operation
public void Run(string[] paths, Library.Utility.IFilter filter = null)
{
- var pathfilter = new Library.Utility.FilterExpression(paths);
- filter = filter ?? new Library.Utility.FilterExpression(null);
-
- // If we have both target paths and a filter, combine into a single filter
- if (!pathfilter.Empty && !filter.Empty)
- {
- filter = new Library.Utility.CompositeFilterExpression(
- ((Library.Utility.CompositeFilterExpression)filter).Filters
- .Union(new KeyValuePair<bool, Library.Utility.IFilter>[] {
- new KeyValuePair<bool, Duplicati.Library.Utility.IFilter> (
- true,
- pathfilter
- )
- }),
- false
- );
- }
- // Both empty
- else if (filter.Empty && pathfilter.Empty)
- {
- // Match all files
- filter = new Library.Utility.CompositeFilterExpression(null, true);
- }
- // Only paths
- else if (filter.Empty)
- {
- filter = pathfilter;
- }
+ // If we have both target paths and a filter, combine into a single filter
+ filter = Library.Utility.JoinedFilterExpression.Join(new Library.Utility.FilterExpression(paths), filter);
if (!m_options.NoLocalDb && System.IO.File.Exists(m_options.Dbpath))
{
diff --git a/Duplicati/Library/Utility/CompositeFilterExpression.cs b/Duplicati/Library/Utility/CompositeFilterExpression.cs
deleted file mode 100644
index 658884a6d..000000000
--- a/Duplicati/Library/Utility/CompositeFilterExpression.cs
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright (C) 2011, Kenneth Skovhede
-
-// http://www.hexad.dk, opensource@hexad.dk
-//
-// This library is free software; you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as
-// published by the Free Software Foundation; either version 2.1 of the
-// License, or (at your option) any later version.
-//
-// This library is distributed in the hope that it will be useful, but
-// WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-using System;
-using System.Collections.Generic;
-using System.Linq;
-
-namespace Duplicati.Library.Utility
-{
- /// <summary>
- /// Represents multiple filters, that can each send true or false if they match or not
- /// </summary>
- public class CompositeFilterExpression : IFilter
- {
- private KeyValuePair<bool, IFilter>[] m_filters;
- private bool m_defaultValue;
-
- public bool Empty { get { return m_filters.Length == 0; } }
-
- public IEnumerable<KeyValuePair<bool, IFilter>> Filters { get { return m_filters; } }
-
- public CompositeFilterExpression(IEnumerable<KeyValuePair<bool, IFilter>> filters, bool defaultvalue)
- {
- m_filters = filters == null ? new KeyValuePair<bool, IFilter>[0] : filters.ToArray();
- m_defaultValue = defaultvalue;
- }
-
- public bool Matches(string entry)
- {
- foreach(var e in m_filters)
- if (e.Value.Matches(entry))
- return e.Key;
-
- return m_defaultValue;
- }
- }
-}
-
diff --git a/Duplicati/Library/Utility/Duplicati.Library.Utility.csproj b/Duplicati/Library/Utility/Duplicati.Library.Utility.csproj
index dba6e2c33..85be4b018 100644
--- a/Duplicati/Library/Utility/Duplicati.Library.Utility.csproj
+++ b/Duplicati/Library/Utility/Duplicati.Library.Utility.csproj
@@ -102,8 +102,8 @@
</Compile>
<Compile Include="IFilter.cs" />
<Compile Include="FilterExpression.cs" />
- <Compile Include="CompositeFilterExpression.cs" />
<Compile Include="FileBackedList.cs" />
+ <Compile Include="JoinedFilterExpression.cs" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
diff --git a/Duplicati/Library/Utility/FilterExpression.cs b/Duplicati/Library/Utility/FilterExpression.cs
index 90cbce962..cecac8b1b 100644
--- a/Duplicati/Library/Utility/FilterExpression.cs
+++ b/Duplicati/Library/Utility/FilterExpression.cs
@@ -85,7 +85,7 @@ namespace Duplicati.Library.Utility
/// <param name="path">The path to match</param>
public bool Matches(string path)
{
- switch(this.Type)
+ switch (this.Type)
{
case FilterType.Simple:
return string.Equals(this.Filter, path, Library.Utility.Utility.ClientFilenameStringComparision);
@@ -94,7 +94,7 @@ namespace Duplicati.Library.Utility
var m = this.Regexp.Match(path);
return m.Success && m.Length == path.Length;
default:
- return false;
+ return false;
}
}
}
@@ -108,6 +108,11 @@ namespace Duplicati.Library.Utility
/// Gets the type of the filter
/// </summary>
public readonly FilterType Type;
+
+ /// <summary>
+ /// Gets the result returned if an entry matches
+ /// </summary>
+ public readonly bool Result;
/// <summary>
/// Gets a value indicating whether this <see cref="Duplicati.Library.Utility.FilterExpression"/> is empty.
@@ -131,26 +136,53 @@ namespace Duplicati.Library.Utility
/// Gets a value indicating if the filter matches the path
/// </summary>
/// <param name="path">The path to match</param>
- public bool Matches(string path)
+ public bool Matches(string path, out bool result)
{
+ result = false;
if (this.Type == FilterType.Empty)
return false;
-
- return m_filters.Where(x => x.Matches(path)).Any();
+
+ if (m_filters.Where(x => x.Matches(path)).Any())
+ {
+ result = this.Result;
+ return true;
+ }
+
+ return false;
+ }
+
+ /// <summary>
+ /// Creates a new <see cref="Duplicati.Library.Utility.FilterExpression"/> instance, representing an empty filter.
+ /// </summary>
+ /// <param name="filter">The filter string that represents the filter</param>
+ public FilterExpression()
+ : this((IEnumerable<string>)null, true)
+ {
}
/// <summary>
- /// Creates a new <see cref="Duplicati.Library.Main.FilterExpression"/> class.
+ /// Creates a new <see cref="Duplicati.Library.Utility.FilterExpression"/> instance.
/// </summary>
/// <param name="filter">The filter string that represents the filter</param>
- public FilterExpression(IEnumerable<string> filter)
+ public FilterExpression(string filter, bool result = true)
+ : this(new string[] { filter }, result)
{
+ }
+
+ /// <summary>
+ /// Creates a new <see cref="Duplicati.Library.Main.FilterExpression"/> instance.
+ /// </summary>
+ /// <param name="filter">The filter string that represents the filter</param>
+ public FilterExpression(IEnumerable<string> filter, bool result = true)
+ {
+ this.Result = result;
+
if (filter == null)
{
this.Type = FilterType.Empty;
return;
}
-
+
m_filters =
(from n in filter
let nx = new FilterEntry(n)
@@ -162,6 +194,34 @@ namespace Duplicati.Library.Utility
else
this.Type = (FilterType)m_filters.Max((a) => a.Type);
}
+
+ /// <summary>
+ /// Utility function to match a filter with a default fall-through value
+ /// </summary>
+ /// <param name="filter">The filter to evaluate</param>
+ /// <param name="path">The path to evaluate</param>
+ /// <param name="default">The default return value if no filter matches</param>
+ public static bool Matches(IFilter filter, string path, bool @default)
+ {
+ if (filter == null || filter.Empty)
+ return @default;
+
+ bool result;
+ if (!filter.Matches(path, out result))
+ result = @default;
+
+ return result;
+ }
+
+ /// <summary>
+ /// Combine the specified filter expressions.
+ /// </summary>
+ /// <param name="first">First.</param>
+ /// <param name="second">Second.</param>
+ public static FilterExpression Combine(FilterExpression first, FilterExpression second)
+ {
+ return new FilterExpression(first.m_filters.Union(second.m_filters).Select(x => x.Type == FilterType.Regexp ? ("[" + x.Filter + "]") : x.Filter), first.Result);
+ }
}
}
diff --git a/Duplicati/Library/Utility/IFilter.cs b/Duplicati/Library/Utility/IFilter.cs
index c2d747872..189c096e6 100644
--- a/Duplicati/Library/Utility/IFilter.cs
+++ b/Duplicati/Library/Utility/IFilter.cs
@@ -33,7 +33,8 @@ namespace Duplicati.Library.Utility
/// Performs a test to see if the entry matches the filter
/// </summary>
/// <param name="entry">The entry to match</param>
- bool Matches(string entry);
+ /// <param name="result">The match result</param>
+ bool Matches(string entry, out bool result);
}
}
diff --git a/Duplicati/Library/Utility/JoinedFilterExpression.cs b/Duplicati/Library/Utility/JoinedFilterExpression.cs
new file mode 100644
index 000000000..186ebe0a8
--- /dev/null
+++ b/Duplicati/Library/Utility/JoinedFilterExpression.cs
@@ -0,0 +1,56 @@
+// Copyright (C) 2011, Kenneth Skovhede
+
+// http://www.hexad.dk, opensource@hexad.dk
+//
+// This library is free software; you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as
+// published by the Free Software Foundation; either version 2.1 of the
+// License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+using System;
+
+namespace Duplicati.Library.Utility
+{
+ public class JoinedFilterExpression : IFilter
+ {
+ private IFilter m_first;
+ private IFilter m_second;
+
+ public JoinedFilterExpression(IFilter first, IFilter second)
+ {
+ m_first = first ?? new FilterExpression();
+ m_second = second ?? new FilterExpression();
+ }
+
+ public bool Matches(string entry, out bool result)
+ {
+ return m_first.Matches(entry, out result) || m_second.Matches(entry, out result);
+ }
+
+ public bool Empty { get { return m_first.Empty && m_second.Empty; } }
+
+ public static IFilter Join(IFilter first, IFilter second)
+ {
+ if (first == null || first.Empty)
+ return second;
+ else if (second == null || second.Empty)
+ return first;
+ else
+ {
+ if (first is FilterExpression && second is FilterExpression && ((FilterExpression)first).Result == ((FilterExpression)second).Result)
+ return FilterExpression.Combine((FilterExpression)first, (FilterExpression)second);
+
+ return new JoinedFilterExpression(first, second);
+ }
+ }
+ }
+}
+
diff --git a/Duplicati/Library/Utility/Utility.cs b/Duplicati/Library/Utility/Utility.cs
index 8c4155811..a48e2a262 100644
--- a/Duplicati/Library/Utility/Utility.cs
+++ b/Duplicati/Library/Utility/Utility.cs
@@ -194,7 +194,14 @@ namespace Duplicati.Library.Utility
/// <returns>A list of the full filenames and foldernames. Foldernames ends with the directoryseparator char</returns>
public static IEnumerable<string> EnumerateFileSystemEntries(string basepath, IFilter filter)
{
- return EnumerateFileSystemEntries(basepath, (rootpath, path, attributes) => filter == null || filter.Matches(path));
+ filter = filter ?? new FilterExpression();
+ return EnumerateFileSystemEntries(basepath, (rootpath, path, attributes) => {
+ bool result;
+ if (!filter.Matches(path, out result))
+ result = true;
+
+ return result;
+ });
}
/// <summary>
@@ -931,6 +938,7 @@ namespace Duplicati.Library.Utility
}
writer.Flush();
}
+
/// <summary>
/// Returns a string representing the object, which can be used for display or logging
/// </summary>