コード例 #1
0
        public void Patching_Builder_LowInstallerHigherPatches()
        {
            var builder = new PatchBuilder(new TestComponent());

            // ACTION
            builder
            .Install("1.0", "2020-10-20", "desc").Action()
            .Patch("1.0", "2.0", "2020-10-20", "desc").Action()
            .Patch("2.0", "3.0", "2020-10-21", "desc").Action();

            // ASSERT
            Assert.AreEqual("MyComp: 1.0 | MyComp: 1.0 <= v < 2.0 --> 2.0 | MyComp: 2.0 <= v < 3.0 --> 3.0",
                            PatchesToString(builder));
        }
コード例 #2
0
        public void Patching_Builder_Installer_BeforeAfter()
        {
            var builder = new PatchBuilder(new TestComponent());

            // ACTION
            builder.Install("1.0", "2020-10-20", "MyComp desc")
            .ActionOnBefore().Action();

            // ASSERT
            var installers = builder.GetPatches()
                             .Select(x => (ComponentInstaller)x).ToArray();

            Assert.IsNull(installers[0].ActionBeforeStart);
            Assert.IsNull(installers[0].Action);
        }
コード例 #3
0
        private PatchBuilder GetPatchA()
        {
            if (null == this.patchA)
            {
                string packageA       = this.GetPackageA().Output;
                string packageAUpdate = this.GetPackageAv101().Output;

                this.patchA = new PatchBuilder(this, "PatchA")
                {
                    TargetPath = packageA, UpgradePath = packageAUpdate
                }.Build();
            }

            return(this.patchA);
        }
コード例 #4
0
        public void PatchesDifferentType()
        {
            var model1 = new Model1 {
                Integer = 3
            };
            var model2 = new Model2 {
                Integer = 3
            };
            var patch1 = PatchBuilder.Build <Model1>(new { Integer = 5 });

            patch1.ApplyToT(model2);

            Assert.Equal(5, model2.Integer);

            Assert.Throws <NotSupportedException>(() => patch1.ApplyTo(model1));
        }
コード例 #5
0
        public void Patching_Builder_Dependency_Direct()
        {
            var builder = new PatchBuilder(new TestComponent());

            // ACTION
            builder.Patch("1.0", "2.0", "2020-10-20", "desc")
            .DependsOn("C1", "1.0")
            .DependsOn("C2", "2.3.0.15")
            .Action();

            // ASSERT
            var patch  = builder.GetPatches()[0] as SnPatch;
            var actual = DependenciesToString(patch?.Dependencies ?? new Dependency[0]);

            Assert.AreEqual("C1: 1.0 <= v | C2: 2.3.0.15 <= v", actual);
        }
コード例 #6
0
ファイル: Burn.PatchTests.cs プロジェクト: zooba/wix3
        public void Burn_PatchInstallUninstall()
        {
            string originalVersion = "1.0.0.0";
            string patchedVersion = "1.0.1.0";

            // Build the packages.
            string packageA = new PackageBuilder(this, "A") { Extensions = WixTests.Extensions }.Build().Output;
            string packageAUpdate = new PackageBuilder(this, "A") { Extensions = WixTests.Extensions, PreprocessorVariables = new Dictionary<string, string>() { { "Version", patchedVersion } }, NeverGetsInstalled = true }.Build().Output;
            string patchA = new PatchBuilder(this, "PatchA") { Extensions = WixTests.Extensions, TargetPath = packageA, UpgradePath = packageAUpdate }.Build().Output;

            // Create the named bind paths to the packages.
            Dictionary<string, string> bindPaths = new Dictionary<string, string>();
            bindPaths.Add("packageA", packageA);
            bindPaths.Add("patchA", patchA);

            string bundleA = new BundleBuilder(this, "BundleA") { BindPaths = bindPaths, Extensions = WixTests.Extensions }.Build().Output;
            string bundleAPatch = new BundleBuilder(this, "PatchBundleA") { BindPaths = bindPaths, Extensions = WixTests.Extensions }.Build().Output;

            // Install the unpatched bundle.
            BundleInstaller installA = new BundleInstaller(this, bundleA).Install();
            using (RegistryKey root = this.GetTestRegistryRoot())
            {
                string actualVersion = root.GetValue("A") as string;
                Assert.Equal(originalVersion, actualVersion);
            }

            // Install the patch bundle.
            BundleInstaller installAPatch = new BundleInstaller(this, bundleAPatch).Install();
            using (RegistryKey root = this.GetTestRegistryRoot())
            {
                string actualVersion = root.GetValue("A") as string;
                Assert.Equal(patchedVersion, actualVersion);
            }

            // Uninstall the patch bundle.
            installAPatch.Uninstall();
            using (RegistryKey root = this.GetTestRegistryRoot())
            {
                string actualVersion = root.GetValue("A") as string;
                Assert.Equal(originalVersion, actualVersion);
            }

            installA.Uninstall();
            Assert.True(null == this.GetTestRegistryRoot(), "Test registry key should have been removed during uninstall.");

            this.Complete();
        }
コード例 #7
0
        public override void Initialize()
        {
            base.Initialize();

            var progress = new Progress <BuilderProgress>();

            progress.ProgressChanged += ProgressChanged;

            _context                   = new AdminPatchContext(CurrentWindow.AdminSettings, progress);
            _context.Logger            = new MHLab.Patch.Utilities.Logging.Logger(CurrentWindow.AdminSettings.GetLogsFilePath(), CurrentWindow.AdminSettings.DebugMode);
            _context.Serializer        = new NewtonsoftSerializer();
            _context.LocalizedMessages = CurrentWindow.Localization;

            _builder = new PatchBuilder(_context);

            InitializePatches();
        }
コード例 #8
0
ファイル: Burn.SlipstreamTests.cs プロジェクト: bleissem/wix3
        public void Burn_AutomaticSlipstreamInstallUninstall()
        {
            const string originalVersion = "1.0.0.0";
            const string patchedVersion = "1.0.1.0";

            // Build the packages.
            string packageA = this.GetPackageA().Output;
            string packageAUpdate = this.GetPackageAv101().Output;
            string packageB = this.GetPackageB().Output;
            string packageBUpdate = new PackageBuilder(this, "B") { PreprocessorVariables = new Dictionary<string, string>() { { "Version", patchedVersion} }, NeverGetsInstalled = true }.Build().Output;
            string patchA = new PatchBuilder(this, "PatchA") { PreprocessorVariables = new Dictionary<string, string>() { { "Version", patchedVersion } }, TargetPaths = new string[] { packageA, packageB }, UpgradePaths = new string[] { packageAUpdate, packageBUpdate } }.Build().Output;
            string patchB = new PatchBuilder(this, "PatchB") { PreprocessorVariables = new Dictionary<string, string>() { { "Version", patchedVersion } }, TargetPaths = new string[] { packageA, packageB }, UpgradePaths = new string[] { packageAUpdate, packageBUpdate } }.Build().Output;

            // Create the named bind paths to the packages.
            Dictionary<string, string> bindPaths = new Dictionary<string, string>();
            bindPaths.Add("packageA", packageA);
            bindPaths.Add("packageB", packageB);
            bindPaths.Add("patchA", patchA);
            bindPaths.Add("patchB", patchB);

            string bundleC = new BundleBuilder(this, "BundleC") { BindPaths = bindPaths, Extensions = Extensions }.Build().Output;
            BundleInstaller install = new BundleInstaller(this, bundleC).Install();

            using (RegistryKey root = this.GetTestRegistryRoot())
            {
                // Product A should've slipstreamed both patches.
                string actualVersion = root.GetValue("A") as string;
                Assert.Equal(patchedVersion, actualVersion);

                actualVersion = root.GetValue("A2") as string;
                Assert.Equal(patchedVersion, actualVersion);

                // Product B should've only slipstreamed patch B.
                actualVersion = root.GetValue("B") as string;
                Assert.Equal(originalVersion, actualVersion);

                actualVersion = root.GetValue("B2") as string;
                Assert.Equal(patchedVersion, actualVersion);
            }

            install.Uninstall();

            Assert.True(null == this.GetTestRegistryRoot(), "Test registry key should have been removed during uninstall.");

            this.Complete();
        }
コード例 #9
0
        public void Patching_Builder_Patch_TooSmallTargetVersion()
        {
            var builder = new PatchBuilder(new TestComponent());

            try
            {
                // ACTION
                builder.Patch("1.0", "1.0", "2020-10-20", "MyComp desc");
                Assert.Fail();
            }
            catch (InvalidPatchException e)
            {
                // ASSERT
                Assert.AreEqual(PatchErrorCode.TooSmallTargetVersion, e.ErrorCode);
                Assert.AreEqual("MyComp: 1.0 <= v < 1.0 --> 1.0", e.Patch.ToString());
            }
        }
コード例 #10
0
        public override void Initialize()
        {
            base.Initialize();

            var progress = new Progress <BuilderProgress>();

            progress.ProgressChanged += ProgressChanged;

            _context                   = new AdminPatchContext(CurrentWindow.AdminSettings, progress);
            _context.Logger            = new SimpleLogger(_context.FileSystem, CurrentWindow.AdminSettings.GetLogsFilePath(), CurrentWindow.AdminSettings.DebugMode);
            _context.Serializer        = new JsonSerializer();
            _context.LocalizedMessages = CurrentWindow.Localization;

            _builder = new PatchBuilder(_context);

            InitializePatches();
        }
コード例 #11
0
        public void Patching_Builder_Dependency_Shared()
        {
            var patchBuilder = new PatchBuilder(new TestComponent());
            var depBuilder   = new DependencyBuilder()
                               .Dependency("C3", "3.0")
                               .Dependency("C4", "4.0");

            // ACTION
            patchBuilder.Patch("1.0", "2.0", "2020-10-20", "desc")
            .DependsOn(depBuilder)
            .Action();

            // ASSERT
            var patch  = patchBuilder.GetPatches()[0] as SnPatch;
            var actual = DependenciesToString(patch?.Dependencies ?? new Dependency[0]);

            Assert.AreEqual("C3: 3.0 <= v | C4: 4.0 <= v", actual);
        }
コード例 #12
0
ファイル: PatchingDemo.cs プロジェクト: onpoc/sensenet
        public override void AddPatches(PatchBuilder builder)
        {
            var dependencies = new DependencyBuilder(builder)
                               .Dependency("SenseNet.Services", "7.7.9");

            builder.Patch("1.0", "1.1", "2020-02-10", "Feature1's PATCH to v1.1 description")
            .DependsOn(dependencies)
            .Action(context =>
            {
                var oldFolderName = "GyebiTesztel_v1.0";
                var newFolderName = "GyebiTesztel_v1.1";
                var newContent    = Content.Load($"/Root/{newFolderName}");
                if (newContent != null)
                {
                    return;
                }
                var oldContent = Content.Load($"/Root/{oldFolderName}");
                if (oldContent != null)
                {
                    oldContent.ContentHandler.Name = newFolderName;
                    oldContent.Save();
                }
                else
                {
                    var parent = Node.LoadNode("/Root");
                    newContent = Content.CreateNew("SystemFolder", parent, newFolderName);
                    newContent.Save();
                }
            });

            builder.Install("1.1", "2020-02-10", "My feature Feature1 description")
            .DependsOn(dependencies)
            .Action((context) =>
            {
                var folderName = "GyebiTesztel_v1.1";
                var content    = Content.Load($"/Root/{folderName}");
                if (content == null)
                {
                    var parent = Node.LoadNode("/Root");
                    content    = Content.CreateNew("SystemFolder", parent, folderName);
                    content.Save();
                }
            });
        }
コード例 #13
0
ファイル: Burn.PatchTests.cs プロジェクト: zooba/wix3
        public void Burn_BuildNonSpecificPatches()
        {
            string patchedVersion = "1.0.1.0";
            string[] extensions = new string[] { "WixBalExtension", "WixTagExtension", };

            // Build the packages.
            string packageA = new PackageBuilder(this, "A") { Extensions = extensions }.Build().Output;
            string packageAUpdate = new PackageBuilder(this, "A") { Extensions = extensions, PreprocessorVariables = new Dictionary<string, string>() { { "Version", patchedVersion } }, NeverGetsInstalled = true }.Build().Output;
            string patchA = new PatchBuilder(this, "PatchA") { Extensions = extensions, TargetPath = packageA, UpgradePath = packageAUpdate }.Build().Output;
            string patchB = new PatchBuilder(this, "PatchB") { Extensions = extensions, TargetPath = packageA, UpgradePath = packageAUpdate }.Build().Output;
            string patchC = new PatchBuilder(this, "PatchC") { Extensions = extensions, TargetPath = packageA, UpgradePath = packageAUpdate }.Build().Output;

            // Build the bundles.
            Dictionary<string, string> bindPaths = new Dictionary<string, string>();
            bindPaths.Add("packageA", packageA);
            bindPaths.Add("patchA", patchA);
            bindPaths.Add("patchB", patchB);
            bindPaths.Add("patchC", patchC);

            string bundleA = new BundleBuilder(this, "BundleA") { BindPaths = bindPaths, Extensions = extensions }.Build().Output;
            WixTest.BundleBuilder bundleAPatch = new BundleBuilder(this, "PatchBundleA") { BindPaths = bindPaths, Extensions = extensions, PreprocessorVariables = new Dictionary<string, string>() { { "Version", patchedVersion } } }.Build();
            WixTest.BundleBuilder bundleBPatch = new BundleBuilder(this, "PatchBundleB") { BindPaths = bindPaths, Extensions = extensions, PreprocessorVariables = new Dictionary<string, string>() { { "Version", patchedVersion } } }.Build();
            WixTest.BundleBuilder bundleCPatch = new BundleBuilder(this, "PatchBundleC") { BindPaths = bindPaths, Extensions = extensions, PreprocessorVariables = new Dictionary<string, string>() { { "Version", patchedVersion } } }.Build();

            // Disassemble the patch bundles and check for PatchTargetCode elements.
            XmlNodeList nodes = PatchTests.GetPatchTargetCodes(bundleAPatch);
            Assert.Equal(1, nodes.Count);
            Assert.True(nodes.OfType<XmlElement>().Any(elem => elem.HasAttribute("Product") && "yes".Equals(elem.Attributes["Product"].Value)));

            nodes = PatchTests.GetPatchTargetCodes(bundleBPatch);
            Assert.Equal(2, nodes.Count);
            Assert.True(nodes.OfType<XmlElement>().Any(elem => elem.HasAttribute("Product") && "yes".Equals(elem.Attributes["Product"].Value)));
            Assert.True(nodes.OfType<XmlElement>().Any(elem => elem.HasAttribute("Product") && "no".Equals(elem.Attributes["Product"].Value)));

            nodes = PatchTests.GetPatchTargetCodes(bundleCPatch);
            Assert.Equal(0, nodes.Count);

            this.Complete();
        }
コード例 #14
0
        public void Patching_Builder_Dependency_Duplicated()
        {
            var patchBuilder = new PatchBuilder(new TestComponent());
            var depBuilder   = new DependencyBuilder()
                               .Dependency("C3", "3.0")
                               .Dependency("C2", "4.0");

            try
            {
                // ACTION
                patchBuilder.Patch("1.0", "2.0", "2020-10-20", "desc")
                .DependsOn("C1", "1.0")
                .DependsOn("C2", "2.0")
                .DependsOn(depBuilder)
                .Action();
                Assert.Fail();
            }
            catch (InvalidPatchException e)
            {
                // ASSERT
                Assert.AreEqual(PatchErrorCode.DuplicatedDependency, e.ErrorCode);
                Assert.AreEqual("MyComp: 1.0 <= v < 2.0 --> 2.0", e.Patch.ToString());
            }
        }
