如何构建 WiX 以便它根据 .msi 的安装位置复制文件?

发布于 2024-10-31 17:36:27 字数 119 浏览 0 评论 0原文

我必须使用 WiX 构建一个 .msi,并将其部署到多个环境中。每个环境。有自己的配置文件。现在,我们为每个环境构建一个 msi,我想放弃这种做法。有没有一种方法可以只构建一个 MSI,它可以根据运行位置智能地复制特定文件?

I have to build an .msi using WiX which gets deployed to several environments. Each env. has its own config file. Right now, we build one msi per environment and I want to move away from this practice. Is there a way to build just one MSI which is intelligent to copy specific files based on where it is running?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

楠木可依 2024-11-07 17:36:27

一旦您确定了您的目标环境实际上是什么,根据您定义的任何特征,您可以为要在每个环境中部署的每个配置文件创建一个离散组件,并为每个组件提供一个条件仅对于该目标环境评估为 true,否则评估为 false。

如果环境可能发生变化,您还需要使组件条件具有传递性,以便修复\升级能够部署正确的配置文件。

您可能面临的一个困难是组件应该代表唯一的资源。但看起来您可能有很多不同的配置文件,它们都具有相同的名称并且指向相同的目标文件夹。您可能会发现为您的配置文件指定所有不同的“伪”名称并使用 CopyFile 将伪版本复制到其终端目的地会更容易。

Once you have decided what your target environment actually is, based on whatever characteristics you define, you can create a discrete component for each of the config files you want to deploy per environment, and give each component a condition that evaluates to true only for that target environment, and false otherwise.

If the environment is likely to change, you need also to make the component condition transitive so that a repair\upgrade will deploy the correct config file.

One difficulty you may face is that components are supposed to represent unique resources. but it looks like you probably have lots of different config files all with the same name and destined for the same target folder. You may find it easier to give your config files all different 'pseudo' names and use a CopyFile to copy the pseudo version to its terminal destination.

江南月 2024-11-07 17:36:27

就我而言,我声明了这样的属性:

<Property Id="MACHINE_ENVIRONMENT" Admin="yes" />

从现在开始,每个组件都有一个“条件”元素,设置如下:

<Component Id="Log4Net_config" Guid="{666}">
  <Condition>MACHINE_ENVIRONMENT = "dev"</Condition>
  <File Id="Log4Net_config" Source="$(var.dir)\Log4Net.config.$(var.Environment)" Name="Log4Net.config" />
</Component>

通过命令行执行安装:

msiexec.exe /i "C:\mymsi.msi" MACHINE_ENVIRONMENT="dev"

这样我的单个 MSI 包含所有不同的 log4net 配置文件,但仅安装相关的取决于提供的标志。

In my case I declared a property like this:

<Property Id="MACHINE_ENVIRONMENT" Admin="yes" />

From now on, every component has a "Condition" element that is set like:

<Component Id="Log4Net_config" Guid="{666}">
  <Condition>MACHINE_ENVIRONMENT = "dev"</Condition>
  <File Id="Log4Net_config" Source="$(var.dir)\Log4Net.config.$(var.Environment)" Name="Log4Net.config" />
</Component>

Execute the installalation via command line:

msiexec.exe /i "C:\mymsi.msi" MACHINE_ENVIRONMENT="dev"

That way my single MSI contains all the different log4net configuration files, but only installs the relevant one depending on the provided flag.

棒棒糖 2024-11-07 17:36:27

MSI 文件表 需要指定要安装的文件的字节大小,要根据安装源位置执行某些操作将需要自定义操作(通常是承认失败)

请参阅我的问题替换 MSI 内小文件的最简单解决方案? - 我得到的解决方案是创建 MSI 转换(MST)。我发布的原始代码片段不适用于 Windows 7,因此这里有一个更新:

Option Explicit

Const MY_CONFIG = "MyConfigApp.xml"
Const CAB_FILE = "config.cab"
Const MSI = "MyApp.msi"

Dim filesys : Set filesys=CreateObject("Scripting.FileSystemObject")

If filesys.FileExists("temp.tmp") Then filesys.DeleteFile("temp.tmp")
filesys.CopyFile MSI, "temp.tmp"

Dim installer, database, database2, view
Set installer = CreateObject("WindowsInstaller.Installer")
Set database = installer.OpenDatabase ("temp.tmp", 1)
Set database2 = installer.OpenDatabase (MSI, 1)

If Not filesys.FileExists(MY_CONFIG) Then WScript.Quit 2 ' No config file, abort!

Dim objFile, size, result, seq, objCab

' MakeCab object has been depreciated so we fallback to makecab.exe for with Windows 7
On Error Resume Next ' Disable error handling, for a moment
Set objCab = CreateObject("MakeCab.MakeCab.1") 
On Error Goto 0  ' Turn error handling back on

