2019-11-04 16:16:13 +00:00
|
|
|
// Copyright © 2019 Ettore Di Giacinto <mudler@gentoo.org>
|
|
|
|
//
|
|
|
|
// This program is free software; you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU General Public License as published by
|
|
|
|
// the Free Software Foundation; either version 2 of the License, or
|
|
|
|
// (at your option) any later version.
|
|
|
|
//
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU General Public License along
|
|
|
|
// with this program; if not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
package compiler
|
|
|
|
|
|
|
|
import (
|
2019-11-08 17:28:01 +00:00
|
|
|
"io/ioutil"
|
|
|
|
"path/filepath"
|
|
|
|
|
2019-11-05 16:36:22 +00:00
|
|
|
pkg "github.com/mudler/luet/pkg/package"
|
2019-11-15 23:38:07 +00:00
|
|
|
"github.com/mudler/luet/pkg/solver"
|
2020-02-13 13:15:43 +00:00
|
|
|
"github.com/otiai10/copy"
|
2019-11-04 16:16:13 +00:00
|
|
|
yaml "gopkg.in/yaml.v2"
|
|
|
|
)
|
|
|
|
|
2019-11-15 17:11:26 +00:00
|
|
|
type LuetCompilationspecs []LuetCompilationSpec
|
|
|
|
|
|
|
|
func NewLuetCompilationspecs(s ...CompilationSpec) CompilationSpecs {
|
|
|
|
all := LuetCompilationspecs{}
|
|
|
|
|
|
|
|
for _, spec := range s {
|
|
|
|
all.Add(spec)
|
|
|
|
}
|
|
|
|
return &all
|
|
|
|
}
|
|
|
|
|
|
|
|
func (specs LuetCompilationspecs) Len() int {
|
|
|
|
return len(specs)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (specs *LuetCompilationspecs) Remove(s CompilationSpecs) CompilationSpecs {
|
|
|
|
newSpecs := LuetCompilationspecs{}
|
|
|
|
SPECS:
|
|
|
|
for _, spec := range specs.All() {
|
|
|
|
for _, target := range s.All() {
|
|
|
|
if target.GetPackage().Matches(spec.GetPackage()) {
|
|
|
|
continue SPECS
|
|
|
|
}
|
|
|
|
}
|
|
|
|
newSpecs.Add(spec)
|
|
|
|
}
|
|
|
|
return &newSpecs
|
|
|
|
}
|
|
|
|
|
|
|
|
func (specs *LuetCompilationspecs) Add(s CompilationSpec) {
|
|
|
|
c, ok := s.(*LuetCompilationSpec)
|
|
|
|
if !ok {
|
|
|
|
panic("LuetCompilationspecs supports only []LuetCompilationSpec")
|
|
|
|
}
|
|
|
|
*specs = append(*specs, *c)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (specs *LuetCompilationspecs) All() []CompilationSpec {
|
|
|
|
var cspecs []CompilationSpec
|
|
|
|
for i, _ := range *specs {
|
|
|
|
f := (*specs)[i]
|
|
|
|
cspecs = append(cspecs, &f)
|
|
|
|
}
|
|
|
|
|
|
|
|
return cspecs
|
|
|
|
}
|
|
|
|
|
|
|
|
func (specs *LuetCompilationspecs) Unique() CompilationSpecs {
|
|
|
|
newSpecs := LuetCompilationspecs{}
|
|
|
|
seen := map[string]bool{}
|
|
|
|
|
|
|
|
for i, _ := range *specs {
|
|
|
|
j := (*specs)[i]
|
|
|
|
_, ok := seen[j.GetPackage().GetFingerPrint()]
|
|
|
|
if !ok {
|
|
|
|
seen[j.GetPackage().GetFingerPrint()] = true
|
|
|
|
newSpecs = append(newSpecs, j)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return &newSpecs
|
|
|
|
}
|
|
|
|
|
2019-11-04 16:16:13 +00:00
|
|
|
type LuetCompilationSpec struct {
|
2019-12-01 20:04:22 +00:00
|
|
|
Steps []string `json:"steps"` // Are run inside a container and the result layer diff is saved
|
|
|
|
Env []string `json:"env"`
|
2019-11-15 23:38:07 +00:00
|
|
|
Prelude []string `json:"prelude"` // Are run inside the image which will be our builder
|
|
|
|
Image string `json:"image"`
|
|
|
|
Seed string `json:"seed"`
|
2019-11-23 14:42:05 +00:00
|
|
|
Package *pkg.DefaultPackage `json:"package"`
|
2019-11-15 23:38:07 +00:00
|
|
|
SourceAssertion solver.PackagesAssertions `json:"-"`
|
2020-05-16 19:34:27 +00:00
|
|
|
PackageDir string `json:"package_dir" yaml:"package_dir"`
|
2019-11-15 23:38:07 +00:00
|
|
|
|
2020-02-13 13:15:43 +00:00
|
|
|
Retrieve []string `json:"retrieve"`
|
|
|
|
|
2019-11-15 23:38:07 +00:00
|
|
|
OutputPath string `json:"-"` // Where the build processfiles go
|
|
|
|
Unpack bool `json:"unpack"`
|
|
|
|
Includes []string `json:"includes"`
|
2020-11-08 14:35:24 +00:00
|
|
|
Excludes []string `json:"excludes"`
|
2019-11-04 16:16:13 +00:00
|
|
|
}
|
|
|
|
|
2019-11-05 16:36:22 +00:00
|
|
|
func NewLuetCompilationSpec(b []byte, p pkg.Package) (CompilationSpec, error) {
|
2019-11-04 16:16:13 +00:00
|
|
|
var spec LuetCompilationSpec
|
|
|
|
err := yaml.Unmarshal(b, &spec)
|
|
|
|
if err != nil {
|
|
|
|
return &spec, err
|
|
|
|
}
|
2019-11-22 23:29:24 +00:00
|
|
|
spec.Package = p.(*pkg.DefaultPackage)
|
2019-11-04 16:16:13 +00:00
|
|
|
return &spec, nil
|
|
|
|
}
|
2019-11-15 23:38:07 +00:00
|
|
|
func (a *LuetCompilationSpec) GetSourceAssertion() solver.PackagesAssertions {
|
|
|
|
return a.SourceAssertion
|
|
|
|
}
|
2019-11-04 16:16:13 +00:00
|
|
|
|
2019-11-15 23:38:07 +00:00
|
|
|
func (a *LuetCompilationSpec) SetSourceAssertion(as solver.PackagesAssertions) {
|
|
|
|
a.SourceAssertion = as
|
|
|
|
}
|
2019-11-05 16:36:22 +00:00
|
|
|
func (cs *LuetCompilationSpec) GetPackage() pkg.Package {
|
|
|
|
return cs.Package
|
|
|
|
}
|
|
|
|
|
2020-05-16 19:34:27 +00:00
|
|
|
func (cs *LuetCompilationSpec) GetPackageDir() string {
|
|
|
|
return cs.PackageDir
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cs *LuetCompilationSpec) SetPackageDir(s string) {
|
|
|
|
cs.PackageDir = s
|
|
|
|
}
|
|
|
|
|
2019-11-05 16:36:22 +00:00
|
|
|
func (cs *LuetCompilationSpec) BuildSteps() []string {
|
|
|
|
return cs.Steps
|
|
|
|
}
|
|
|
|
|
2019-11-13 08:42:52 +00:00
|
|
|
func (cs *LuetCompilationSpec) ImageUnpack() bool {
|
|
|
|
return cs.Unpack
|
|
|
|
}
|
|
|
|
|
2019-11-08 17:28:01 +00:00
|
|
|
func (cs *LuetCompilationSpec) GetPreBuildSteps() []string {
|
2019-11-10 09:45:13 +00:00
|
|
|
return cs.Prelude
|
2019-11-08 17:28:01 +00:00
|
|
|
}
|
|
|
|
|
2019-11-14 16:43:47 +00:00
|
|
|
func (cs *LuetCompilationSpec) GetIncludes() []string {
|
|
|
|
return cs.Includes
|
|
|
|
}
|
|
|
|
|
2020-11-08 14:35:24 +00:00
|
|
|
func (cs *LuetCompilationSpec) GetExcludes() []string {
|
|
|
|
return cs.Excludes
|
|
|
|
}
|
|
|
|
|
2020-02-13 13:15:43 +00:00
|
|
|
func (cs *LuetCompilationSpec) GetRetrieve() []string {
|
|
|
|
return cs.Retrieve
|
|
|
|
}
|
|
|
|
|
2019-11-05 16:36:22 +00:00
|
|
|
func (cs *LuetCompilationSpec) GetSeedImage() string {
|
|
|
|
return cs.Seed
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cs *LuetCompilationSpec) GetImage() string {
|
|
|
|
return cs.Image
|
|
|
|
}
|
|
|
|
|
2019-11-08 17:30:13 +00:00
|
|
|
func (cs *LuetCompilationSpec) GetOutputPath() string {
|
|
|
|
return cs.OutputPath
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *LuetCompilationSpec) Rel(s string) string {
|
|
|
|
return filepath.Join(p.GetOutputPath(), s)
|
|
|
|
}
|
|
|
|
|
2019-11-05 16:36:22 +00:00
|
|
|
func (cs *LuetCompilationSpec) SetImage(s string) {
|
|
|
|
cs.Image = s
|
|
|
|
}
|
|
|
|
|
2019-11-08 17:30:13 +00:00
|
|
|
func (cs *LuetCompilationSpec) SetOutputPath(s string) {
|
|
|
|
cs.OutputPath = s
|
|
|
|
}
|
|
|
|
|
2019-11-05 16:36:22 +00:00
|
|
|
func (cs *LuetCompilationSpec) SetSeedImage(s string) {
|
|
|
|
cs.Seed = s
|
|
|
|
}
|
|
|
|
|
2021-01-03 19:08:04 +00:00
|
|
|
func (cs *LuetCompilationSpec) EmptyPackage() bool {
|
|
|
|
return len(cs.BuildSteps()) == 0 && len(cs.GetPreBuildSteps()) == 0 && !cs.UnpackedPackage()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cs *LuetCompilationSpec) UnpackedPackage() bool {
|
|
|
|
// If package_dir was specified in the spec, we want to treat the content of the directory
|
|
|
|
// as the root of our archive. ImageUnpack is implied to be true. override it
|
|
|
|
unpack := cs.ImageUnpack()
|
|
|
|
if cs.GetPackageDir() != "" {
|
|
|
|
unpack = true
|
|
|
|
}
|
|
|
|
return unpack
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cs *LuetCompilationSpec) HasImageSource() bool {
|
|
|
|
return len(cs.GetPackage().GetRequires()) != 0 || cs.GetImage() != ""
|
|
|
|
}
|
|
|
|
|
2020-02-13 13:15:43 +00:00
|
|
|
func (cs *LuetCompilationSpec) CopyRetrieves(dest string) error {
|
|
|
|
var err error
|
|
|
|
if len(cs.Retrieve) > 0 {
|
|
|
|
for _, s := range cs.Retrieve {
|
|
|
|
matches, err := filepath.Glob(cs.Rel(s))
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, m := range matches {
|
|
|
|
err = copy.Copy(m, filepath.Join(dest, filepath.Base(m)))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-12-12 10:16:34 +00:00
|
|
|
func (cs *LuetCompilationSpec) genDockerfile(image string, steps []string) string {
|
2019-11-05 16:36:22 +00:00
|
|
|
spec := `
|
2020-12-12 10:16:34 +00:00
|
|
|
FROM ` + image + `
|
2019-11-05 16:36:22 +00:00
|
|
|
COPY . /luetbuild
|
|
|
|
WORKDIR /luetbuild
|
2019-12-01 20:04:22 +00:00
|
|
|
ENV PACKAGE_NAME=` + cs.Package.GetName() + `
|
|
|
|
ENV PACKAGE_VERSION=` + cs.Package.GetVersion() + `
|
2019-12-01 20:26:50 +00:00
|
|
|
ENV PACKAGE_CATEGORY=` + cs.Package.GetCategory()
|
2019-12-01 20:04:22 +00:00
|
|
|
|
2020-02-13 13:15:43 +00:00
|
|
|
if len(cs.Retrieve) > 0 {
|
|
|
|
for _, s := range cs.Retrieve {
|
|
|
|
//var file string
|
|
|
|
// if helpers.IsValidUrl(s) {
|
|
|
|
// file = s
|
|
|
|
// } else {
|
|
|
|
// file = cs.Rel(s)
|
|
|
|
// }
|
|
|
|
spec = spec + `
|
|
|
|
ADD ` + s + ` /luetbuild/`
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-01 20:04:22 +00:00
|
|
|
for _, s := range cs.Env {
|
|
|
|
spec = spec + `
|
|
|
|
ENV ` + s
|
|
|
|
}
|
|
|
|
|
2020-12-12 10:16:34 +00:00
|
|
|
for _, s := range steps {
|
2019-11-08 17:28:01 +00:00
|
|
|
spec = spec + `
|
|
|
|
RUN ` + s
|
|
|
|
}
|
2020-12-12 10:16:34 +00:00
|
|
|
return spec
|
2019-11-05 16:36:22 +00:00
|
|
|
}
|
|
|
|
|
2020-12-12 10:55:25 +00:00
|
|
|
// RenderBuildImage renders the dockerfile of the image used as a pre-build step
|
2020-12-12 10:16:34 +00:00
|
|
|
func (cs *LuetCompilationSpec) RenderBuildImage() (string, error) {
|
|
|
|
return cs.genDockerfile(cs.GetSeedImage(), cs.GetPreBuildSteps()), nil
|
2020-12-06 23:00:32 +00:00
|
|
|
|
2020-12-12 10:16:34 +00:00
|
|
|
}
|
2019-11-05 16:36:22 +00:00
|
|
|
|
2020-12-12 10:55:25 +00:00
|
|
|
// RenderStepImage renders the dockerfile used for the image used for building the package
|
2020-12-12 10:16:34 +00:00
|
|
|
func (cs *LuetCompilationSpec) RenderStepImage(image string) (string, error) {
|
|
|
|
return cs.genDockerfile(image, cs.BuildSteps()), nil
|
2019-11-05 16:36:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (cs *LuetCompilationSpec) WriteBuildImageDefinition(path string) error {
|
|
|
|
data, err := cs.RenderBuildImage()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return ioutil.WriteFile(path, []byte(data), 0644)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cs *LuetCompilationSpec) WriteStepImageDefinition(fromimage, path string) error {
|
|
|
|
data, err := cs.RenderStepImage(fromimage)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return ioutil.WriteFile(path, []byte(data), 0644)
|
2019-11-04 16:16:13 +00:00
|
|
|
}
|