コード例 #15
0
        public override void AddPatches(PatchBuilder builder)
        {
            builder.Install("1.0.0", "2020-10-15", "MS SQL data provider extension for the Exclusive lock feature.")
            .ActionOnBefore(context =>
            {
                if (!(DataStore.DataProvider is RelationalDataProviderBase dataProvider))
                {
                    throw new InvalidOperationException("Cannot install MsSqlExclusiveLockComponent because it is " +
                                                        $"incompatible with Data provider {DataStore.DataProvider.GetType().FullName}.");
                }


                try
                {
                    using var ctx = dataProvider.CreateDataContext(CancellationToken.None);
                    ctx.ExecuteNonQueryAsync(MsSqlExclusiveLockDataProvider.CreationScript).GetAwaiter().GetResult();
                }
                catch (Exception ex)
                {
                    context.Log($"Error during installation of MsSqlExclusiveLockComponent: {ex.Message}");
                    throw;
                }
            });
        }
コード例 #16
0
 private JsonMergePatchDocument <NewtonsoftTestModel> GetTestPatch(object patchObject, JsonMergePatchOptions options = null)
 => PatchBuilder.Build <NewtonsoftTestModel>(patchObject, options);
コード例 #17
0
        public void Burn_InstallUninstallPatchBundle()
        {
            const string patchVersion = "1.0.1.0";

            // Build the packages.
            string packageA1 = new PackageBuilder(this, "A").Build().Output;
            string packageA2 = new PackageBuilder(this, "A") { PreprocessorVariables = new Dictionary<string, string>() { { "Version", patchVersion } }, NeverGetsInstalled = true }.Build().Output;

            string packageB1 = new PackageBuilder(this, "B").Build().Output;
            string packageB2 = new PackageBuilder(this, "B") { PreprocessorVariables = new Dictionary<string, string>() { { "Version", patchVersion } }, NeverGetsInstalled = true }.Build().Output;

            string patchB = new PatchBuilder(this, "PatchB") { PreprocessorVariables = new Dictionary<string, string>() { { "Version", patchVersion } }, TargetPath = packageB1, UpgradePath = packageB2 }.Build().Output;

            PatchBuilder patchBuilderAB = new PatchBuilder(this, "PatchAB") { PreprocessorVariables = new Dictionary<string, string>() { { "Version", patchVersion } } };
            patchBuilderAB.TargetPaths = new string[] { packageA1, packageB1 };
            patchBuilderAB.UpgradePaths = new string[] { packageA2, packageB2 };
            string patchAB = patchBuilderAB.Build().Output;

            // Create the named bind paths to the packages.
            Dictionary<string, string> bindPaths = new Dictionary<string, string>();
            bindPaths.Add("packageA", packageA1);
            bindPaths.Add("patchAB", patchAB);
            bindPaths.Add("packageB", packageB1);
            bindPaths.Add("patchB", patchB);

            // Build the bundles.
            string bundleA = new BundleBuilder(this, "BundleA") { BindPaths = bindPaths, Extensions = Extensions }.Build().Output;
            string bundleB = new BundleBuilder(this, "BundleB") { PreprocessorVariables = new Dictionary<string, string>() { { "Version", patchVersion } }, BindPaths = bindPaths, Extensions = Extensions }.Build().Output;

            // Install the msi bundles.
            BundleInstaller installerA = new BundleInstaller(this, bundleA).Install();
            // Test both packages are installed.
            Assert.True(MsiVerifier.IsPackageInstalled(packageA1));
            Assert.True(MsiVerifier.IsPackageInstalled(packageB1));

            // Install the patch bundle.
            //     Slow the caching of patchB to ensure that patchAB finishes caching and needs to wait for patchB to be cached.
            this.SetPackageSlowCache("patchB", 10000);
            BundleInstaller installerB = new BundleInstaller(this, bundleB).Install();

            using (RegistryKey root = this.GetTestRegistryRoot())
            {
                string actualVersion = root.GetValue("A2") as string;
                Assert.Equal(patchVersion, actualVersion);

                actualVersion = root.GetValue("B") as string;
                Assert.Equal(patchVersion, actualVersion);

                actualVersion = root.GetValue("B2") as string;
                Assert.Equal(patchVersion, actualVersion);
            }

            // Attempt to uninstall bundleA.
            installerA.Uninstall();

            // Test that uninstalling bundle A detected and would remove bundle B.
            Assert.True(LogVerifier.MessageInLogFileRegex(installerA.LastLogFile, @"Detected related bundle: \{[0-9A-Za-z\-]{36}\}, type: Patch, scope: PerMachine, version: 1\.0\.1\.0, operation: Remove"));

            // Test both packages are uninstalled.
            Assert.False(MsiVerifier.IsPackageInstalled(packageA1));
            Assert.Null(this.GetTestRegistryRoot());

            this.Complete();
        }
コード例 #18
0
        public void Burn_InstallPatchBundle()
        {
            const string expectedVersion = "1.0.1.0";

            // Build the packages.
            string packageA1 = new PackageBuilder(this, "A")
            {
                Extensions = Extensions
            }.Build().Output;
            string packageA2 = new PackageBuilder(this, "A")
            {
                Extensions = Extensions, PreprocessorVariables = new Dictionary <string, string>()
                {
                    { "Version", expectedVersion }
                }, NeverGetsInstalled = true
            }.Build().Output;
            string packageB = new PackageBuilder(this, "B")
            {
                Extensions = Extensions
            }.Build().Output;
            string patchA = new PatchBuilder(this, "PatchA")
            {
                PreprocessorVariables = new Dictionary <string, string>()
                {
                    { "Version", expectedVersion }
                }, TargetPath = packageA1, UpgradePath = packageA2
            }.Build().Output;

            // Create the named bind paths to the packages.
            Dictionary <string, string> bindPaths = new Dictionary <string, string>();

            bindPaths.Add("packageA", packageA1);
            bindPaths.Add("packageB", packageB);
            bindPaths.Add("patchA", patchA);

            // Build the bundles.
            string bundleF = new BundleBuilder(this, "BundleF")
            {
                BindPaths = bindPaths, Extensions = Extensions
            }.Build().Output;
            string bundleG = new BundleBuilder(this, "BundleG")
            {
                BindPaths = bindPaths, Extensions = Extensions
            }.Build().Output;

            // Install the base bundle and make sure all packages are installed.
            BundleInstaller installerF = new BundleInstaller(this, bundleF).Install();

            Assert.IsTrue(MsiVerifier.IsPackageInstalled(packageA1));
            Assert.IsTrue(MsiVerifier.IsPackageInstalled(packageB));

            // Install patch bundle and make sure all packages are installed.
            BundleInstaller installerG = new BundleInstaller(this, bundleG).Install();

            Assert.IsTrue(MsiVerifier.IsPackageInstalled(packageA1));
            Assert.IsTrue(MsiVerifier.IsPackageInstalled(packageB));
            Assert.IsTrue(MsiUtils.IsPatchInstalled(patchA));

            // Uninstall the base bundle and make sure all packages are uninstalled.
            installerF.Uninstall();
            Assert.IsFalse(MsiVerifier.IsPackageInstalled(packageA1));
            Assert.IsFalse(MsiVerifier.IsPackageInstalled(packageB));
            Assert.IsFalse(MsiUtils.IsPatchInstalled(patchA));

            this.CleanTestArtifacts = true;
        }
コード例 #19
0
        public void Burn_InstallUpgradeSlipstreamBundle()
        {
            const string expectedVersion1 = "1.0.0.0";
            const string expectedVersion2 = "1.0.1.0";

            // Build the packages.
            string packageA = new PackageBuilder(this, "A")
            {
                Extensions = Extensions
            }.Build().Output;
            string packageA1 = new PackageBuilder(this, "A")
            {
                Extensions = Extensions, PreprocessorVariables = new Dictionary <string, string>()
                {
                    { "Version", expectedVersion2 }
                }, NeverGetsInstalled = true
            }.Build().Output;
            string patchA = new PatchBuilder(this, "PatchA")
            {
                PreprocessorVariables = new Dictionary <string, string>()
                {
                    { "Version", expectedVersion2 }
                }, TargetPath = packageA, UpgradePath = packageA1
            }.Build().Output;

            // Create the named bind paths to the packages.
            Dictionary <string, string> bindPaths = new Dictionary <string, string>();

            bindPaths.Add("packageA", packageA);
            bindPaths.Add("patchA", patchA);

            // Build the bundles.
            string bundleA = new BundleBuilder(this, "BundleA")
            {
                BindPaths = bindPaths, Extensions = Extensions
            }.Build().Output;
            string bundleC = new BundleBuilder(this, "BundleC")
            {
                BindPaths = bindPaths, Extensions = Extensions, PreprocessorVariables = new Dictionary <string, string>()
                {
                    { "Version", expectedVersion2 }
                }
            }.Build().Output;

            // Install the base bundle and make sure it's installed.
            BundleInstaller installerA = new BundleInstaller(this, bundleA).Install();

            Assert.IsTrue(MsiVerifier.IsPackageInstalled(packageA));
            using (RegistryKey root = this.GetTestRegistryRoot())
            {
                string actualVersion = root.GetValue("Version") as string;
                Assert.AreEqual(expectedVersion1, actualVersion);
            }

            // Install the upgrade bundle with a slipstreamed patch and make sure the patch is installed.
            // SFBUG:3387046 - Uninstalling bundle registers a dependency on a package
            BundleInstaller installerC = new BundleInstaller(this, bundleC).Install();

            Assert.IsTrue(MsiUtils.IsPatchInstalled(patchA));

            // BundleC doesn't carry the EXE, so make sure it's removed.
            using (RegistryKey root = this.GetTestRegistryRoot())
            {
                Assert.IsNull(root.GetValue("Version"));
            }

            // Repair the upgrade bundle to make sure it does not prompt for source.
            // SFBUG:3386927 - MSIs get removed from cache during upgrade
            installerC.Repair();

            // Uninstall the slipstream bundle and make sure both packages are uninstalled.
            installerC.Uninstall();
            Assert.IsFalse(MsiUtils.IsPatchInstalled(patchA));
            Assert.IsFalse(MsiVerifier.IsPackageInstalled(packageA));

            this.CleanTestArtifacts = true;
        }
コード例 #20
0
        public void Burn_PatchInstallUninstall()
        {
            string originalVersion = "1.0.0.0";
            string patchedVersion  = "1.0.1.0";

            // Build the packages.
            string packageA = new PackageBuilder(this, "A")
            {
                Extensions = WixTests.Extensions
            }.Build().Output;
            string packageAUpdate = new PackageBuilder(this, "A")
            {
                Extensions = WixTests.Extensions, PreprocessorVariables = new Dictionary <string, string>()
                {
                    { "Version", patchedVersion }
                }, NeverGetsInstalled = true
            }.Build().Output;
            string patchA = new PatchBuilder(this, "PatchA")
            {
                Extensions = WixTests.Extensions, TargetPath = packageA, UpgradePath = packageAUpdate
            }.Build().Output;

            // Create the named bind paths to the packages.
            Dictionary <string, string> bindPaths = new Dictionary <string, string>();

            bindPaths.Add("packageA", packageA);
            bindPaths.Add("patchA", patchA);

            string bundleA = new BundleBuilder(this, "BundleA")
            {
                BindPaths = bindPaths, Extensions = Extensions
            }.Build().Output;
            string bundleAPatch = new BundleBuilder(this, "PatchBundleA")
            {
                BindPaths = bindPaths, Extensions = Extensions
            }.Build().Output;

            // Install the unpatched bundle.
            BundleInstaller installA = new BundleInstaller(this, bundleA).Install();

            using (RegistryKey root = this.GetTestRegistryRoot())
            {
                string actualVersion = root.GetValue("A") as string;
                Assert.AreEqual(originalVersion, actualVersion);
            }

            // Install the patch bundle.
            BundleInstaller installAPatch = new BundleInstaller(this, bundleAPatch).Install();

            using (RegistryKey root = this.GetTestRegistryRoot())
            {
                string actualVersion = root.GetValue("A") as string;
                Assert.AreEqual(patchedVersion, actualVersion);
            }

            // Uninstall the patch bundle.
            installAPatch.Uninstall();
            using (RegistryKey root = this.GetTestRegistryRoot())
            {
                string actualVersion = root.GetValue("A") as string;
                Assert.AreEqual(originalVersion, actualVersion);
            }

            installA.Uninstall();
            Assert.IsNull(this.GetTestRegistryRoot(), "Test registry key should have been removed during uninstall.");

            this.CleanTestArtifacts = true;
        }
コード例 #21
0
        public void Burn_PatchTag()
        {
            string originalVersion = "1.0.0.0";
            string patchedVersion  = "1.0.1.0";
            string actualVersion   = null;

            // Build the packages.
            string packageA = new PackageBuilder(this, "A")
            {
                Extensions = WixTests.Extensions
            }.Build().Output;
            string packageAUpdate = new PackageBuilder(this, "A")
            {
                Extensions = WixTests.Extensions, PreprocessorVariables = new Dictionary <string, string>()
                {
                    { "Version", patchedVersion }
                }, NeverGetsInstalled = true
            }.Build().Output;
            string patchA = new PatchBuilder(this, "PatchA")
            {
                Extensions = WixTests.Extensions, TargetPath = packageA, UpgradePath = packageAUpdate
            }.Build().Output;

            // Create the named bind paths to the packages.
            Dictionary <string, string> bindPaths = new Dictionary <string, string>();

            bindPaths.Add("packageA", packageA);
            bindPaths.Add("patchA", patchA);

            string bundleA = new BundleBuilder(this, "BundleA")
            {
                BindPaths = bindPaths, Extensions = WixTests.Extensions
            }.Build().Output;
            string bundleAPatch = new BundleBuilder(this, "PatchBundleA")
            {
                BindPaths = bindPaths, Extensions = WixTests.Extensions, PreprocessorVariables = new Dictionary <string, string>()
                {
                    { "Version", patchedVersion }
                }
            }.Build().Output;

            // Install the unpatched bundle.
            BundleInstaller installA = new BundleInstaller(this, bundleA).Install();

            actualVersion = GetTagVersion("~Burn_PatchTag - Bundle A");
            Assert.AreEqual(originalVersion, actualVersion);
            actualVersion = GetTagVersion("~Burn_PatchTag - A");
            Assert.AreEqual(originalVersion, actualVersion);

            // Install the patch bundle.
            BundleInstaller installAPatch = new BundleInstaller(this, bundleAPatch).Install();

            actualVersion = GetTagVersion("~Burn_PatchTag - Patch Bundle A");
            Assert.AreEqual(patchedVersion, actualVersion);
            actualVersion = GetTagVersion("~Burn_PatchTag - A");
            Assert.AreEqual(patchedVersion, actualVersion);

            // Uninstall the patch bundle.
            installAPatch.Uninstall();
            actualVersion = GetTagVersion("~Burn_PatchTag - A");
            Assert.AreEqual(originalVersion, actualVersion);

            // Uninstall the original bundle and ensure all the tags are gone.
            installA.Uninstall();
            actualVersion = GetTagVersion("~Burn_PatchTag - Bundle A");
            Assert.IsNull(actualVersion);
            actualVersion = GetTagVersion("~Burn_PatchTag - A");
            Assert.IsNull(actualVersion);

            this.CleanTestArtifacts = true;
        }
