fsprojects / FAKE

FAKE - F# Make
https://fake.build
Other
1.28k stars 585 forks source link

Document how to create msi setup using WIX. #288

Closed nripendra closed 10 years ago

nripendra commented 10 years ago

Hi I'm trying to build msi installer using WIX and FAKE. But it seems there is no useful documentation for this. Could any one point me to right direction?

forki commented 10 years ago

We have a little bit (incl. sample) of this here: http://fsharp.github.io/FAKE/apidocs/fake-wixhelper.html

nripendra commented 10 years ago

Yeah saw that one, but couldn't understand it. Sorry :)

forki commented 10 years ago

Yep someone needs to write a tutorial.

The basic idea is:

Most of the work is still in understanding WiX (which is soooo weird toolset)

nripendra commented 10 years ago

Thanks I'll give it a try. My wix templates uses visualstudio Macros like $(var.SolutionDir) how to pass them?

nripendra commented 10 years ago

Also I'm not quite sure about setupFiles, bundledDir..

Could you please point out what these lines are doing??

"@HelpFiles@",getFilesAsWiXString helpFiles "@ScriptFiles@",getFilesAsWiXString scriptFiles "@icons@", wixDir ALLFILES true (directoryInfo(bundledDir @@ "icons"))

forki commented 10 years ago

you can't use visual studio macros, but usually you know theses paths in the build script.

FullName "." // returns the full path of the current directory where your build script is located
forki commented 10 years ago
 "@HelpFiles@",getFilesAsWiXString helpFiles

The problem with files in Wix is that you have to give each of them a unique ID. If you want to replace a pattern with multiple files you need to keep the IDs unique. FAKE can help here.

But if your template doesn't need dynamic replacements than just remove these replacements for now.

nripendra commented 10 years ago

Thanks a lot

forki commented 10 years ago

and all of these are only samples for possible replacements.

forki commented 10 years ago

Did it work?

nripendra commented 10 years ago

Yes, I'm not using Fake to create my installers :)

Thank you

forki commented 10 years ago

fair enough ;-)

nripendra commented 10 years ago

Sorry, for typo :)

Yes, I'm now using Fake to create my installers :D

forki commented 10 years ago

oh. cool :+1:

devfunkd commented 9 years ago

Is there a sample script somewhere to see the basic implementation for WiXHelper? Sorry but the apidocs are very vague and difficult to understand as it doesn't piece things together well.

I've spent over a week with WixHelper and not making much progress, all I have is a WinForms application with another folder ("MobileInstall") in the solution root that I need bundled into a msi file.

Target "BuildSetup" (fun _ ->
    // Copy all important files to the deploy directory
    !! (buildDir + "/**/*.dll")
      ++ (buildDir + "/**/*.exe")
      ++ (buildDir + "/**/*.config")
      |> Copy deployDir 

    let TRUE = fun _ -> true
    let ALLFILES = fun _ -> true

    let _dir_files = "./"
    let dir_bin = directoryInfo (buildDir)
    let dir_mobile = directoryInfo (_dir_files @@ "MobileInstall")

    let wix_directories =
        [dir_bin; dir_mobile]
        |> Seq.map (fun dir -> (wixDir ALLFILES true dir))
        |> Seq.reduce (+)

    let replacements = [
        "@product.name@", "Foobar App"
        "@product.company@", "Foobar Company"
        "@product.description@", "Foobar Description"
        "@product.version@", "0.1.0.0"
        "@product.productcode@", "21654944-cf96-447f-890f-f7642e3128ec"
        "@productComponents@", getComponentIdsFromWiXString wix_directories]

    processTemplates replacements

    // run the WiX tools
    WiX (fun p -> {p with ToolDirectory = WiXPath}) 
        "setup"
        ("./Setup.wxs")
)

Am I missing something here? I've read the documentation over and over without much luck.

forki commented 9 years ago

WiX is realy complictaed thingy. I created exactly one WiX file in my life and I hope to never touch it again. But maybe we can find other people that are working with this. I will try to look into the history to see who else was playing with it.

That said: did you take a look at https://github.com/squirrel/squirrel.windows? people say only good things about it and we have a squirrel helper (which I personally never tried).

forki commented 9 years ago

/cc @bentayloruk, @DigitalFlow

devfunkd commented 9 years ago

I'll be happy to spend the time to a write a tutorial on this afterwards if someone is able to spend some time with me getting through these hurdles.

Here is the setup.wsx template I am using

