Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable libexec artifacts #408

Merged
merged 9 commits into from
Oct 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions artifacts.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import (
type Artifacts struct {
// Binaries is the list of binaries to include in the package.
Binaries map[string]ArtifactConfig `yaml:"binaries,omitempty" json:"binaries,omitempty"`
// Libexec is the list of additional binaries that may be invoked by the main package binary.
Libexec map[string]ArtifactConfig `yaml:"libexec,omitempty" json:"libexec,omitempty"`
// Manpages is the list of manpages to include in the package.
Manpages map[string]ArtifactConfig `yaml:"manpages,omitempty" json:"manpages,omitempty"`
// DataDirs is a list of read-only architecture-independent data files, to be placed in /usr/share/
Expand Down
7 changes: 7 additions & 0 deletions docs/spec.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,13 @@
"type": "object",
"description": "Binaries is the list of binaries to include in the package."
},
"libexec": {
"additionalProperties": {
"$ref": "#/$defs/ArtifactConfig"
},
"type": "object",
"description": "Libexec is the list of additional binaries that may be invoked by the main package binary."
},
"manpages": {
"additionalProperties": {
"$ref": "#/$defs/ArtifactConfig"
Expand Down
10 changes: 10 additions & 0 deletions frontend/deb/debroot.go
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,16 @@ func createInstallScripts(worker llb.State, spec *dalec.Spec, dir string) []llb.
}
}

if len(spec.Artifacts.Libexec) > 0 {
sorted := dalec.SortMapKeys(spec.Artifacts.Libexec)
for _, key := range sorted {
cfg := spec.Artifacts.Libexec[key]
resolved := cfg.ResolveName(key)
targetDir := filepath.Join(`/usr/libexec`, cfg.SubPath)
writeInstall(key, targetDir, resolved)
}
}

if len(spec.Artifacts.Libs) > 0 {
sorted := dalec.SortMapKeys(spec.Artifacts.Libs)
for _, key := range sorted {
Expand Down
18 changes: 18 additions & 0 deletions frontend/rpm/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,14 @@ func (w *specWrapper) Install() fmt.Stringer {
}
}

if w.Spec.Artifacts.Libexec != nil {
cpuguy83 marked this conversation as resolved.
Show resolved Hide resolved
libexecFileKeys := dalec.SortMapKeys(w.Spec.Artifacts.Libexec)
for _, k := range libexecFileKeys {
le := w.Spec.Artifacts.Libexec[k]
copyArtifact(`%{buildroot}/%{_libexecdir}`, k, &le)
}
}

configKeys := dalec.SortMapKeys(w.Spec.Artifacts.ConfigFiles)
for _, c := range configKeys {
cfg := w.Spec.Artifacts.ConfigFiles[c]
Expand Down Expand Up @@ -599,6 +607,16 @@ func (w *specWrapper) Files() fmt.Stringer {
}
}

if w.Spec.Artifacts.Libexec != nil {
dataKeys := dalec.SortMapKeys(w.Spec.Artifacts.Libexec)
for _, k := range dataKeys {
le := w.Spec.Artifacts.Libexec[k]
targetDir := filepath.Join(`%{_libexecdir}`, le.SubPath)
fullPath := filepath.Join(targetDir, le.ResolveName(k))
fmt.Fprintln(b, fullPath)
}
}

configKeys := dalec.SortMapKeys(w.Spec.Artifacts.ConfigFiles)
for _, c := range configKeys {
cfg := w.Spec.Artifacts.ConfigFiles[c]
Expand Down
104 changes: 104 additions & 0 deletions test/azlinux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1015,6 +1015,110 @@ Environment="KUBELET_KUBECONFIG_ARGS=--bootstrap-kubeconfig=/etc/kubernetes/boot
})
})