コード例 #22
0
        public void Burn_InstallUninstallPatchBundle()
        {
            const string patchVersion = "1.0.1.0";

            // Build the packages.
            string packageA1 = new PackageBuilder(this, "A").Build().Output;
            string packageA2 = new PackageBuilder(this, "A")
            {
                PreprocessorVariables = new Dictionary <string, string>()
                {
                    { "Version", patchVersion }
                }, NeverGetsInstalled = true
            }.Build().Output;

            string packageB1 = new PackageBuilder(this, "B").Build().Output;
            string packageB2 = new PackageBuilder(this, "B")
            {
                PreprocessorVariables = new Dictionary <string, string>()
                {
                    { "Version", patchVersion }
                }, NeverGetsInstalled = true
            }.Build().Output;

            string patchB = new PatchBuilder(this, "PatchB")
            {
                PreprocessorVariables = new Dictionary <string, string>()
                {
                    { "Version", patchVersion }
                }, TargetPath = packageB1, UpgradePath = packageB2
            }.Build().Output;

            PatchBuilder patchBuilderAB = new PatchBuilder(this, "PatchAB")
            {
                PreprocessorVariables = new Dictionary <string, string>()
                {
                    { "Version", patchVersion }
                }
            };

            patchBuilderAB.TargetPaths  = new string[] { packageA1, packageB1 };
            patchBuilderAB.UpgradePaths = new string[] { packageA2, packageB2 };
            string patchAB = patchBuilderAB.Build().Output;

            // Create the named bind paths to the packages.
            Dictionary <string, string> bindPaths = new Dictionary <string, string>();

            bindPaths.Add("packageA", packageA1);
            bindPaths.Add("patchAB", patchAB);
            bindPaths.Add("packageB", packageB1);
            bindPaths.Add("patchB", patchB);

            // Build the bundles.
            string bundleA = new BundleBuilder(this, "BundleA")
            {
                BindPaths = bindPaths, Extensions = Extensions
            }.Build().Output;
            string bundleB = new BundleBuilder(this, "BundleB")
            {
                PreprocessorVariables = new Dictionary <string, string>()
                {
                    { "Version", patchVersion }
                }, BindPaths = bindPaths, Extensions = Extensions
            }.Build().Output;

            // Install the msi bundles.
            BundleInstaller installerA = new BundleInstaller(this, bundleA).Install();

            // Test both packages are installed.
            Assert.True(MsiVerifier.IsPackageInstalled(packageA1));
            Assert.True(MsiVerifier.IsPackageInstalled(packageB1));


            // Install the patch bundle.
            //     Slow the caching of patchB to ensure that patchAB finishes caching and needs to wait for patchB to be cached.
            this.SetPackageSlowCache("patchB", 10000);
            BundleInstaller installerB = new BundleInstaller(this, bundleB).Install();

            using (RegistryKey root = this.GetTestRegistryRoot())
            {
                string actualVersion = root.GetValue("A2") as string;
                Assert.Equal(patchVersion, actualVersion);

                actualVersion = root.GetValue("B") as string;
                Assert.Equal(patchVersion, actualVersion);

                actualVersion = root.GetValue("B2") as string;
                Assert.Equal(patchVersion, actualVersion);
            }

            // Attempt to uninstall bundleA.
            installerA.Uninstall();

            // Test that uninstalling bundle A detected and would remove bundle B.
            Assert.True(LogVerifier.MessageInLogFileRegex(installerA.LastLogFile, @"Detected related bundle: \{[0-9A-Za-z\-]{36}\}, type: Patch, scope: PerMachine, version: 1\.0\.1\.0, operation: Remove"));

            // Test both packages are uninstalled.
            Assert.False(MsiVerifier.IsPackageInstalled(packageA1));
            Assert.Null(this.GetTestRegistryRoot());

            this.Complete();
        }
コード例 #23
0
ファイル: Burn.SlipstreamTests.cs プロジェクト: roni8686/wix3
        public void Burn_AutomaticSlipstreamInstallUninstall()
        {
            const string originalVersion = "1.0.0.0";
            const string patchedVersion  = "1.0.1.0";

            // Build the packages.
            string packageA       = this.GetPackageA().Output;
            string packageAUpdate = this.GetPackageAv101().Output;
            string packageB       = this.GetPackageB().Output;
            string packageBUpdate = new PackageBuilder(this, "B")
            {
                PreprocessorVariables = new Dictionary <string, string>()
                {
                    { "Version", patchedVersion }
                }, NeverGetsInstalled = true
            }.Build().Output;
            string patchA = new PatchBuilder(this, "PatchA")
            {
                PreprocessorVariables = new Dictionary <string, string>()
                {
                    { "Version", patchedVersion }
                }, TargetPaths = new string[] { packageA, packageB }, UpgradePaths = new string[] { packageAUpdate, packageBUpdate }
            }.Build().Output;
            string patchB = new PatchBuilder(this, "PatchB")
            {
                PreprocessorVariables = new Dictionary <string, string>()
                {
                    { "Version", patchedVersion }
                }, TargetPaths = new string[] { packageA, packageB }, UpgradePaths = new string[] { packageAUpdate, packageBUpdate }
            }.Build().Output;

            // Create the named bind paths to the packages.
            Dictionary <string, string> bindPaths = new Dictionary <string, string>();

            bindPaths.Add("packageA", packageA);
            bindPaths.Add("packageB", packageB);
            bindPaths.Add("patchA", patchA);
            bindPaths.Add("patchB", patchB);

            string bundleC = new BundleBuilder(this, "BundleC")
            {
                BindPaths = bindPaths, Extensions = Extensions
            }.Build().Output;
            BundleInstaller install = new BundleInstaller(this, bundleC).Install();

            using (RegistryKey root = this.GetTestRegistryRoot())
            {
                // Product A should've slipstreamed both patches.
                string actualVersion = root.GetValue("A") as string;
                Assert.Equal(patchedVersion, actualVersion);

                actualVersion = root.GetValue("A2") as string;
                Assert.Equal(patchedVersion, actualVersion);

                // Product B should've only slipstreamed patch B.
                actualVersion = root.GetValue("B") as string;
                Assert.Equal(originalVersion, actualVersion);

                actualVersion = root.GetValue("B2") as string;
                Assert.Equal(patchedVersion, actualVersion);
            }

            install.Uninstall();

            Assert.True(null == this.GetTestRegistryRoot(), "Test registry key should have been removed during uninstall.");

            this.Complete();
        }
