Skip to content

Commit

Permalink
Add support for headers artifacts
Browse files Browse the repository at this point in the history
Signed-off-by: Jose Blanquicet <josebl@microsoft.com>
  • Loading branch information
blanquicet committed Oct 7, 2024
1 parent dce4d67 commit 156dfcb
Show file tree
Hide file tree
Showing 7 changed files with 156 additions and 2 deletions.
7 changes: 7 additions & 0 deletions artifacts.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ type Artifacts struct {
// the [ImageConfig].
Links []ArtifactSymlinkConfig `yaml:"links,omitempty" json:"links,omitempty"`

// Headers is a list of header files and/or folders to be installed.
// On linux this would typically be installed to /usr/include/.
Headers map[string]ArtifactConfig `yaml:"headers,omitempty" json:"headers,omitempty"`

// TODO: other types of artifacts (libexec, etc)
}

Expand Down Expand Up @@ -135,5 +139,8 @@ func (a *Artifacts) IsEmpty() bool {
if len(a.Links) > 0 {
return false
}
if len(a.Headers) > 0 {
return false
}
return true
}
7 changes: 7 additions & 0 deletions docs/spec.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,13 @@
},
"type": "array",
"description": "Links is the list of symlinks to be installed with the package\nLinks should only be used if the *package* should contain the link.\nFor making a container compatible with another image, use [PostInstall] in\nthe [ImageConfig]."
},
"headers": {
"additionalProperties": {
"$ref": "#/$defs/ArtifactConfig"
},
"type": "object",
"description": "Headers is a list of header files and/or folders to be installed.\nOn linux this would typically be installed to /usr/include/."
}
},
"additionalProperties": false,
Expand Down
9 changes: 9 additions & 0 deletions frontend/deb/debroot.go
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,15 @@ func createInstallScripts(worker llb.State, spec *dalec.Spec, dir string) []llb.
}
}

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

if units := spec.Artifacts.Systemd.GetUnits(); len(units) > 0 {
// deb-systemd will look for service files in DEBIAN/<package-name>[.<service-name>].<unit-type>
// To handle this we'll create symlinks to the actual unit files in the source.
Expand Down
15 changes: 15 additions & 0 deletions frontend/rpm/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,12 @@ func (w *specWrapper) Install() fmt.Stringer {
fmt.Fprintln(b, "ln -sf", l.Source, "%{buildroot}/"+l.Dest)
}

headersKeys := dalec.SortMapKeys(w.Spec.Artifacts.Headers)
for _, h := range headersKeys {
cfg := w.Spec.Artifacts.Headers[h]
copyArtifact(`%{buildroot}/%{_includedir}`, h, &cfg)
}

b.WriteString("\n")
return b
}
Expand Down Expand Up @@ -673,6 +679,15 @@ func (w *specWrapper) Files() fmt.Stringer {
fmt.Fprintln(b, l.Dest)
}

if len(w.Spec.Artifacts.Headers) > 0 {
headersKeys := dalec.SortMapKeys(w.Spec.Artifacts.Headers)
for _, h := range headersKeys {
hf := w.Spec.Artifacts.Headers[h]
path := filepath.Join(`%{_includedir}`, hf.SubPath, hf.ResolveName(h))
fmt.Fprintln(b, path)
}
}

b.WriteString("\n")
return b
}
Expand Down
41 changes: 41 additions & 0 deletions frontend/rpm/template_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,47 @@ fi
want := `%files
%license %{_licensedir}/test-pkg/licenses/LICENSE.md
`
assert.Equal(t, want, got)
})

t.Run("test headers templating using defaults", func(t *testing.T) {
t.Parallel()
w := &specWrapper{Spec: &dalec.Spec{
Name: "test-pkg",
Artifacts: dalec.Artifacts{
Headers: map[string]dalec.ArtifactConfig{
"test-headers": {},
},
},
}}

got := w.Files().String()
want := `%files
%{_includedir}/test-headers
`
assert.Equal(t, want, got)
})

