rubrapack Manual←↑→

4 More files and folders

Goal: install a whole program folder - the program, a readme under another name, a settings file the user may change, a folder of documents, samples in sub folders, an empty folder for data - and clean up the log files the program writes.

4.1 The folder#

C:\work\hello\
    dist\
        hello.exe
        readme.txt
        settings.ini
        docs\
            guide.txt
        samples\
            sample1.txt
            sub\
                sample2.txt
    hello.toml

4.2 The source#

# tutorial 04: hello.toml
format = 1

[package]
name = "Hello"
manufacturer = "Example Software"
version = "$(VERSION)"
arch = "x64"
upgrade-code = "{3F2A6C1D-8B4E-4F7A-9C2D-5E6F7A8B9C0D}"

[define]
VERSION = "1.2.0"

[dir.INSTALLDIR]
path = "$(ProgramFiles)/Hello"

[dir.DocsDir]
path = "$(INSTALLDIR)/docs"

[dir.SamplesDir]
path = "$(INSTALLDIR)/samples"

[file.Hello]
dir = "INSTALLDIR"
source = "dist/hello.exe"

[file.Readme]
dir = "INSTALLDIR"
source = "dist/readme.txt"
name = "Read me.txt"
vital = false

[file.Settings]
dir = "INSTALLDIR"
source = "dist/settings.ini"
keep = true

[files.DocFiles]
dir = "DocsDir"
glob = "dist/docs/**"

[files.SampleFiles]
dir = "SamplesDir"
glob = "dist/samples/**/*.txt"

[folder.Data]
dir = "INSTALLDIR"
name = "data"
keep = true

[remove.Logs]
dir = "INSTALLDIR"
name = "*.log"
on = "uninstall"

[copy.ReadmeInDocs]
source = "file:Readme"
dir = "DocsDir"
name = "readme.txt"

Build it and look at the files:

C:\work\hello> rubrapack build hello.toml -o hello.msi
C:\work\hello> rubrapack inspect hello.msi --files
[ProgramFiles64Folder]\Hello\Read me.txt	8	Readme
[ProgramFiles64Folder]\Hello\docs\guide.txt	6	F_6d1508f52f6615459567
[ProgramFiles64Folder]\Hello\hello.exe	17920	Hello
[ProgramFiles64Folder]\Hello\samples\sample1.txt	7	F_1dc2b5e85973ee91d955
[ProgramFiles64Folder]\Hello\samples\sub\sample2.txt	7	F_c9c5c4da73214a6abf37
[ProgramFiles64Folder]\Hello\settings.ini	23	Settings

(The output has more columns; only the path, the size and the ID are shown here.)

4.3 Folders: [dir.ID]#

A dir's path starts from a Windows folder or from another dir, written $(...), then names the folders below it:

pathOn the user's computer (typical)
$(ProgramFiles)/HelloC:\Program Files\Hello (for an x86 package: C:\Program Files (x86)\Hello)
$(INSTALLDIR)/docsC:\Program Files\Hello\docs - below the dir INSTALLDIR, wherever the user put it
$(ProgramData)/HelloC:\ProgramData\Hello - data shared by all users
$(LOCALAPPDATA)/HelloC:\Users\<name>\AppData\Local\Hello

The Windows folders carry the names of their environment variables (%ProgramData%, %LOCALAPPDATA%); background chapter 9 explains them. Building on INSTALLDIR rather than repeating $(ProgramFiles)/Hello matters once users may choose the install folder (chapter 6): docs then follows the folder they chose. The full list is in the Reference part (Windows names).

4.4 One file: [file.ID]#

4.5 Many files: [files.ID]#

glob is a path with wildcards: * is any characters within one folder name, ? one character, ** any number of folders. Every file that matches is installed, and the folders below the first wildcard are recreated under dir:

globdist\samples\sub\sample2.txt goes to
dist/samples/**/*.txt into SamplesDir...\Hello\samples\sub\sample2.txt
dist/samples/*.txt into SamplesDirnot installed: * does not go into sub

The matches are sorted by name, so the package is the same whatever order the file system lists them in. A glob that matches nothing stops the build (RP1503) - usually a typo in the path. rubrapack gives each matched file an ID of its own (F_ and a number derived from its path).

4.6 An empty folder: [folder.ID]#

[folder.Data] creates data inside INSTALLDIR although no file goes there - a place for the program to write. keep = true leaves it (and whatever the program wrote in it) when the product is removed.

4.7 Cleaning up: [remove.ID]#

Files the program creates itself - logs, caches - are not the installer's, so Windows Installer would leave them, and with them the folder. [remove.Logs] deletes *.log in INSTALLDIR when the product is removed (on = "uninstall"). on = "install" deletes at installation (files an earlier version left behind), on = "both" at either. Without name, the folder itself is removed if it is empty. Folders that existed before the installation are never removed, and a failed installation puts removed files back.

An upgrade removes the old version, so it also runs the old version's on = "uninstall" rows. If the new version still wants those files - a cache it would rebuild slowly, say - add upgrade = false: they are then deleted only when the product is really removed. Since the old version's own rows run, this helps from the first version that has it.

4.8 A second copy: [copy.ID]#

[copy.ReadmeInDocs] installs another copy of the file Readme into DocsDir as readme.txt. The copy comes and goes with its source.

4.9 Two more keys you may meet#

4.10 What happened inside#

Windows Installer installs components: small groups of resources that are installed and removed together, each with a GUID and a key path (the thing whose presence means "installed"). rubrapack makes one component per file, which is the safe rule, and one more for each folder, removal and copy that needs one:

C:\work\hello> rubrapack inspect hello.msi Component
...
C_74a883a037bc227f9189	{51A68DD4-96FA-83C0-86AA-F20D51339238}	INSTALLDIR	272		Settings
C_cec3a9b89b2e391393d0	{615660C7-986E-8FB8-87AF-0616B544A6F9}	Data	272
...

The 272 in the attributes column is 256 + 16: 256 means a 64-bit component, 16 "permanent" - keep = true. Part IV describes these tables; RemoveFile, CreateFolder and DuplicateFile hold the removal, the empty folder and the copy.