コード例 #24
0
        public override void AddPatches(PatchBuilder builder)
        {
            builder.Patch("7.7.11", "7.7.12", "2020-09-7", "Upgrades sensenet content repository.")
            .Action(context =>
            {
                #region CTD changes

                var cb = new ContentTypeBuilder();

                cb.Type("Settings")
                .Field("Description", "LongText")
                .VisibleBrowse(FieldVisibility.Hide)
                .VisibleEdit(FieldVisibility.Show)
                .VisibleNew(FieldVisibility.Show);

                cb.Apply();

                #endregion

                #region Settings Description field changes

                SetSettingsDescription("Indexing", "In this Settings file you can customize the indexing behavior (for example the text extractor used in case of different file types) of the system.");
                SetSettingsDescription("Logging", "Contains logging-related settings, for example which events are sent to the trace. You can control tracing by category: switch on or off writing messages in certain categories to the trace channel.");
                SetSettingsDescription("MailProcessor", "The content list Inbox feature requires an Exchange or POP3 server configuration and other settings related to connecting libraries to a mailbox.");
                SetSettingsDescription("OAuth", "When users log in using one of the configured OAuth providers (like Google or Facebook), these settings control the type and place of the newly created users.");
                SetSettingsDescription("OfficeOnline", "To open or edit Office documents in the browser, the system needs to know the address of the Office Online Server that provides the user interface for the feature. In this section you can configure that and other OOS-related settings.");
                SetSettingsDescription("Sharing", "Content sharing related options.");
                SetSettingsDescription("TaskManagement", "When the Task Management module is installed, this is the place where you can configure the connection to the central task management service.");
                SetSettingsDescription("UserProfile", "When a user is created, and the profile feature is enabled (in the app configuration), they automatically get a profile – a workspace dedicated to the user’s personal documents and tasks. In this setting section you can customize the content type and the place of this profile.");

                void SetSettingsDescription(string name, string description)
                {
                    var settings = Content.Load("/Root/System/Settings/" + name + ".settings");
                    if (settings == null)
                    {
                        return;
                    }
                    settings["Description"] = description;
                    settings.SaveSameVersion();
                }

                #endregion

                #region App changes

                var app1 = Content.Load("/Root/(apps)/Folder/Add");
                if (app1 != null)
                {
                    app1["Scenario"] = string.Empty;
                    app1.SaveSameVersion();
                }

                var app2 = Content.Load("/Root/(apps)/ContentType/Edit");
                if (app2 == null)
                {
                    var parent = RepositoryTools.CreateStructure("/Root/(apps)/ContentType") ??
                                 Content.Load("/Root/(apps)/ContentType");

                    app2 = Content.CreateNew("ClientApplication", parent.ContentHandler, "Edit");
                    app2["DisplayName"]         = "$Action,Edit";
                    app2["Scenario"]            = "ContextMenu";
                    app2["Icon"]                = "edit";
                    app2["RequiredPermissions"] = "See;Open;OpenMinor;Save";
                    app2.Save();

                    // set app permissions
                    var developersGroupId = NodeHead.Get("/Root/IMS/BuiltIn/Portal/Developers")?.Id ?? 0;
                    var aclEditor         = SecurityHandler.SecurityContext.CreateAclEditor();
                    aclEditor
                    .Allow(app2.Id, Identifiers.AdministratorsGroupId,
                           false, PermissionType.RunApplication);
                    if (developersGroupId > 0)
                    {
                        aclEditor.Allow(app2.Id, developersGroupId,
                                        false, PermissionType.RunApplication);
                    }

                    aclEditor.Apply();
                }

                #endregion
            });

            builder.Patch("7.7.12", "7.7.13", "2020-09-23", "Upgrades sensenet content repository.")
            .Action(context =>
            {
                #region String resources

                var rb = new ResourceBuilder();

                rb.Content("CtdResourcesAB.xml")
                .Class("Ctd-BinaryFieldSetting")
                .Culture("en")
                .AddResource("DisplayName", "Binary field")
                .Culture("hu")
                .AddResource("DisplayName", "Bináris mező");

                rb.Content("CtdResourcesCD.xml")
                .Class("Ctd-ChoiceFieldSetting")
                .Culture("en")
                .AddResource("DisplayName", "Choice field")
                .Culture("hu")
                .AddResource("DisplayName", "Választó mező")
                .Class("Ctd-CurrencyFieldSetting")
                .Culture("en")
                .AddResource("DisplayName", "Currency field")
                .Culture("hu")
                .AddResource("DisplayName", "Pénzérték mező")
                .Class("Ctd-DateTimeFieldSetting")
                .Culture("en")
                .AddResource("DisplayName", "DateTime field")
                .Culture("hu")
                .AddResource("DisplayName", "Dátum mező");

                rb.Content("CtdResourcesEF.xml")
                .Class("Ctd-FieldControlTemplate")
                .Culture("en")
                .AddResource("DisplayName", "FieldControlTemplate")
                .AddResource("Description", "A type for FieldControl templates.")
                .Culture("hu")
                .AddResource("DisplayName", "Mező vezérlő sablon")
                .AddResource("Description", "Mező vezérlő sablont tároló fájl")
                .Class("Ctd-FieldControlTemplates")
                .Culture("en")
                .AddResource("DisplayName", "FieldControlTemplates")
                .AddResource("Description", "This is the container type for ContentViews. Instances are allowed only at /Root/Global/fieldcontroltemplates.")
                .Culture("hu")
                .AddResource("DisplayName", "Mező vezérlő sablonok")
                .AddResource("Description", "Mező vezérlő sablonokat tároló mappa. Csak egy lehet, itt: /Root/Global/fieldcontroltemplates.");

                rb.Content("CtdResourcesGH.xml")
                .Class("Ctd-HyperLinkFieldSetting")
                .Culture("en")
                .AddResource("DisplayName", "Hyperlink field")
                .Culture("hu")
                .AddResource("DisplayName", "Hivatkozás mező");


                rb.Content("CtdResourcesIJK.xml")
                .Class("Ctd-Image")
                .Culture("en")
                .AddResource("DisplayName", "Image")
                .AddResource("Name-DisplayName", "Name")
                .Culture("hu")
                .AddResource("DisplayName", "Kép")
                .AddResource("Name-DisplayName", "Név")
                .Class("Ctd-IntegerFieldSetting")
                .Culture("en")
                .AddResource("DisplayName", "Integer field")
                .Culture("hu")
                .AddResource("DisplayName", "Egész szám mező");

                rb.Content("CtdResourcesLM.xml")
                .Class("Ctd-LongTextFieldSetting")
                .Culture("en")
                .AddResource("DisplayName", "Longtext field")
                .Culture("hu")
                .AddResource("DisplayName", "Hosszú szöveges mező");

                rb.Content("CtdResourcesNOP.xml")
                .Class("Ctd-NullFieldSetting")
                .Culture("en")
                .AddResource("DisplayName", "Null field")
                .Culture("hu")
                .AddResource("DisplayName", "Null mező")
                .Class("Ctd-NumberFieldSetting")
                .Culture("en")
                .AddResource("DisplayName", "Number field")
                .Culture("hu")
                .AddResource("DisplayName", "Szám mező")
                .Class("Ctd-PasswordFieldSetting")
                .Culture("en")
                .AddResource("DisplayName", "Password field")
                .Culture("hu")
                .AddResource("DisplayName", "Jelszó mező")
                .Class("Ctd-PermissionChoiceFieldSetting")
                .Culture("en")
                .AddResource("DisplayName", "Permission choice field")
                .Culture("hu")
                .AddResource("DisplayName", "Jogosultság választó mező");

                rb.Content("CtdResourcesRS.xml")
                .Class("Ctd-ReferenceFieldSetting")
                .Culture("en")
                .AddResource("DisplayName", "Reference field")
                .Culture("hu")
                .AddResource("DisplayName", "Referencia mező")
                .Class("Ctd-ShortTextFieldSetting")
                .Culture("en")
                .AddResource("DisplayName", "ShortText field")
                .Culture("hu")
                .AddResource("DisplayName", "Rövid szöveges mező");

                rb.Content("CtdResourcesTZ.xml")
                .Class("Ctd-Workspace")
                .Culture("en")
                .AddResource("Name-DisplayName", "Name")
                .Culture("hu")
                .AddResource("Name-DisplayName", "Név")
                .Class("Ctd-TextFieldSetting")
                .Culture("en")
                .AddResource("DisplayName", "Text field")
                .Culture("hu")
                .AddResource("DisplayName", "Szöveges mező")
                .Class("Ctd-UserControl")
                .Culture("en")
                .AddResource("DisplayName", "User control")
                .AddResource("Description", "A type for storing ASP.NET user controls.")
                .Culture("hu")
                .AddResource("DisplayName", "Egyéni vezérlőelem")
                .AddResource("Description", "ASP.NET user control tárolására.")
                .Class("Ctd-ViewBase")
                .Culture("en")
                .AddResource("DisplayName", "View base")
                .AddResource("Description", "An abstract type for ContentList views.")
                .AddResource("IsDefault-DisplayName", "Default")
                .AddResource("IsDefault-Description",
                             "Whether this is the default view on the parent ContentList.")
                .AddResource("Template-DisplayName", "Markup template")
                .AddResource("Template-Description", "The Xslt template used to generate the view.")
                .AddResource("FilterXml-DisplayName", "Filtering")
                .AddResource("FilterXml-Description", "Define filtering rules for the view.")
                .AddResource("EnableAutofilters-DisplayName", "Enable autofilters")
                .AddResource("EnableAutofilters-Description",
                             "If autofilters are enabled system content will be filtered from the query.")
                .AddResource("EnableLifespanFilter-DisplayName", "Enable lifespan filter")
                .AddResource("EnableLifespanFilter-Description",
                             "If lifespan filter is enabled only valid content will be in the result.")
                .AddResource("Hidden-Description",
                             "The view won't show in the selector menu if checked. (If unsure, leave unchecked).")
                .AddResource("QueryTop-DisplayName", "Top")
                .AddResource("QueryTop-Description",
                             "If you do not want to display all content please specify here a value greater than 0.")
                .AddResource("QuerySkip-DisplayName", "Skip")
                .AddResource("QuerySkip-Description",
                             "If you do not want to display the first several content please specify here a value greater than 0.")
                .AddResource("Icon-DisplayName", "Icon identifier")
                .AddResource("Icon-Description", "The string identifier of the View's icon.")
                .Culture("hu")
                .AddResource("DisplayName", "View base")
                .AddResource("Description", "Minden view (listanézet) őse.")
                .AddResource("IsDefault-DisplayName", "Alapértelmezett")
                .AddResource("IsDefault-Description", "Legyen ez az alapértelmezett listanézet..")
                .AddResource("Template-DisplayName", "Sablon")
                .AddResource("Template-Description", "A listát generáló xslt sablon.")
                .AddResource("FilterXml-DisplayName", "Szűrés")
                .AddResource("FilterXml-Description", "A listanézet szűrési feltételei.")
                .AddResource("EnableAutofilters-DisplayName", "Automata szűrések bekapcsolása")
                .AddResource("EnableAutofilters-Description",
                             "Ha be van kapcsolva, a rendszer fájlok kiszűrésre kerülnek.")
                .AddResource("EnableLifespanFilter-DisplayName", "Élettartam szűrés")
                .AddResource("EnableLifespanFilter-Description",
                             "Ha be van kapcsolva, akkor csak az időben aktuális elemek jelennek meg.")
                .AddResource("Hidden-Description",
                             "Ha be van pipálva, akkor a listanézet nem jelenik meg a választhatók között a felületen.")
                .AddResource("QueryTop-DisplayName", "Elemszám")
                .AddResource("QueryTop-Description",
                             "Ha nem akarja az összes elemet megjeleníteni, írjon be egy nullánál nagyobb számot.")
                .AddResource("QuerySkip-DisplayName", "Kihagyott elemek")
                .AddResource("QuerySkip-Description",
                             "Ha a lista első valahány elemét ki szeretné hagyni a megjelenítésből, írja be az elhagyni kívánt elemek számát.")
                .AddResource("Icon-DisplayName", "Ikon azonosító")
                .AddResource("Icon-Description", "Név amely a listanézet ikonját azonosítja.")
                .Class("Ctd-WebContent")
                .Culture("en")
                .AddResource("DisplayName", "Web Content (structured web content)")
                .AddResource("Description", "Web Content is the base type for structured web content.")
                .AddResource("ReviewDate-DisplayName", "Review date")
                .AddResource("ReviewDate-Description", "")
                .AddResource("ArchiveDate-DisplayName", "Archive date")
                .AddResource("ArchiveDate-Description", "")
                .Culture("hu")
                .AddResource("DisplayName", "Webes tartalom")
                .AddResource("Description", "")
                .AddResource("ReviewDate-DisplayName", "Ellenőrzés dátuma")
                .AddResource("ReviewDate-Description", "")
                .AddResource("ArchiveDate-DisplayName", "Archiválás dátuma")
                .AddResource("ArchiveDate-Description", "")
                .Class("Ctd-XmlFieldSetting")
                .Culture("en")
                .AddResource("DisplayName", "Xml field")
                .Culture("hu")
                .AddResource("DisplayName", "Xml mező")
                .Class("Ctd-XsltApplication")
                .Culture("en")
                .AddResource("DisplayName", "Xslt application")
                .AddResource("Description", "Xslt rendering application.")
                .AddResource("Binary-DisplayName", "Xslt template")
                .AddResource("Binary-Description", "Upload or enter the Xslt template to be used in rendering.")
                .AddResource("MimeType-DisplayName", "MIME type")
                .AddResource("MimeType-Description",
                             "Sets HTTP MIME type of the output stream. Default value: application/xml.")
                .AddResource("OmitXmlDeclaration-DisplayName", "OmitXmlDeclaration")
                .AddResource("OmitXmlDeclaration-Description",
                             "Sets a value indicating whether to write XML declaration.")
                .AddResource("ResponseEncoding-DisplayName", "Response encoding")
                .AddResource("ResponseEncoding-Description",
                             "Sets the text encoding to use. Default value: UTF-8.")
                .AddResource("WithChildren-DisplayName", "With children")
                .AddResource("WithChildren-Description",
                             "Sets a value indicating whether to render content with all children Default value: true.")
                .AddResource("Cacheable-DisplayName", "Application is cached")
                .AddResource("Cacheable-Description",
                             "If set the output of the application will be cached. <div class='ui-helper-clearfix sn-dialog-editportlet-warning'><img class='sn-icon sn-icon16 sn-floatleft' src='/Root/Global/images/icons/16/warning.png' /><i>Switching off application cache may cause performance issues!</i></div>")
                .AddResource("CacheableForLoggedInUser-DisplayName",
                             "Application is cached for logged in users")
                .AddResource("CacheableForLoggedInUser-Description",
                             "If set the output of the application will be cached for logged in users. <div class='ui-helper-clearfix sn-dialog-editportlet-warning'><img class='sn-icon sn-icon16 sn-floatleft' src='/Root/Global/images/icons/16/warning.png' /><i>Switching off application cache may cause performance issues!</i></div>")
                .AddResource("CacheByPath-DisplayName", "Request path influences caching")
                .AddResource("CacheByPath-Description",
                             "Defines whether the requested content path is included in the cache key. When unchecked application output is preserved regardless of the page's current context content or request path. Check it if you want to cache application output depending on the requested context content.")
                .AddResource("CacheByParams-DisplayName", "Url query params influence caching")
                .AddResource("CacheByParams-Description",
                             "Defines whether the url query params are also included in the cache key. When unchecked application output is preserved regardless of changing url params.")
                .AddResource("CacheByLanguage-DisplayName", "Language influences caching")
                .AddResource("CacheByLanguage-Description",
                             "Defines whether the language code is also included in the cache key. When unchecked application output is preserved regardless of the language that the users use to browse the site.")
                .AddResource("CacheByHost-DisplayName", "Host influences caching")
                .AddResource("CacheByHost-Description",
                             "Defines whether the URL-host (e.g. 'example.com') is also included in the cache key. When unchecked application output is preserved regardless of the host that the users use to browse the site.")
                .AddResource("AbsoluteExpiration-DisplayName", "Absolute expiration")
                .AddResource("AbsoluteExpiration-Description",
                             "Given in seconds. The application will be refreshed periodically with the given time period. -1 means that the value is defined by 'AbsoluteExpirationSeconds' setting in the web.config.")
                .AddResource("SlidingExpirationMinutes-DisplayName", "Sliding expiration")
                .AddResource("SlidingExpirationMinutes-Description",
                             "Given in seconds. The application is refreshed when it has not been accessed for the given seconds. -1 means that the value is defined by 'SlidingExpirationSeconds' setting in the web.config.")
                .AddResource("CustomCacheKey-DisplayName", "Custom cache key")
                .AddResource("CustomCacheKey-Description",
                             "Defines a custom cache key independent of requested path and query params. Useful when the same static output is rendered at various pages. <div class='ui-helper-clearfix sn-dialog-editportlet-warning'><img class='sn-icon sn-icon16 sn-floatleft' src='/Root/Global/images/icons/16/warning.png' /><i>For experts only! Leave empty if unsure.</i></div>")
                .Culture("hu")
                .AddResource("DisplayName", "Xslt alkalmazás")
                .AddResource("Description",
                             "Alkalmazás, amely XSLT segítségével jeleníti meg az aktuális tartalmat.")
                .AddResource("Binary-DisplayName", "Xslt sablon")
                .AddResource("Binary-Description", "Adja meg az xslt sablont a megjelenítéshez.")
                .AddResource("MimeType-DisplayName", "MIME type")
                .AddResource("MimeType-Description",
                             "Beállítja a kimeneti stream HTTP MIME type-ját. Alapértelmezett érték: <i>alkalmazás/xml</i>.")
                .AddResource("OmitXmlDeclaration-DisplayName", "Xml deklaráció kihagyása")
                .AddResource("OmitXmlDeclaration-Description",
                             "Megadhatja, hogy kihagyjuk-e az xml deklarációt.")
                .AddResource("ResponseEncoding-DisplayName", "Kimeneti stream kódolás")
                .AddResource("ResponseEncoding-Description",
                             "Beállítja a szöveg kódolását. Alapértelmezett érték: <i>UTF-8</i>.")
                .AddResource("WithChildren-DisplayName", "Gyermek tartalmak")
                .AddResource("WithChildren-Description",
                             "Ha be van állítva, a gyermek elemek is szerepelni fognak az oldalon.")
                .AddResource("Cacheable-DisplayName", "Az oldal kerüljön be a gyorsítótárba")
                .AddResource("Cacheable-Description",
                             "Ha be van állítva, az oldal kimenete bekerül a gyorsítótárba<div class='ui-helper-clearfix sn-dialog-editportlet-warning'><img class='sn-icon sn-icon16 sn-floatleft' src='/Root/Global/images/icons/16/warning.png' /><i>Ennek kikapcsolása nagy terhelés alatt sebesség-problémákat okozhat!</i></div>")
                .AddResource("CacheableForLoggedInUser-DisplayName",
                             "Az oldal kerüljön be a gyorsítótárba belépett felhasználók számára.")
                .AddResource("CacheableForLoggedInUser-Description",
                             "Ha be van állítva, az oldal kimenete bekerül a gyorsítótárba belépett felhasználók számára. <div class='ui-helper-clearfix sn-dialog-editportlet-warning'><img class='sn-icon sn-icon16 sn-floatleft' src='/Root/Global/images/icons/16/warning.png' /><i>Ennek kikapcsolása nagy terhelés alatt sebesség-problémákat okozhat!</i></div>")
                .AddResource("CacheByPath-DisplayName", "Az aktuális tartalom befolyásolja a cache-elést")
                .AddResource("CacheByPath-Description",
                             "Ha be van állítva, a kért tartalom útvonala (Path) befolyásolja a gyorsítótárat. Ha nincs, az oldal kimenete ugyanaz lesz, függetlenül az aktuális tartalomtól.")
                .AddResource("CacheByParams-DisplayName", "URL paraméterek befolyásolják a gyorsítótárat")
                .AddResource("CacheByParams-Description",
                             "Ha nincs bekapcsolva, az oldal kimenete ugyanaz lesz, függetlenül az URL paraméterektől.")
                .AddResource("CacheByLanguage-DisplayName", "A nyelv befolyásolja a gyorsítótárat")
                .AddResource("CacheByLanguage-Description",
                             "Ha nincs bekapcsolva, az oldal kimenete ugyanaz lesz, függetlenül attól, hogy a felhasználó milyen nyelven nézi az oldalt.")
                .AddResource("CacheByHost-DisplayName", "A host befolyásolja a gyorsítótárat")
                .AddResource("CacheByHost-Description",
                             "Ha nincs bekapcsolva, az oldal kimenete ugyanaz lesz, függetlenül attól, hogy a felhasználó milyen url-host-ról nézi az oldalt.")
                .AddResource("AbsoluteExpiration-DisplayName", "Abszolút gyorsítótár lejárat")
                .AddResource("AbsoluteExpiration-Description",
                             "Másodpercben megadott lejárat. Az oldal rendszeresen frissülni fog a megadott idő után. <br />-1 azt jelenti, hogy az értéket az <i>AbsoluteExpirationSeconds</i> web.config beállítás határozza meg.")
                .AddResource("SlidingExpirationMinutes-DisplayName", "Csúszó gyorsítótár lejárat")
                .AddResource("SlidingExpirationMinutes-Description",
                             "Másodpercben megadott lejárat. Az oldal frissülni fog, ha nem érkezett rá kérés a megadott időn belül. <br />-1 azt jelenti, hogy az értéket az <i>SlidingExpirationSeconds</i> web.config beállítás határozza meg.")
                .AddResource("CustomCacheKey-DisplayName", "Egyedi gyorsítótár (cache) kulcs")
                .AddResource("CustomCacheKey-Description",
                             "Megadhat egyedi gyorsítótár kulcsot, függetlenül az aktuális tartalomtól és URL paraméterektől. Akkor érdemes használni, ha ugyanazt a statikus tartalmat szeretné megjeleníteni több különböző oldalon. <div class='ui-helper-clearfix sn-dialog-editportlet-warning'><img class='sn-icon sn-icon16 sn-floatleft' src='/Root/Global/images/icons/16/warning.png' /><i>Csak adminisztrátoroknak. Hagyja üresen, ha nem biztos a dologban.</i></div>")
                .Class("Ctd-YesNoFieldSetting")
                .Culture("en")
                .AddResource("DisplayName", "Yes/No field")
                .Culture("hu")
                .AddResource("DisplayName", "Igen/nem mező");

                rb.Apply();

                #endregion

                #region CTD changes

                var cb = new ContentTypeBuilder();

                cb.Type("CalendarEvent")
                .Field("StartDate")
                .DefaultValue("@@currenttime@@")
                .Field("EndDate")
                .DefaultValue("@@currenttime@@");
                cb.Type("GenericContent")
                .Field("ValidFrom")
                .DefaultValue("@@currenttime@@")
                .Field("ValidTill")
                .DefaultValue("@@currenttime@@");

                cb.Type("Link")
                .Field("Url")
                .DefaultValue("https://");

                cb.Type("User")
                .Field("LoginName")
                .VisibleEdit(FieldVisibility.Hide)
                .Field("Email")
                .VisibleBrowse(FieldVisibility.Show)
                .VisibleEdit(FieldVisibility.Hide)
                .VisibleNew(FieldVisibility.Show)
                .Field("BirthDate")
                .DefaultValue("@@currenttime@@");

                cb.Type("Group")
                .Field("AllRoles")
                .VisibleBrowse(FieldVisibility.Hide)
                .VisibleEdit(FieldVisibility.Hide)
                .VisibleNew(FieldVisibility.Hide)
                .Field("DirectRoles")
                .VisibleBrowse(FieldVisibility.Hide)
                .VisibleEdit(FieldVisibility.Hide)
                .VisibleNew(FieldVisibility.Hide);

                cb.Apply();

                #endregion

                #region Permission changes

                SecurityHandler.SecurityContext.CreateAclEditor()
                .Allow(NodeHead.Get("/Root/Localization").Id, Identifiers.OwnersGroupId, false,
                       PermissionType.Save, PermissionType.Delete)
                .Apply();

                #endregion
            });

            builder.Patch("7.7.13", "7.7.14", "2020-11-19", "Upgrades sensenet content repository.")
            .Action(context =>
            {
                #region CTD changes

                var cb = new ContentTypeBuilder();

                cb.Type("ListItem")
                .Field("ModifiedBy")
                .VisibleEdit(FieldVisibility.Hide);

                cb.Type("User")
                .Field("BirthDate")
                .DefaultValue("");

                cb.Apply();

                #endregion
            });

            builder.Patch("7.7.14", "7.7.16", "2020-12-08", "Upgrades sensenet content repository.")
            .Action(context =>
            {
                #region CTD changes

                var cb = new ContentTypeBuilder();

                // We can set the new regex only if the current regex is the old default
                // (otherwise we do not want to overwrite a custom regex).
                // NOTE: in the old regex below the & character appears as is (in the middle
                // of the first line), but in the new const we had to replace it with &amp;
                // to let the patch algorithm set the correct value in the XML.

                const string oldUrlRegex = "^(http|https)\\://([a-zA-Z0-9\\.\\-]+(\\:[a-zA-Z0-9\\.&%\\$\\-]+)*@)*((25[0-5]|" +
                                           "2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9])\\.(25[0-5]|2[0-4][0-9]|[0-1]{1}" +
                                           "[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}" +
                                           "[0-9]{1}|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9])|" +
                                           "localhost|([a-zA-Z0-9\\-]+\\.)*[a-zA-Z0-9\\-]+(\\.(com|edu|gov|int|mil|net|org|biz|" +
                                           "arpa|info|name|pro|aero|coop|museum|hu|[a-zA-Z]{2})){0,1})(\\:[0-9]+)*((\\#|/)($|" +
                                           "[a-zA-Z0-9\\.\\,\\?\\'\\\\\\+&%\\$#\\=~_\\-]+))*$";
                const string newUrlRegex = "^(https?|ftp)\\://([a-zA-Z0-9\\.\\-]+(\\:[a-zA-Z0-9\\.&amp;%\\$\\-]+)*@)*((25[0-5]|" +
                                           "2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9])\\.(25[0-5]|2[0-4][0-9]|[0-1]{1}" +
                                           "[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}" +
                                           "[0-9]{1}|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9])|" +
                                           "localhost|([a-zA-Z0-9\\-]+\\.)*[a-zA-Z0-9\\-]+(\\.(com|edu|gov|int|mil|net|org|biz|" +
                                           "arpa|info|name|pro|aero|coop|museum|hu|[a-zA-Z]{2})){0,1})(\\:[0-9]+)*" +
                                           "(\\/[\\w\\-\\@\\/\\(\\)]*){0,1}((\\?|\\#)(($|[\\w\\.\\,\\'\\\\\\+&amp;" +
                                           "%\\$#\\=~_\\-\\(\\)]+)*)){0,1}$";

                var currentRegex =
                    ((ShortTextFieldSetting)ContentType.GetByName("Link").GetFieldSettingByName("Url")).Regex;

                // replace the regex only if it was the original default
                if (string.Equals(oldUrlRegex, currentRegex, StringComparison.Ordinal))
                {
                    cb.Type("Link")
                    .Field("Url")
                    .Configure("Regex", newUrlRegex);
                }

                cb.Apply();

                #endregion

                #region Content changes

                // create the new public admin user
                if (User.PublicAdministrator == null)
                {
                    var publicAdmin          = Content.CreateNew("User", OrganizationalUnit.Portal, "PublicAdmin");
                    publicAdmin["Enabled"]   = true;
                    publicAdmin["FullName"]  = "PublicAdmin";
                    publicAdmin["LoginName"] = "PublicAdmin";
                    publicAdmin.Save();
                }

                #endregion
            });

            builder.Patch("7.7.16", "7.7.17", "2021-01-25", "Upgrades sensenet content repository.")
            .Action(context =>
            {
                #region CTD changes

                const string ctDefaultValue = @"&lt;?xml version=""1.0"" encoding=""utf-8""?&gt;
&lt;ContentType name=""MyType"" parentType=""GenericContent"" handler=""SenseNet.ContentRepository.GenericContent"" xmlns=""http://schemas.sensenet.com/SenseNet/ContentRepository/ContentTypeDefinition""&gt;
  &lt;DisplayName&gt;MyType&lt;/DisplayName&gt;
  &lt;Description&gt;&lt;/Description&gt;
  &lt;Icon&gt;Content&lt;/Icon&gt;
  &lt;AllowIncrementalNaming&gt;true&lt;/AllowIncrementalNaming&gt;
  &lt;AllowedChildTypes&gt;ContentTypeName1,ContentTypeName2&lt;/AllowedChildTypes&gt;
  &lt;Fields&gt;
    &lt;Field name=""ShortTextField"" type=""ShortText""&gt;
      &lt;DisplayName&gt;ShortTextField&lt;/DisplayName&gt;
      &lt;Description&gt;&lt;/Description&gt;
      &lt;Configuration&gt;
        &lt;MaxLength&gt;100&lt;/MaxLength&gt;
        &lt;MinLength&gt;0&lt;/MinLength&gt;
        &lt;Regex&gt;[a-zA-Z0-9]*$&lt;/Regex&gt;
        &lt;ReadOnly&gt;false&lt;/ReadOnly&gt;
        &lt;Compulsory&gt;false&lt;/Compulsory&gt;
        &lt;DefaultValue&gt;&lt;/DefaultValue&gt;
        &lt;VisibleBrowse&gt;Show|Hide&lt;/VisibleBrowse&gt;
        &lt;VisibleEdit&gt;Show|Hide&lt;/VisibleEdit&gt;
        &lt;VisibleNew&gt;Show|Hide&lt;/VisibleNew&gt;
      &lt;/Configuration&gt;
    &lt;/Field&gt;
    &lt;Field name=""LongTextField"" type=""LongText""&gt;
      &lt;DisplayName&gt;LongTextField&lt;/DisplayName&gt;
      &lt;Description&gt;&lt;/Description&gt;
      &lt;Configuration&gt;
        &lt;MaxLength&gt;100&lt;/MaxLength&gt;
        &lt;MinLength&gt;0&lt;/MinLength&gt;
        &lt;TextType&gt;LongText|RichText&lt;/TextType&gt;
        &lt;ReadOnly&gt;false&lt;/ReadOnly&gt;
        &lt;Compulsory&gt;false&lt;/Compulsory&gt;
        &lt;DefaultValue&gt;&lt;/DefaultValue&gt;
        &lt;VisibleBrowse&gt;Show|Hide&lt;/VisibleBrowse&gt;
        &lt;VisibleEdit&gt;Show|Hide&lt;/VisibleEdit&gt;
        &lt;VisibleNew&gt;Show|Hide&lt;/VisibleNew&gt;
      &lt;/Configuration&gt;
    &lt;/Field&gt;
    &lt;Field name=""NumberField"" type=""Number""&gt;
      &lt;DisplayName&gt;NumberField&lt;/DisplayName&gt;
      &lt;Description&gt;&lt;/Description&gt;
      &lt;Configuration&gt;
        &lt;MinValue&gt;0&lt;/MinValue&gt;
        &lt;MaxValue&gt;100.5&lt;/MaxValue&gt;
        &lt;Digits&gt;2&lt;/Digits&gt;
        &lt;ReadOnly&gt;false&lt;/ReadOnly&gt;
        &lt;Compulsory&gt;false&lt;/Compulsory&gt;
        &lt;DefaultValue&gt;&lt;/DefaultValue&gt;
        &lt;VisibleBrowse&gt;Show|Hide&lt;/VisibleBrowse&gt;
        &lt;VisibleEdit&gt;Show|Hide&lt;/VisibleEdit&gt;
        &lt;VisibleNew&gt;Show|Hide&lt;/VisibleNew&gt;
      &lt;/Configuration&gt;
    &lt;/Field&gt;
    &lt;Field name=""IntegerField"" type=""Integer""&gt;
      &lt;DisplayName&gt;IntegerField&lt;/DisplayName&gt;
      &lt;Description&gt;&lt;/Description&gt;
      &lt;Configuration&gt;
        &lt;MinValue&gt;0&lt;/MinValue&gt;
        &lt;MaxValue&gt;100&lt;/MaxValue&gt;
        &lt;ReadOnly&gt;false&lt;/ReadOnly&gt;
        &lt;Compulsory&gt;false&lt;/Compulsory&gt;
        &lt;DefaultValue&gt;&lt;/DefaultValue&gt;
        &lt;VisibleBrowse&gt;Show|Hide&lt;/VisibleBrowse&gt;
        &lt;VisibleEdit&gt;Show|Hide&lt;/VisibleEdit&gt;
        &lt;VisibleNew&gt;Show|Hide&lt;/VisibleNew&gt;
      &lt;/Configuration&gt;
    &lt;/Field&gt;
    &lt;Field name=""BooleanField"" type=""Boolean""&gt;
      &lt;DisplayName&gt;BooleanField&lt;/DisplayName&gt;
      &lt;Description&gt;&lt;/Description&gt;
      &lt;Configuration&gt;
        &lt;ReadOnly&gt;false&lt;/ReadOnly&gt;
        &lt;Compulsory&gt;false&lt;/Compulsory&gt;
        &lt;DefaultValue&gt;&lt;/DefaultValue&gt;
        &lt;VisibleBrowse&gt;Show|Hide&lt;/VisibleBrowse&gt;
        &lt;VisibleEdit&gt;Show|Hide&lt;/VisibleEdit&gt;
        &lt;VisibleNew&gt;Show|Hide&lt;/VisibleNew&gt;
      &lt;/Configuration&gt;
    &lt;/Field&gt;
    &lt;Field name=""ChoiceField"" type=""Choice""&gt;
      &lt;DisplayName&gt;ChoiceField&lt;/DisplayName&gt;
      &lt;Description&gt;&lt;/Description&gt;
      &lt;Configuration&gt;
        &lt;AllowMultiple&gt;false&lt;/AllowMultiple&gt;
        &lt;AllowExtraValue&gt;false&lt;/AllowExtraValue&gt;
        &lt;Options&gt;
          &lt;Option selected=""true""&gt;1&lt;/Option&gt;
          &lt;Option&gt;2&lt;/Option&gt;
        &lt;/Options&gt;
        &lt;ReadOnly&gt;false&lt;/ReadOnly&gt;
        &lt;Compulsory&gt;false&lt;/Compulsory&gt;
        &lt;DefaultValue&gt;&lt;/DefaultValue&gt;
        &lt;VisibleBrowse&gt;Show|Hide&lt;/VisibleBrowse&gt;
        &lt;VisibleEdit&gt;Show|Hide&lt;/VisibleEdit&gt;
        &lt;VisibleNew&gt;Show|Hide&lt;/VisibleNew&gt;
      &lt;/Configuration&gt;
    &lt;/Field&gt;
    &lt;Field name=""DateTimeField"" type=""DateTime""&gt;
      &lt;DisplayName&gt;DateTimeField&lt;/DisplayName&gt;
      &lt;Description&gt;&lt;/Description&gt;
      &lt;Configuration&gt;
        &lt;DateTimeMode&gt;DateAndTime&lt;/DateTimeMode&gt;
        &lt;Precision&gt;Second&lt;/Precision&gt;
        &lt;ReadOnly&gt;false&lt;/ReadOnly&gt;
        &lt;Compulsory&gt;false&lt;/Compulsory&gt;
        &lt;DefaultValue&gt;&lt;/DefaultValue&gt;
        &lt;VisibleBrowse&gt;Show|Hide&lt;/VisibleBrowse&gt;
        &lt;VisibleEdit&gt;Show|Hide&lt;/VisibleEdit&gt;
        &lt;VisibleNew&gt;Show|Hide&lt;/VisibleNew&gt;
      &lt;/Configuration&gt;
    &lt;/Field&gt;
    &lt;Field name=""ReferenceField"" type=""Reference""&gt;
      &lt;DisplayName&gt;ReferenceField&lt;/DisplayName&gt;
      &lt;Description&gt;&lt;/Description&gt;
      &lt;Configuration&gt;
        &lt;AllowMultiple&gt;true&lt;/AllowMultiple&gt;
        &lt;AllowedTypes&gt;
          &lt;Type&gt;Type1&lt;/Type&gt;
          &lt;Type&gt;Type2&lt;/Type&gt;
        &lt;/AllowedTypes&gt;
        &lt;SelectionRoot&gt;
          &lt;Path&gt;/Root/Path1&lt;/Path&gt;
          &lt;Path&gt;/Root/Path2&lt;/Path&gt;
        &lt;/SelectionRoot&gt;
        &lt;DefaultValue&gt;/Root/Path1,/Root/Path2&lt;/DefaultValue&gt;
        &lt;ReadOnly&gt;false&lt;/ReadOnly&gt;
        &lt;Compulsory&gt;false&lt;/Compulsory&gt;
        &lt;VisibleBrowse&gt;Show|Hide&lt;/VisibleBrowse&gt;
        &lt;VisibleEdit&gt;Show|Hide&lt;/VisibleEdit&gt;
        &lt;VisibleNew&gt;Show|Hide&lt;/VisibleNew&gt;
      &lt;/Configuration&gt;
    &lt;/Field&gt;
    &lt;Field name=""BinaryField"" type=""Binary""&gt;
      &lt;DisplayName&gt;BinaryField&lt;/DisplayName&gt;
      &lt;Description&gt;&lt;/Description&gt;
      &lt;Configuration&gt;
        &lt;IsText&gt;true&lt;/IsText&gt;
        &lt;ReadOnly&gt;false&lt;/ReadOnly&gt;
        &lt;Compulsory&gt;false&lt;/Compulsory&gt;
        &lt;DefaultValue&gt;&lt;/DefaultValue&gt;
        &lt;VisibleBrowse&gt;Show|Hide&lt;/VisibleBrowse&gt;
        &lt;VisibleEdit&gt;Show|Hide&lt;/VisibleEdit&gt;
        &lt;VisibleNew&gt;Show|Hide&lt;/VisibleNew&gt;
      &lt;/Configuration&gt;
    &lt;/Field&gt;
  &lt;/Fields&gt;
&lt;/ContentType&gt;";

                var cb = new ContentTypeBuilder();

                cb.Type("ContentType")
                .Field("Binary")
                .DefaultValue(ctDefaultValue);

                cb.Apply();

                #endregion
            });

            builder.Patch("7.7.17", "7.7.18", "2021-02-17", "Upgrades sensenet content repository.")
            .Action(context =>
            {
                #region String resources

                var rb = new ResourceBuilder();

                rb.Content("CtdResourcesQ.xml")
                .Class("Ctd-Query")
                .Culture("en")
                .AddResource("UiFilters-DisplayName", "UI filters")
                .AddResource("UiFilters-Description", "Technical field for filter data.")
                .Culture("hu")
                .AddResource("UiFilters-DisplayName", "UI szűrők")
                .AddResource("UiFilters-Description", "Technikai mező szűrő adatoknak.");

                rb.Content("ActionResources.xml")
                .Class("Action")
                .Culture("en")
                .AddResource("Browse", "Details");

                rb.Apply();

                #endregion

                #region CTD changes

                var cb = new ContentTypeBuilder();

                cb.Type("Query")
                .Field("UiFilters", "LongText")
                .DisplayName("$Ctd-Query,UiFilters-DisplayName")
                .Description("$Ctd-Query,UiFilters-Description")
                .VisibleBrowse(FieldVisibility.Hide)
                .VisibleEdit(FieldVisibility.Hide)
                .VisibleNew(FieldVisibility.Hide);

                cb.Type("File")
                .Field("Size")
                .ControlHint("sn:FileSize");

                cb.Apply();

                #endregion
            });
        }
