Skip to content

Commit a2a6d10

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 4e25af7 commit a2a6d10

File tree

6 files changed

+221
-0
lines changed

6 files changed

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

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)