mirror of
https://github.com/mudler/luet.git
synced 2025-09-03 16:25:19 +00:00
Compare commits
13 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
356350f724 | ||
|
9d2ee1b760 | ||
|
fd12227d53 | ||
|
1e617b0c67 | ||
|
77b49d9c4a | ||
|
4c3532e3c6 | ||
|
f2ec065a89 | ||
|
7193ea03f9 | ||
|
beeb0dcaaa | ||
|
0de3177ddd | ||
|
45c8dfa19f | ||
|
186ac33156 | ||
|
bdc24b84a4 |
@@ -247,11 +247,12 @@ Build packages specifying multiple definition trees:
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, sp := range toCalculate {
|
for _, sp := range toCalculate {
|
||||||
packs, err := luetCompiler.ComputeDepTree(sp)
|
ht := compiler.NewHashTree(generalRecipe.GetDatabase())
|
||||||
|
hashTree, err := ht.Query(luetCompiler, sp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs = append(errs, err)
|
errs = append(errs, err)
|
||||||
}
|
}
|
||||||
for _, p := range packs {
|
for _, p := range hashTree.Dependencies {
|
||||||
results.Packages = append(results.Packages,
|
results.Packages = append(results.Packages,
|
||||||
PackageResult{
|
PackageResult{
|
||||||
Name: p.Package.GetName(),
|
Name: p.Package.GetName(),
|
||||||
|
@@ -40,7 +40,7 @@ var Verbose bool
|
|||||||
var LockedCommands = []string{"install", "uninstall", "upgrade"}
|
var LockedCommands = []string{"install", "uninstall", "upgrade"}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
LuetCLIVersion = "0.14.2"
|
LuetCLIVersion = "0.14.7"
|
||||||
LuetEnvPrefix = "LUET"
|
LuetEnvPrefix = "LUET"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -97,7 +97,7 @@ To build a package, from a tree definition:
|
|||||||
|
|
||||||
plugin := viper.GetStringSlice("plugin")
|
plugin := viper.GetStringSlice("plugin")
|
||||||
|
|
||||||
bus.Manager.Load(plugin...).Register()
|
bus.Manager.Initialize(plugin...)
|
||||||
if len(bus.Manager.Plugins) != 0 {
|
if len(bus.Manager.Plugins) != 0 {
|
||||||
Info(":lollipop:Enabled plugins:")
|
Info(":lollipop:Enabled plugins:")
|
||||||
for _, p := range bus.Manager.Plugins {
|
for _, p := range bus.Manager.Plugins {
|
||||||
|
3
go.mod
3
go.mod
@@ -16,7 +16,6 @@ require (
|
|||||||
github.com/docker/docker v20.10.0-beta1.0.20201110211921-af34b94a78a1+incompatible
|
github.com/docker/docker v20.10.0-beta1.0.20201110211921-af34b94a78a1+incompatible
|
||||||
github.com/docker/go-units v0.4.0
|
github.com/docker/go-units v0.4.0
|
||||||
github.com/ecooper/qlearning v0.0.0-20160612200101-3075011a69fd
|
github.com/ecooper/qlearning v0.0.0-20160612200101-3075011a69fd
|
||||||
github.com/fsouza/go-dockerclient v1.6.4
|
|
||||||
github.com/genuinetools/img v0.5.11
|
github.com/genuinetools/img v0.5.11
|
||||||
github.com/ghodss/yaml v1.0.0
|
github.com/ghodss/yaml v1.0.0
|
||||||
github.com/google/go-containerregistry v0.2.1
|
github.com/google/go-containerregistry v0.2.1
|
||||||
@@ -37,7 +36,7 @@ require (
|
|||||||
github.com/moby/sys/mount v0.2.0 // indirect
|
github.com/moby/sys/mount v0.2.0 // indirect
|
||||||
github.com/mudler/cobra-extensions v0.0.0-20200612154940-31a47105fe3d
|
github.com/mudler/cobra-extensions v0.0.0-20200612154940-31a47105fe3d
|
||||||
github.com/mudler/docker-companion v0.4.6-0.20200418093252-41846f112d87
|
github.com/mudler/docker-companion v0.4.6-0.20200418093252-41846f112d87
|
||||||
github.com/mudler/go-pluggable v0.0.0-20201113184918-d36448fc8f82
|
github.com/mudler/go-pluggable v0.0.0-20210513155700-54c6443073af
|
||||||
github.com/mudler/topsort v0.0.0-20201103161459-db5c7901c290
|
github.com/mudler/topsort v0.0.0-20201103161459-db5c7901c290
|
||||||
github.com/onsi/ginkgo v1.14.2
|
github.com/onsi/ginkgo v1.14.2
|
||||||
github.com/onsi/gomega v1.10.3
|
github.com/onsi/gomega v1.10.3
|
||||||
|
6
go.sum
6
go.sum
@@ -188,8 +188,6 @@ github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGX
|
|||||||
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
|
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
|
||||||
github.com/codahale/hdrhistogram v0.0.0-20160425231609-f8ad88b59a58/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
|
github.com/codahale/hdrhistogram v0.0.0-20160425231609-f8ad88b59a58/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
|
||||||
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
|
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
|
||||||
github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 h1:sDMmm+q/3+BukdIpxwO365v/Rbspp2Nt5XntgQRXq8Q=
|
|
||||||
github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM=
|
|
||||||
github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f h1:tSNMc+rJDfmYntojat8lljbt1mgKNpTxUZJsSzJ9Y1s=
|
github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f h1:tSNMc+rJDfmYntojat8lljbt1mgKNpTxUZJsSzJ9Y1s=
|
||||||
github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko=
|
github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko=
|
||||||
github.com/containerd/cgroups v0.0.0-20200217135630-d732e370d46d h1:UKAt78F1OvM4ceTn1VvXuYuatXohsFU1eSI2IBtTw9g=
|
github.com/containerd/cgroups v0.0.0-20200217135630-d732e370d46d h1:UKAt78F1OvM4ceTn1VvXuYuatXohsFU1eSI2IBtTw9g=
|
||||||
@@ -760,8 +758,8 @@ github.com/mudler/cobra-extensions v0.0.0-20200612154940-31a47105fe3d h1:fKh+rvw
|
|||||||
github.com/mudler/cobra-extensions v0.0.0-20200612154940-31a47105fe3d/go.mod h1:puRUWSwyecW2V355tKncwPVPRAjQBduPsFjG0mrV/Nw=
|
github.com/mudler/cobra-extensions v0.0.0-20200612154940-31a47105fe3d/go.mod h1:puRUWSwyecW2V355tKncwPVPRAjQBduPsFjG0mrV/Nw=
|
||||||
github.com/mudler/docker-companion v0.4.6-0.20200418093252-41846f112d87 h1:mGz7T8KvmHH0gLWPI5tQne8xl2cO3T8wrrb6Aa16Jxo=
|
github.com/mudler/docker-companion v0.4.6-0.20200418093252-41846f112d87 h1:mGz7T8KvmHH0gLWPI5tQne8xl2cO3T8wrrb6Aa16Jxo=
|
||||||
github.com/mudler/docker-companion v0.4.6-0.20200418093252-41846f112d87/go.mod h1:1w4zI1LYXDeiUXqedPcrT5eQJnmKR6dbg5iJMgSIP/Y=
|
github.com/mudler/docker-companion v0.4.6-0.20200418093252-41846f112d87/go.mod h1:1w4zI1LYXDeiUXqedPcrT5eQJnmKR6dbg5iJMgSIP/Y=
|
||||||
github.com/mudler/go-pluggable v0.0.0-20201113184918-d36448fc8f82 h1:Hkefw2tzoKATVUTFsCtDlUnY180+OE851qGbq45ATxk=
|
github.com/mudler/go-pluggable v0.0.0-20210513155700-54c6443073af h1:jixIxEgLSqu24eMiyzfCI+roa5IaOUhF546ePSFyHeY=
|
||||||
github.com/mudler/go-pluggable v0.0.0-20201113184918-d36448fc8f82/go.mod h1:4P/ULate+2QxoAQtojaRjyO5VGMhV0KLnSdAS8nuBbo=
|
github.com/mudler/go-pluggable v0.0.0-20210513155700-54c6443073af/go.mod h1:WmKcT8ONmhDQIqQ+HxU+tkGWjzBEyY/KFO8LTGCu4AI=
|
||||||
github.com/mudler/topsort v0.0.0-20201103161459-db5c7901c290 h1:426hFyXMpXeqIeGJn2cGAW9ogvM2Jf+Jv23gtVPvBLM=
|
github.com/mudler/topsort v0.0.0-20201103161459-db5c7901c290 h1:426hFyXMpXeqIeGJn2cGAW9ogvM2Jf+Jv23gtVPvBLM=
|
||||||
github.com/mudler/topsort v0.0.0-20201103161459-db5c7901c290/go.mod h1:uP5BBgFxq2wNWo7n1vnY5SSbgL0WDshVJrOO12tZ/lA=
|
github.com/mudler/topsort v0.0.0-20201103161459-db5c7901c290/go.mod h1:uP5BBgFxq2wNWo7n1vnY5SSbgL0WDshVJrOO12tZ/lA=
|
||||||
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||||
|
@@ -1,6 +1,8 @@
|
|||||||
package bus
|
package bus
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
. "github.com/mudler/luet/pkg/logger"
|
||||||
|
|
||||||
"github.com/mudler/go-pluggable"
|
"github.com/mudler/go-pluggable"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -47,21 +49,47 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Manager is the bus instance manager, which subscribes plugins to events emitted by Luet
|
// Manager is the bus instance manager, which subscribes plugins to events emitted by Luet
|
||||||
var Manager *pluggable.Manager = pluggable.NewManager(
|
var Manager *Bus = &Bus{
|
||||||
[]pluggable.EventType{
|
Manager: pluggable.NewManager(
|
||||||
EventPackageInstall,
|
[]pluggable.EventType{
|
||||||
EventPackageUnInstall,
|
EventPackageInstall,
|
||||||
EventPackagePreBuild,
|
EventPackageUnInstall,
|
||||||
EventPackagePreBuildArtifact,
|
EventPackagePreBuild,
|
||||||
EventPackagePostBuildArtifact,
|
EventPackagePreBuildArtifact,
|
||||||
EventPackagePostBuild,
|
EventPackagePostBuildArtifact,
|
||||||
EventRepositoryPreBuild,
|
EventPackagePostBuild,
|
||||||
EventRepositoryPostBuild,
|
EventRepositoryPreBuild,
|
||||||
EventImagePreBuild,
|
EventRepositoryPostBuild,
|
||||||
EventImagePrePull,
|
EventImagePreBuild,
|
||||||
EventImagePrePush,
|
EventImagePrePull,
|
||||||
EventImagePostBuild,
|
EventImagePrePush,
|
||||||
EventImagePostPull,
|
EventImagePostBuild,
|
||||||
EventImagePostPush,
|
EventImagePostPull,
|
||||||
},
|
EventImagePostPush,
|
||||||
)
|
},
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
type Bus struct {
|
||||||
|
*pluggable.Manager
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Bus) Initialize(plugin ...string) {
|
||||||
|
b.Manager.Load(plugin...).Register()
|
||||||
|
|
||||||
|
for _, e := range b.Manager.Events {
|
||||||
|
b.Manager.Response(e, func(p *pluggable.Plugin, r *pluggable.EventResponse) {
|
||||||
|
if r.Errored() {
|
||||||
|
Fatal("Plugin", p.Name, "at", p.Executable, "Error", r.Error)
|
||||||
|
}
|
||||||
|
Debug(
|
||||||
|
"plugin_event",
|
||||||
|
"received from",
|
||||||
|
p.Name,
|
||||||
|
"at",
|
||||||
|
p.Executable,
|
||||||
|
r,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -146,11 +146,6 @@ func (cs *LuetCompiler) CompileParallel(keepPermissions bool, ps *compilerspec.L
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, p := range ps.All() {
|
for _, p := range ps.All() {
|
||||||
asserts, err := cs.ComputeDepTree(p)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
p.SetSourceAssertion(asserts)
|
|
||||||
all <- p
|
all <- p
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -295,17 +290,6 @@ func (cs *LuetCompiler) unpackDelta(concurrency int, keepPermissions bool, p *co
|
|||||||
return artifact, nil
|
return artifact, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cs *LuetCompiler) genBuilderImageTag(p *compilerspec.LuetCompilationSpec, packageImage string) string {
|
|
||||||
// Use packageImage as salt into the fp being used
|
|
||||||
// so the hash is unique also in cases where
|
|
||||||
// some package deps does have completely different
|
|
||||||
// depgraphs
|
|
||||||
// TODO: We should use the image tag, or pass by the package assertion hash which is unique
|
|
||||||
// and identifies the deptree of the package.
|
|
||||||
return fmt.Sprintf("builder-%s", p.GetPackage().HashFingerprint(helpers.StripRegistryFromImage(packageImage)))
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cs *LuetCompiler) buildPackageImage(image, buildertaggedImage, packageImage string,
|
func (cs *LuetCompiler) buildPackageImage(image, buildertaggedImage, packageImage string,
|
||||||
concurrency int, keepPermissions bool,
|
concurrency int, keepPermissions bool,
|
||||||
p *compilerspec.LuetCompilationSpec) (backend.Options, backend.Options, error) {
|
p *compilerspec.LuetCompilationSpec) (backend.Options, backend.Options, error) {
|
||||||
@@ -680,33 +664,7 @@ func (cs *LuetCompiler) FromDatabase(db pkg.PackageDatabase, minimum bool, dst s
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ComputeMinimumCompilableSet strips specs that are eventually compiled by leafs
|
|
||||||
func (cs *LuetCompiler) ComputeMinimumCompilableSet(p ...*compilerspec.LuetCompilationSpec) ([]*compilerspec.LuetCompilationSpec, error) {
|
|
||||||
// Generate a set with all the deps of the provided specs
|
|
||||||
// we will use that set to remove the deps from the list of provided compilation specs
|
|
||||||
allDependencies := solver.PackagesAssertions{} // Get all packages that will be in deps
|
|
||||||
result := []*compilerspec.LuetCompilationSpec{}
|
|
||||||
for _, spec := range p {
|
|
||||||
ass, err := cs.ComputeDepTree(spec)
|
|
||||||
if err != nil {
|
|
||||||
return result, errors.Wrap(err, "computin specs deptree")
|
|
||||||
}
|
|
||||||
|
|
||||||
allDependencies = append(allDependencies, ass.Drop(spec.GetPackage())...)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, spec := range p {
|
|
||||||
if found := allDependencies.Search(spec.GetPackage().GetFingerPrint()); found == nil {
|
|
||||||
result = append(result, spec)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ComputeDepTree computes the dependency tree of a compilation spec and returns solver assertions
|
|
||||||
// in order to be able to compile the spec.
|
|
||||||
func (cs *LuetCompiler) ComputeDepTree(p *compilerspec.LuetCompilationSpec) (solver.PackagesAssertions, error) {
|
func (cs *LuetCompiler) ComputeDepTree(p *compilerspec.LuetCompilationSpec) (solver.PackagesAssertions, error) {
|
||||||
|
|
||||||
s := solver.NewResolver(cs.Options.SolverOptions.Options, pkg.NewInMemoryDatabase(false), cs.Database, pkg.NewInMemoryDatabase(false), cs.Options.SolverOptions.Resolver())
|
s := solver.NewResolver(cs.Options.SolverOptions.Options, pkg.NewInMemoryDatabase(false), cs.Database, pkg.NewInMemoryDatabase(false), cs.Options.SolverOptions.Resolver())
|
||||||
|
|
||||||
solution, err := s.Install(pkg.Packages{p.GetPackage()})
|
solution, err := s.Install(pkg.Packages{p.GetPackage()})
|
||||||
@@ -718,31 +676,34 @@ func (cs *LuetCompiler) ComputeDepTree(p *compilerspec.LuetCompilationSpec) (sol
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "While order a solution for "+p.GetPackage().HumanReadableString())
|
return nil, errors.Wrap(err, "While order a solution for "+p.GetPackage().HumanReadableString())
|
||||||
}
|
}
|
||||||
|
return dependencies, nil
|
||||||
|
}
|
||||||
|
|
||||||
assertions := solver.PackagesAssertions{}
|
// ComputeMinimumCompilableSet strips specs that are eventually compiled by leafs
|
||||||
for _, assertion := range dependencies { //highly dependent on the order
|
func (cs *LuetCompiler) ComputeMinimumCompilableSet(p ...*compilerspec.LuetCompilationSpec) ([]*compilerspec.LuetCompilationSpec, error) {
|
||||||
if assertion.Value {
|
// Generate a set with all the deps of the provided specs
|
||||||
nthsolution := dependencies.Cut(assertion.Package)
|
// we will use that set to remove the deps from the list of provided compilation specs
|
||||||
assertion.Hash = solver.PackageHash{
|
allDependencies := solver.PackagesAssertions{} // Get all packages that will be in deps
|
||||||
BuildHash: nthsolution.HashFrom(assertion.Package),
|
result := []*compilerspec.LuetCompilationSpec{}
|
||||||
PackageHash: nthsolution.AssertionHash(),
|
for _, spec := range p {
|
||||||
}
|
sol, err := cs.ComputeDepTree(spec)
|
||||||
assertion.Package.SetTreeDir(p.Package.GetTreeDir())
|
if err != nil {
|
||||||
assertions = append(assertions, assertion)
|
return nil, errors.Wrap(err, "failed querying hashtree")
|
||||||
|
}
|
||||||
|
allDependencies = append(allDependencies, sol.Drop(spec.GetPackage())...)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, spec := range p {
|
||||||
|
if found := allDependencies.Search(spec.GetPackage().GetFingerPrint()); found == nil {
|
||||||
|
result = append(result, spec)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
p.SetSourceAssertion(assertions)
|
return result, nil
|
||||||
return assertions, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compile is a non-parallel version of CompileParallel. It builds the compilation specs and generates
|
// Compile is a non-parallel version of CompileParallel. It builds the compilation specs and generates
|
||||||
// an artifact
|
// an artifact
|
||||||
func (cs *LuetCompiler) Compile(keepPermissions bool, p *compilerspec.LuetCompilationSpec) (*artifact.PackageArtifact, error) {
|
func (cs *LuetCompiler) Compile(keepPermissions bool, p *compilerspec.LuetCompilationSpec) (*artifact.PackageArtifact, error) {
|
||||||
asserts, err := cs.ComputeDepTree(p)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
p.SetSourceAssertion(asserts)
|
|
||||||
return cs.compile(cs.Options.Concurrency, keepPermissions, p)
|
return cs.compile(cs.Options.Concurrency, keepPermissions, p)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -773,11 +734,6 @@ func (cs *LuetCompiler) inheritSpecBuildOptions(p *compilerspec.LuetCompilationS
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (cs *LuetCompiler) compile(concurrency int, keepPermissions bool, p *compilerspec.LuetCompilationSpec) (*artifact.PackageArtifact, error) {
|
func (cs *LuetCompiler) compile(concurrency int, keepPermissions bool, p *compilerspec.LuetCompilationSpec) (*artifact.PackageArtifact, error) {
|
||||||
// TODO: Racy, remove it
|
|
||||||
// Inherit build options from compilation specs metadata
|
|
||||||
// orig := cs.Options.PullImageRepository
|
|
||||||
// defer func() { cs.Options.PullImageRepository = orig }()
|
|
||||||
|
|
||||||
Info(":package: Compiling", p.GetPackage().HumanReadableString(), ".... :coffee:")
|
Info(":package: Compiling", p.GetPackage().HumanReadableString(), ".... :coffee:")
|
||||||
|
|
||||||
Debug(fmt.Sprintf("%s: has images %t, empty package: %t", p.GetPackage().HumanReadableString(), p.HasImageSource(), p.EmptyPackage()))
|
Debug(fmt.Sprintf("%s: has images %t, empty package: %t", p.GetPackage().HumanReadableString(), p.HasImageSource(), p.EmptyPackage()))
|
||||||
@@ -789,36 +745,42 @@ func (cs *LuetCompiler) compile(concurrency int, keepPermissions bool, p *compil
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
targetAssertion := p.GetSourceAssertion().Search(p.GetPackage().GetFingerPrint())
|
ht := NewHashTree(cs.Database)
|
||||||
|
|
||||||
|
packageHashTree, err := ht.Query(cs, p)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "failed querying hashtree")
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is in order to have the metadata in the yaml
|
||||||
|
p.SetSourceAssertion(packageHashTree.Solution)
|
||||||
|
targetAssertion := packageHashTree.Target
|
||||||
|
|
||||||
bus.Manager.Publish(bus.EventPackagePreBuild, struct {
|
bus.Manager.Publish(bus.EventPackagePreBuild, struct {
|
||||||
CompileSpec *compilerspec.LuetCompilationSpec
|
CompileSpec *compilerspec.LuetCompilationSpec
|
||||||
Assert solver.PackageAssert
|
Assert solver.PackageAssert
|
||||||
|
PackageHashTree *PackageImageHashTree
|
||||||
}{
|
}{
|
||||||
CompileSpec: p,
|
CompileSpec: p,
|
||||||
Assert: *targetAssertion,
|
Assert: *targetAssertion,
|
||||||
|
PackageHashTree: packageHashTree,
|
||||||
})
|
})
|
||||||
|
|
||||||
// Update compilespec build options - it will be then serialized into the compilation metadata file
|
// Update compilespec build options - it will be then serialized into the compilation metadata file
|
||||||
//p.SetBuildOptions(cs.Options)
|
|
||||||
p.BuildOptions.PushImageRepository = cs.Options.PushImageRepository
|
p.BuildOptions.PushImageRepository = cs.Options.PushImageRepository
|
||||||
//p.BuildOptions.BuildValues = cs.Options.BuildValues
|
|
||||||
//p.BuildOptions.BuildValuesFile = cs.Options.BuildValuesFile
|
|
||||||
|
|
||||||
// - If image is set we just generate a plain dockerfile
|
// - If image is set we just generate a plain dockerfile
|
||||||
// Treat last case (easier) first. The image is provided and we just compute a plain dockerfile with the images listed as above
|
// Treat last case (easier) first. The image is provided and we just compute a plain dockerfile with the images listed as above
|
||||||
if p.GetImage() != "" {
|
if p.GetImage() != "" {
|
||||||
return cs.compileWithImage(p.GetImage(), cs.genBuilderImageTag(p, targetAssertion.Hash.PackageHash), targetAssertion.Hash.PackageHash, concurrency, keepPermissions, cs.Options.KeepImg, p, true)
|
return cs.compileWithImage(p.GetImage(), packageHashTree.BuilderImageHash, targetAssertion.Hash.PackageHash, concurrency, keepPermissions, cs.Options.KeepImg, p, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// - If image is not set, we read a base_image. Then we will build one image from it to kick-off our build based
|
// - If image is not set, we read a base_image. Then we will build one image from it to kick-off our build based
|
||||||
// on how we compute the resolvable tree.
|
// on how we compute the resolvable tree.
|
||||||
// This means to recursively build all the build-images needed to reach that tree part.
|
// This means to recursively build all the build-images needed to reach that tree part.
|
||||||
// - We later on compute an hash used to identify the image, so each similar deptree keeps the same build image.
|
// - We later on compute an hash used to identify the image, so each similar deptree keeps the same build image.
|
||||||
|
dependencies := packageHashTree.Dependencies // at this point we should have a flattened list of deps to build, including all of them (with all constraints propagated already)
|
||||||
dependencies := p.GetSourceAssertion().Drop(p.GetPackage()) // at this point we should have a flattened list of deps to build, including all of them (with all constraints propagated already)
|
departifacts := []*artifact.PackageArtifact{} // TODO: Return this somehow
|
||||||
departifacts := []*artifact.PackageArtifact{} // TODO: Return this somehow
|
|
||||||
var lastHash string
|
|
||||||
depsN := 0
|
depsN := 0
|
||||||
currentN := 0
|
currentN := 0
|
||||||
|
|
||||||
@@ -845,8 +807,6 @@ func (cs *LuetCompiler) compile(concurrency int, keepPermissions bool, p *compil
|
|||||||
Debug("PullImage repos:", compileSpec.BuildOptions.PullImageRepository)
|
Debug("PullImage repos:", compileSpec.BuildOptions.PullImageRepository)
|
||||||
|
|
||||||
compileSpec.SetOutputPath(p.GetOutputPath())
|
compileSpec.SetOutputPath(p.GetOutputPath())
|
||||||
Debug(pkgTag, " :arrow_right_hook: :whale: Builder image from hash", assertion.Hash.BuildHash)
|
|
||||||
Debug(pkgTag, " :arrow_right_hook: :whale: Package image from hash", assertion.Hash.PackageHash)
|
|
||||||
|
|
||||||
bus.Manager.Publish(bus.EventPackagePreBuild, struct {
|
bus.Manager.Publish(bus.EventPackagePreBuild, struct {
|
||||||
CompileSpec *compilerspec.LuetCompilationSpec
|
CompileSpec *compilerspec.LuetCompilationSpec
|
||||||
@@ -856,29 +816,43 @@ func (cs *LuetCompiler) compile(concurrency int, keepPermissions bool, p *compil
|
|||||||
Assert: assertion,
|
Assert: assertion,
|
||||||
})
|
})
|
||||||
|
|
||||||
lastHash = assertion.Hash.PackageHash
|
buildHash, err := packageHashTree.DependencyBuildImage(assertion.Package)
|
||||||
// for the source instead, pick an image and a buildertaggedImage from hashes if they exists.
|
if err != nil {
|
||||||
// otherways fallback to the pushed repo
|
return nil, errors.Wrap(err, "failed looking for dependency in hashtree")
|
||||||
// Resolve images from the hashtree
|
|
||||||
resolvedBuildImage := cs.resolveExistingImageHash(assertion.Hash.BuildHash, compileSpec)
|
|
||||||
if compileSpec.GetImage() != "" {
|
|
||||||
Debug(pkgTag, " :wrench: Compiling "+compileSpec.GetPackage().HumanReadableString()+" from image")
|
|
||||||
|
|
||||||
a, err := cs.compileWithImage(compileSpec.GetImage(), assertion.Hash.BuildHash, assertion.Hash.PackageHash, concurrency, keepPermissions, cs.Options.KeepImg, compileSpec, packageDeps)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "Failed compiling "+compileSpec.GetPackage().HumanReadableString())
|
|
||||||
}
|
|
||||||
departifacts = append(departifacts, a)
|
|
||||||
Info(pkgTag, ":white_check_mark: Done")
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Debug(pkgTag, " :wrench: Compiling "+compileSpec.GetPackage().HumanReadableString()+" from tree")
|
Debug(pkgTag, " :arrow_right_hook: :whale: Builder image from hash", assertion.Hash.BuildHash)
|
||||||
a, err := cs.compileWithImage(resolvedBuildImage, cs.genBuilderImageTag(compileSpec, targetAssertion.Hash.PackageHash), assertion.Hash.PackageHash, concurrency, keepPermissions, cs.Options.KeepImg, compileSpec, packageDeps)
|
Debug(pkgTag, " :arrow_right_hook: :whale: Package image from hash", assertion.Hash.PackageHash)
|
||||||
|
|
||||||
|
var sourceImage string
|
||||||
|
|
||||||
|
if compileSpec.GetImage() != "" {
|
||||||
|
Debug(pkgTag, " :wrench: Compiling "+compileSpec.GetPackage().HumanReadableString()+" from image")
|
||||||
|
sourceImage = compileSpec.GetImage()
|
||||||
|
} else {
|
||||||
|
// for the source instead, pick an image and a buildertaggedImage from hashes if they exists.
|
||||||
|
// otherways fallback to the pushed repo
|
||||||
|
// Resolve images from the hashtree
|
||||||
|
sourceImage = cs.resolveExistingImageHash(assertion.Hash.BuildHash, compileSpec)
|
||||||
|
Debug(pkgTag, " :wrench: Compiling "+compileSpec.GetPackage().HumanReadableString()+" from tree")
|
||||||
|
}
|
||||||
|
|
||||||
|
a, err := cs.compileWithImage(
|
||||||
|
sourceImage,
|
||||||
|
buildHash,
|
||||||
|
assertion.Hash.PackageHash,
|
||||||
|
concurrency,
|
||||||
|
keepPermissions,
|
||||||
|
cs.Options.KeepImg,
|
||||||
|
compileSpec,
|
||||||
|
packageDeps,
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "Failed compiling "+compileSpec.GetPackage().HumanReadableString())
|
return nil, errors.Wrap(err, "Failed compiling "+compileSpec.GetPackage().HumanReadableString())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Info(pkgTag, ":white_check_mark: Done")
|
||||||
|
|
||||||
bus.Manager.Publish(bus.EventPackagePostBuild, struct {
|
bus.Manager.Publish(bus.EventPackagePostBuild, struct {
|
||||||
CompileSpec *compilerspec.LuetCompilationSpec
|
CompileSpec *compilerspec.LuetCompilationSpec
|
||||||
Artifact *artifact.PackageArtifact
|
Artifact *artifact.PackageArtifact
|
||||||
@@ -888,18 +862,14 @@ func (cs *LuetCompiler) compile(concurrency int, keepPermissions bool, p *compil
|
|||||||
})
|
})
|
||||||
|
|
||||||
departifacts = append(departifacts, a)
|
departifacts = append(departifacts, a)
|
||||||
Info(pkgTag, ":white_check_mark: Done")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if len(dependencies) > 0 {
|
|
||||||
lastHash = dependencies[len(dependencies)-1].Hash.PackageHash
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if buildTarget {
|
if buildTarget {
|
||||||
resolvedBuildImage := cs.resolveExistingImageHash(lastHash, p)
|
resolvedSourceImage := cs.resolveExistingImageHash(packageHashTree.SourceHash, p)
|
||||||
Info(":rocket: All dependencies are satisfied, building package requested by the user", p.GetPackage().HumanReadableString())
|
Info(":rocket: All dependencies are satisfied, building package requested by the user", p.GetPackage().HumanReadableString())
|
||||||
Info(":package:", p.GetPackage().HumanReadableString(), " Using image: ", resolvedBuildImage)
|
Info(":package:", p.GetPackage().HumanReadableString(), " Using image: ", resolvedSourceImage)
|
||||||
a, err := cs.compileWithImage(resolvedBuildImage, cs.genBuilderImageTag(p, targetAssertion.Hash.PackageHash), targetAssertion.Hash.PackageHash, concurrency, keepPermissions, cs.Options.KeepImg, p, true)
|
a, err := cs.compileWithImage(resolvedSourceImage, packageHashTree.BuilderImageHash, targetAssertion.Hash.PackageHash, concurrency, keepPermissions, cs.Options.KeepImg, p, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return a, err
|
return a, err
|
||||||
}
|
}
|
||||||
|
126
pkg/compiler/imagehashtree.go
Normal file
126
pkg/compiler/imagehashtree.go
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
// Copyright © 2021 Ettore Di Giacinto <mudler@mocaccino.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 (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
compilerspec "github.com/mudler/luet/pkg/compiler/types/spec"
|
||||||
|
"github.com/mudler/luet/pkg/config"
|
||||||
|
pkg "github.com/mudler/luet/pkg/package"
|
||||||
|
"github.com/mudler/luet/pkg/solver"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ImageHashTree struct {
|
||||||
|
Database pkg.PackageDatabase
|
||||||
|
SolverOptions config.LuetSolverOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
type PackageImageHashTree struct {
|
||||||
|
Target *solver.PackageAssert
|
||||||
|
Dependencies solver.PackagesAssertions
|
||||||
|
Solution solver.PackagesAssertions
|
||||||
|
dependencyBuilderImageHashes map[string]string
|
||||||
|
SourceHash string
|
||||||
|
BuilderImageHash string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewHashTree(db pkg.PackageDatabase) *ImageHashTree {
|
||||||
|
return &ImageHashTree{
|
||||||
|
Database: db,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ht *PackageImageHashTree) DependencyBuildImage(p pkg.Package) (string, error) {
|
||||||
|
found, ok := ht.dependencyBuilderImageHashes[p.GetFingerPrint()]
|
||||||
|
if !ok {
|
||||||
|
return "", errors.New("package hash not found")
|
||||||
|
}
|
||||||
|
return found, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: ___ When computing the hash per package (and evaluating the sat solver solution tree part)
|
||||||
|
// we should use the hash of each package + its fingerprint instead as a salt.
|
||||||
|
// That's because the hash will be salted with its `build.yaml`.
|
||||||
|
// In this way, we trigger recompilations if some dep of a target changes
|
||||||
|
// a build.yaml, without touching the version
|
||||||
|
func (ht *ImageHashTree) Query(cs *LuetCompiler, p *compilerspec.LuetCompilationSpec) (*PackageImageHashTree, error) {
|
||||||
|
assertions, err := ht.resolve(cs, p)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
targetAssertion := assertions.Search(p.GetPackage().GetFingerPrint())
|
||||||
|
|
||||||
|
dependencies := assertions.Drop(p.GetPackage())
|
||||||
|
var sourceHash string
|
||||||
|
imageHashes := map[string]string{}
|
||||||
|
for _, assertion := range dependencies {
|
||||||
|
var depbuildImageTag string
|
||||||
|
compileSpec, err := cs.FromPackage(assertion.Package)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error while generating compilespec for "+assertion.Package.GetName())
|
||||||
|
}
|
||||||
|
if compileSpec.GetImage() != "" {
|
||||||
|
depbuildImageTag = assertion.Hash.BuildHash
|
||||||
|
} else {
|
||||||
|
depbuildImageTag = ht.genBuilderImageTag(compileSpec, targetAssertion.Hash.PackageHash)
|
||||||
|
}
|
||||||
|
imageHashes[assertion.Package.GetFingerPrint()] = depbuildImageTag
|
||||||
|
sourceHash = assertion.Hash.PackageHash
|
||||||
|
}
|
||||||
|
|
||||||
|
return &PackageImageHashTree{
|
||||||
|
Dependencies: dependencies,
|
||||||
|
Target: targetAssertion,
|
||||||
|
SourceHash: sourceHash,
|
||||||
|
BuilderImageHash: ht.genBuilderImageTag(p, targetAssertion.Hash.PackageHash),
|
||||||
|
dependencyBuilderImageHashes: imageHashes,
|
||||||
|
Solution: assertions,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ht *ImageHashTree) genBuilderImageTag(p *compilerspec.LuetCompilationSpec, packageImage string) string {
|
||||||
|
// Use packageImage as salt into the fp being used
|
||||||
|
// so the hash is unique also in cases where
|
||||||
|
// some package deps does have completely different
|
||||||
|
// depgraphs
|
||||||
|
return fmt.Sprintf("builder-%s", p.GetPackage().HashFingerprint(packageImage))
|
||||||
|
}
|
||||||
|
|
||||||
|
// resolve computes the dependency tree of a compilation spec and returns solver assertions
|
||||||
|
// in order to be able to compile the spec.
|
||||||
|
func (ht *ImageHashTree) resolve(cs *LuetCompiler, p *compilerspec.LuetCompilationSpec) (solver.PackagesAssertions, error) {
|
||||||
|
dependencies, err := cs.ComputeDepTree(p)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "While computing a solution for "+p.GetPackage().HumanReadableString())
|
||||||
|
}
|
||||||
|
|
||||||
|
assertions := solver.PackagesAssertions{}
|
||||||
|
for _, assertion := range dependencies { //highly dependent on the order
|
||||||
|
if assertion.Value {
|
||||||
|
nthsolution := dependencies.Cut(assertion.Package)
|
||||||
|
assertion.Hash = solver.PackageHash{
|
||||||
|
BuildHash: nthsolution.HashFrom(assertion.Package),
|
||||||
|
PackageHash: nthsolution.AssertionHash(),
|
||||||
|
}
|
||||||
|
assertion.Package.SetTreeDir(p.Package.GetTreeDir())
|
||||||
|
assertions = append(assertions, assertion)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return assertions, nil
|
||||||
|
}
|
94
pkg/compiler/imagehashtree_test.go
Normal file
94
pkg/compiler/imagehashtree_test.go
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
// Copyright © 2021 Ettore Di Giacinto <mudler@mocaccino.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_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
. "github.com/mudler/luet/pkg/compiler"
|
||||||
|
sd "github.com/mudler/luet/pkg/compiler/backend"
|
||||||
|
"github.com/mudler/luet/pkg/compiler/types/options"
|
||||||
|
pkg "github.com/mudler/luet/pkg/package"
|
||||||
|
"github.com/mudler/luet/pkg/tree"
|
||||||
|
. "github.com/onsi/ginkgo"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = Describe("ImageHashTree", func() {
|
||||||
|
generalRecipe := tree.NewCompilerRecipe(pkg.NewInMemoryDatabase(false))
|
||||||
|
compiler := NewLuetCompiler(sd.NewSimpleDockerBackend(), generalRecipe.GetDatabase(), options.Concurrency(2))
|
||||||
|
hashtree := NewHashTree(generalRecipe.GetDatabase())
|
||||||
|
Context("Simple package definition", func() {
|
||||||
|
BeforeEach(func() {
|
||||||
|
generalRecipe = tree.NewCompilerRecipe(pkg.NewInMemoryDatabase(false))
|
||||||
|
err := generalRecipe.Load("../../tests/fixtures/buildable")
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
compiler = NewLuetCompiler(sd.NewSimpleDockerBackend(), generalRecipe.GetDatabase(), options.Concurrency(2))
|
||||||
|
hashtree = NewHashTree(generalRecipe.GetDatabase())
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
It("Calculates the hash correctly", func() {
|
||||||
|
|
||||||
|
spec, err := compiler.FromPackage(&pkg.DefaultPackage{Name: "b", Category: "test", Version: "1.0"})
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
packageHash, err := hashtree.Query(compiler, spec)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(packageHash.Target.Hash.BuildHash).To(Equal("6490e800fe443b99328fc363529aee74bda513930fb27ce6ab814d692bba068e"))
|
||||||
|
Expect(packageHash.Target.Hash.PackageHash).To(Equal("79d7107d13d578b362e6a7bf10ec850efce26316405b8d732ce8f9e004d64281"))
|
||||||
|
Expect(packageHash.BuilderImageHash).To(Equal("builder-79462b60bf899ad79db63f194a3c9c2a"))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Context("complex package definition", func() {
|
||||||
|
BeforeEach(func() {
|
||||||
|
generalRecipe = tree.NewCompilerRecipe(pkg.NewInMemoryDatabase(false))
|
||||||
|
|
||||||
|
err := generalRecipe.Load("../../tests/fixtures/upgrade_old_repo_revision")
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
compiler = NewLuetCompiler(sd.NewSimpleDockerBackend(), generalRecipe.GetDatabase(), options.Concurrency(2))
|
||||||
|
hashtree = NewHashTree(generalRecipe.GetDatabase())
|
||||||
|
|
||||||
|
})
|
||||||
|
It("Calculates the hash correctly", func() {
|
||||||
|
spec, err := compiler.FromPackage(&pkg.DefaultPackage{Name: "c", Category: "test", Version: "1.0"})
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
packageHash, err := hashtree.Query(compiler, spec)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
Expect(packageHash.Dependencies[len(packageHash.Dependencies)-1].Hash.PackageHash).To(Equal("c46e653125d71ee3fd696b3941ec1ed6e8a0268f896204c7a222a5aa03eb9982"))
|
||||||
|
Expect(packageHash.SourceHash).To(Equal("c46e653125d71ee3fd696b3941ec1ed6e8a0268f896204c7a222a5aa03eb9982"))
|
||||||
|
Expect(packageHash.BuilderImageHash).To(Equal("builder-37f4d05ba8a39525742ca364f69b4090"))
|
||||||
|
|
||||||
|
//Expect(packageHash.Target.Hash.BuildHash).To(Equal("79d7107d13d578b362e6a7bf10ec850efce26316405b8d732ce8f9e004d64281"))
|
||||||
|
Expect(packageHash.Target.Hash.PackageHash).To(Equal("bb1d9a99c0c309a297c75b436504e664a42121fadbb4e035bda403cd418117aa"))
|
||||||
|
a := &pkg.DefaultPackage{Name: "a", Category: "test", Version: "1.1"}
|
||||||
|
hash, err := packageHash.DependencyBuildImage(a)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(hash).To(Equal("79d7107d13d578b362e6a7bf10ec850efce26316405b8d732ce8f9e004d64281"))
|
||||||
|
|
||||||
|
assertionA := packageHash.Dependencies.Search(a.GetFingerPrint())
|
||||||
|
Expect(assertionA.Hash.PackageHash).To(Equal("c46e653125d71ee3fd696b3941ec1ed6e8a0268f896204c7a222a5aa03eb9982"))
|
||||||
|
b := &pkg.DefaultPackage{Name: "b", Category: "test", Version: "1.0"}
|
||||||
|
assertionB := packageHash.Dependencies.Search(b.GetFingerPrint())
|
||||||
|
Expect(assertionB.Hash.PackageHash).To(Equal("79d7107d13d578b362e6a7bf10ec850efce26316405b8d732ce8f9e004d64281"))
|
||||||
|
hashB, err := packageHash.DependencyBuildImage(b)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(hashB).To(Equal("6490e800fe443b99328fc363529aee74bda513930fb27ce6ab814d692bba068e"))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
@@ -19,6 +19,8 @@ import (
|
|||||||
"archive/tar"
|
"archive/tar"
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"crypto/sha1"
|
||||||
|
"encoding/base64"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
@@ -316,7 +318,6 @@ func (a *PackageArtifact) Compress(src string, concurrency int) error {
|
|||||||
default:
|
default:
|
||||||
return helpers.Tar(src, a.getCompressedName())
|
return helpers.Tar(src, a.getCompressedName())
|
||||||
}
|
}
|
||||||
return errors.New("Compression type must be supplied")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *PackageArtifact) getCompressedName() string {
|
func (a *PackageArtifact) getCompressedName() string {
|
||||||
@@ -339,6 +340,28 @@ func (a *PackageArtifact) GetUncompressedName() string {
|
|||||||
return a.Path
|
return a.Path
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func hashContent(bv []byte) string {
|
||||||
|
hasher := sha1.New()
|
||||||
|
hasher.Write(bv)
|
||||||
|
sha := base64.URLEncoding.EncodeToString(hasher.Sum(nil))
|
||||||
|
return sha
|
||||||
|
}
|
||||||
|
|
||||||
|
func hashFileContent(path string) (string, error) {
|
||||||
|
f, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
h := sha1.New()
|
||||||
|
if _, err := io.Copy(h, f); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return base64.URLEncoding.EncodeToString(h.Sum(nil)), nil
|
||||||
|
}
|
||||||
|
|
||||||
func tarModifierWrapperFunc(dst, path string, header *tar.Header, content io.Reader) (*tar.Header, []byte, error) {
|
func tarModifierWrapperFunc(dst, path string, header *tar.Header, content io.Reader) (*tar.Header, []byte, error) {
|
||||||
// If the destination path already exists I rename target file name with postfix.
|
// If the destination path already exists I rename target file name with postfix.
|
||||||
var destPath string
|
var destPath string
|
||||||
@@ -350,6 +373,7 @@ func tarModifierWrapperFunc(dst, path string, header *tar.Header, content io.Rea
|
|||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
tarHash := hashContent(buffer.Bytes())
|
||||||
|
|
||||||
// If file is not present on archive but is defined on mods
|
// If file is not present on archive but is defined on mods
|
||||||
// I receive the callback. Prevent nil exception.
|
// I receive the callback. Prevent nil exception.
|
||||||
@@ -362,8 +386,21 @@ func tarModifierWrapperFunc(dst, path string, header *tar.Header, content io.Rea
|
|||||||
return header, buffer.Bytes(), nil
|
return header, buffer.Bytes(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
existingHash := ""
|
||||||
|
f, err := os.Lstat(destPath)
|
||||||
|
if err == nil {
|
||||||
|
Debug("File exists already, computing hash for", destPath)
|
||||||
|
hash, herr := hashFileContent(destPath)
|
||||||
|
if herr == nil {
|
||||||
|
existingHash = hash
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug("Existing file hash: ", existingHash, "Tar file hashsum: ", tarHash)
|
||||||
|
// We want to protect file only if the hash of the files are differing OR the file size are
|
||||||
|
differs := (existingHash != "" && existingHash != tarHash) || (err != nil && f != nil && header.Size != f.Size())
|
||||||
// Check if exists
|
// Check if exists
|
||||||
if helpers.Exists(destPath) {
|
if helpers.Exists(destPath) && differs {
|
||||||
for i := 1; i < 1000; i++ {
|
for i := 1; i < 1000; i++ {
|
||||||
name := filepath.Join(filepath.Join(filepath.Dir(path),
|
name := filepath.Join(filepath.Join(filepath.Dir(path),
|
||||||
fmt.Sprintf("._cfg%04d_%s", i, filepath.Base(path))))
|
fmt.Sprintf("._cfg%04d_%s", i, filepath.Base(path))))
|
||||||
|
@@ -16,6 +16,7 @@
|
|||||||
package compilerspec
|
package compilerspec
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
@@ -85,6 +86,13 @@ func (specs *LuetCompilationspecs) Unique() *LuetCompilationspecs {
|
|||||||
return &newSpecs
|
return &newSpecs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CopyField struct {
|
||||||
|
Package *pkg.DefaultPackage `json:"package"`
|
||||||
|
Image string `json:"image"`
|
||||||
|
Source string `json:"src"`
|
||||||
|
Destination string `json:"dst"`
|
||||||
|
}
|
||||||
|
|
||||||
type LuetCompilationSpec struct {
|
type LuetCompilationSpec struct {
|
||||||
Steps []string `json:"steps"` // Are run inside a container and the result layer diff is saved
|
Steps []string `json:"steps"` // Are run inside a container and the result layer diff is saved
|
||||||
Env []string `json:"env"`
|
Env []string `json:"env"`
|
||||||
@@ -103,6 +111,8 @@ type LuetCompilationSpec struct {
|
|||||||
Excludes []string `json:"excludes"`
|
Excludes []string `json:"excludes"`
|
||||||
|
|
||||||
BuildOptions *options.Compiler `json:"build_options"`
|
BuildOptions *options.Compiler `json:"build_options"`
|
||||||
|
|
||||||
|
Copy []CopyField `json:"copy"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewLuetCompilationSpec(b []byte, p pkg.Package) (*LuetCompilationSpec, error) {
|
func NewLuetCompilationSpec(b []byte, p pkg.Package) (*LuetCompilationSpec, error) {
|
||||||
@@ -256,6 +266,12 @@ ADD ` + s + ` /luetbuild/`
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, c := range cs.Copy {
|
||||||
|
if c.Image != "" {
|
||||||
|
spec = spec + fmt.Sprintf("\nCOPY --from=%s %s %s\n", c.Image, c.Source, c.Destination)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for _, s := range cs.Env {
|
for _, s := range cs.Env {
|
||||||
spec = spec + `
|
spec = spec + `
|
||||||
ENV ` + s
|
ENV ` + s
|
||||||
|
@@ -90,8 +90,7 @@ func UntarProtect(src, dst string, sameOwner bool, protectedFiles []string, modi
|
|||||||
}
|
}
|
||||||
|
|
||||||
if sameOwner {
|
if sameOwner {
|
||||||
// PRE: i have root privileged.
|
// we do have root permissions, so we can extract keeping the same permissions.
|
||||||
|
|
||||||
replacerArchive := archive.ReplaceFileTarWrapper(in, mods)
|
replacerArchive := archive.ReplaceFileTarWrapper(in, mods)
|
||||||
|
|
||||||
opts := &archive.TarOptions{
|
opts := &archive.TarOptions{
|
||||||
|
4
tests/fixtures/plugin/test-foo
vendored
4
tests/fixtures/plugin/test-foo
vendored
@@ -1,3 +1,5 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
echo "$1" >> $EVENT_FILE
|
echo "$1" >> $EVENT_FILE
|
||||||
echo "$2" >> $PAYLOAD_FILE
|
echo "$2" >> $PAYLOAD_FILE
|
||||||
|
|
||||||
|
echo "{}"
|
107
tests/integration/12_config_protect_samefile.sh
Executable file
107
tests/integration/12_config_protect_samefile.sh
Executable file
@@ -0,0 +1,107 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
export LUET_NOLOCK=true
|
||||||
|
|
||||||
|
oneTimeSetUp() {
|
||||||
|
export tmpdir="$(mktemp -d)"
|
||||||
|
}
|
||||||
|
|
||||||
|
oneTimeTearDown() {
|
||||||
|
rm -rf "$tmpdir"
|
||||||
|
}
|
||||||
|
|
||||||
|
testBuild() {
|
||||||
|
mkdir $tmpdir/testrootfs/testbuild -p
|
||||||
|
luet build --tree "$ROOT_DIR/tests/fixtures/config_protect" \
|
||||||
|
--destination $tmpdir/testrootfs/testbuild --compression gzip test/a
|
||||||
|
buildst=$?
|
||||||
|
assertEquals 'builds successfully' "$buildst" "0"
|
||||||
|
assertTrue 'create package' "[ -e '$tmpdir/testrootfs/testbuild/a-test-1.0.package.tar.gz' ]"
|
||||||
|
}
|
||||||
|
|
||||||
|
testRepo() {
|
||||||
|
assertTrue 'no repository' "[ ! -e '$tmpdir/testbuild/repository.yaml' ]"
|
||||||
|
luet create-repo --tree "$ROOT_DIR/tests/fixtures/config_protect" \
|
||||||
|
--output $tmpdir/testrootfs/testbuild \
|
||||||
|
--packages $tmpdir/testrootfs/testbuild \
|
||||||
|
--name "test" \
|
||||||
|
--descr "Test Repo" \
|
||||||
|
--urls $tmpdir/testrootfs \
|
||||||
|
--type disk > /dev/null
|
||||||
|
|
||||||
|
createst=$?
|
||||||
|
assertEquals 'create repo successfully' "$createst" "0"
|
||||||
|
assertTrue 'create repository' "[ -e '$tmpdir/testrootfs/testbuild/repository.yaml' ]"
|
||||||
|
}
|
||||||
|
|
||||||
|
testConfig() {
|
||||||
|
|
||||||
|
mkdir $tmpdir/testrootfs/etc/luet/config.protect.d -p
|
||||||
|
|
||||||
|
cat <<EOF > $tmpdir/testrootfs/etc/luet/config.protect.d/conf1.yml
|
||||||
|
name: "protect1"
|
||||||
|
dirs:
|
||||||
|
- /etc/
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat <<EOF > $tmpdir/luet.yaml
|
||||||
|
general:
|
||||||
|
debug: true
|
||||||
|
system:
|
||||||
|
rootfs: $tmpdir/testrootfs
|
||||||
|
database_path: "/"
|
||||||
|
database_engine: "boltdb"
|
||||||
|
config_protect_confdir:
|
||||||
|
- /etc/luet/config.protect.d
|
||||||
|
config_from_host: false
|
||||||
|
repositories:
|
||||||
|
- name: "main"
|
||||||
|
type: "disk"
|
||||||
|
enable: true
|
||||||
|
urls:
|
||||||
|
- "/testbuild"
|
||||||
|
EOF
|
||||||
|
luet config --config $tmpdir/luet.yaml
|
||||||
|
res=$?
|
||||||
|
assertEquals 'config test successfully' "$res" "0"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
testInstall() {
|
||||||
|
|
||||||
|
# Simulate previous installation
|
||||||
|
mkdir $tmpdir/testrootfs/etc/a -p
|
||||||
|
echo config > $tmpdir/testrootfs/etc/a/conf
|
||||||
|
|
||||||
|
luet install -y --config $tmpdir/luet.yaml test/a
|
||||||
|
installst=$?
|
||||||
|
assertEquals 'install test successfully' "$installst" "0"
|
||||||
|
|
||||||
|
|
||||||
|
# Simulate config protect
|
||||||
|
assertTrue 'package A installed' "[ -e '$tmpdir/testrootfs/c' ]"
|
||||||
|
assertTrue 'config protect not created, file is the same' "[ ! -e '$tmpdir/testrootfs/etc/a/._cfg0001_conf' ]"
|
||||||
|
assertEquals 'config protect content' "$(cat $tmpdir/testrootfs/etc/a/conf)" "config"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
testUnInstall() {
|
||||||
|
luet uninstall -y --full --config $tmpdir/luet.yaml test/a
|
||||||
|
installst=$?
|
||||||
|
assertEquals 'uninstall test successfully' "$installst" "0"
|
||||||
|
assertTrue 'package uninstalled' "[ ! -e '$tmpdir/testrootfs/c' ]"
|
||||||
|
assertTrue 'config protect maintains the protected files' "[ -e '$tmpdir/testrootfs/etc/a/conf' ]"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
testCleanup() {
|
||||||
|
luet cleanup --config $tmpdir/luet.yaml
|
||||||
|
installst=$?
|
||||||
|
assertEquals 'install test successfully' "$installst" "0"
|
||||||
|
assertTrue 'package installed' "[ ! -e '$tmpdir/testrootfs/packages/a-test-1.0.package.tar.gz' ]"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Load shUnit2.
|
||||||
|
. "$ROOT_DIR/tests/integration/shunit2"/shunit2
|
||||||
|
|
2
vendor/github.com/codegangsta/inject/.gitignore
generated
vendored
2
vendor/github.com/codegangsta/inject/.gitignore
generated
vendored
@@ -1,2 +0,0 @@
|
|||||||
inject
|
|
||||||
inject.test
|
|
20
vendor/github.com/codegangsta/inject/LICENSE
generated
vendored
20
vendor/github.com/codegangsta/inject/LICENSE
generated
vendored
@@ -1,20 +0,0 @@
|
|||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (c) 2013 Jeremy Saenz
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
||||||
this software and associated documentation files (the "Software"), to deal in
|
|
||||||
the Software without restriction, including without limitation the rights to
|
|
||||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
||||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
|
||||||
subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
||||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
||||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
||||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
||||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
92
vendor/github.com/codegangsta/inject/README.md
generated
vendored
92
vendor/github.com/codegangsta/inject/README.md
generated
vendored
@@ -1,92 +0,0 @@
|
|||||||
# inject
|
|
||||||
--
|
|
||||||
import "github.com/codegangsta/inject"
|
|
||||||
|
|
||||||
Package inject provides utilities for mapping and injecting dependencies in
|
|
||||||
various ways.
|
|
||||||
|
|
||||||
Language Translations:
|
|
||||||
* [简体中文](translations/README_zh_cn.md)
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
#### func InterfaceOf
|
|
||||||
|
|
||||||
```go
|
|
||||||
func InterfaceOf(value interface{}) reflect.Type
|
|
||||||
```
|
|
||||||
InterfaceOf dereferences a pointer to an Interface type. It panics if value is
|
|
||||||
not an pointer to an interface.
|
|
||||||
|
|
||||||
#### type Applicator
|
|
||||||
|
|
||||||
```go
|
|
||||||
type Applicator interface {
|
|
||||||
// Maps dependencies in the Type map to each field in the struct
|
|
||||||
// that is tagged with 'inject'. Returns an error if the injection
|
|
||||||
// fails.
|
|
||||||
Apply(interface{}) error
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Applicator represents an interface for mapping dependencies to a struct.
|
|
||||||
|
|
||||||
#### type Injector
|
|
||||||
|
|
||||||
```go
|
|
||||||
type Injector interface {
|
|
||||||
Applicator
|
|
||||||
Invoker
|
|
||||||
TypeMapper
|
|
||||||
// SetParent sets the parent of the injector. If the injector cannot find a
|
|
||||||
// dependency in its Type map it will check its parent before returning an
|
|
||||||
// error.
|
|
||||||
SetParent(Injector)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Injector represents an interface for mapping and injecting dependencies into
|
|
||||||
structs and function arguments.
|
|
||||||
|
|
||||||
#### func New
|
|
||||||
|
|
||||||
```go
|
|
||||||
func New() Injector
|
|
||||||
```
|
|
||||||
New returns a new Injector.
|
|
||||||
|
|
||||||
#### type Invoker
|
|
||||||
|
|
||||||
```go
|
|
||||||
type Invoker interface {
|
|
||||||
// Invoke attempts to call the interface{} provided as a function,
|
|
||||||
// providing dependencies for function arguments based on Type. Returns
|
|
||||||
// a slice of reflect.Value representing the returned values of the function.
|
|
||||||
// Returns an error if the injection fails.
|
|
||||||
Invoke(interface{}) ([]reflect.Value, error)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Invoker represents an interface for calling functions via reflection.
|
|
||||||
|
|
||||||
#### type TypeMapper
|
|
||||||
|
|
||||||
```go
|
|
||||||
type TypeMapper interface {
|
|
||||||
// Maps the interface{} value based on its immediate type from reflect.TypeOf.
|
|
||||||
Map(interface{}) TypeMapper
|
|
||||||
// Maps the interface{} value based on the pointer of an Interface provided.
|
|
||||||
// This is really only useful for mapping a value as an interface, as interfaces
|
|
||||||
// cannot at this time be referenced directly without a pointer.
|
|
||||||
MapTo(interface{}, interface{}) TypeMapper
|
|
||||||
// Provides a possibility to directly insert a mapping based on type and value.
|
|
||||||
// This makes it possible to directly map type arguments not possible to instantiate
|
|
||||||
// with reflect like unidirectional channels.
|
|
||||||
Set(reflect.Type, reflect.Value) TypeMapper
|
|
||||||
// Returns the Value that is mapped to the current type. Returns a zeroed Value if
|
|
||||||
// the Type has not been mapped.
|
|
||||||
Get(reflect.Type) reflect.Value
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
TypeMapper represents an interface for mapping interface{} values based on type.
|
|
187
vendor/github.com/codegangsta/inject/inject.go
generated
vendored
187
vendor/github.com/codegangsta/inject/inject.go
generated
vendored
@@ -1,187 +0,0 @@
|
|||||||
// Package inject provides utilities for mapping and injecting dependencies in various ways.
|
|
||||||
package inject
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"reflect"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Injector represents an interface for mapping and injecting dependencies into structs
|
|
||||||
// and function arguments.
|
|
||||||
type Injector interface {
|
|
||||||
Applicator
|
|
||||||
Invoker
|
|
||||||
TypeMapper
|
|
||||||
// SetParent sets the parent of the injector. If the injector cannot find a
|
|
||||||
// dependency in its Type map it will check its parent before returning an
|
|
||||||
// error.
|
|
||||||
SetParent(Injector)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Applicator represents an interface for mapping dependencies to a struct.
|
|
||||||
type Applicator interface {
|
|
||||||
// Maps dependencies in the Type map to each field in the struct
|
|
||||||
// that is tagged with 'inject'. Returns an error if the injection
|
|
||||||
// fails.
|
|
||||||
Apply(interface{}) error
|
|
||||||
}
|
|
||||||
|
|
||||||
// Invoker represents an interface for calling functions via reflection.
|
|
||||||
type Invoker interface {
|
|
||||||
// Invoke attempts to call the interface{} provided as a function,
|
|
||||||
// providing dependencies for function arguments based on Type. Returns
|
|
||||||
// a slice of reflect.Value representing the returned values of the function.
|
|
||||||
// Returns an error if the injection fails.
|
|
||||||
Invoke(interface{}) ([]reflect.Value, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TypeMapper represents an interface for mapping interface{} values based on type.
|
|
||||||
type TypeMapper interface {
|
|
||||||
// Maps the interface{} value based on its immediate type from reflect.TypeOf.
|
|
||||||
Map(interface{}) TypeMapper
|
|
||||||
// Maps the interface{} value based on the pointer of an Interface provided.
|
|
||||||
// This is really only useful for mapping a value as an interface, as interfaces
|
|
||||||
// cannot at this time be referenced directly without a pointer.
|
|
||||||
MapTo(interface{}, interface{}) TypeMapper
|
|
||||||
// Provides a possibility to directly insert a mapping based on type and value.
|
|
||||||
// This makes it possible to directly map type arguments not possible to instantiate
|
|
||||||
// with reflect like unidirectional channels.
|
|
||||||
Set(reflect.Type, reflect.Value) TypeMapper
|
|
||||||
// Returns the Value that is mapped to the current type. Returns a zeroed Value if
|
|
||||||
// the Type has not been mapped.
|
|
||||||
Get(reflect.Type) reflect.Value
|
|
||||||
}
|
|
||||||
|
|
||||||
type injector struct {
|
|
||||||
values map[reflect.Type]reflect.Value
|
|
||||||
parent Injector
|
|
||||||
}
|
|
||||||
|
|
||||||
// InterfaceOf dereferences a pointer to an Interface type.
|
|
||||||
// It panics if value is not an pointer to an interface.
|
|
||||||
func InterfaceOf(value interface{}) reflect.Type {
|
|
||||||
t := reflect.TypeOf(value)
|
|
||||||
|
|
||||||
for t.Kind() == reflect.Ptr {
|
|
||||||
t = t.Elem()
|
|
||||||
}
|
|
||||||
|
|
||||||
if t.Kind() != reflect.Interface {
|
|
||||||
panic("Called inject.InterfaceOf with a value that is not a pointer to an interface. (*MyInterface)(nil)")
|
|
||||||
}
|
|
||||||
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
|
|
||||||
// New returns a new Injector.
|
|
||||||
func New() Injector {
|
|
||||||
return &injector{
|
|
||||||
values: make(map[reflect.Type]reflect.Value),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Invoke attempts to call the interface{} provided as a function,
|
|
||||||
// providing dependencies for function arguments based on Type.
|
|
||||||
// Returns a slice of reflect.Value representing the returned values of the function.
|
|
||||||
// Returns an error if the injection fails.
|
|
||||||
// It panics if f is not a function
|
|
||||||
func (inj *injector) Invoke(f interface{}) ([]reflect.Value, error) {
|
|
||||||
t := reflect.TypeOf(f)
|
|
||||||
|
|
||||||
var in = make([]reflect.Value, t.NumIn()) //Panic if t is not kind of Func
|
|
||||||
for i := 0; i < t.NumIn(); i++ {
|
|
||||||
argType := t.In(i)
|
|
||||||
val := inj.Get(argType)
|
|
||||||
if !val.IsValid() {
|
|
||||||
return nil, fmt.Errorf("Value not found for type %v", argType)
|
|
||||||
}
|
|
||||||
|
|
||||||
in[i] = val
|
|
||||||
}
|
|
||||||
|
|
||||||
return reflect.ValueOf(f).Call(in), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Maps dependencies in the Type map to each field in the struct
|
|
||||||
// that is tagged with 'inject'.
|
|
||||||
// Returns an error if the injection fails.
|
|
||||||
func (inj *injector) Apply(val interface{}) error {
|
|
||||||
v := reflect.ValueOf(val)
|
|
||||||
|
|
||||||
for v.Kind() == reflect.Ptr {
|
|
||||||
v = v.Elem()
|
|
||||||
}
|
|
||||||
|
|
||||||
if v.Kind() != reflect.Struct {
|
|
||||||
return nil // Should not panic here ?
|
|
||||||
}
|
|
||||||
|
|
||||||
t := v.Type()
|
|
||||||
|
|
||||||
for i := 0; i < v.NumField(); i++ {
|
|
||||||
f := v.Field(i)
|
|
||||||
structField := t.Field(i)
|
|
||||||
if f.CanSet() && (structField.Tag == "inject" || structField.Tag.Get("inject") != "") {
|
|
||||||
ft := f.Type()
|
|
||||||
v := inj.Get(ft)
|
|
||||||
if !v.IsValid() {
|
|
||||||
return fmt.Errorf("Value not found for type %v", ft)
|
|
||||||
}
|
|
||||||
|
|
||||||
f.Set(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Maps the concrete value of val to its dynamic type using reflect.TypeOf,
|
|
||||||
// It returns the TypeMapper registered in.
|
|
||||||
func (i *injector) Map(val interface{}) TypeMapper {
|
|
||||||
i.values[reflect.TypeOf(val)] = reflect.ValueOf(val)
|
|
||||||
return i
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *injector) MapTo(val interface{}, ifacePtr interface{}) TypeMapper {
|
|
||||||
i.values[InterfaceOf(ifacePtr)] = reflect.ValueOf(val)
|
|
||||||
return i
|
|
||||||
}
|
|
||||||
|
|
||||||
// Maps the given reflect.Type to the given reflect.Value and returns
|
|
||||||
// the Typemapper the mapping has been registered in.
|
|
||||||
func (i *injector) Set(typ reflect.Type, val reflect.Value) TypeMapper {
|
|
||||||
i.values[typ] = val
|
|
||||||
return i
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *injector) Get(t reflect.Type) reflect.Value {
|
|
||||||
val := i.values[t]
|
|
||||||
|
|
||||||
if val.IsValid() {
|
|
||||||
return val
|
|
||||||
}
|
|
||||||
|
|
||||||
// no concrete types found, try to find implementors
|
|
||||||
// if t is an interface
|
|
||||||
if t.Kind() == reflect.Interface {
|
|
||||||
for k, v := range i.values {
|
|
||||||
if k.Implements(t) {
|
|
||||||
val = v
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Still no type found, try to look it up on the parent
|
|
||||||
if !val.IsValid() && i.parent != nil {
|
|
||||||
val = i.parent.Get(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
return val
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *injector) SetParent(parent Injector) {
|
|
||||||
i.parent = parent
|
|
||||||
}
|
|
3
vendor/github.com/codegangsta/inject/update_readme.sh
generated
vendored
3
vendor/github.com/codegangsta/inject/update_readme.sh
generated
vendored
@@ -1,3 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
go get github.com/robertkrimen/godocdown/godocdown
|
|
||||||
godocdown > README.md
|
|
27
vendor/github.com/mudler/go-pluggable/README.md
generated
vendored
27
vendor/github.com/mudler/go-pluggable/README.md
generated
vendored
@@ -1,6 +1,7 @@
|
|||||||
# go-pluggable
|
# :bento: go-pluggable
|
||||||
|
[](https://pkg.go.dev/github.com/mudler/go-pluggable) [](https://goreportcard.com/report/github.com/mudler/go-pluggable) [](https://github.com/mudler/go-pluggable/actions?query=workflow%3ATest)
|
||||||
|
|
||||||
light Bus-event driven plugin library for Golang.
|
:bento: *go-pluggable* is a light Bus-event driven plugin library for Golang.
|
||||||
|
|
||||||
`go-pluggable` implements the event/sub pattern to extend your Golang project with external binary plugins that can be written in any language.
|
`go-pluggable` implements the event/sub pattern to extend your Golang project with external binary plugins that can be written in any language.
|
||||||
|
|
||||||
@@ -24,8 +25,24 @@ func main() {
|
|||||||
m.Autoload("test", temp)
|
m.Autoload("test", temp)
|
||||||
m.Register()
|
m.Register()
|
||||||
|
|
||||||
// ...
|
// Optionally process plugin results response
|
||||||
m.Publish(myEv, map[string]string{"foo": "bar"}) // test-foo, will receive our data as json payload
|
// The plugins has to return as output a json in stdout in the format { 'state': "somestate", data: "some data", error: "some error" }
|
||||||
|
// e.g. with jq:
|
||||||
|
// jq --arg key0 'state' \
|
||||||
|
// --arg value0 '' \
|
||||||
|
// --arg key1 'data' \
|
||||||
|
// --arg value1 "" \
|
||||||
|
// --arg key2 'error' \
|
||||||
|
// --arg value2 '' \
|
||||||
|
// '. | .[$key0]=$value0 | .[$key1]=$value1 | .[$key2]=$value2' \
|
||||||
|
// <<<'{}'
|
||||||
|
m.Response(myEv, func(p *pluggable.Plugin, r *pluggable.EventResponse) { ... })
|
||||||
|
|
||||||
|
// Emit events, they are encoded and passed as JSON payloads to the plugins.
|
||||||
|
// In our case, test-foo will receive the map as JSON
|
||||||
|
m.Publish(myEv, map[string]string{"foo": "bar"})
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
|
73
vendor/github.com/mudler/go-pluggable/bus.go
generated
vendored
73
vendor/github.com/mudler/go-pluggable/bus.go
generated
vendored
@@ -1,73 +0,0 @@
|
|||||||
// Copyright © 2020 Ettore Di Giacinto <mudler@mocaccino.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 pluggable
|
|
||||||
|
|
||||||
import (
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/chuckpreslar/emission"
|
|
||||||
"github.com/codegangsta/inject"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Bus represent the bus event system
|
|
||||||
type Bus struct {
|
|
||||||
inject.Injector
|
|
||||||
emission.Emitter
|
|
||||||
sync.Mutex
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewBus returns a new Bus instance
|
|
||||||
func NewBus() *Bus {
|
|
||||||
return &Bus{
|
|
||||||
Injector: inject.New(),
|
|
||||||
Emitter: *emission.NewEmitter(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Listen Binds a callback to an event, mapping the arguments on a global level
|
|
||||||
func (a *Bus) Listen(event EventType, listener interface{}) *Bus {
|
|
||||||
a.Lock()
|
|
||||||
defer a.Unlock()
|
|
||||||
a.On(string(event), func() { a.Invoke(listener) })
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
|
|
||||||
// Publish publishes an event, it does accept only the event as argument, since
|
|
||||||
// the callback will have access to the service mapped by the injector
|
|
||||||
func (a *Bus) Publish(e *Event) *Bus {
|
|
||||||
a.Lock()
|
|
||||||
defer a.Unlock()
|
|
||||||
a.Map(e)
|
|
||||||
a.Emit(string(e.Name))
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
|
|
||||||
// OnlyOnce Binds a callback to an event, mapping the arguments on a global level
|
|
||||||
// It is fired only once.
|
|
||||||
func (a *Bus) OnlyOnce(event EventType, listener interface{}) *Bus {
|
|
||||||
a.Lock()
|
|
||||||
defer a.Unlock()
|
|
||||||
a.Once(string(event), func() { a.Invoke(listener) })
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *Bus) propagateEvent(p Plugin) func(e *Event) {
|
|
||||||
return func(e *Event) {
|
|
||||||
resp, _ := p.Run(*e)
|
|
||||||
a.Map(&resp)
|
|
||||||
a.Emit(p.Name)
|
|
||||||
}
|
|
||||||
}
|
|
18
vendor/github.com/mudler/go-pluggable/events.go
generated
vendored
18
vendor/github.com/mudler/go-pluggable/events.go
generated
vendored
@@ -15,7 +15,10 @@
|
|||||||
|
|
||||||
package pluggable
|
package pluggable
|
||||||
|
|
||||||
import "encoding/json"
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
// EventType describes an event type
|
// EventType describes an event type
|
||||||
type EventType string
|
type EventType string
|
||||||
@@ -26,6 +29,7 @@ type EventType string
|
|||||||
type Event struct {
|
type Event struct {
|
||||||
Name EventType `json:"name"`
|
Name EventType `json:"name"`
|
||||||
Data string `json:"data"`
|
Data string `json:"data"`
|
||||||
|
File string `json:"file"` // If Data >> 10K write content to file instead
|
||||||
}
|
}
|
||||||
|
|
||||||
// EventResponse describes the event response structure
|
// EventResponse describes the event response structure
|
||||||
@@ -42,6 +46,16 @@ func (e Event) JSON() (string, error) {
|
|||||||
return string(dat), err
|
return string(dat), err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Copy returns a copy of Event
|
||||||
|
func (e Event) Copy() *Event {
|
||||||
|
copy := &e
|
||||||
|
return copy
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e Event) ResponseEventName(s string) EventType {
|
||||||
|
return EventType(fmt.Sprintf("%s-%s", e.Name, s))
|
||||||
|
}
|
||||||
|
|
||||||
// Unmarshal decodes the json payload in the given parameteer
|
// Unmarshal decodes the json payload in the given parameteer
|
||||||
func (r EventResponse) Unmarshal(i interface{}) error {
|
func (r EventResponse) Unmarshal(i interface{}) error {
|
||||||
return json.Unmarshal([]byte(r.Data), i)
|
return json.Unmarshal([]byte(r.Data), i)
|
||||||
@@ -52,7 +66,7 @@ func (r EventResponse) Errored() bool {
|
|||||||
return len(r.Error) != 0
|
return len(r.Error) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewEvent retuns a new event which can be used for publishing
|
// NewEvent returns a new event which can be used for publishing
|
||||||
// the obj gets automatically serialized in json.
|
// the obj gets automatically serialized in json.
|
||||||
func NewEvent(name EventType, obj interface{}) (*Event, error) {
|
func NewEvent(name EventType, obj interface{}) (*Event, error) {
|
||||||
dat, err := json.Marshal(obj)
|
dat, err := json.Marshal(obj)
|
||||||
|
1
vendor/github.com/mudler/go-pluggable/go.mod
generated
vendored
1
vendor/github.com/mudler/go-pluggable/go.mod
generated
vendored
@@ -4,7 +4,6 @@ go 1.14
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/chuckpreslar/emission v0.0.0-20170206194824-a7ddd980baf9
|
github.com/chuckpreslar/emission v0.0.0-20170206194824-a7ddd980baf9
|
||||||
github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0
|
|
||||||
github.com/onsi/ginkgo v1.14.2
|
github.com/onsi/ginkgo v1.14.2
|
||||||
github.com/onsi/gomega v1.10.3
|
github.com/onsi/gomega v1.10.3
|
||||||
github.com/pkg/errors v0.9.1
|
github.com/pkg/errors v0.9.1
|
||||||
|
2
vendor/github.com/mudler/go-pluggable/go.sum
generated
vendored
2
vendor/github.com/mudler/go-pluggable/go.sum
generated
vendored
@@ -1,7 +1,5 @@
|
|||||||
github.com/chuckpreslar/emission v0.0.0-20170206194824-a7ddd980baf9 h1:xz6Nv3zcwO2Lila35hcb0QloCQsc38Al13RNEzWRpX4=
|
github.com/chuckpreslar/emission v0.0.0-20170206194824-a7ddd980baf9 h1:xz6Nv3zcwO2Lila35hcb0QloCQsc38Al13RNEzWRpX4=
|
||||||
github.com/chuckpreslar/emission v0.0.0-20170206194824-a7ddd980baf9/go.mod h1:2wSM9zJkl1UQEFZgSd68NfCgRz1VL1jzy/RjCg+ULrs=
|
github.com/chuckpreslar/emission v0.0.0-20170206194824-a7ddd980baf9/go.mod h1:2wSM9zJkl1UQEFZgSd68NfCgRz1VL1jzy/RjCg+ULrs=
|
||||||
github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 h1:sDMmm+q/3+BukdIpxwO365v/Rbspp2Nt5XntgQRXq8Q=
|
|
||||||
github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM=
|
|
||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||||
|
40
vendor/github.com/mudler/go-pluggable/manager.go
generated
vendored
40
vendor/github.com/mudler/go-pluggable/manager.go
generated
vendored
@@ -21,6 +21,7 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/chuckpreslar/emission"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -29,14 +30,14 @@ import (
|
|||||||
type Manager struct {
|
type Manager struct {
|
||||||
Plugins []Plugin
|
Plugins []Plugin
|
||||||
Events []EventType
|
Events []EventType
|
||||||
Bus *Bus
|
Bus *emission.Emitter
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewManager returns a manager instance with a new bus and
|
// NewManager returns a manager instance with a new bus and
|
||||||
func NewManager(events []EventType) *Manager {
|
func NewManager(events []EventType) *Manager {
|
||||||
return &Manager{
|
return &Manager{
|
||||||
Events: events,
|
Events: events,
|
||||||
Bus: NewBus(),
|
Bus: emission.NewEmitter(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,19 +48,41 @@ func (m *Manager) Register() *Manager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Publish is a wrapper around NewEvent and the Manager internal Bus publishing system
|
// Publish is a wrapper around NewEvent and the Manager internal Bus publishing system
|
||||||
|
// It accepts optionally a list of functions that are called with the plugin result (only once)
|
||||||
func (m *Manager) Publish(event EventType, obj interface{}) (*Manager, error) {
|
func (m *Manager) Publish(event EventType, obj interface{}) (*Manager, error) {
|
||||||
ev, err := NewEvent(event, obj)
|
ev, err := NewEvent(event, obj)
|
||||||
if err == nil && ev != nil {
|
if err == nil && ev != nil {
|
||||||
m.Bus.Publish(ev)
|
m.Bus.Emit(string(ev.Name), ev)
|
||||||
}
|
}
|
||||||
return m, err
|
return m, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Response binds a set of listeners to an event type. The listeners are called for each result from
|
||||||
|
// every plugin when Publish is called.
|
||||||
|
func (m *Manager) Response(event EventType, listener ...func(p *Plugin, r *EventResponse)) *Manager {
|
||||||
|
ev, _ := NewEvent(event, nil)
|
||||||
|
for _, l := range listener {
|
||||||
|
m.Bus.On(string(ev.ResponseEventName("results")), l)
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Manager) propagateEvent(p Plugin) func(e *Event) {
|
||||||
|
return func(e *Event) {
|
||||||
|
resp, err := p.Run(*e)
|
||||||
|
r := &resp
|
||||||
|
if err != nil && !resp.Errored() {
|
||||||
|
resp.Error = err.Error()
|
||||||
|
}
|
||||||
|
m.Bus.Emit(string(e.ResponseEventName("results")), &p, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Subscribe subscribes the plugin to the events in the given bus
|
// Subscribe subscribes the plugin to the events in the given bus
|
||||||
func (m *Manager) Subscribe(b *Bus) *Manager {
|
func (m *Manager) Subscribe(b *emission.Emitter) *Manager {
|
||||||
for _, p := range m.Plugins {
|
for _, p := range m.Plugins {
|
||||||
for _, e := range m.Events {
|
for _, e := range m.Events {
|
||||||
b.Listen(e, b.propagateEvent(p))
|
b.On(string(e), m.propagateEvent(p))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return m
|
return m
|
||||||
@@ -74,13 +97,6 @@ func relativeToCwd(p string) (string, error) {
|
|||||||
return filepath.Join(cwd, p), nil
|
return filepath.Join(cwd, p), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListenAll Binds a callback to all plugins event
|
|
||||||
func (m *Manager) ListenAll(event EventType, listener interface{}) {
|
|
||||||
for _, p := range m.Plugins {
|
|
||||||
m.Bus.Listen(EventType(p.Name), listener)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Autoload automatically loads plugins binaries prefixed by 'prefix' in the current path
|
// Autoload automatically loads plugins binaries prefixed by 'prefix' in the current path
|
||||||
// optionally takes a list of paths to look also into
|
// optionally takes a list of paths to look also into
|
||||||
func (m *Manager) Autoload(prefix string, extensionpath ...string) *Manager {
|
func (m *Manager) Autoload(prefix string, extensionpath ...string) *Manager {
|
||||||
|
31
vendor/github.com/mudler/go-pluggable/plugin.go
generated
vendored
31
vendor/github.com/mudler/go-pluggable/plugin.go
generated
vendored
@@ -16,7 +16,9 @@
|
|||||||
package pluggable
|
package pluggable
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
|
||||||
@@ -29,19 +31,42 @@ type Plugin struct {
|
|||||||
Executable string
|
Executable string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A safe threshold to avoid unpleasant exec buffer fill for argv too big. Seems 128K is the limit on Linux.
|
||||||
|
const maxMessageSize = 1 << 13
|
||||||
|
|
||||||
// Run runs the Event on the plugin, and returns an EventResponse
|
// Run runs the Event on the plugin, and returns an EventResponse
|
||||||
func (p Plugin) Run(e Event) (EventResponse, error) {
|
func (p Plugin) Run(e Event) (EventResponse, error) {
|
||||||
r := EventResponse{}
|
r := EventResponse{}
|
||||||
k, err := e.JSON()
|
|
||||||
|
eventToprocess := &e
|
||||||
|
|
||||||
|
if len(e.Data) > maxMessageSize {
|
||||||
|
copy := e.Copy()
|
||||||
|
copy.Data = ""
|
||||||
|
f, err := ioutil.TempFile(os.TempDir(), "pluggable")
|
||||||
|
if err != nil {
|
||||||
|
return r, errors.Wrap(err, "while creating temporary file")
|
||||||
|
}
|
||||||
|
if err := ioutil.WriteFile(f.Name(), []byte(e.Data), os.ModePerm); err != nil {
|
||||||
|
return r, errors.Wrap(err, "while writing to temporary file")
|
||||||
|
}
|
||||||
|
copy.File = f.Name()
|
||||||
|
eventToprocess = copy
|
||||||
|
defer os.RemoveAll(f.Name())
|
||||||
|
}
|
||||||
|
|
||||||
|
k, err := eventToprocess.JSON()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return r, errors.Wrap(err, "while marshalling event")
|
return r, errors.Wrap(err, "while marshalling event")
|
||||||
}
|
}
|
||||||
cmd := exec.Command(p.Executable, string(e.Name), k)
|
cmd := exec.Command(p.Executable, string(e.Name), k)
|
||||||
cmd.Env = os.Environ()
|
cmd.Env = os.Environ()
|
||||||
|
var b bytes.Buffer
|
||||||
|
cmd.Stderr = &b
|
||||||
out, err := cmd.Output()
|
out, err := cmd.Output()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.Error = err.Error()
|
r.Error = "error while executing plugin: " + err.Error() + string(b.String())
|
||||||
return r, errors.Wrap(err, "while executing plugin")
|
return r, errors.Wrap(err, "while executing plugin: "+string(b.String()))
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := json.Unmarshal(out, &r); err != nil {
|
if err := json.Unmarshal(out, &r); err != nil {
|
||||||
|
5
vendor/modules.txt
vendored
5
vendor/modules.txt
vendored
@@ -62,8 +62,6 @@ github.com/cavaliercoder/grab/bps
|
|||||||
github.com/cespare/xxhash/v2
|
github.com/cespare/xxhash/v2
|
||||||
# github.com/chuckpreslar/emission v0.0.0-20170206194824-a7ddd980baf9
|
# github.com/chuckpreslar/emission v0.0.0-20170206194824-a7ddd980baf9
|
||||||
github.com/chuckpreslar/emission
|
github.com/chuckpreslar/emission
|
||||||
# github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0
|
|
||||||
github.com/codegangsta/inject
|
|
||||||
# github.com/containerd/cgroups v0.0.0-20200217135630-d732e370d46d
|
# github.com/containerd/cgroups v0.0.0-20200217135630-d732e370d46d
|
||||||
github.com/containerd/cgroups/stats/v1
|
github.com/containerd/cgroups/stats/v1
|
||||||
# github.com/containerd/containerd v1.4.1-0.20201117152358-0edc412565dc => github.com/containerd/containerd v1.3.1-0.20200227195959-4d242818bf55
|
# github.com/containerd/containerd v1.4.1-0.20201117152358-0edc412565dc => github.com/containerd/containerd v1.3.1-0.20200227195959-4d242818bf55
|
||||||
@@ -209,7 +207,6 @@ github.com/fatih/color
|
|||||||
# github.com/fsnotify/fsnotify v1.4.9
|
# github.com/fsnotify/fsnotify v1.4.9
|
||||||
github.com/fsnotify/fsnotify
|
github.com/fsnotify/fsnotify
|
||||||
# github.com/fsouza/go-dockerclient v1.6.4
|
# github.com/fsouza/go-dockerclient v1.6.4
|
||||||
## explicit
|
|
||||||
github.com/fsouza/go-dockerclient
|
github.com/fsouza/go-dockerclient
|
||||||
# github.com/genuinetools/img v0.5.11
|
# github.com/genuinetools/img v0.5.11
|
||||||
## explicit
|
## explicit
|
||||||
@@ -478,7 +475,7 @@ github.com/mudler/cobra-extensions
|
|||||||
# github.com/mudler/docker-companion v0.4.6-0.20200418093252-41846f112d87
|
# github.com/mudler/docker-companion v0.4.6-0.20200418093252-41846f112d87
|
||||||
## explicit
|
## explicit
|
||||||
github.com/mudler/docker-companion/api
|
github.com/mudler/docker-companion/api
|
||||||
# github.com/mudler/go-pluggable v0.0.0-20201113184918-d36448fc8f82
|
# github.com/mudler/go-pluggable v0.0.0-20210513155700-54c6443073af
|
||||||
## explicit
|
## explicit
|
||||||
github.com/mudler/go-pluggable
|
github.com/mudler/go-pluggable
|
||||||
# github.com/mudler/topsort v0.0.0-20201103161459-db5c7901c290
|
# github.com/mudler/topsort v0.0.0-20201103161459-db5c7901c290
|
||||||
|
Reference in New Issue
Block a user