コード例 #25
0
ファイル: Burn.PatchTests.cs プロジェクト: zooba/wix3
        public void Burn_PatchOnePackageTwoPatches()
        {
            string originalVersion = "1.0.0.0";
            string patchedVersion = "1.0.1.0";

            // Build the packages.
            string packageA = new PackageBuilder(this, "A") { Extensions = WixTests.Extensions }.Build().Output;
            string packageAUpdate = new PackageBuilder(this, "A") { Extensions = WixTests.Extensions, PreprocessorVariables = new Dictionary<string, string>() { { "Version", patchedVersion } }, NeverGetsInstalled = true }.Build().Output;
            string patchA = new PatchBuilder(this, "PatchA") { Extensions = WixTests.Extensions, TargetPath = packageA, UpgradePath = packageAUpdate }.Build().Output;
            string patchA2 = new PatchBuilder(this, "PatchA2") { Extensions = WixTests.Extensions, TargetPath = packageA, UpgradePath = packageAUpdate }.Build().Output;

            // Create the named bind paths to the packages.
            Dictionary<string, string> bindPaths = new Dictionary<string, string>();
            bindPaths.Add("patchA", patchA);
            bindPaths.Add("patchA2", patchA2);

            string bundlePatch = new BundleBuilder(this, "PatchBundleA2") { BindPaths = bindPaths, Extensions = WixTests.Extensions, SuppressPatchSequenceData = true }.Build().Output;

            // Install the original MSI and ensure the registry keys that get patched are as expected.
            MSIExec.InstallProduct(packageA, MSIExec.MSIExecReturnCode.SUCCESS);
            using (RegistryKey root = this.GetTestRegistryRoot())
            {
                string actualVersion = root.GetValue("A") as string;
                Assert.Equal(originalVersion, actualVersion);

                actualVersion = root.GetValue("A2") as string;
                Assert.Equal(originalVersion, actualVersion);
            }

            // Install the bundle of patches and ensure all the registry keys are updated.
            BundleInstaller installPatches = new BundleInstaller(this, bundlePatch).Install();
            using (RegistryKey root = this.GetTestRegistryRoot())
            {
                string actualVersion = root.GetValue("A") as string;
                Assert.Equal(patchedVersion, actualVersion);

                actualVersion = root.GetValue("A2") as string;
                Assert.Equal(patchedVersion, actualVersion);
            }

            // Uninstall the patch bundle and verify the keys go back to original values.
            installPatches.Uninstall();
            using (RegistryKey root = this.GetTestRegistryRoot())
            {
                string actualVersion = root.GetValue("A") as string;
                Assert.Equal(originalVersion, actualVersion);

                actualVersion = root.GetValue("A2") as string;
                Assert.Equal(originalVersion, actualVersion);
            }

            this.Complete();
        }
コード例 #26
0
        /* ============================================================ TOOLS */

        private string PatchesToString(PatchBuilder builder)
        {
            return(string.Join(" | ", builder.GetPatches()));
        }
