Skip to content

Commit 8da90ed

Browse files
committed
actions: install-deb: Implement action to install local Debian packages
The install-deb action allows local .deb packages to be installed using the apt command, much like the apt action but for local packages rather than for packages retrieved from remote apt repositories. Resolves: #157 Closes: #165 Signed-off-by: Christopher Obbard <[email protected]>
1 parent f55fbfa commit 8da90ed

File tree

6 files changed

+220
-0
lines changed

6 files changed

+220
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ Some of the actions provided by debos to customise and produce images are:
4545
* `download`: download a single file from the internet
4646
* `filesystem-deploy`: deploy a root filesystem to an image previously created
4747
* `image-partition`: create an image file, make partitions and format them
48+
* `install-deb`: install packages and their dependencies from local deb packages
4849
* `ostree-commit`: create an OSTree commit from rootfs
4950
* `ostree-deploy`: deploy an OSTree branch to the image
5051
* `overlay`: do a recursive copy of directories or files to the target filesystem

actions/install_deb_action.go

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
/*
2+
InstallDeb Action
3+
4+
Install packages from .deb files and their dependencies to the target rootfs
5+
using 'apt'.
6+
7+
Dependencies will be satisfied first from the `packages` list (i.e. locally
8+
available packages) and then from the target's configured apt repositories. If
9+
`no-deps` is set to true, dependencies will not be installed.
10+
11+
Attempting to downgrade packages which are already installed is not allowed and
12+
will throw an error.
13+
14+
# Yaml syntax:
15+
- action: install-deb
16+
origin: name
17+
recommends: bool
18+
unauthenticated: bool
19+
no-deps: bool
20+
packages:
21+
- package_path.deb
22+
- *.deb
23+
24+
Mandatory properties:
25+
26+
- packages -- list of package files to install from the filesystem (or named
27+
origin). Resolves Unix-style glob patterns. If installing from a named origin,
28+
e.g. the result of a download action, the package path will be automatically
29+
generated from the origin contents and the `packages` property can be omitted.
30+
31+
Optional properties:
32+
33+
- origin -- reference to named origin. Defaults to `recipe` to install from local filesystem.
34+
35+
- recommends -- boolean indicating if suggested packages will be installed. Defaults to false.
36+
37+
- unauthenticated -- boolean indicating if unauthenticated packages can be installed. Defaults to false.
38+
39+
- no-deps -- boolean indicating if dependencies are not resolved by apt. Defaults to false.
40+
41+
- update -- boolean indicating if `apt update` will be ran before installing packages. Defaults to true.
42+
43+
Example to install all packages from recipe subdirectory `pkgs/`:
44+
45+
- action: install-deb
46+
description: Install Debian packages from local recipe
47+
packages:
48+
- pkgs/*.deb
49+
50+
Example to install named packages from recipe subdirectory `pkgs/`:
51+
52+
- action: install-deb
53+
description: Install Debian packages from local recipe
54+
packages:
55+
- pkgs/bmap-tools_*_all.deb
56+
- pkgs/fakemachine_*_amd64.deb
57+
58+
Example to download and install a package:
59+
60+
- action: download
61+
description: Install Debian package from url
62+
url: http://ftp.us.debian.org/debian/pool/main/b/bmap-tools/bmap-tools_3.5-2_all.deb
63+
name: bmap-tools-pkg
64+
65+
- action: install-deb
66+
description: Install Debian package from url
67+
origin: bmap-tools-pkg
68+
packages:
69+
- bmap-tools_*_all.deb
70+
*/
71+
72+
package actions
73+
74+
import (
75+
"fmt"
76+
"log"
77+
"os"
78+
"path"
79+
"path/filepath"
80+
"strings"
81+
82+
"github.com/go-debos/debos"
83+
"github.com/go-debos/debos/wrapper"
84+
)
85+
86+
type InstallDebAction struct {
87+
debos.BaseAction `yaml:",inline"`
88+
Recommends bool
89+
Unauthenticated bool
90+
NoDeps bool `yaml:"no-deps"`
91+
Update bool
92+
Origin string
93+
Packages []string
94+
}
95+
96+
func NewInstallDebAction() *InstallDebAction {
97+
return &InstallDebAction{Update: true}
98+
}
99+
100+
func (apt *InstallDebAction) Run(context *debos.Context) error {
101+
aptCommand := wrapper.NewAptCommand(*context, "install-deb")
102+
103+
/* check if named origin exists or fallback to RecipeDir if no origin set */
104+
var origin = context.RecipeDir
105+
if len(apt.Origin) > 0 {
106+
var found bool
107+
if origin, found = context.Origins[apt.Origin]; !found {
108+
return fmt.Errorf("origin %s not found", apt.Origin)
109+
}
110+
}
111+
112+
/* create a list of full paths of packages to install: if the origin is a
113+
* single file (e.g download action) then just return that package, otherwise
114+
* append package name to the origin path and glob to create a list of packages.
115+
* In other words, install all packages which are in the origin's directory.
116+
*/
117+
packages := []string{}
118+
file, err := os.Stat(origin)
119+
if err != nil {
120+
return err
121+
}
122+
123+
if file.IsDir() {
124+
if len(apt.Packages) == 0 {
125+
return fmt.Errorf("no packages defined")
126+
}
127+
for _, pattern := range apt.Packages {
128+
// resolve globs
129+
source := path.Join(origin, pattern)
130+
matches, err := filepath.Glob(source)
131+
if err != nil {
132+
return err
133+
}
134+
if len(matches) == 0 {
135+
return fmt.Errorf("file(s) not found after globbing: %s", pattern)
136+
}
137+
138+
packages = append(packages, matches...)
139+
}
140+
} else {
141+
if len(apt.Packages) > 0 {
142+
return fmt.Errorf("packages cannot be used when origin points to a single file")
143+
}
144+
packages = append(packages, origin)
145+
}
146+
147+
// de-duplicate the package list while preserving order
148+
seen := make(map[string]struct{}, len(packages))
149+
dedup := make([]string, 0, len(packages))
150+
for _, pkg := range packages {
151+
if _, ok := seen[pkg]; ok {
152+
continue
153+
}
154+
seen[pkg] = struct{}{}
155+
dedup = append(dedup, pkg)
156+
}
157+
packages = dedup
158+
159+
/* bind mount each package into rootfs & update the list with the
160+
* path relative to the chroot */
161+
for idx, pkg := range packages {
162+
log.Printf("Adding %s to install list", pkg)
163+
164+
/* Only bind mount the package if the file is outside the rootfs */
165+
if strings.HasPrefix(pkg, context.Rootdir) {
166+
pkg = strings.TrimPrefix(pkg, context.Rootdir)
167+
} else {
168+
aptCommand.AddBindMount(pkg, "")
169+
}
170+
171+
/* update pkg list with the complete resolved path */
172+
packages[idx] = pkg
173+
}
174+
175+
if apt.Update {
176+
if err := aptCommand.Update(); err != nil {
177+
return err
178+
}
179+
}
180+
181+
if err := aptCommand.Install(packages, apt.Recommends, apt.Unauthenticated, apt.NoDeps); err != nil {
182+
return err
183+
}
184+
185+
if err := aptCommand.Clean(); err != nil {
186+
return err
187+
}
188+
189+
return nil
190+
}