<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
  <Product Id="*" UpgradeCode="9e578e3d-0119-425c-8633-f54ffaaa4929" Name="@product.name@" Version="@product.version@" Manufacturer="@product.company@" Language="1033">
    <Package InstallerVersion="400" Compressed="yes" InstallScope="perMachine" Comments="@product.version@" Description="@product.description@"/>
    <Media Id="1" Cabinet="product.cab" EmbedCab="yes"/>

    <Property Id="WIXUI_INSTALLDIR" Value="APPLICATIONROOTDIRECTORY" />
    <PropertyRef Id="NETFRAMEWORK35"/>
    <PropertyRef Id="NETFRAMEWORK45"/>
    <!-- Remove repair -->
    <Property Id="ARPNOREPAIR" Value="yes" Secure="yes" />

    <Upgrade Id="9e578e3d-0119-425c-8633-f54ffaaa4929">
      <UpgradeVersion Minimum="@product.version@" IncludeMinimum="no" OnlyDetect="yes" Property="NEWPRODUCTFOUND" />
    </Upgrade>

    <InstallExecuteSequence>
      <Custom Action="PreventDowngrading" After="FindRelatedProducts">NEWPRODUCTFOUND</Custom>
      <RemoveExistingProducts After="InstallValidate" />
    </InstallExecuteSequence>

    <InstallUISequence>
      <Custom Action="PreventDowngrading" After="FindRelatedProducts">NEWPRODUCTFOUND</Custom>
    </InstallUISequence>

    <CustomAction Id="PreventDowngrading" Error="Newer version already installed" />

    <Condition Message="This application requires .NET Framework 4.5.2. Please install the .NET Framework then run this installer again.">
      <![CDATA[Installed OR NETFRAMEWORK45]]>
    </Condition>
    <Condition Message="This application requires at least Windows 7 or Windows Server 2008 R2">
      <![CDATA[Installed OR (VersionNT >= 601)]]>
    </Condition>

    <!-- Step 1: Define the directory structure -->
    <Directory Id="TARGETDIR" Name="SourceDir">
      <Directory Id="ProgramFilesFolder">
        <Directory Id="APPLICATIONROOTDIRECTORY" Name="@product.name@">
        </Directory>
      </Directory>
    </Directory>

     <!-- Step 3: Tell WiX to install the files -->
     <Feature Id="Feature.Core"
                     Title="Core Components"
                     Description="Something Good"
                     Display="expand"
                     ConfigurableDirectory="TARGETDIR"
                     Level="1"
                     Absent="disallow"
                     AllowAdvertise="no">
          @productComponents@
        </Feature>

    <UI Id="WixUI_InstallDir">
        <TextStyle Id="WixUI_Font_Normal" FaceName="Tahoma" Size="8" />
        <TextStyle Id="WixUI_Font_Bigger" FaceName="Tahoma" Size="12" />
        <TextStyle Id="WixUI_Font_Title" FaceName="Tahoma" Size="9" Bold="yes" />

        <Property Id="DefaultUIFont" Value="WixUI_Font_Normal" />
        <Property Id="WixUI_Mode" Value="InstallDir" />

        <DialogRef Id="BrowseDlg" />
        <DialogRef Id="DiskCostDlg" />
        <DialogRef Id="ErrorDlg" />
        <DialogRef Id="FatalError" />
        <DialogRef Id="FilesInUse" />
        <DialogRef Id="MsiRMFilesInUse" />
        <DialogRef Id="PrepareDlg" />
        <DialogRef Id="ProgressDlg" />
        <DialogRef Id="ResumeDlg" />
        <DialogRef Id="UserExit" />

        <Publish Dialog="ExitDialog" Control="Finish" Event="EndDialog" Value="Return" Order="999">1</Publish>

        <Publish Dialog="WelcomeDlg" Control="Next" Event="NewDialog" Value="InstallDirDlg">1</Publish>

        <Publish Dialog="InstallDirDlg" Control="Back" Event="NewDialog" Value="WelcomeDlg">1</Publish>
        <Publish Dialog="InstallDirDlg" Control="Next" Event="SetTargetPath" Value="[WIXUI_INSTALLDIR]" Order="1">1</Publish>
        <Publish Dialog="InstallDirDlg" Control="Next" Event="NewDialog" Value="CustomizeDlg" Order="2">1</Publish>
        <Publish Dialog="InstallDirDlg" Control="ChangeFolder" Property="_BrowseProperty" Value="[WIXUI_INSTALLDIR]" Order="1">1</Publish>
        <Publish Dialog="InstallDirDlg" Control="ChangeFolder" Event="SpawnDialog" Value="BrowseDlg" Order="2">1</Publish>

        <Publish Dialog="CustomizeDlg" Control="Back" Event="NewDialog" Value="InstallDirDlg">NOT Installed</Publish>
        <Publish Dialog="CustomizeDlg" Control="Back" Event="NewDialog" Value="MaintenanceTypeDlg">Installed</Publish>
        <Publish Dialog="CustomizeDlg" Control="Next" Event="NewDialog" Value="VerifyReadyDlg">1</Publish>

        <Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="CustomizeDlg" Order="1">NOT Installed</Publish>
        <Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="MaintenanceTypeDlg" Order="2">Installed</Publish>

        <Publish Dialog="MaintenanceWelcomeDlg" Control="Next" Event="NewDialog" Value="MaintenanceTypeDlg">1</Publish>

        <Publish Dialog="MaintenanceTypeDlg" Control="ChangeButton" Event="NewDialog" Value="CustomizeDlg">1</Publish>
        <Publish Dialog="MaintenanceTypeDlg" Control="RemoveButton" Event="NewDialog" Value="VerifyReadyDlg">1</Publish>
        <Publish Dialog="MaintenanceTypeDlg" Control="Back" Event="NewDialog" Value="MaintenanceWelcomeDlg">1</Publish>

    </UI>

    <UIRef Id="WixUI_Common" />
    <UIRef Id="WixUI_ErrorProgressText" />
  </Product>