コード例 #27
0
        public override void AddPatches(PatchBuilder builder)
        {
            builder
            .Install("0.0.4", "2021-06-09", "sensenet WebHooks")
            .DependsOn("SenseNet.Services", "7.7.22")
            .Action(context =>
            {
                #region String resource

                InstallStringResource("CtdResourcesWebHookSubscription.xml");

                #endregion

                #region Install CTD

                InstallCtd("WebHookSubscriptionCtd.xml");

                #endregion

                #region Content items

                CreateWebHooksContainer();

                #endregion
            });

            builder.Patch("0.0.1", "0.0.3", "2021-03-17", "Upgrades the WebHook component")
            .DependsOn("SenseNet.Services", "7.7.19")
            .Action(context =>
            {
                #region String resources

                var rb = new ResourceBuilder();

                rb.Content("CtdResourcesWebHookSubscription.xml")
                .Class("Ctd-WebHookSubscription")
                .Culture("en")
                .AddResource("DisplayName", "Webhook")
                .Culture("hu")
                .AddResource("DisplayName", "Webhook");

                rb.Apply();

                #endregion

                #region CTD changes

                var cb = new ContentTypeBuilder(context.GetService <ILogger <ContentTypeBuilder> >());

                cb.Type("WebHookSubscription")
                .Icon("Settings")
                .Field("WebHookPayload", "LongText")
                .DisplayName("$Ctd-WebHookSubscription,WebHookPayload-DisplayName")
                .Description("$Ctd-WebHookSubscription,WebHookPayload-Description")
                .VisibleBrowse(FieldVisibility.Show)
                .VisibleEdit(FieldVisibility.Show)
                .VisibleNew(FieldVisibility.Show)
                .FieldIndex(10)
                .ControlHint("sn:WebhookPayload")
                .Field("WebHookFilter")
                .FieldIndex(50)
                .Field("WebHookHeaders")
                .FieldIndex(40)
                .Field("Enabled")
                .FieldIndex(90)
                .Field("IsValid")
                .FieldIndex(30)
                .VisibleBrowse(FieldVisibility.Hide)
                .Field("InvalidFields")
                .RemoveConfiguration("FieldIndex")
                .VisibleBrowse(FieldVisibility.Hide)
                .VisibleEdit(FieldVisibility.Hide)
                .VisibleNew(FieldVisibility.Hide)
                .Field("SuccessfulCalls")
                .FieldIndex(20)
                .Field("WebHookHttpMethod")
                .DefaultValue("POST");

                cb.Apply();

                #endregion

                #region Content items

                CreateWebHooksContainer();

                #endregion
            });

            builder.Patch("0.0.3", "0.0.4", "2021-06-09", "Upgrades the WebHook component")
            .DependsOn("SenseNet.Services", "7.7.22")
            .Action(context =>
            {
                // Do nothing, this is just a version update, because the CTD change (richtext type
                // change of the Description field) is already handled by the Services component patch.
            });
        }
        private IInternalJsonMergePatchDocument CreatePatchDocument(Type jsonMergePatchType, Type modelType, JsonElement jsonElement)
        {
            var jsonMergePatchDocument = PatchBuilder.CreatePatchDocument(modelType, jsonElement, base.SerializerOptions, this._jsonMergePatchOptions);

            return(jsonMergePatchDocument);
        }
コード例 #29
0
        private PatchBuilder GetPatchA()
        {
            if (null == this.patchA)
            {
                string packageA = this.GetPackageA().Output;
                string packageAUpdate = this.GetPackageAv101().Output;

                this.patchA = new PatchBuilder(this, "PatchA") { TargetPath = packageA, UpgradePath = packageAUpdate }.Build();
            }

            return this.patchA;
        }
コード例 #30
0
ファイル: Burn.PatchTests.cs プロジェクト: zooba/wix3
        public void Burn_PatchTag()
        {
            string originalVersion = "1.0.0.0";
            string patchedVersion = "1.0.1.0";
            string actualVersion = null;

            // Build the packages.
            string packageA = new PackageBuilder(this, "A") { Extensions = WixTests.Extensions }.Build().Output;
            string packageAUpdate = new PackageBuilder(this, "A") { Extensions = WixTests.Extensions, PreprocessorVariables = new Dictionary<string, string>() { { "Version", patchedVersion } }, NeverGetsInstalled = true }.Build().Output;
            string patchA = new PatchBuilder(this, "PatchA") { Extensions = WixTests.Extensions, TargetPath = packageA, UpgradePath = packageAUpdate }.Build().Output;

            // Create the named bind paths to the packages.
            Dictionary<string, string> bindPaths = new Dictionary<string, string>();
            bindPaths.Add("packageA", packageA);
            bindPaths.Add("patchA", patchA);

            string bundleA = new BundleBuilder(this, "BundleA") { BindPaths = bindPaths, Extensions = WixTests.Extensions }.Build().Output;
            string bundleAPatch = new BundleBuilder(this, "PatchBundleA") { BindPaths = bindPaths, Extensions = WixTests.Extensions, PreprocessorVariables = new Dictionary<string, string>() { { "Version", patchedVersion } } }.Build().Output;

            // Install the unpatched bundle.
            BundleInstaller installA = new BundleInstaller(this, bundleA).Install();
            actualVersion = GetTagVersion("~Burn_PatchTag - Bundle A");
            Assert.Equal(originalVersion, actualVersion);
            actualVersion = GetTagVersion("~Burn_PatchTag - A");
            Assert.Equal(originalVersion, actualVersion);

            // Install the patch bundle.
            BundleInstaller installAPatch = new BundleInstaller(this, bundleAPatch).Install();
            actualVersion = GetTagVersion("~Burn_PatchTag - Patch Bundle A");
            Assert.Equal(patchedVersion, actualVersion);
            actualVersion = GetTagVersion("~Burn_PatchTag - A");
            Assert.Equal(patchedVersion, actualVersion);

            // Uninstall the patch bundle.
            installAPatch.Uninstall();
            actualVersion = GetTagVersion("~Burn_PatchTag - A");
            Assert.Equal(originalVersion, actualVersion);

            // Uninstall the original bundle and ensure all the tags are gone.
            installA.Uninstall();
            actualVersion = GetTagVersion("~Burn_PatchTag - Bundle A");
            Assert.Null(actualVersion);
            actualVersion = GetTagVersion("~Burn_PatchTag - A");
            Assert.Null(actualVersion);

            this.Complete();
        }
コード例 #31
0
ファイル: Burn.SlipstreamTests.cs プロジェクト: bleissem/wix3
        public void Burn_MajorUpgradeWithSlipstream()
        {
            const string originalVersion = "1.0.0.0";
            const string upgradeVersion = "2.0.0.0";
            const string patchedVersion = "2.0.1.0";

            // Build the packages.
            string originalPackageA = this.GetPackageA().Output;
            string upgradePackageA = new PackageBuilder(this, "A") { PreprocessorVariables = new Dictionary<string, string>() { { "Version", upgradeVersion } }, }.Build().Output;
            string packageAUpdate = new PackageBuilder(this, "A") { PreprocessorVariables = new Dictionary<string, string>() { { "Version", patchedVersion } }, NeverGetsInstalled = true }.Build().Output;
            string patchA = new PatchBuilder(this, "PatchA") { PreprocessorVariables = new Dictionary<string, string>() { { "Version", patchedVersion } }, TargetPaths = new string[] { upgradePackageA }, UpgradePaths = new string[] { packageAUpdate } }.Build().Output;

            // Create the named bind paths to the packages in the bundle.
            Dictionary<string, string> bindPaths = new Dictionary<string, string>();
            bindPaths.Add("packageA", upgradePackageA);
            bindPaths.Add("patchA", patchA);

            string bundleA = new BundleBuilder(this, "BundleA") { BindPaths = bindPaths, Extensions = Extensions }.Build().Output;

            // Install the original MSI.
            MSIExec.InstallProduct(originalPackageA, MSIExec.MSIExecReturnCode.SUCCESS);

            Assert.True(MsiVerifier.IsPackageInstalled(originalPackageA));
            using (RegistryKey root = this.GetTestRegistryRoot())
            {
                // Original Product A should be present.
                string actualVersion = root.GetValue("A") as string;
                Assert.Equal(originalVersion, actualVersion);
            }

            // Now install the bundle that should upgrade the MSI and apply the patch.
            BundleInstaller install = new BundleInstaller(this, bundleA).Install();

            Assert.False(MsiVerifier.IsPackageInstalled(originalPackageA));
            Assert.True(MsiVerifier.IsPackageInstalled(upgradePackageA));
            using (RegistryKey root = this.GetTestRegistryRoot())
            {
                // Product A should've slipstreamed with its patch.
                string actualVersion = root.GetValue("A") as string;
                Assert.Equal(patchedVersion, actualVersion);
            }

            install.Uninstall();

            Assert.True(null == this.GetTestRegistryRoot(), "Test registry key should have been removed during uninstall.");

            this.Complete();
        }
コード例 #32
0
        public void Burn_InstallUninstallStickyPatchRelatedBundle()
        {
            const string patchVersion = "1.0.1.0";

            // Build the packages.
            string packageA1 = new PackageBuilder(this, "A").Build().Output;
            string packageA2 = new PackageBuilder(this, "A") { PreprocessorVariables = new Dictionary<string, string>() { { "Version", patchVersion } }, NeverGetsInstalled = true }.Build().Output;
            string packageB1 = new PackageBuilder(this, "B").Build().Output;
            string packageB2 = new PackageBuilder(this, "B") { PreprocessorVariables = new Dictionary<string, string>() { { "Version", patchVersion } }, NeverGetsInstalled = true }.Build().Output;
            string patchA = new PatchBuilder(this, "PatchA")
            {
                PreprocessorVariables = new Dictionary<string, string>() { { "Version", patchVersion } },
                TargetPaths = new string[] { packageA1, packageB1 },
                UpgradePaths = new string[] { packageA2, packageB2 }
            }.Build().Output;

            // Create the named bind paths to the packages.
            Dictionary<string, string> bindPaths = new Dictionary<string, string>();
            bindPaths.Add("packageA", packageA1);
            bindPaths.Add("packageB", packageB1);
            bindPaths.Add("patchA", patchA);

            // Build the bundles.
            string bundleA = new BundleBuilder(this, "BundleA") { BindPaths = bindPaths, Extensions = Extensions }.Build().Output;
            string bundleB = new BundleBuilder(this, "BundleB") { BindPaths = bindPaths, Extensions = Extensions }.Build().Output;
            string bundleD = new BundleBuilder(this, "BundleD") { PreprocessorVariables = new Dictionary<string, string>() { { "Version", patchVersion } }, BindPaths = bindPaths, Extensions = Extensions }.Build().Output;

            // Install the bundles.
            BundleInstaller installerA = new BundleInstaller(this, bundleA).Install();
            BundleInstaller installerD = new BundleInstaller(this, bundleD).Install();

            // Make sure that bundle D detected dependent bundle A.
            Assert.IsTrue(LogVerifier.MessageInLogFileRegex(installerD.LastLogFile, @"Detected related bundle: \{[0-9A-Za-z\-]{36}\}, type: Dependent, scope: PerMachine, version: 1\.0\.0\.0, operation: None"));

            // Test that packageA1 and patchA are installed.
            Assert.IsTrue(MsiVerifier.IsPackageInstalled(packageA1));
            using (RegistryKey root = this.GetTestRegistryRoot())
            {
                string actualVersion = root.GetValue("A") as string;
                Assert.AreEqual(patchVersion, actualVersion);
            }

            // Install bundle B (tests sticky patching).
            BundleInstaller installerB = new BundleInstaller(this, bundleB).Install();

            Assert.IsTrue(LogVerifier.MessageInLogFileRegex(installerB.LastLogFile, @"Detected related bundle: \{[0-9A-Za-z\-]{36}\}, type: Patch, scope: PerMachine, version: 1\.0\.1\.0, operation: Install"));
            Assert.IsTrue(LogVerifier.MessageInLogFileRegex(installerB.LastLogFile, @"Detected related bundle: \{[0-9A-Za-z\-]{36}\}, type: Detect, scope: PerMachine, version: 1\.0\.0\.0, operation: None"));

            // Test that packageB and patchA are installed.
            Assert.IsTrue(MsiVerifier.IsPackageInstalled(packageB1));
            using (RegistryKey root = this.GetTestRegistryRoot())
            {
                string actualVersion = root.GetValue("B") as string;
                Assert.AreEqual(patchVersion, actualVersion);
            }

            // Attempt to uninstall bundleA.
            installerA.Uninstall();

            // Test that packageA is still installed (ref-counted).
            Assert.IsTrue(MsiVerifier.IsPackageInstalled(packageA1));

            // Test that uninstalling bundle A detected bundle D (ref-counted).
            Assert.IsTrue(LogVerifier.MessageInLogFileRegex(installerA.LastLogFile, @"Detected related bundle: \{[0-9A-Za-z\-]{36}\}, type: Patch, scope: PerMachine, version: 1\.0\.1\.0, operation: Remove"));
            Assert.IsTrue(LogVerifier.MessageInLogFileRegex(installerA.LastLogFile, @"Will not uninstall package: \{[0-9A-Za-z\-]{36}\}, found dependents: 1"));

            // Attempt to uninstall bundleB.
            installerB.Uninstall();

            // Test that all packages are uninstalled.
            Assert.IsFalse(MsiVerifier.IsPackageInstalled(packageA1));
            Assert.IsFalse(MsiVerifier.IsPackageInstalled(packageB1));
            Assert.IsNull(this.GetTestRegistryRoot());

            // Test that uninstalling bundle B detected and removed bundle D (ref-counted).
            Assert.IsTrue(LogVerifier.MessageInLogFileRegex(installerB.LastLogFile, @"Detected related bundle: \{[0-9A-Za-z\-]{36}\}, type: Patch, scope: PerMachine, version: 1\.0\.1\.0, operation: Remove"));

            this.CleanTestArtifacts = true;
        }
コード例 #33
0
ファイル: Burn.SlipstreamTests.cs プロジェクト: roni8686/wix3
        public void Burn_MajorUpgradeWithSlipstream()
        {
            const string originalVersion = "1.0.0.0";
            const string upgradeVersion  = "2.0.0.0";
            const string patchedVersion  = "2.0.1.0";

            // Build the packages.
            string originalPackageA = this.GetPackageA().Output;
            string upgradePackageA  = new PackageBuilder(this, "A")
            {
                PreprocessorVariables = new Dictionary <string, string>()
                {
                    { "Version", upgradeVersion }
                },
            }.Build().Output;
            string packageAUpdate = new PackageBuilder(this, "A")
            {
                PreprocessorVariables = new Dictionary <string, string>()
                {
                    { "Version", patchedVersion }
                }, NeverGetsInstalled = true
            }.Build().Output;
            string patchA = new PatchBuilder(this, "PatchA")
            {
                PreprocessorVariables = new Dictionary <string, string>()
                {
                    { "Version", patchedVersion }
                }, TargetPaths = new string[] { upgradePackageA }, UpgradePaths = new string[] { packageAUpdate }
            }.Build().Output;

            // Create the named bind paths to the packages in the bundle.
            Dictionary <string, string> bindPaths = new Dictionary <string, string>();

            bindPaths.Add("packageA", upgradePackageA);
            bindPaths.Add("patchA", patchA);

            string bundleA = new BundleBuilder(this, "BundleA")
            {
                BindPaths = bindPaths, Extensions = Extensions
            }.Build().Output;

            // Install the original MSI.
            MSIExec.InstallProduct(originalPackageA, MSIExec.MSIExecReturnCode.SUCCESS);

            Assert.True(MsiVerifier.IsPackageInstalled(originalPackageA));
            using (RegistryKey root = this.GetTestRegistryRoot())
            {
                // Original Product A should be present.
                string actualVersion = root.GetValue("A") as string;
                Assert.Equal(originalVersion, actualVersion);
            }

            // Now install the bundle that should upgrade the MSI and apply the patch.
            BundleInstaller install = new BundleInstaller(this, bundleA).Install();

            Assert.False(MsiVerifier.IsPackageInstalled(originalPackageA));
            Assert.True(MsiVerifier.IsPackageInstalled(upgradePackageA));
            using (RegistryKey root = this.GetTestRegistryRoot())
            {
                // Product A should've slipstreamed with its patch.
                string actualVersion = root.GetValue("A") as string;
                Assert.Equal(patchedVersion, actualVersion);
            }

            install.Uninstall();

            Assert.True(null == this.GetTestRegistryRoot(), "Test registry key should have been removed during uninstall.");

            this.Complete();
        }