actions/recipe.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ other value than '512' is not supported by the 'uml' fakemachine backend.
6262
6363
- image-partition -- https://godoc.org/github.com/go-debos/debos/actions#hdr-ImagePartition_Action
6464
65+
- install-deb -- https://godoc.org/github.com/go-debos/debos/actions#hdr-InstallDeb_Action
66+
6567
- ostree-commit -- https://godoc.org/github.com/go-debos/debos/actions#hdr-OstreeCommit_Action
6668
6769
- ostree-deploy -- https://godoc.org/github.com/go-debos/debos/actions#hdr-OstreeDeploy_Action
@@ -146,6 +148,8 @@ func (y *YamlAction) UnmarshalYAML(unmarshal func(interface{}) error) error {
146148
y.Action = &OverlayAction{}
147149
case "image-partition":
148150
y.Action = &ImagePartitionAction{}
151+
case "install-deb":
152+
y.Action = NewInstallDebAction()
149153
case "filesystem-deploy":
150154
y.Action = NewFilesystemDeployAction()
151155
case "raw":

actions/recipe_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ actions:
5252
- action: download
5353
- action: filesystem-deploy
5454
- action: image-partition
55+
- action: install-deb
5556
- action: ostree-commit
5657
- action: ostree-deploy
5758
- action: overlay

tests/install-deb/pkgs/.empty

Whitespace-only changes.

tests/install-deb/test.yaml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
architecture: "amd64"
2+
3+
actions:
4+
- action: install-deb
5+
description: Install Debian packages from local recipe
6+
packages:
7+
- pkgs/*.deb
8+
9+
- action: install-deb
10+
description: Install Debian packages from local recipe
11+
packages:
12+
- pkgs/bmap-tools_*_all.deb
13+
- pkgs/fakemachine_*_amd64.deb
14+
15+
- action: download
16+
description: Install Debian package from url
17+
url: http://ftp.us.debian.org/debian/pool/main/b/bmap-tools/bmap-tools_3.5-2_all.deb
18+
name: bmap-tools-pkg
19+
20+
- action: install-deb
21+
description: Install Debian package from url
22+
origin: bmap-tools-pkg
23+
packages:
24+
- bmap-tools_*_all.deb

0 commit comments

Comments
 (0)