t.Run("test libexec file installation", func(t *testing.T) {
t.Parallel()
spec := &dalec.Spec{
Name: "libexec-test",
Version: "0.0.1",
Revision: "1",
License: "MIT",
Website: "https://github.com/azure/dalec",
Vendor: "Dalec",
Packager: "Dalec",
Description: "Should install specified data files",
Sources: map[string]dalec.Source{
"no_name_no_subpath": {
Inline: &dalec.SourceInline{
File: &dalec.SourceInlineFile{
Contents: "#!/usr/bin/env bash\necho hello world",
Permissions: 0o755,
},
},
},
"name_only": {
Inline: &dalec.SourceInline{
File: &dalec.SourceInlineFile{
Contents: "#!/usr/bin/env bash\necho hello world",
Permissions: 0o755,
},
},
},
"name_and_subpath": {
Inline: &dalec.SourceInline{
File: &dalec.SourceInlineFile{
Contents: "#!/usr/bin/env bash\necho hello world",
Permissions: 0o755,
},
},
},
"subpath_only": {
Inline: &dalec.SourceInline{
File: &dalec.SourceInlineFile{
Contents: "#!/usr/bin/env bash\necho hello world",
Permissions: 0o755,
},
},
},
"nested_subpath": {
Inline: &dalec.SourceInline{
File: &dalec.SourceInlineFile{
Contents: "#!/usr/bin/env bash\necho hello world",
Permissions: 0o755,
},
},
},
},
Build: dalec.ArtifactBuild{},
Artifacts: dalec.Artifacts{
Binaries: map[string]dalec.ArtifactConfig{
"no_name_no_subpath": {},
},
Libexec: map[string]dalec.ArtifactConfig{
"no_name_no_subpath": {},
"name_only": {
Name: "this_is_the_name_only",
},
"name_and_subpath": {
SubPath: "subpath",
Name: "custom_name",
},
"subpath_only": dalec.ArtifactConfig{
SubPath: "custom",
},
"nested_subpath": dalec.ArtifactConfig{
SubPath: "libexec-test/abcdefg",
},
},
},
}

testEnv.RunTest(ctx, t, func(ctx context.Context, client gwclient.Client) {
req := newSolveRequest(withBuildTarget(testConfig.Target.Container), withSpec(ctx, t, spec))
res := solveT(ctx, t, client, req)

ref, err := res.SingleRef()
if err != nil {
t.Fatal(err)
}

if err := validatePathAndPermissions(ctx, ref, "/usr/libexec/no_name_no_subpath", 0o755); err != nil {
t.Fatal(err)
}
if err := validatePathAndPermissions(ctx, ref, "/usr/libexec/this_is_the_name_only", 0o755); err != nil {
t.Fatal(err)
}
if err := validatePathAndPermissions(ctx, ref, "/usr/libexec/subpath/custom_name", 0o755); err != nil {
t.Fatal(err)
}
if err := validatePathAndPermissions(ctx, ref, "/usr/libexec/custom/subpath_only", 0o755); err != nil {
t.Fatal(err)
}
if err := validatePathAndPermissions(ctx, ref, "/usr/libexec/libexec-test/abcdefg/nested_subpath", 0o755); err != nil {
t.Fatal(err)
}
})
})

t.Run("test config files handled", func(t *testing.T) {
t.Parallel()
spec := &dalec.Spec{
Expand Down
26 changes: 26 additions & 0 deletions website/docs/artifacts.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,32 @@ artifacts:
You may use a trailing wildcard to specify multiple binaries in a directory,
though behavior may differ between different OS's/distros.

### Libexec

Libexec files are additional executable files that may be executed by one of
the main package executables. On Linux these would typically get installed into
`/usr/libexec/` or `/usr/libexec/<main-executable-name>`.

Files under libexec are a mapping of file path to [artifact configuration](#artifact-configuration).
If `subpath` is not supplied, the artifact will be installed in `/usr/libexec`
directly. The file path is the path to a file that must be available after the
build section has finished. This path is relative to the working directory of
the build phase *before* any directory changes are made.

Example:

```yaml
name: my_package

artifacts:
# the following config will install my_bin at /usr/libexec/my package/my_bin
libexec:
src/my_bin:
```

You may use a trailing wildcard to specify multiple binaries in a directory,
though behavior may differ between different OS's/distros.

### Manpages

Manpages is short for manual pages.
Expand Down