</Wix>

The error I keep getting is:

Setup.wxs
C:\project\main\Setup.wxs(2) : error CNDL0108 : The Product/@Version attrib
ute's value, '@product.version@', is not a valid version.  Legal version values
should look like 'x.x.x.x' where x is an integer from 0 to 65534.
C:\project\main\Setup.wxs(2) : error CNDL0010 : The Product/@Version attrib
ute was not found; it is required.
0x53A commented 9 years ago

It looks like @product.version@ does not get replaced before the file is processed by WiX, so I would look into processTemplates

devfunkd commented 9 years ago

processTemplates is not my function, it's part of WixHelper correct?

DigitalFlow commented 9 years ago

@devfunkd: ProcessTemplates is not WiX specific, it's pretty general. The Problem is that you are using it wrong. You need to pass in the files that the replacements should be applied onto. Try calling it like this:

processTemplates replacements "./Setup.wxs"

Kind Regards

devfunkd commented 9 years ago

Ok that seemed to work once I put "./Setup.wxs" between brackets [ ]. However it seems to not put any files into the .cab?

I checked my build folder and the files are there, so not sure why Wix isn't grabbing them and adding them?

Getting this: "C:\Projects\main\Setup.wxs(4) : warning LGHT1079 : The cabinet 'product .cab' does not contain any files. If this installation contains no files, this warning can likely be safely ignored. Otherwise, please add files to the cabine t or remove it. Finished Target: BuildSetup


Build Time Report

Target Duration


Clean 00:00:00.0146372 Build 00:00:01.4361398 BuildSetup 00:00:01.9114949 Total: 00:00:03.3861558

Status: Ok

Thank you so much for the help thus far, I've learn alot already and made some good progress these past few hours thanks to your help!

DigitalFlow commented 9 years ago

The reason for no files being in your setup is this:

<Directory Id="TARGETDIR" Name="SourceDir">
      <Directory Id="ProgramFilesFolder">
        <Directory Id="APPLICATIONROOTDIRECTORY" Name="@product.name@">
        </Directory>
      </Directory>
    </Directory>

You are not adding any files to this directory. Try changing it to:

<Directory Id=\"TARGETDIR\" Name=\"SourceDir\">
              <Directory Id=\"ProgramFilesFolder\" Name=\"ProgramFiles\">
                <Directory Id=\"PUBLISHERDIR\" Name=\"@Product.Publisher@\">
                  <Directory Id=\"INSTALLDIR\" Name=\"@Product.ProductName@\">
                    @Product.Directories@
                  </Directory>
                </Directory>
              </Directory>
            </Directory>

You can pass your wix_Directories into @Product.Directories@. Your WiX Feature may not contain the directories directly, you need the component refs. You can use the output of getComponentIdsFromWiXString wix_Directories for passing as your @productComponents@. You can also have a look at the API, we have functions for assisting in filling out your WiX script and even functions for generating WiX Templates on the fly: http://fsharp.github.io/FAKE/apidocs/fake-wixhelper.html

devfunkd commented 9 years ago

I've tried that and it didn't work, is there no working example of a full script implementation?

DigitalFlow commented 8 years ago

Now there is: http://fsharp.github.io/FAKE/wix.html

devfunkd commented 8 years ago

This is great, very helpful thank you!