コード例 #34
0
        public void Burn_BuildNonSpecificPatches()
        {
            string patchedVersion = "1.0.1.0";

            string[] extensions = new string[] { "WixBalExtension", "WixTagExtension", };

            // Build the packages.
            string packageA = new PackageBuilder(this, "A")
            {
                Extensions = extensions
            }.Build().Output;
            string packageAUpdate = new PackageBuilder(this, "A")
            {
                Extensions = extensions, PreprocessorVariables = new Dictionary <string, string>()
                {
                    { "Version", patchedVersion }
                }, NeverGetsInstalled = true
            }.Build().Output;
            string patchA = new PatchBuilder(this, "PatchA")
            {
                Extensions = extensions, TargetPath = packageA, UpgradePath = packageAUpdate
            }.Build().Output;
            string patchB = new PatchBuilder(this, "PatchB")
            {
                Extensions = extensions, TargetPath = packageA, UpgradePath = packageAUpdate
            }.Build().Output;
            string patchC = new PatchBuilder(this, "PatchC")
            {
                Extensions = extensions, TargetPath = packageA, UpgradePath = packageAUpdate
            }.Build().Output;

            // Build the bundles.
            Dictionary <string, string> bindPaths = new Dictionary <string, string>();

            bindPaths.Add("packageA", packageA);
            bindPaths.Add("patchA", patchA);
            bindPaths.Add("patchB", patchB);
            bindPaths.Add("patchC", patchC);

            string bundleA = new BundleBuilder(this, "BundleA")
            {
                BindPaths = bindPaths, Extensions = extensions
            }.Build().Output;

            WixTest.BundleBuilder bundleAPatch = new BundleBuilder(this, "PatchBundleA")
            {
                BindPaths = bindPaths, Extensions = extensions, PreprocessorVariables = new Dictionary <string, string>()
                {
                    { "Version", patchedVersion }
                }
            }.Build();
            WixTest.BundleBuilder bundleBPatch = new BundleBuilder(this, "PatchBundleB")
            {
                BindPaths = bindPaths, Extensions = extensions, PreprocessorVariables = new Dictionary <string, string>()
                {
                    { "Version", patchedVersion }
                }
            }.Build();
            WixTest.BundleBuilder bundleCPatch = new BundleBuilder(this, "PatchBundleC")
            {
                BindPaths = bindPaths, Extensions = extensions, PreprocessorVariables = new Dictionary <string, string>()
                {
                    { "Version", patchedVersion }
                }
            }.Build();

            // Disassemble the patch bundles and check for PatchTargetCode elements.
            XmlNodeList nodes = PatchTests.GetPatchTargetCodes(bundleAPatch);

            Assert.Equal(1, nodes.Count);
            Assert.True(nodes.OfType <XmlElement>().Any(elem => elem.HasAttribute("Product") && "yes".Equals(elem.Attributes["Product"].Value)));

            nodes = PatchTests.GetPatchTargetCodes(bundleBPatch);
            Assert.Equal(2, nodes.Count);
            Assert.True(nodes.OfType <XmlElement>().Any(elem => elem.HasAttribute("Product") && "yes".Equals(elem.Attributes["Product"].Value)));
            Assert.True(nodes.OfType <XmlElement>().Any(elem => elem.HasAttribute("Product") && "no".Equals(elem.Attributes["Product"].Value)));

            nodes = PatchTests.GetPatchTargetCodes(bundleCPatch);
            Assert.Equal(0, nodes.Count);

            this.Complete();
        }
コード例 #35
0
        public void Burn_InstallUpgradeSlipstreamBundle()
        {
            const string expectedVersion1 = "1.0.0.0";
            const string expectedVersion2 = "1.0.1.0";

            // Build the packages.
            string packageA = new PackageBuilder(this, "A") { Extensions = Extensions }.Build().Output;
            string packageA1 = new PackageBuilder(this, "A") { Extensions = Extensions, PreprocessorVariables = new Dictionary<string, string>() { { "Version", expectedVersion2 } }, NeverGetsInstalled = true }.Build().Output;
            string patchA = new PatchBuilder(this, "PatchA") { PreprocessorVariables = new Dictionary<string, string>() { { "Version", expectedVersion2 } }, TargetPath = packageA, UpgradePath = packageA1 }.Build().Output;

            // Create the named bind paths to the packages.
            Dictionary<string, string> bindPaths = new Dictionary<string, string>();
            bindPaths.Add("packageA", packageA);
            bindPaths.Add("patchA", patchA);

            // Build the bundles.
            string bundleA = new BundleBuilder(this, "BundleA") { BindPaths = bindPaths, Extensions = Extensions }.Build().Output;
            string bundleC = new BundleBuilder(this, "BundleC") { BindPaths = bindPaths, Extensions = Extensions, PreprocessorVariables = new Dictionary<string, string>() { { "Version", expectedVersion2 } } }.Build().Output;

            // Install the base bundle and make sure it's installed.
            BundleInstaller installerA = new BundleInstaller(this, bundleA).Install();
            Assert.IsTrue(MsiVerifier.IsPackageInstalled(packageA));
            using (RegistryKey root = this.GetTestRegistryRoot())
            {
                string actualVersion = root.GetValue("Version") as string;
                Assert.AreEqual(expectedVersion1, actualVersion);
            }

            // Install the upgrade bundle with a slipstreamed patch and make sure the patch is installed.
            // SFBUG:3387046 - Uninstalling bundle registers a dependency on a package
            BundleInstaller installerC = new BundleInstaller(this, bundleC).Install();
            Assert.IsTrue(MsiUtils.IsPatchInstalled(patchA));

            // BundleC doesn't carry the EXE, so make sure it's removed.
            using (RegistryKey root = this.GetTestRegistryRoot())
            {
                Assert.IsNull(root.GetValue("Version"));
            }

            // Repair the upgrade bundle to make sure it does not prompt for source.
            // SFBUG:3386927 - MSIs get removed from cache during upgrade
            installerC.Repair();

            // Uninstall the slipstream bundle and make sure both packages are uninstalled.
            installerC.Uninstall();
            Assert.IsFalse(MsiUtils.IsPatchInstalled(patchA));
            Assert.IsFalse(MsiVerifier.IsPackageInstalled(packageA));

            this.CleanTestArtifacts = true;
        }
コード例 #36
0
        public void Burn_PatchOnePackageTwoPatches()
        {
            string originalVersion = "1.0.0.0";
            string patchedVersion  = "1.0.1.0";

            // Build the packages.
            string packageA = new PackageBuilder(this, "A")
            {
                Extensions = WixTests.Extensions
            }.Build().Output;
            string packageAUpdate = new PackageBuilder(this, "A")
            {
                Extensions = WixTests.Extensions, PreprocessorVariables = new Dictionary <string, string>()
                {
                    { "Version", patchedVersion }
                }, NeverGetsInstalled = true
            }.Build().Output;
            string patchA = new PatchBuilder(this, "PatchA")
            {
                Extensions = WixTests.Extensions, TargetPath = packageA, UpgradePath = packageAUpdate
            }.Build().Output;
            string patchA2 = new PatchBuilder(this, "PatchA2")
            {
                Extensions = WixTests.Extensions, TargetPath = packageA, UpgradePath = packageAUpdate
            }.Build().Output;

            // Create the named bind paths to the packages.
            Dictionary <string, string> bindPaths = new Dictionary <string, string>();

            bindPaths.Add("patchA", patchA);
            bindPaths.Add("patchA2", patchA2);

            string bundlePatch = new BundleBuilder(this, "PatchBundleA2")
            {
                BindPaths = bindPaths, Extensions = Extensions
            }.Build().Output;

            // Install the original MSI and ensure the registry keys that get patched are as expected.
            MSIExec.InstallProduct(packageA, MSIExec.MSIExecReturnCode.SUCCESS);
            using (RegistryKey root = this.GetTestRegistryRoot())
            {
                string actualVersion = root.GetValue("A") as string;
                Assert.AreEqual(originalVersion, actualVersion);

                actualVersion = root.GetValue("A2") as string;
                Assert.AreEqual(originalVersion, actualVersion);
            }

            // Install the bundle of patches and ensure all the registry keys are updated.
            BundleInstaller installPatches = new BundleInstaller(this, bundlePatch).Install();

            using (RegistryKey root = this.GetTestRegistryRoot())
            {
                string actualVersion = root.GetValue("A") as string;
                Assert.AreEqual(patchedVersion, actualVersion);

                actualVersion = root.GetValue("A2") as string;
                Assert.AreEqual(patchedVersion, actualVersion);
            }

            // Uninstall the patch bundle and verify the keys go back to original values.
            installPatches.Uninstall();
            using (RegistryKey root = this.GetTestRegistryRoot())
            {
                string actualVersion = root.GetValue("A") as string;
                Assert.AreEqual(originalVersion, actualVersion);

                actualVersion = root.GetValue("A2") as string;
                Assert.AreEqual(originalVersion, actualVersion);
            }

            this.CleanTestArtifacts = true;
        }
コード例 #37
0
 public virtual void AddPatches(PatchBuilder builder)
 {
     // do nothing
 }
コード例 #38
0
        public void Burn_InstallUninstallUpgradePatchRelatedBundleWithAddon()
        {
            const string patchVersion1 = "1.0.1.0";
            const string patchVersion2 = "1.0.2.0";

            // Build the packages.
            string packageA1 = new PackageBuilder(this, "A").Build().Output;
            string packageA2 = new PackageBuilder(this, "A") { PreprocessorVariables = new Dictionary<string, string>() { { "Version", patchVersion1 } }, NeverGetsInstalled = true }.Build().Output;
            string packageA3 = new PackageBuilder(this, "A") { PreprocessorVariables = new Dictionary<string, string>() { { "Version", patchVersion2 } }, NeverGetsInstalled = true }.Build().Output;
            string packageC = new PackageBuilder(this, "C").Build().Output;
            string packageD = new PackageBuilder(this, "D").Build().Output;
            string patchA1 = new PatchBuilder(this, "PatchA") { PreprocessorVariables = new Dictionary<string, string>() { { "Version", patchVersion1 } }, TargetPath = packageA1, UpgradePath = packageA2 }.Build().Output;
            string patchA2 = new PatchBuilder(this, "PatchA") { PreprocessorVariables = new Dictionary<string, string>() { { "Version", patchVersion2 } }, TargetPath = packageA1, UpgradePath = packageA3 }.Build().Output;

            // Create the named bind paths to the packages.
            Dictionary<string, string> bindPaths = new Dictionary<string, string>();
            bindPaths.Add("packageA", packageA1);
            bindPaths.Add("packageC", packageC);
            bindPaths.Add("packageD", packageD);
            bindPaths.Add("patchA", patchA1);

            // Build the bundles.
            string bundleA = new BundleBuilder(this, "BundleA") { BindPaths = bindPaths, Extensions = Extensions }.Build().Output;
            string bundleC = new BundleBuilder(this, "BundleC") { BindPaths = bindPaths, Extensions = Extensions }.Build().Output;
            string bundleD1 = new BundleBuilder(this, "BundleD") { PreprocessorVariables = new Dictionary<string, string>() { { "Version", patchVersion1 } }, BindPaths = bindPaths, Extensions = Extensions }.Build().Output;

            // Build the v2 patch bundle.
            bindPaths["patchA"] = patchA2;
            string bundleD2 = new BundleBuilder(this, "BundleD") { PreprocessorVariables = new Dictionary<string, string>() { { "Version", patchVersion2 } }, BindPaths = bindPaths, Extensions = Extensions }.Build().Output;

            // Install the bundles.
            BundleInstaller installerA = new BundleInstaller(this, bundleA).Install();
            BundleInstaller installerD1 = new BundleInstaller(this, bundleD1).Install();

            // Test both packages are installed.
            Assert.IsTrue(MsiVerifier.IsPackageInstalled(packageA1));
            using (RegistryKey root = this.GetTestRegistryRoot())
            {
                string actualVersion = root.GetValue("A") as string;
                Assert.AreEqual(patchVersion1, actualVersion);
            }

            // Install the addon bundle.
            BundleInstaller installerC = new BundleInstaller(this, bundleC).Install();

            // Test that package C but not D is installed.
            Assert.IsTrue(MsiVerifier.IsPackageInstalled(packageC));
            Assert.IsFalse(MsiVerifier.IsPackageInstalled(packageD));

            // Install the v2 patch bundles.
            BundleInstaller installerD2 = new BundleInstaller(this, bundleD2).Install();

            // Test that all packages but D are installed.
            Assert.IsTrue(MsiVerifier.IsPackageInstalled(packageA1));
            Assert.IsTrue(MsiVerifier.IsPackageInstalled(packageC));
            Assert.IsFalse(MsiVerifier.IsPackageInstalled(packageD));
            using (RegistryKey root = this.GetTestRegistryRoot())
            {
                string actualVersion = root.GetValue("A") as string;
                Assert.AreEqual(patchVersion2, actualVersion);
            }

            // Test that installing D2 upgrades D1.
            Assert.IsTrue(LogVerifier.MessageInLogFileRegex(installerD2.LastLogFile, @"Detected related bundle: \{[0-9A-Za-z\-]{36}\}, type: Upgrade, scope: PerMachine, version: 1\.0\.1\.0, operation: MajorUpgrade"));

            // Attempt to uninstall bundleA.
            installerA.Uninstall();

            // Test that uninstalling bundle A detected and would remove bundles C and D.
            Assert.IsTrue(LogVerifier.MessageInLogFileRegex(installerA.LastLogFile, @"Detected related bundle: \{[0-9A-Za-z\-]{36}\}, type: Addon, scope: PerMachine, version: 1\.0\.0\.0, operation: Remove"));
            Assert.IsTrue(LogVerifier.MessageInLogFileRegex(installerA.LastLogFile, @"Detected related bundle: \{[0-9A-Za-z\-]{36}\}, type: Patch, scope: PerMachine, version: 1\.0\.2\.0, operation: Remove"));

            // Test all packages are uninstalled.
            Assert.IsFalse(MsiVerifier.IsPackageInstalled(packageA1));
            Assert.IsFalse(MsiVerifier.IsPackageInstalled(packageC));
            Assert.IsFalse(MsiVerifier.IsPackageInstalled(packageD));
            Assert.IsNull(this.GetTestRegistryRoot());

            this.CleanTestArtifacts = true;
        }
コード例 #39
0
        public void Burn_InstallPatchBundle()
        {
            const string expectedVersion = "1.0.1.0";

            // Build the packages.
            string packageA1 = new PackageBuilder(this, "A") { Extensions = Extensions }.Build().Output;
            string packageA2 = new PackageBuilder(this, "A") { Extensions = Extensions, PreprocessorVariables = new Dictionary<string, string>() { { "Version", expectedVersion } }, NeverGetsInstalled = true }.Build().Output;
            string packageB = new PackageBuilder(this, "B") { Extensions = Extensions }.Build().Output;
            string patchA = new PatchBuilder(this, "PatchA") { PreprocessorVariables = new Dictionary<string, string>() { { "Version", expectedVersion } }, TargetPath = packageA1, UpgradePath = packageA2 }.Build().Output;

            // Create the named bind paths to the packages.
            Dictionary<string, string> bindPaths = new Dictionary<string, string>();
            bindPaths.Add("packageA", packageA1);
            bindPaths.Add("packageB", packageB);
            bindPaths.Add("patchA", patchA);

            // Build the bundles.
            string bundleF = new BundleBuilder(this, "BundleF") { BindPaths = bindPaths, Extensions = Extensions }.Build().Output;
            string bundleG = new BundleBuilder(this, "BundleG") { BindPaths = bindPaths, Extensions = Extensions }.Build().Output;

            // Install the base bundle and make sure all packages are installed.
            BundleInstaller installerF = new BundleInstaller(this, bundleF).Install();
            Assert.IsTrue(MsiVerifier.IsPackageInstalled(packageA1));
            Assert.IsTrue(MsiVerifier.IsPackageInstalled(packageB));

            // Install patch bundle and make sure all packages are installed.
            BundleInstaller installerG = new BundleInstaller(this, bundleG).Install();
            Assert.IsTrue(MsiVerifier.IsPackageInstalled(packageA1));
            Assert.IsTrue(MsiVerifier.IsPackageInstalled(packageB));
            Assert.IsTrue(MsiUtils.IsPatchInstalled(patchA));

            // Uninstall the base bundle and make sure all packages are uninstalled.
            installerF.Uninstall();
            Assert.IsFalse(MsiVerifier.IsPackageInstalled(packageA1));
            Assert.IsFalse(MsiVerifier.IsPackageInstalled(packageB));
            Assert.IsFalse(MsiUtils.IsPatchInstalled(patchA));

            this.CleanTestArtifacts = true;
        }