If IsObject(objCab) Then ' Object creation successful - use XP method   
    objCab.CreateCab CAB_FILE, False, False, False
    objCab.AddFile MY_CONFIG, filesys.GetFileName(MY_CONFIG)
    objCab.CloseCab
    Set objCab = Nothing
Else ' object creation failed - try Windows 7 method
    Dim WshShell, oExec
    Set WshShell = CreateObject("WScript.Shell")
    Set oExec = WshShell.Exec("makecab " & filesys.GetFileName(MY_CONFIG) & " " & CAB_FILE)
End If

Set objFile = filesys.GetFile(MY_CONFIG)
size = objFile.Size

Set view = database.OpenView ("SELECT LastSequence FROM Media WHERE DiskId = 1")
view.Execute
Set result = view.Fetch
seq = result.StringData(1) + 1 ' Sequence for new configuration file

Set view = database.OpenView ("INSERT INTO Media (DiskId, LastSequence, Cabinet) VALUES ('2', '" & seq & "', '" & CAB_FILE & "')")
view.Execute

Set view = database.OpenView ("UPDATE File SET FileSize = " & size & ", Sequence = " & seq & ", FileName = 'MYC~2.CNF|MyConfigApp.xml' WHERE File = '" & MY_CONFIG & "'")
view.Execute

database.GenerateTransform database2, "CustomConfig.mst"
database.CreateTransformSummaryInfo database2, "CustomConfig.mst", 0, 0
filesys.DeleteFile("temp.tmp")

Set view = nothing
Set installer = nothing
Set database = nothing
Set database2 = nothing
Set filesys = Nothing
WScript.Quit 0

The MSI File Table requires specifying the byte size of the file to be installed, to do something based on install source location would require a custom action (which are generally an admission of failure)

See my question Simplest solution to replace a tiny file inside an MSI? - the solution I arrived at is to create an MSI Transform (MST). The original code snippet I posted doesn't work on Windows 7, so here's an update:

Option Explicit

Const MY_CONFIG = "MyConfigApp.xml"
Const CAB_FILE = "config.cab"
Const MSI = "MyApp.msi"

Dim filesys : Set filesys=CreateObject("Scripting.FileSystemObject")

If filesys.FileExists("temp.tmp") Then filesys.DeleteFile("temp.tmp")
filesys.CopyFile MSI, "temp.tmp"

Dim installer, database, database2, view
Set installer = CreateObject("WindowsInstaller.Installer")
Set database = installer.OpenDatabase ("temp.tmp", 1)
Set database2 = installer.OpenDatabase (MSI, 1)

If Not filesys.FileExists(MY_CONFIG) Then WScript.Quit 2 ' No config file, abort!

Dim objFile, size, result, seq, objCab

' MakeCab object has been depreciated so we fallback to makecab.exe for with Windows 7
On Error Resume Next ' Disable error handling, for a moment
Set objCab = CreateObject("MakeCab.MakeCab.1") 
On Error Goto 0  ' Turn error handling back on

If IsObject(objCab) Then ' Object creation successful - use XP method   
    objCab.CreateCab CAB_FILE, False, False, False
    objCab.AddFile MY_CONFIG, filesys.GetFileName(MY_CONFIG)
    objCab.CloseCab
    Set objCab = Nothing
Else ' object creation failed - try Windows 7 method
    Dim WshShell, oExec
    Set WshShell = CreateObject("WScript.Shell")
    Set oExec = WshShell.Exec("makecab " & filesys.GetFileName(MY_CONFIG) & " " & CAB_FILE)
End If

Set objFile = filesys.GetFile(MY_CONFIG)
size = objFile.Size

Set view = database.OpenView ("SELECT LastSequence FROM Media WHERE DiskId = 1")
view.Execute
Set result = view.Fetch
seq = result.StringData(1) + 1 ' Sequence for new configuration file

Set view = database.OpenView ("INSERT INTO Media (DiskId, LastSequence, Cabinet) VALUES ('2', '" & seq & "', '" & CAB_FILE & "')")
view.Execute

Set view = database.OpenView ("UPDATE File SET FileSize = " & size & ", Sequence = " & seq & ", FileName = 'MYC~2.CNF|MyConfigApp.xml' WHERE File = '" & MY_CONFIG & "'")
view.Execute

database.GenerateTransform database2, "CustomConfig.mst"
database.CreateTransformSummaryInfo database2, "CustomConfig.mst", 0, 0
filesys.DeleteFile("temp.tmp")

Set view = nothing
Set installer = nothing
Set database = nothing
Set database2 = nothing
Set filesys = Nothing
WScript.Quit 0
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文