Обновление отдельной функции в дереве функций WIX без удаления / обновления других функций - PullRequest
8 голосов
/ 16 ноября 2009

Я пытаюсь создать проект установки, используя WIX , который позволит мне установить несколько функций одного продукта. Как я могу обновить одну из установленных функций (которая не зависит от других установленных функций) без необходимости переустанавливать другие функции в дереве функций?

Например, я хочу иметь возможность иметь проект (возвращающийся к HelloWolrd) с именем HelloWolrd, который (удивительно) печатает «Hello world!» на экране. Допустим, у меня есть три из этих приложений hello world: Hello World 1, Hello World 2 и Hello World 3. Каждое из которых печатает на экране Hello World 1, 2 или 3, с уважением. Я хотел бы создать MSI, который по умолчанию устанавливает все три эти «функции», но также позволяет обновлять каждую функцию в отдельности позднее.

Вот мой макет моего решения:

Обозреватель решений http://img12.imageshack.us/img12/5671/solutionexplorerm.jpg

Мой файл WIX Product.wxs выглядит следующим образом:

<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
    <Product Id="ca484210-c719-4b2e-b960-45212d407c11" Name="HelloWorldInstaller" Language="1033" Version="1.0.0.0" Manufacturer="HelloWorldInstaller" UpgradeCode="68eeb8cb-9ef3-443c-870c-9b406129f7ff">
        <Package InstallerVersion="200" Compressed="yes" />

        <Media Id="1" Cabinet="media1.cab" EmbedCab="yes" />

        <!-- Create Directory Structure -->
        <Directory Id="TARGETDIR" Name="SourceDir">
            <Directory Id="ProgramFilesFolder">
                <Directory Id="INSTALLLOCATION" Name="Hello World" />
            </Directory>
            <Directory Id="DesktopFolder" Name="Desktop"/>
        </Directory>

        <DirectoryRef Id="INSTALLLOCATION">
            <Component Id="HelloWorld1" Guid="6D1D9D33-DA17-4db3-8132-C39F32200C3A">
                <RegistryKey Root="HKCU" Key="Software\HelloWorldInstaller\HelloWorld1\Install" Action="createAndRemoveOnUninstall">
                    <RegistryValue Name="DTSC" Value="1" Type="integer" KeyPath="yes" />
                </RegistryKey>

                <File Id="HelloWorld1.exe" Name="$(var.HelloWorld1.TargetFileName)" Source="$(var.HelloWorld1.TargetPath)" DiskId="1" Checksum="yes">
                    <Shortcut Id="HelloWorld1ApplicationDesktopShortcut" Name="Hello World 1" Description="Hello World Application 1" Directory="DesktopFolder" WorkingDirectory="INSTALLLOCATION" />
                </File>

            </Component>
            <Component Id="HelloWorld2" Guid="B2D51F85-358B-41a7-8C45-B4BB341158F8">
                <RegistryKey Root="HKCU" Key="Software\HelloWorldInstaller\HelloWorld2\Install" Action="createAndRemoveOnUninstall">
                    <RegistryValue Name="DTSC" Value="1" Type="integer" KeyPath="yes" />
                </RegistryKey>

                <File Id="HelloWorld2.exe" Name="$(var.HelloWorld2.TargetFileName)" Source="$(var.HelloWorld2.TargetPath)" DiskId="1" Checksum="yes">
                    <Shortcut Id="HelloWorld2ApplicationDesktopShortcut" Name="Hello World 2" Description="Hello World Application 2" Directory="DesktopFolder" WorkingDirectory="INSTALLLOCATION" />
                </File>
            </Component>
            <Component Id="HelloWorld3" Guid="A550223E-792F-4169-90A3-574D4240F3C4">
                <RegistryKey Root="HKCU" Key="Software\HelloWorldInstaller\HelloWorld3\Install" Action="createAndRemoveOnUninstall">
                    <RegistryValue Name="DTSC" Value="1" Type="integer" KeyPath="yes" />
                </RegistryKey>

                <File Id="HelloWorld3.exe" Name="$(var.HelloWorld3.TargetFileName)" Source="$(var.HelloWorld3.TargetPath)" DiskId="1" Checksum="yes">
                    <Shortcut Id="HelloWorld3ApplicationDesktopShortcut" Name="Hello World 3" Description="Hello World Application 3" Directory="DesktopFolder" WorkingDirectory="INSTALLLOCATION" />
                </File>
            </Component>
        </DirectoryRef>

        <Feature Id="HelloWorld1Feature" Title="Hello World 1" Level="1">
            <ComponentRef Id="HelloWorld1"/>
        </Feature>
        <Feature Id="HelloWorld2Feature" Title="Hello World 2" Level="1">
            <ComponentRef Id="HelloWorld2"/>
        </Feature>
        <Feature Id="HelloWorld3Feature" Title="Hello World 3" Level="1">
            <ComponentRef Id="HelloWorld3"/>
        </Feature>

    </Product>