t.Run("test headers templating using ArtifactConfig", func(t *testing.T) {
t.Parallel()
w := &specWrapper{Spec: &dalec.Spec{
Name: "test-pkg",
Artifacts: dalec.Artifacts{
Headers: map[string]dalec.ArtifactConfig{
"test-headers": {
Name: "sub-module-headers",
SubPath: "sub-module",
},
},
},
}}

got := w.Files().String()
want := `%files
%{_includedir}/sub-module/sub-module-headers
`
assert.Equal(t, want, got)
})
Expand Down
50 changes: 48 additions & 2 deletions test/azlinux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1059,7 +1059,7 @@ Environment="KUBELET_KUBECONFIG_ARGS=--bootstrap-kubeconfig=/etc/kubernetes/boot
})
})

t.Run("docs and licenses are handled correctly", func(t *testing.T) {
t.Run("docs and headers and licenses are handled correctly", func(t *testing.T) {
t.Parallel()
spec := &dalec.Spec{
Name: "test-docs-handled",
Expand Down Expand Up @@ -1103,6 +1103,30 @@ Environment="KUBELET_KUBECONFIG_ARGS=--bootstrap-kubeconfig=/etc/kubernetes/boot
},
},
},
"src5": {
Inline: &dalec.SourceInline{
Dir: &dalec.SourceInlineDir{
Files: map[string]*dalec.SourceInlineFile{
"header.h": {
Contents: "message=hello",
Permissions: 0o644,
},
},
},
},
},
"src6": {
Inline: &dalec.SourceInline{
Dir: &dalec.SourceInlineDir{
Files: map[string]*dalec.SourceInlineFile{
"header.h": {
Contents: "message=hello",
Permissions: 0o644,
},
},
},
},
},
},
Artifacts: dalec.Artifacts{
Docs: map[string]dalec.ArtifactConfig{
Expand All @@ -1117,15 +1141,37 @@ Environment="KUBELET_KUBECONFIG_ARGS=--bootstrap-kubeconfig=/etc/kubernetes/boot
SubPath: "license-subpath",
},
},
Headers: map[string]dalec.ArtifactConfig{
// Files with and without ArtifactConfig
"src1": {
Name: "renamed-src1",
SubPath: "header-subpath-src1",
},
"src2": {},
// Directories with and without ArtifactConfig
"src5": {
Name: "renamed-src5",
SubPath: "header-subpath-src5",
},
"src6": {},
},
},
Tests: []*dalec.TestSpec{
{
Name: "Doc files should be created in correct place",
Name: "Doc, lib and header files should be created in correct place",
Files: map[string]dalec.FileCheckOutput{
"/usr/share/doc/test-docs-handled/src1": {},
"/usr/share/doc/test-docs-handled/subpath/src2": {},
filepath.Join(testConfig.LicenseDir, "test-docs-handled/src3"): {},
filepath.Join(testConfig.LicenseDir, "test-docs-handled/license-subpath/src4"): {},
"/usr/include/header-subpath-src1/renamed-src1": {},
"/usr/include/src2": {},
"/usr/include/header-subpath-src5/renamed-src5": {
IsDir: true,
},
"/usr/include/src6": {
IsDir: true,
},
},
},
},
Expand Down
29 changes: 29 additions & 0 deletions website/docs/artifacts.md
Original file line number Diff line number Diff line change
Expand Up @@ -232,3 +232,32 @@ artifacts:
- source: /usr/lib/golang/go
dest: /usr/bin/go
```

### Headers

Headers are header to be included with the package. On Linux these typically go
under `/usr/include/`.

Headers are a mapping of file path to [artifact configuration](#artifact-configuration).
The file path is the path to a file or directory 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.

```yaml
artifacts:
headers:
src/my_header.h:
```

or for a directory:

```yaml
artifacts:
headers:
src/my_headers/:
```

Note that headers are not installed within a subdirectory of `/usr/include/`
with the name of the package. They are installed directly into `/usr/include/`.
For instance, for the above examples, the headers would be installed to
`/usr/include/my_header.h` and `/usr/include/my_headers/` respectively.

0 comments on commit 156dfcb

Please sign in to comment.