diff --git a/src/SIL.Machine/Corpora/FileParatextProjectSettingsParser.cs b/src/SIL.Machine/Corpora/FileParatextProjectSettingsParser.cs index 27a51b42..108677f7 100644 --- a/src/SIL.Machine/Corpora/FileParatextProjectSettingsParser.cs +++ b/src/SIL.Machine/Corpora/FileParatextProjectSettingsParser.cs @@ -2,12 +2,12 @@ { public class FileParatextProjectSettingsParser : ParatextProjectSettingsParserBase { - public FileParatextProjectSettingsParser(string projectDir) - : base(new FileParatextProjectFileHandler(projectDir)) { } + public FileParatextProjectSettingsParser(string projectDir, ParatextProjectSettings parentSettings = null) + : base(new FileParatextProjectFileHandler(projectDir), parentSettings) { } - public static ParatextProjectSettings Parse(string projectDir) + public static ParatextProjectSettings Parse(string projectDir, ParatextProjectSettings parentSettings = null) { - return new FileParatextProjectSettingsParser(projectDir).Parse(); + return new FileParatextProjectSettingsParser(projectDir, parentSettings).Parse(); } } } diff --git a/src/SIL.Machine/Corpora/FileParatextProjectTextUpdater.cs b/src/SIL.Machine/Corpora/FileParatextProjectTextUpdater.cs index 6389b76a..a47d4c3f 100644 --- a/src/SIL.Machine/Corpora/FileParatextProjectTextUpdater.cs +++ b/src/SIL.Machine/Corpora/FileParatextProjectTextUpdater.cs @@ -2,8 +2,10 @@ { public class FileParatextProjectTextUpdater : ParatextProjectTextUpdaterBase { - public FileParatextProjectTextUpdater(string projectDir) - : base(new FileParatextProjectFileHandler(projectDir), FileParatextProjectSettingsParser.Parse(projectDir)) - { } + public FileParatextProjectTextUpdater(string projectDir, ParatextProjectSettings parentSettings = null) + : base( + new FileParatextProjectFileHandler(projectDir), + FileParatextProjectSettingsParser.Parse(projectDir, parentSettings) + ) { } } } diff --git a/src/SIL.Machine/Corpora/FileParatextProjectVersificationErrorDetector.cs b/src/SIL.Machine/Corpora/FileParatextProjectVersificationErrorDetector.cs index 17e1e8aa..a99f8d0e 100644 --- a/src/SIL.Machine/Corpora/FileParatextProjectVersificationErrorDetector.cs +++ b/src/SIL.Machine/Corpora/FileParatextProjectVersificationErrorDetector.cs @@ -2,8 +2,13 @@ namespace SIL.Machine.Corpora { public class FileParatextProjectVersificationErrorDetector : ParatextProjectVersificationErrorDetectorBase { - public FileParatextProjectVersificationErrorDetector(string projectDir) - : base(new FileParatextProjectFileHandler(projectDir), FileParatextProjectSettingsParser.Parse(projectDir)) - { } + public FileParatextProjectVersificationErrorDetector( + string projectDir, + ParatextProjectSettings parentSettings = null + ) + : base( + new FileParatextProjectFileHandler(projectDir), + FileParatextProjectSettingsParser.Parse(projectDir, parentSettings) + ) { } } } diff --git a/src/SIL.Machine/Corpora/ParatextBackupTermsCorpus.cs b/src/SIL.Machine/Corpora/ParatextBackupTermsCorpus.cs index 30640657..b11692ab 100644 --- a/src/SIL.Machine/Corpora/ParatextBackupTermsCorpus.cs +++ b/src/SIL.Machine/Corpora/ParatextBackupTermsCorpus.cs @@ -10,16 +10,26 @@ public ParatextBackupTermsCorpus( string fileName, IEnumerable termCategories, bool useTermGlosses = true, - IDictionary> chapters = null + IDictionary> chapters = null, + string parentFileName = null ) { + ParatextProjectSettings parentSettings = null; + if (parentFileName != null) + { + using (var archive = ZipFile.OpenRead(parentFileName)) + { + parentSettings = ZipParatextProjectSettingsParser.Parse(archive); + } + } + using (var archive = ZipFile.OpenRead(fileName)) { - IEnumerable keyTerms = new ZipParatextProjectTermsParser(archive) + IEnumerable keyTerms = new ZipParatextProjectTermsParser(archive, parentSettings) .Parse(termCategories, useTermGlosses, chapters) .OrderBy(g => g.Id); - ParatextProjectSettings settings = ZipParatextProjectSettingsParser.Parse(archive); + ParatextProjectSettings settings = ZipParatextProjectSettingsParser.Parse(archive, parentSettings); string textId = $"{settings.BiblicalTermsListType}:{settings.BiblicalTermsProjectName}:{settings.BiblicalTermsFileName}"; diff --git a/src/SIL.Machine/Corpora/ParatextBackupTextCorpus.cs b/src/SIL.Machine/Corpora/ParatextBackupTextCorpus.cs index 28e0a654..af47db29 100644 --- a/src/SIL.Machine/Corpora/ParatextBackupTextCorpus.cs +++ b/src/SIL.Machine/Corpora/ParatextBackupTextCorpus.cs @@ -4,11 +4,25 @@ namespace SIL.Machine.Corpora { public class ParatextBackupTextCorpus : ScriptureTextCorpus { - public ParatextBackupTextCorpus(string fileName, bool includeMarkers = false, bool includeAllText = false) + public ParatextBackupTextCorpus( + string fileName, + bool includeMarkers = false, + bool includeAllText = false, + string parentFileName = null + ) { + ParatextProjectSettings parentSettings = null; + if (parentFileName != null) + { + using (var archive = ZipFile.OpenRead(parentFileName)) + { + parentSettings = ZipParatextProjectSettingsParser.Parse(archive); + } + } + using (ZipArchive archive = ZipFile.OpenRead(fileName)) { - var parser = new ZipParatextProjectSettingsParser(archive); + var parser = new ZipParatextProjectSettingsParser(archive, parentSettings); ParatextProjectSettings settings = parser.Parse(); Versification = settings.Versification; diff --git a/src/SIL.Machine/Corpora/ParatextProjectSettings.cs b/src/SIL.Machine/Corpora/ParatextProjectSettings.cs index ecbcfa0f..e1875715 100644 --- a/src/SIL.Machine/Corpora/ParatextProjectSettings.cs +++ b/src/SIL.Machine/Corpora/ParatextProjectSettings.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Globalization; using System.Text; using SIL.Scripture; @@ -8,6 +9,7 @@ namespace SIL.Machine.Corpora public class ParatextProjectSettings { public ParatextProjectSettings( + string guid, string name, string fullName, Encoding encoding, @@ -19,9 +21,14 @@ public ParatextProjectSettings( string biblicalTermsListType, string biblicalTermsProjectName, string biblicalTermsFileName, - string languageCode + string languageCode, + string translationType, + string parentGuid = null, + string parentName = null, + ParatextProjectSettings parentSettings = null ) { + Guid = guid; Name = name; FullName = fullName; Encoding = encoding; @@ -34,12 +41,17 @@ string languageCode BiblicalTermsProjectName = biblicalTermsProjectName; BiblicalTermsFileName = biblicalTermsFileName; LanguageCode = languageCode; + TranslationType = translationType; + ParentGuid = parentGuid; + ParentName = parentName; + _parent = parentSettings; } + public string Guid { get; } public string Name { get; } public string FullName { get; } public Encoding Encoding { get; } - public ScrVers Versification { get; } + public ScrVers Versification { get; private set; } public UsfmStylesheet Stylesheet { get; } public string FileNamePrefix { get; } public string FileNameForm { get; } @@ -47,8 +59,22 @@ string languageCode public string BiblicalTermsListType { get; } public string BiblicalTermsProjectName { get; } public string BiblicalTermsFileName { get; } - public string LanguageCode { get; } + public string TranslationType { get; } + public string ParentGuid { get; } + public string ParentName { get; } + public ParatextProjectSettings Parent + { + get { return _parent; } + set + { + if (!IsDaughterProjectOf(value)) + throw new ArgumentException($"Project {value.Name} is not the parent project of project {Name}."); + _parent = value; + Versification = value.Versification; + } + } + private ParatextProjectSettings _parent; public bool IsBookFileName(string fileName, out string bookId) { @@ -114,6 +140,15 @@ public IEnumerable GetAllScriptureBookIds() } } + public bool HasParent => !string.IsNullOrEmpty(ParentGuid); + + public bool IsDaughterProjectOf(ParatextProjectSettings parentSettings) + { + if (!HasParent) + return false; + return ParentGuid.Equals(parentSettings.Guid); + } + private static string GetBookFileNameDigits(string bookId) { int bookNum = Canon.BookIdToNumber(bookId); diff --git a/src/SIL.Machine/Corpora/ParatextProjectSettingsParserBase.cs b/src/SIL.Machine/Corpora/ParatextProjectSettingsParserBase.cs index 52b54cba..b2b25e55 100644 --- a/src/SIL.Machine/Corpora/ParatextProjectSettingsParserBase.cs +++ b/src/SIL.Machine/Corpora/ParatextProjectSettingsParserBase.cs @@ -9,10 +9,15 @@ namespace SIL.Machine.Corpora public abstract class ParatextProjectSettingsParserBase { private readonly IParatextProjectFileHandler _paratextProjectFileHandler; + private readonly ParatextProjectSettings _parentParatextProjectSettings; - public ParatextProjectSettingsParserBase(IParatextProjectFileHandler paratextProjectFileHandler) + public ParatextProjectSettingsParserBase( + IParatextProjectFileHandler paratextProjectFileHandler, + ParatextProjectSettings parentParatextProjectSettings = null + ) { _paratextProjectFileHandler = paratextProjectFileHandler; + _parentParatextProjectSettings = parentParatextProjectSettings; } public ParatextProjectSettings Parse() @@ -29,6 +34,7 @@ public ParatextProjectSettings Parse() settingsDoc = XDocument.Load(stream); } + string guid = settingsDoc.Root.Element("Guid").Value; string name = settingsDoc.Root.Element("Name").Value; string fullName = settingsDoc.Root.Element("FullName").Value; @@ -45,7 +51,6 @@ public ParatextProjectSettings Parse() var versification = new ScrVers((ScrVersType)scrVersType); if (_paratextProjectFileHandler.Exists("custom.vrs")) { - var guid = (string)settingsDoc.Root.Element("Guid"); string versName = ((ScrVersType)scrVersType).ToString() + "-" + guid; if (Versification.Table.Implementation.Exists(versName)) { @@ -107,14 +112,27 @@ public ParatextProjectSettings Parse() string languageIsoCodeSetting = settingsDoc.Root.Element("LanguageIsoCode")?.Value; if (languageIsoCodeSetting != null) { - string[] languageIsoCodeSettingParts = settingsDoc.Root.Element("LanguageIsoCode").Value.Split(':'); + string[] languageIsoCodeSettingParts = languageIsoCodeSetting.Split(':'); if (languageIsoCodeSettingParts.Length > 0) { languageCode = languageIsoCodeSettingParts[0]; } } - return new ParatextProjectSettings( + string translationInfoSetting = settingsDoc.Root.Element("TranslationInfo")?.Value; + string translationType = "Standard"; + string parentName = null; + string parentGuid = null; + if (translationInfoSetting != null) + { + string[] translationInfoSettingParts = translationInfoSetting.Split(':'); + translationType = translationInfoSettingParts[0]; + parentName = translationInfoSettingParts[1] != "" ? translationInfoSettingParts[1] : null; + parentGuid = translationInfoSettingParts[2] != "" ? translationInfoSettingParts[2] : null; + } + + var settings = new ParatextProjectSettings( + guid, name, fullName, encoding, @@ -126,8 +144,18 @@ public ParatextProjectSettings Parse() parts[0], parts[1], parts[2], - languageCode + languageCode, + translationType, + parentGuid, + parentName ); + + if (_parentParatextProjectSettings != null && settings.HasParent) + { + settings.Parent = _parentParatextProjectSettings; + } + + return settings; } } } diff --git a/src/SIL.Machine/Corpora/ParatextTextCorpus.cs b/src/SIL.Machine/Corpora/ParatextTextCorpus.cs index 486fbfb2..40cd9121 100644 --- a/src/SIL.Machine/Corpora/ParatextTextCorpus.cs +++ b/src/SIL.Machine/Corpora/ParatextTextCorpus.cs @@ -4,9 +4,21 @@ namespace SIL.Machine.Corpora { public class ParatextTextCorpus : ScriptureTextCorpus { - public ParatextTextCorpus(string projectDir, bool includeMarkers = false, bool includeAllText = false) + public ParatextTextCorpus( + string projectDir, + bool includeMarkers = false, + bool includeAllText = false, + string parentProjectDir = null + ) { - var parser = new FileParatextProjectSettingsParser(projectDir); + ParatextProjectSettings parentSettings = null; + if (parentProjectDir != null) + { + var parentParser = new FileParatextProjectSettingsParser(parentProjectDir); + parentSettings = parentParser.Parse(); + } + + var parser = new FileParatextProjectSettingsParser(projectDir, parentSettings); ParatextProjectSettings settings = parser.Parse(); Versification = settings.Versification; diff --git a/src/SIL.Machine/Corpora/ZipParatextProjectSettingsParser.cs b/src/SIL.Machine/Corpora/ZipParatextProjectSettingsParser.cs index aed8cfb3..d7e6c463 100644 --- a/src/SIL.Machine/Corpora/ZipParatextProjectSettingsParser.cs +++ b/src/SIL.Machine/Corpora/ZipParatextProjectSettingsParser.cs @@ -4,12 +4,12 @@ namespace SIL.Machine.Corpora { public class ZipParatextProjectSettingsParser : ParatextProjectSettingsParserBase { - public ZipParatextProjectSettingsParser(ZipArchive archive) - : base(new ZipParatextProjectFileHandler(archive)) { } + public ZipParatextProjectSettingsParser(ZipArchive archive, ParatextProjectSettings parentSettings = null) + : base(new ZipParatextProjectFileHandler(archive), parentSettings) { } - public static ParatextProjectSettings Parse(ZipArchive archive) + public static ParatextProjectSettings Parse(ZipArchive archive, ParatextProjectSettings parentSettings = null) { - return new ZipParatextProjectSettingsParser(archive).Parse(); + return new ZipParatextProjectSettingsParser(archive, parentSettings).Parse(); } } } diff --git a/src/SIL.Machine/Corpora/ZipParatextProjectTermsParser.cs b/src/SIL.Machine/Corpora/ZipParatextProjectTermsParser.cs index 55a9e6f2..939a7187 100644 --- a/src/SIL.Machine/Corpora/ZipParatextProjectTermsParser.cs +++ b/src/SIL.Machine/Corpora/ZipParatextProjectTermsParser.cs @@ -4,7 +4,10 @@ namespace SIL.Machine.Corpora { public class ZipParatextProjectTermsParser : ParatextProjectTermsParserBase { - public ZipParatextProjectTermsParser(ZipArchive archive) - : base(new ZipParatextProjectFileHandler(archive), ZipParatextProjectSettingsParser.Parse(archive)) { } + public ZipParatextProjectTermsParser(ZipArchive archive, ParatextProjectSettings parentSettings = null) + : base( + new ZipParatextProjectFileHandler(archive), + ZipParatextProjectSettingsParser.Parse(archive, parentSettings) + ) { } } } diff --git a/src/SIL.Machine/Corpora/ZipParatextProjectTextUpdater.cs b/src/SIL.Machine/Corpora/ZipParatextProjectTextUpdater.cs index 4903a4db..ad00c63b 100644 --- a/src/SIL.Machine/Corpora/ZipParatextProjectTextUpdater.cs +++ b/src/SIL.Machine/Corpora/ZipParatextProjectTextUpdater.cs @@ -4,7 +4,10 @@ namespace SIL.Machine.Corpora { public class ZipParatextProjectTextUpdater : ParatextProjectTextUpdaterBase { - public ZipParatextProjectTextUpdater(ZipArchive archive) - : base(new ZipParatextProjectFileHandler(archive), ZipParatextProjectSettingsParser.Parse(archive)) { } + public ZipParatextProjectTextUpdater(ZipArchive archive, ParatextProjectSettings parentSettings = null) + : base( + new ZipParatextProjectFileHandler(archive), + ZipParatextProjectSettingsParser.Parse(archive, parentSettings) + ) { } } } diff --git a/src/SIL.Machine/Corpora/ZipParatextProjectVersificationErrorDetector.cs b/src/SIL.Machine/Corpora/ZipParatextProjectVersificationErrorDetector.cs index 71139836..a77fd629 100644 --- a/src/SIL.Machine/Corpora/ZipParatextProjectVersificationErrorDetector.cs +++ b/src/SIL.Machine/Corpora/ZipParatextProjectVersificationErrorDetector.cs @@ -4,7 +4,13 @@ namespace SIL.Machine.Corpora { public class ZipParatextProjectVersificationErrorDetector : ParatextProjectVersificationErrorDetectorBase { - public ZipParatextProjectVersificationErrorDetector(ZipArchive archive) - : base(new ZipParatextProjectFileHandler(archive), ZipParatextProjectSettingsParser.Parse(archive)) { } + public ZipParatextProjectVersificationErrorDetector( + ZipArchive archive, + ParatextProjectSettings parentSettings = null + ) + : base( + new ZipParatextProjectFileHandler(archive), + ZipParatextProjectSettingsParser.Parse(archive, parentSettings) + ) { } } } diff --git a/src/SIL.Machine/PunctuationAnalysis/ZipParatextProjectQuoteConventionDetector.cs b/src/SIL.Machine/PunctuationAnalysis/ZipParatextProjectQuoteConventionDetector.cs index 1df1db84..b4aab841 100644 --- a/src/SIL.Machine/PunctuationAnalysis/ZipParatextProjectQuoteConventionDetector.cs +++ b/src/SIL.Machine/PunctuationAnalysis/ZipParatextProjectQuoteConventionDetector.cs @@ -5,7 +5,13 @@ namespace SIL.Machine.PunctuationAnalysis { public class ZipParatextProjectQuoteConventionDetector : ParatextProjectQuoteConventionDetector { - public ZipParatextProjectQuoteConventionDetector(ZipArchive archive) - : base(new ZipParatextProjectFileHandler(archive), ZipParatextProjectSettingsParser.Parse(archive)) { } + public ZipParatextProjectQuoteConventionDetector( + ZipArchive archive, + ParatextProjectSettings parentSettings = null + ) + : base( + new ZipParatextProjectFileHandler(archive), + ZipParatextProjectSettingsParser.Parse(archive, parentSettings) + ) { } } } diff --git a/tests/SIL.Machine.Tests/Corpora/FileParatextProjectSettingsParserTests.cs b/tests/SIL.Machine.Tests/Corpora/FileParatextProjectSettingsParserTests.cs index 058cffd6..52470253 100644 --- a/tests/SIL.Machine.Tests/Corpora/FileParatextProjectSettingsParserTests.cs +++ b/tests/SIL.Machine.Tests/Corpora/FileParatextProjectSettingsParserTests.cs @@ -13,4 +13,22 @@ public void Parse_CustomStylesheet() Assert.That(testTag.StyleType, Is.EqualTo(UsfmStyleType.Character)); Assert.That(testTag.TextType, Is.EqualTo(UsfmTextType.Other)); } + + [Test] + public void Parse_ParentProject() + { + FileParatextProjectSettingsParser parser = new(CorporaTestHelpers.UsfmTestProjectPath); + ParatextProjectSettings settings = parser.Parse(); + Assert.That(settings.HasParent); + Assert.That(settings.IsDaughterProjectOf(settings)); + Assert.That(settings.TranslationType, Is.EqualTo("Standard")); + Assert.That(settings.Parent, Is.Null); + + parser = new(CorporaTestHelpers.UsfmTestProjectPath, parentSettings: settings); + settings = parser.Parse(); + Assert.That(settings.HasParent); + Assert.That(settings.IsDaughterProjectOf(settings)); + Assert.That(settings.TranslationType, Is.EqualTo("Standard")); + Assert.That(settings.Parent, Is.Not.Null); + } } diff --git a/tests/SIL.Machine.Tests/Corpora/MemoryParatextProjectFileHandler.cs b/tests/SIL.Machine.Tests/Corpora/MemoryParatextProjectFileHandler.cs index df869d1e..5bf1b1d1 100644 --- a/tests/SIL.Machine.Tests/Corpora/MemoryParatextProjectFileHandler.cs +++ b/tests/SIL.Machine.Tests/Corpora/MemoryParatextProjectFileHandler.cs @@ -30,6 +30,7 @@ public string Find(string extension) } public class DefaultParatextProjectSettings( + string id = "Id", string name = "Test", string fullName = "TestProject", Encoding? encoding = null, @@ -41,9 +42,13 @@ public class DefaultParatextProjectSettings( string biblicalTermsListType = "Project", string biblicalTermsProjectName = "Test", string biblicalTermsFileName = "ProjectBiblicalTerms.xml", - string languageCode = "en" + string languageCode = "en", + string translationType = "Standard", + string? parentGuid = null, + string? parentName = null ) : ParatextProjectSettings( + id, name, fullName, encoding ?? Encoding.UTF8, @@ -55,6 +60,9 @@ public class DefaultParatextProjectSettings( biblicalTermsListType, biblicalTermsProjectName, biblicalTermsFileName, - languageCode + languageCode, + translationType, + parentGuid, + parentName ) { } } diff --git a/tests/SIL.Machine.Tests/Corpora/ParatextProjectSettingsTests.cs b/tests/SIL.Machine.Tests/Corpora/ParatextProjectSettingsTests.cs index f53ac9b7..1fecc472 100644 --- a/tests/SIL.Machine.Tests/Corpora/ParatextProjectSettingsTests.cs +++ b/tests/SIL.Machine.Tests/Corpora/ParatextProjectSettingsTests.cs @@ -174,6 +174,7 @@ public void IsBookFileName_WrongBookPart_BookNumBookId() private static ParatextProjectSettings CreateSettings(string fileNameForm) { return new ParatextProjectSettings( + "Id", "Name", "Name", Encoding.UTF8, @@ -185,7 +186,8 @@ private static ParatextProjectSettings CreateSettings(string fileNameForm) "Major", "", "BiblicalTerms.xml", - "en" + "en", + "Standard" ); } } diff --git a/tests/SIL.Machine.Tests/Corpora/TestData/usfm/Tes/Settings.xml b/tests/SIL.Machine.Tests/Corpora/TestData/usfm/Tes/Settings.xml index d76bcbc5..0b683c63 100644 --- a/tests/SIL.Machine.Tests/Corpora/TestData/usfm/Tes/Settings.xml +++ b/tests/SIL.Machine.Tests/Corpora/TestData/usfm/Tes/Settings.xml @@ -24,7 +24,7 @@ F F Public - Standard:: + Standard:Tes:a7e0b3ce0200736062f9f810a444dbfbe64aca35 3 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 diff --git a/tests/SIL.Machine.Tests/Corpora/ZipParatextProjectSettingsParserTests.cs b/tests/SIL.Machine.Tests/Corpora/ZipParatextProjectSettingsParserTests.cs index 0c58100b..2794f189 100644 --- a/tests/SIL.Machine.Tests/Corpora/ZipParatextProjectSettingsParserTests.cs +++ b/tests/SIL.Machine.Tests/Corpora/ZipParatextProjectSettingsParserTests.cs @@ -16,23 +16,41 @@ public void Parse_CustomStylesheet() Assert.That(testTag.TextType, Is.EqualTo(UsfmTextType.Other)); } + [Test] + public void Parse_ParentProject() + { + using var env = new TestEnvironment(); + ParatextProjectSettings settings = env.Parser.Parse(); + Assert.That(settings.HasParent); + Assert.That(settings.IsDaughterProjectOf(settings)); + Assert.That(settings.TranslationType, Is.EqualTo("Standard")); + Assert.That(settings.Parent, Is.Null); + + env.Parser = new ZipParatextProjectSettingsParser(env.Archive, settings); + settings = env.Parser.Parse(); + Assert.That(settings.HasParent); + Assert.That(settings.IsDaughterProjectOf(settings)); + Assert.That(settings.TranslationType, Is.EqualTo("Standard")); + Assert.That(settings.Parent, Is.Not.Null); + } + private class TestEnvironment : DisposableBase { private readonly string _backupPath; - private readonly ZipArchive _archive; public TestEnvironment() { _backupPath = CorporaTestHelpers.CreateTestParatextBackup(); - _archive = ZipFile.OpenRead(_backupPath); - Parser = new ZipParatextProjectSettingsParser(_archive); + Archive = ZipFile.OpenRead(_backupPath); + Parser = new ZipParatextProjectSettingsParser(Archive); } - public ZipParatextProjectSettingsParser Parser { get; } + public ZipParatextProjectSettingsParser Parser { get; set; } + public ZipArchive Archive { get; } protected override void DisposeManagedResources() { - _archive.Dispose(); + Archive.Dispose(); if (File.Exists(_backupPath)) File.Delete(_backupPath); }