</Wix>

Теперь, когда он построен, он устанавливает функции так, как вы ожидаете. Однако, когда вы вносите изменения в HelloWorld1.vb и перекомпилируете, я бы хотел, чтобы он мог переустанавливать (обновлять) только эту функцию, а не все.

Когда я обновляю один файл и перестраиваю решение, затем пытаюсь установить MSI, я получаю эту ошибку:

Ошибка MSI http://img696.imageshack.us/img696/849/anotherversionisinstall.jpg

Я обновил свой код, чтобы разрешить удаление функций и разрешить использование кодов обновления, но это привело к удалению всех функций и их повторной установке.

<ч />

- Применение в реальном мире -

Реальным приложением для этого является большой программный пакет, для которого требуется несколько приложений поддержки, которые регулярно выполняются в виде служб / запланированных задач. Я хотел бы получить установку этих приложений поддержки в одном MSI, что позволит нам не иметь такой кошмар развертывания каждого exe в отдельности. Я знаю, что если у нас есть обновление одного из исполняемых файлов, мы могли бы просто вручную скомпилировать этот исполняемый файл и развернуть его, но я хотел бы сделать это полностью воспроизводимым способом.

Любая помощь будет оценена,

Спасибо!

РЕДАКТИРОВАТЬ:

Я добавил источник для скачивания из Google Code . Еще раз спасибо!

Ответы [ 2 ]

13 голосов
/ 18 ноября 2009

Я понял это и подумал, что выложу ответ здесь для дальнейшего использования другими. Итак, я полностью объяснил проблему, я углублюсь в сценарий реального мира.

У нас есть довольно крупное программное обеспечение, которое требует от нас нескольких вспомогательных приложений, работающих на нескольких разных серверах. Наш текущий прогресс обновлений делает умеренно сложным обновление кода надежным способом. В настоящее время мы используем самораспаковывающиеся exe-файлы для развертывания нашего кода на разных серверах. Проблема возникает, когда у нас так много поддерживающих приложений, что становится трудно убедиться, что приложения установлены правильно с правильными настройками конфигурации и т. Д. Чтобы решить эту проблему, мы рассматриваем возможность вместо сжатия каждого из Поддерживая приложения, мы создаем единый установщик (MSI), который позволит команде инфраструктуры установить определенный набор вспомогательных приложений для каждой машины. Когда у нас будет существенное изменение (например, с 1.0 до 2.0), мы сделаем полную установку обновления (то есть все службы / процессы должны быть остановлены, удалены, установлены и запущены.) Когда у нас есть незначительное изменение, мы хотели бы только остановить и переустановить затронутые службы / процессы, не затрагивая другие приложения. Теперь, хватит мне бродить, давайте доберемся до решения:

Я изменил WIX Product.wxs, чтобы удалить ярлыки, так как они нам не нужны в нашем сценарии. Вот обновленный файл wxs:

<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
 <Product Id="13C373D3-5C27-487e-A020-C2C89E4607B1" Name="HelloWorldInstaller" Language="1033" Version="1.0.0.0"
      Manufacturer="HelloWorldInstaller" UpgradeCode="E7CB3C76-4D51-48a8-BFB4-6D11B2E2E65B">

  <Package InstallerVersion="200" Compressed="yes" />

  <Media Id="1" Cabinet="product.cab" EmbedCab="yes" />
  <FeatureRef Id="HelloWorld1Feature" />
  <FeatureRef Id="HelloWorld2Feature" />
  <FeatureRef Id="HelloWorld3Feature" />
 </Product>

 <Fragment>
  <Directory Id="TARGETDIR" Name="SourceDir">
   <Directory Id="ProgramFilesFolder">
    <Directory Id="INSTALLLOCATION" Name="Hello World" />
   </Directory>
   <Directory Id="DesktopFolder" Name="Desktop"/>
  </Directory>
 </Fragment>

 <Fragment>
  <DirectoryRef Id="INSTALLLOCATION">
   <Directory Id="HelloWorld1Directory" Name="Hello World 1">
    <Component Id="HelloWorld1Component" Guid="6D1D9D33-DA17-4db3-8132-C39F32200C3A">
     <File Id="HelloWorld1.exe" Name="HelloWorld1.exe" Source="HelloWorld1.exe" DiskId="1" Checksum="yes" />    
    </Component>
   </Directory>
   <Directory Id="HelloWorld2Directory" Name="Hello World 2">
    <Component Id="HelloWorld2Component" Guid="B2D51F85-358B-41a7-8C45-B4BB341158F8">
     <File Id="HelloWorld2.exe" Name="HelloWorld2.exe" Source="HelloWorld2.exe" DiskId="1" Checksum="yes" />
    </Component>
   </Directory>
   <Directory Id="HelloWorld3Directory" Name="Hello World 3">
    <Component Id="HelloWorld3Component" Guid="A550223E-792F-4169-90A3-574D4240F3C4">
     <File Id="HelloWorld3.exe" Name="HelloWorld3.exe" Source="HelloWorld3.exe" DiskId="1" Checksum="yes" />
    </Component>
   </Directory>
  </DirectoryRef>
 </Fragment>

 <Fragment>
  <Feature Id="HelloWorld1Feature" Title="Hello World 1" Level="1">
   <ComponentRef Id="HelloWorld1Component"/>
  </Feature>
 </Fragment>
 <Fragment>
  <Feature Id="HelloWorld2Feature" Title="Hello World 2" Level="1">
   <ComponentRef Id="HelloWorld2Component"/>
  </Feature>
 </Fragment>
 <Fragment>
  <Feature Id="HelloWorld3Feature" Title="Hello World 3" Level="1">
   <ComponentRef Id="HelloWorld3Component"/>
  </Feature>
 </Fragment>
</Wix>

Теперь, наряду с этим, для наших небольших обновлений мы будем выпускать исправления для наших компонентов.

Например, допустим, у нас есть ProductA, который имеет три компонента - 1,2 и 3. Эти три компонента должны запускаться либо как службы, либо как запланированные задачи. Характер нашего продукта, мы не можем закрыть все наши службы, чтобы обновить или исправить один из наших компонентов. Итак, если после установки версии 1.0 мы обнаружим ошибку в компоненте 2, но мы не хотим, чтобы исправление, применяемое к этой ошибке, затронуло 1 или 3, мы выпустим патч для компонента 2, таким образом, будет затронут только компонент 2.

Для нашего быстрого примера, приведенного выше, мы используем HelloWorld1, HelloWorld2 и HelloWorld3 в качестве трех компонентов в нашем программном приложении. Мысль заключается в том, что мы должны иметь возможность установить все три с одним MSI, но затем обновить каждый независимо, не затрагивая другие установленные компоненты.