コード例 #40
0
        public void Burn_InstallUninstallStickyPatchRelatedBundle()
        {
            const string patchVersion = "1.0.1.0";

            // Build the packages.
            string packageA1 = new PackageBuilder(this, "A").Build().Output;
            string packageA2 = new PackageBuilder(this, "A")
            {
                PreprocessorVariables = new Dictionary <string, string>()
                {
                    { "Version", patchVersion }
                }, NeverGetsInstalled = true
            }.Build().Output;
            string packageB1 = new PackageBuilder(this, "B").Build().Output;
            string packageB2 = new PackageBuilder(this, "B")
            {
                PreprocessorVariables = new Dictionary <string, string>()
                {
                    { "Version", patchVersion }
                }, NeverGetsInstalled = true
            }.Build().Output;
            string patchA = new PatchBuilder(this, "PatchA")
            {
                PreprocessorVariables = new Dictionary <string, string>()
                {
                    { "Version", patchVersion }
                },
                TargetPaths  = new string[] { packageA1, packageB1 },
                UpgradePaths = new string[] { packageA2, packageB2 }
            }.Build().Output;

            // Create the named bind paths to the packages.
            Dictionary <string, string> bindPaths = new Dictionary <string, string>();

            bindPaths.Add("packageA", packageA1);
            bindPaths.Add("packageB", packageB1);
            bindPaths.Add("patchA", patchA);

            // Build the bundles.
            string bundleA = new BundleBuilder(this, "BundleA")
            {
                BindPaths = bindPaths, Extensions = Extensions
            }.Build().Output;
            string bundleB = new BundleBuilder(this, "BundleB")
            {
                BindPaths = bindPaths, Extensions = Extensions
            }.Build().Output;
            string bundleD = new BundleBuilder(this, "BundleD")
            {
                PreprocessorVariables = new Dictionary <string, string>()
                {
                    { "Version", patchVersion }
                }, BindPaths = bindPaths, Extensions = Extensions
            }.Build().Output;

            // Install the bundles.
            BundleInstaller installerA = new BundleInstaller(this, bundleA).Install();
            BundleInstaller installerD = new BundleInstaller(this, bundleD).Install();

            // Make sure that bundle D detected dependent bundle A.
            Assert.True(LogVerifier.MessageInLogFileRegex(installerD.LastLogFile, @"Detected related bundle: \{[0-9A-Za-z\-]{36}\}, type: Dependent, scope: PerMachine, version: 1\.0\.0\.0, operation: None"));

            // Test that packageA1 and patchA are installed.
            Assert.True(MsiVerifier.IsPackageInstalled(packageA1));
            using (RegistryKey root = this.GetTestRegistryRoot())
            {
                string actualVersion = root.GetValue("A") as string;
                Assert.Equal(patchVersion, actualVersion);
            }

            // Install bundle B (tests sticky patching).
            BundleInstaller installerB = new BundleInstaller(this, bundleB).Install();

            Assert.True(LogVerifier.MessageInLogFileRegex(installerB.LastLogFile, @"Detected related bundle: \{[0-9A-Za-z\-]{36}\}, type: Patch, scope: PerMachine, version: 1\.0\.1\.0, operation: Install"));
            Assert.True(LogVerifier.MessageInLogFileRegex(installerB.LastLogFile, @"Detected related bundle: \{[0-9A-Za-z\-]{36}\}, type: Detect, scope: PerMachine, version: 1\.0\.0\.0, operation: None"));

            // Test that packageB and patchA are installed.
            Assert.True(MsiVerifier.IsPackageInstalled(packageB1));
            using (RegistryKey root = this.GetTestRegistryRoot())
            {
                string actualVersion = root.GetValue("B") as string;
                Assert.Equal(patchVersion, actualVersion);
            }

            // Attempt to uninstall bundleA.
            installerA.Uninstall();

            // Test that packageA is still installed (ref-counted).
            Assert.True(MsiVerifier.IsPackageInstalled(packageA1));

            // Test that uninstalling bundle A detected bundle D (ref-counted).
            Assert.True(LogVerifier.MessageInLogFileRegex(installerA.LastLogFile, @"Detected related bundle: \{[0-9A-Za-z\-]{36}\}, type: Patch, scope: PerMachine, version: 1\.0\.1\.0, operation: Remove"));
            Assert.True(LogVerifier.MessageInLogFileRegex(installerA.LastLogFile, @"Will not uninstall package: \{[0-9A-Za-z\-]{36}\}, found dependents: 1"));

            // Attempt to uninstall bundleB.
            installerB.Uninstall();

            // Test that all packages are uninstalled.
            Assert.False(MsiVerifier.IsPackageInstalled(packageA1));
            Assert.False(MsiVerifier.IsPackageInstalled(packageB1));
            Assert.Null(this.GetTestRegistryRoot());

            // Test that uninstalling bundle B detected and removed bundle D (ref-counted).
            Assert.True(LogVerifier.MessageInLogFileRegex(installerB.LastLogFile, @"Detected related bundle: \{[0-9A-Za-z\-]{36}\}, type: Patch, scope: PerMachine, version: 1\.0\.1\.0, operation: Remove"));

            this.Complete();
        }
コード例 #41
0
        // Patch Creation
        private void btnCreatePatch_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                // Check the user isn't completly retarded
                if (!CheckAllCreateMandatoryFields())
                {
                    return;
                }

                // Check the user isn't a skid
                if (!CheckAllCreateMetaFilesExists())
                {
                    return;
                }

                // Paths
                string cleanMapPath  = txtCreatePatchUnModifiedMap.Text;
                string moddedMapPath = txtCreatePatchModifiedMap.Text;
                string outputPath    = txtCreatePatchOutputPatch.Text;
                string previewImage  = txtCreatePatchPreviewImage.Text;

                // Details
                string author     = txtCreatePatchContentAuthor.Text;
                string desc       = txtCreatePatchContentDescription.Text;
                string name       = txtCreatePatchContentName.Text;
                string outputName = txtCreatePatchOutputName.Text;

                // Make dat patch
                var patch = new Patch
                {
                    Author      = author,
                    Description = desc,
                    Name        = name,
                    OutputName  = outputName,
                    Screenshot  = String.IsNullOrEmpty(previewImage)
                                                ? null
                                                : File.ReadAllBytes(previewImage),
                    BuildString = _buildInfo.Version,
                    PC          = String.IsNullOrEmpty(_buildInfo.GameExecutable)
                                                ? false
                                                : true
                };

                EndianReader originalReader = null;
                EndianReader newReader      = null;
                try
                {
                    originalReader = new EndianReader(File.OpenRead(cleanMapPath), Endian.BigEndian);
                    newReader      = new EndianReader(File.OpenRead(moddedMapPath), Endian.BigEndian);

                    ICacheFile originalFile = CacheFileLoader.LoadCacheFile(originalReader, cleanMapPath,
                                                                            App.AssemblyStorage.AssemblySettings.DefaultDatabase);
                    ICacheFile newFile = CacheFileLoader.LoadCacheFile(newReader, moddedMapPath, App.AssemblyStorage.AssemblySettings.DefaultDatabase);

                    if (cbCreatePatchHasCustomMeta.IsChecked != null && (bool)cbCreatePatchHasCustomMeta.IsChecked &&
                        cboxCreatePatchTargetGame.SelectedIndex < 4)
                    {
                        var      targetGame      = (TargetGame)cboxCreatePatchTargetGame.SelectedIndex;
                        byte[]   mapInfo         = File.ReadAllBytes(txtCreatePatchMapInfo.Text);
                        var      mapInfoFileInfo = new FileInfo(txtCreatePatchMapInfo.Text);
                        FileInfo blfFileInfo;

                        patch.CustomBlfContent = new BlfContent(mapInfoFileInfo.FullName, mapInfo, targetGame);

                        #region Blf Data

                        if (PatchCreationBlfOption0.Visibility == Visibility.Visible)
                        {
                            blfFileInfo = new FileInfo(txtCreatePatchblf0.Text);
                            patch.CustomBlfContent.BlfContainerEntries.Add(new BlfContainerEntry(blfFileInfo.Name,
                                                                                                 File.ReadAllBytes(blfFileInfo.FullName)));
                        }
                        if (PatchCreationBlfOption1.Visibility == Visibility.Visible)
                        {
                            blfFileInfo = new FileInfo(txtCreatePatchblf1.Text);
                            patch.CustomBlfContent.BlfContainerEntries.Add(new BlfContainerEntry(blfFileInfo.Name,
                                                                                                 File.ReadAllBytes(blfFileInfo.FullName)));
                        }
                        if (PatchCreationBlfOption2.Visibility == Visibility.Visible)
                        {
                            blfFileInfo = new FileInfo(txtCreatePatchblf2.Text);
                            patch.CustomBlfContent.BlfContainerEntries.Add(new BlfContainerEntry(blfFileInfo.Name,
                                                                                                 File.ReadAllBytes(blfFileInfo.FullName)));
                        }
                        if (PatchCreationBlfOption3.Visibility == Visibility.Visible)
                        {
                            blfFileInfo = new FileInfo(txtCreatePatchblf3.Text);
                            patch.CustomBlfContent.BlfContainerEntries.Add(new BlfContainerEntry(blfFileInfo.Name,
                                                                                                 File.ReadAllBytes(blfFileInfo.FullName)));
                        }

                        #endregion
                    }

                    PatchBuilder.BuildPatch(originalFile, originalReader, newFile, newReader, patch);
                }
                finally
                {
                    if (originalReader != null)
                    {
                        originalReader.Dispose();
                    }
                    if (newReader != null)
                    {
                        newReader.Dispose();
                    }
                }

                IWriter output = new EndianWriter(File.Open(outputPath, FileMode.Create, FileAccess.Write), Endian.BigEndian);
                AssemblyPatchWriter.WritePatch(patch, output);
                output.Dispose();

                MetroMessageBox.Show("Patch Created!",
                                     "Your patch has been created in the designated location. Happy sailing, modder!");
            }
            catch (Exception ex)
            {
                MetroException.Show(ex);
            }
        }
コード例 #42
0
        public void Burn_InstallUninstallUpgradePatchRelatedBundleWithAddon()
        {
            const string patchVersion1 = "1.0.1.0";
            const string patchVersion2 = "1.0.2.0";

            // Build the packages.
            string packageA1 = new PackageBuilder(this, "A").Build().Output;
            string packageA2 = new PackageBuilder(this, "A")
            {
                PreprocessorVariables = new Dictionary <string, string>()
                {
                    { "Version", patchVersion1 }
                }, NeverGetsInstalled = true
            }.Build().Output;
            string packageA3 = new PackageBuilder(this, "A")
            {
                PreprocessorVariables = new Dictionary <string, string>()
                {
                    { "Version", patchVersion2 }
                }, NeverGetsInstalled = true
            }.Build().Output;
            string packageC = new PackageBuilder(this, "C").Build().Output;
            string packageD = new PackageBuilder(this, "D").Build().Output;
            string patchA1  = new PatchBuilder(this, "PatchA")
            {
                PreprocessorVariables = new Dictionary <string, string>()
                {
                    { "Version", patchVersion1 }
                }, TargetPath = packageA1, UpgradePath = packageA2
            }.Build().Output;
            string patchA2 = new PatchBuilder(this, "PatchA")
            {
                PreprocessorVariables = new Dictionary <string, string>()
                {
                    { "Version", patchVersion2 }
                }, TargetPath = packageA1, UpgradePath = packageA3
            }.Build().Output;

            // Create the named bind paths to the packages.
            Dictionary <string, string> bindPaths = new Dictionary <string, string>();

            bindPaths.Add("packageA", packageA1);
            bindPaths.Add("packageC", packageC);
            bindPaths.Add("packageD", packageD);
            bindPaths.Add("patchA", patchA1);

            // Build the bundles.
            string bundleA = new BundleBuilder(this, "BundleA")
            {
                BindPaths = bindPaths, Extensions = Extensions
            }.Build().Output;
            string bundleC = new BundleBuilder(this, "BundleC")
            {
                BindPaths = bindPaths, Extensions = Extensions
            }.Build().Output;
            string bundleD1 = new BundleBuilder(this, "BundleD")
            {
                PreprocessorVariables = new Dictionary <string, string>()
                {
                    { "Version", patchVersion1 }
                }, BindPaths = bindPaths, Extensions = Extensions
            }.Build().Output;

            // Build the v2 patch bundle.
            bindPaths["patchA"] = patchA2;
            string bundleD2 = new BundleBuilder(this, "BundleD")
            {
                PreprocessorVariables = new Dictionary <string, string>()
                {
                    { "Version", patchVersion2 }
                }, BindPaths = bindPaths, Extensions = Extensions
            }.Build().Output;

            // Install the bundles.
            BundleInstaller installerA  = new BundleInstaller(this, bundleA).Install();
            BundleInstaller installerD1 = new BundleInstaller(this, bundleD1).Install();

            // Test both packages are installed.
            Assert.True(MsiVerifier.IsPackageInstalled(packageA1));
            using (RegistryKey root = this.GetTestRegistryRoot())
            {
                string actualVersion = root.GetValue("A") as string;
                Assert.Equal(patchVersion1, actualVersion);
            }

            // Install the addon bundle.
            BundleInstaller installerC = new BundleInstaller(this, bundleC).Install();

            // Test that package C but not D is installed.
            Assert.True(MsiVerifier.IsPackageInstalled(packageC));
            Assert.False(MsiVerifier.IsPackageInstalled(packageD));

            // Install the v2 patch bundles.
            BundleInstaller installerD2 = new BundleInstaller(this, bundleD2).Install();

            // Test that all packages but D are installed.
            Assert.True(MsiVerifier.IsPackageInstalled(packageA1));
            Assert.True(MsiVerifier.IsPackageInstalled(packageC));
            Assert.False(MsiVerifier.IsPackageInstalled(packageD));
            using (RegistryKey root = this.GetTestRegistryRoot())
            {
                string actualVersion = root.GetValue("A") as string;
                Assert.Equal(patchVersion2, actualVersion);
            }

            // Test that installing D2 upgrades D1.
            Assert.True(LogVerifier.MessageInLogFileRegex(installerD2.LastLogFile, @"Detected related bundle: \{[0-9A-Za-z\-]{36}\}, type: Upgrade, scope: PerMachine, version: 1\.0\.1\.0, operation: MajorUpgrade"));

            // Attempt to uninstall bundleA.
            installerA.Uninstall();

            // Test that uninstalling bundle A detected and would remove bundles C and D.
            Assert.True(LogVerifier.MessageInLogFileRegex(installerA.LastLogFile, @"Detected related bundle: \{[0-9A-Za-z\-]{36}\}, type: Addon, scope: PerMachine, version: 1\.0\.0\.0, operation: Remove"));
            Assert.True(LogVerifier.MessageInLogFileRegex(installerA.LastLogFile, @"Detected related bundle: \{[0-9A-Za-z\-]{36}\}, type: Patch, scope: PerMachine, version: 1\.0\.2\.0, operation: Remove"));

            // Test all packages are uninstalled.
            Assert.False(MsiVerifier.IsPackageInstalled(packageA1));
            Assert.False(MsiVerifier.IsPackageInstalled(packageC));
            Assert.False(MsiVerifier.IsPackageInstalled(packageD));
            Assert.Null(this.GetTestRegistryRoot());

            this.Complete();
        }