Итак, чтобы продемонстрировать это, я создал три консольных приложения, которые будут отображать «Hello World 1!», «Hello World 2!» И «Hello World 3!». Затем, после того, как мы выпустим исходный MSI, допустим, что мы нашли «ошибку», которая заставляет HelloWorld1 сказать «Hello World 1! Обновлено». вместо. Вот что мы будем делать, чтобы смоделировать это:

  1. Создайте Product.wixobj, выполнив эту команду в командной строке:
    candle.exe Product.wxs
    Помните, что для того, чтобы вызвать свечу или любую из команд WIX, в каталоге установки Wix должно быть в вашей переменной PATH. ( Краткое руководство по обновлению переменной среды PATH ) Кроме того, выполните команды в том же каталоге, что и файл Product.wxs.
  2. Создайте первую версию своего продукта (скажем, 1.0):
    light.exe Product.wixobj -out ProductA-1.0.msi
  3. Теперь найдите ошибку (измените вывод HelloWorld1 на «Hello World 1! Обновлено.»), Затем обновите версию сборки и версию файла . Это важно, так как это то, как WIX может сказать, что исполняемые файлы разные.
  4. Выполните ту же команду, что и на первом этапе (для правильной оценки):
    candle.exe Product.wxs
  5. Выполните почти ту же команду, что и на втором шаге:
    light.exe Product.wixobj -out ProductA-1.1.msi
    Обратите внимание, что это версия 1.1 вместо 1.0 (это msi с нашим обновленным кодом). Однако мы не хотим просто установить это, продолжайте читать.
  6. Вот забавная часть, мы получаем разницу в двух MSI с помощью следующей команды:
    torch.exe -p -xi ProductA-1.0.wixpdb ProductA-1.1.wixpdb -out Diff.WixMst
  7. Теперь мы создадим файл патча из этого (Patch.wxs будет объяснен ниже):
    candle.exe Patch.wxs
  8. Теперь мы создадим файл WixMsp с помощью этой команды:
    light.exe Patch.wixobj -out Patch.WixMsp
  9. А теперь самое интересное. Создайте файл MSP с помощью этой команды:
    pyro.exe Patch.WixMsp -out Patch.msp -t RTM Diff.Wixmst

Теперь, если все прошло по плану, у вас должно быть два файла msi и один файл msp. Если вы установили первую версию msi (ProductA-1.0.msi) и запустили HelloWorld1.exe, вы должны увидеть сообщение «Hello World 1!». Просто для забавы (и пример), запустите оба других приложения и оставьте их работающими (я сделал остановку, чтобы они оставались открытыми). Закройте HelloWorld1.exe, так как теперь мы собираемся применить обновление для этого exe-файла, но при этом мы не затронем HelloWorld2.exe или HelloWorld3.exe. Если вы сейчас установите файл msp (Patch.msp), а затем запустите HelloWorld1.exe, вы увидите обновленное сообщение «Hello World 1! Обновлено».

Теперь для магического файла Patch.wxs:

<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
 <Patch
   AllowRemoval="yes"
   Manufacturer="Dynamo Corp"
   MoreInfoURL="http://www.dynamocorp.com/"
   DisplayName="Sample Patch"
   Description="Small Update Patch"
   Classification="Update"
        >

  <Media Id="5000" Cabinet="RTM.cab">
   <PatchBaseline Id="RTM"/>
  </Media>

  <PatchFamilyRef Id="SamplePatchFamily"/>
 </Patch>

 <Fragment>
  <PatchFamily Id='SamplePatchFamily' Version='1.0.0' Supersede='yes'>
   <ComponentRef Id="HelloWorld1Component"/>
  </PatchFamily>
 </Fragment>
</Wix>

Не очень много, правда? Ну, самые интересные части это:

  1. <PatchBaseline Id="RTM"/> - Это, если вы помните, используется в нашем создании патча MSI. «RTM» упоминается в последнем шаге выше: -t RTM - они должны совпадать.
  2. <ComponentRef Id="HelloWorld1Component"/> - Это указывает патч на правильный компонент для обновления, в нашем случае HelloWorld1Component.

Если вы выполняли какие-либо поиски, приведенный выше код может показаться вам знакомым, поскольку он взят из Блог Питера Марку : WiX: Создание патча с использованием новой системы сборки патчей - Часть 3

Я также очень полагался на Блог Алекса Шевчука : От MSI до WiX, часть 8 - значительное обновление

Если вам интересно: «Вау, это много шагов, зачем кому-то делать это много шагов?», Пожалуйста, помните, что после тяжелой работы (см. Выше) вам нужно перенести это в свою процедуру интеграции. , Это правильно, интегрировать, интегрировать, интегрировать ! Как ты это делаешь? Ну, это немного больше исследований, и, возможно, сообщение в блоге? - Наверное. Чтобы получить правильную информацию, вот отличная статья о Автоматизация релизов с помощью MSBuild и установщика Windows XML .

Ух ты, я надеюсь, что ты прочитал все это (все вы двое) и многому научился. Я надеюсь, что это помогает кому-то, кроме меня.

Спасибо!

0 голосов
/ 17 ноября 2009

Похоже, вы выяснили сценарий обновления, теперь вам просто нужно выяснить Где разместить RemoveExistingProducts в крупном обновлении MSI , чтобы не переустанавливать функции, если они не изменились:)

...