mirror of
https://github.com/mudler/luet.git
synced 2025-09-03 08:14:46 +00:00
Compare commits
61 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
56e9c6f82e | ||
|
92ea69a2b9 | ||
|
838899aa83 | ||
|
76695b2fc8 | ||
|
5c84e5b0a7 | ||
|
06fa8b1c87 | ||
|
ff153f367f | ||
|
459676397c | ||
|
93057fbf6d | ||
|
5e1a7c50df | ||
|
0ceaf09615 | ||
|
0dc78ebe41 | ||
|
27c2e3c51f | ||
|
e83f600ed3 | ||
|
6344e47eb3 | ||
|
8b1c5558b2 | ||
|
c277ac0f94 | ||
|
d8c8c2194f | ||
|
4494385f5b | ||
|
85a7968ecc | ||
|
1ba987b0f1 | ||
|
c72b5be364 | ||
|
1ef18ed2c5 | ||
|
4b1b711a5c | ||
|
7f047e4fc2 | ||
|
356350f724 | ||
|
9d2ee1b760 | ||
|
fd12227d53 | ||
|
1e617b0c67 | ||
|
77b49d9c4a | ||
|
4c3532e3c6 | ||
|
f2ec065a89 | ||
|
7193ea03f9 | ||
|
beeb0dcaaa | ||
|
0de3177ddd | ||
|
45c8dfa19f | ||
|
186ac33156 | ||
|
bdc24b84a4 | ||
|
e5d6d21178 | ||
|
0379855592 | ||
|
958b8c32e1 | ||
|
b0b95d1721 | ||
|
f85891e362 | ||
|
946524f90d | ||
|
2cbd97ff3a | ||
|
a4d77f8f99 | ||
|
adcb459fd2 | ||
|
55ae67be0f | ||
|
848215eef0 | ||
|
7bfff97f57 | ||
|
a73f5f9b65 | ||
|
0288eedbc3 | ||
|
b27237b7ff | ||
|
c9aed37fa7 | ||
|
788b889d14 | ||
|
ef92f23221 | ||
|
562fcc2421 | ||
|
54be45dcff | ||
|
413572a8e3 | ||
|
ecc41ce370 | ||
|
dd6501a642 |
10
cmd/build.go
10
cmd/build.go
@@ -111,6 +111,8 @@ Build packages specifying multiple definition trees:
|
||||
onlydeps := viper.GetBool("onlydeps")
|
||||
onlyTarget, _ := cmd.Flags().GetBool("only-target-package")
|
||||
full, _ := cmd.Flags().GetBool("full")
|
||||
rebuild, _ := cmd.Flags().GetBool("rebuild")
|
||||
|
||||
concurrent, _ := cmd.Flags().GetBool("solver-concurrent")
|
||||
var results Results
|
||||
backendArgs := viper.GetStringSlice("backend-args")
|
||||
@@ -176,6 +178,7 @@ Build packages specifying multiple definition trees:
|
||||
options.WithBuildValues(values),
|
||||
options.WithPullRepositories(pullRepo),
|
||||
options.WithPushRepository(imageRepository),
|
||||
options.Rebuild(rebuild),
|
||||
options.WithSolverOptions(*opts),
|
||||
options.Wait(wait),
|
||||
options.OnlyTarget(onlyTarget),
|
||||
@@ -244,11 +247,12 @@ Build packages specifying multiple definition trees:
|
||||
}
|
||||
|
||||
for _, sp := range toCalculate {
|
||||
packs, err := luetCompiler.ComputeDepTree(sp)
|
||||
ht := compiler.NewHashTree(generalRecipe.GetDatabase())
|
||||
hashTree, err := ht.Query(luetCompiler, sp)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
for _, p := range packs {
|
||||
for _, p := range hashTree.Dependencies {
|
||||
results.Packages = append(results.Packages,
|
||||
PackageResult{
|
||||
Name: p.Package.GetName(),
|
||||
@@ -329,7 +333,7 @@ func init() {
|
||||
buildCmd.Flags().Bool("solver-concurrent", false, "Use concurrent solver (experimental)")
|
||||
buildCmd.Flags().Bool("live-output", LuetCfg.GetGeneral().ShowBuildOutput, "Enable live output of the build phase.")
|
||||
buildCmd.Flags().Bool("from-repositories", false, "Consume the user-defined repositories to pull specfiles from")
|
||||
|
||||
buildCmd.Flags().Bool("rebuild", false, "To combine with --pull. Allows to rebuild the target package even if an image is available, against a local values file")
|
||||
buildCmd.Flags().Bool("pretend", false, "Just print what packages will be compiled")
|
||||
buildCmd.Flags().StringArrayP("pull-repository", "p", []string{}, "A list of repositories to pull the cache from")
|
||||
|
||||
|
@@ -40,7 +40,7 @@ var Verbose bool
|
||||
var LockedCommands = []string{"install", "uninstall", "upgrade"}
|
||||
|
||||
const (
|
||||
LuetCLIVersion = "0.13.0"
|
||||
LuetCLIVersion = "0.16.4"
|
||||
LuetEnvPrefix = "LUET"
|
||||
)
|
||||
|
||||
@@ -97,7 +97,7 @@ To build a package, from a tree definition:
|
||||
|
||||
plugin := viper.GetStringSlice("plugin")
|
||||
|
||||
bus.Manager.Load(plugin...).Register()
|
||||
bus.Manager.Initialize(plugin...)
|
||||
if len(bus.Manager.Plugins) != 0 {
|
||||
Info(":lollipop:Enabled plugins:")
|
||||
for _, p := range bus.Manager.Plugins {
|
||||
|
@@ -96,9 +96,14 @@ func NewTreeImageCommand() *cobra.Command {
|
||||
if err != nil {
|
||||
Fatal("Error: " + err.Error())
|
||||
}
|
||||
asserts, err := luetCompiler.ComputeDepTree(spec)
|
||||
|
||||
for _, assertion := range asserts { //highly dependent on the order
|
||||
ht := compiler.NewHashTree(reciper.GetDatabase())
|
||||
hashtree, err := ht.Query(luetCompiler, spec)
|
||||
if err != nil {
|
||||
Fatal("Error: " + err.Error())
|
||||
}
|
||||
|
||||
for _, assertion := range hashtree.Solution { //highly dependent on the order
|
||||
|
||||
//buildImageHash := imageRepository + ":" + assertion.Hash.BuildHash
|
||||
currentPackageImageHash := imageRepository + ":" + assertion.Hash.PackageHash
|
||||
|
4
go.mod
4
go.mod
@@ -16,7 +16,6 @@ require (
|
||||
github.com/docker/docker v20.10.0-beta1.0.20201110211921-af34b94a78a1+incompatible
|
||||
github.com/docker/go-units v0.4.0
|
||||
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/ghodss/yaml v1.0.0
|
||||
github.com/google/go-containerregistry v0.2.1
|
||||
@@ -33,11 +32,12 @@ require (
|
||||
github.com/kyokomi/emoji v2.1.0+incompatible
|
||||
github.com/logrusorgru/aurora v0.0.0-20190417123914-21d75270181e
|
||||
github.com/marcsauter/single v0.0.0-20181104081128-f8bf46f26ec0
|
||||
github.com/mitchellh/hashstructure/v2 v2.0.1
|
||||
github.com/moby/buildkit v0.7.2
|
||||
github.com/moby/sys/mount v0.2.0 // indirect
|
||||
github.com/mudler/cobra-extensions v0.0.0-20200612154940-31a47105fe3d
|
||||
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/onsi/ginkgo v1.14.2
|
||||
github.com/onsi/gomega v1.10.3
|
||||
|
31
go.sum
31
go.sum
@@ -91,13 +91,12 @@ github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbt
|
||||
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||
github.com/Sabayon/pkgs-checker v0.7.2 h1:mh53u5D7FTCeBJevYQA9cCxAWGTSuKqw7m/x7GsQVb0=
|
||||
github.com/Sabayon/pkgs-checker v0.7.2/go.mod h1:GFGM6ZzSE5owdGgjLnulj0+Vt9UTd5LFGmB2AOVPYrE=
|
||||
github.com/Sabayon/pkgs-checker v0.8.1 h1:pVen975z9WIecq7luntUn+0XzGdiyz2CsDay8w+ZmOw=
|
||||
github.com/Sabayon/pkgs-checker v0.8.1/go.mod h1:GC9PBUzcq0QVEBGRA1IIMXf6wHxo34KH5BeqoyJsLpo=
|
||||
github.com/Sereal/Sereal v0.0.0-20181211220259-509a78ddbda3 h1:Xu7z47ZiE/J+sKXHZMGxEor/oY2q6dq51fkO0JqdSwY=
|
||||
github.com/Sereal/Sereal v0.0.0-20181211220259-509a78ddbda3/go.mod h1:D0JMgToj/WdxCgd30Kc1UcA9E+WdZoJqeVOuYW7iTBM=
|
||||
github.com/Shopify/logrus-bugsnag v0.0.0-20170309145241-6dbc35f2c30d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ=
|
||||
github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d h1:UrqY+r/OJnIp5u0s1SbQ8dVfLCZJsnvazdBP5hS4iRs=
|
||||
github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ=
|
||||
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
||||
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
||||
@@ -146,18 +145,24 @@ github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+Ce
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
github.com/bitly/go-hostpool v0.1.0 h1:XKmsF6k5el6xHG3WPJ8U0Ku/ye7njX7W81Ng7O2ioR0=
|
||||
github.com/bitly/go-hostpool v0.1.0/go.mod h1:4gOCgp6+NZnVqlKyZ/iBZFTAJKembaVENUpMkpg42fw=
|
||||
github.com/bitly/go-simplejson v0.5.0 h1:6IH+V8/tVMab511d5bn4M7EwGXZf9Hj6i2xSwkNEM+Y=
|
||||
github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA=
|
||||
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
|
||||
github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
|
||||
github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
|
||||
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY=
|
||||
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
|
||||
github.com/briandowns/spinner v1.12.1-0.20201220203425-e201aaea0a31 h1:yInAg9pE5qGec5eQ7XdfOTTaGwGxD3bKFVjmD6VKkwc=
|
||||
github.com/briandowns/spinner v1.12.1-0.20201220203425-e201aaea0a31/go.mod h1:QOuQk7x+EaDASo80FEXwlwiA+j/PPIcX3FScO+3/ZPQ=
|
||||
github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk=
|
||||
github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8=
|
||||
github.com/bugsnag/bugsnag-go v1.0.5-0.20150529004307-13fd6b8acda0 h1:s7+5BfS4WFJoVF9pnB8kBk03S7pZXRdKamnV0FOl5Sc=
|
||||
github.com/bugsnag/bugsnag-go v1.0.5-0.20150529004307-13fd6b8acda0/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8=
|
||||
github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b h1:otBG+dV+YK+Soembjv71DPz3uX/V/6MMlSyD9JBQ6kQ=
|
||||
github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50=
|
||||
github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0 h1:nvj0OLI3YqYXer/kZD8Ri1aaunCxIEsOst1BVJswV0o=
|
||||
github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE=
|
||||
github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
|
||||
github.com/cavaliercoder/grab v1.0.1-0.20201108051000-98a5bfe305ec h1:4XvMn0XuV7qxCH22gbnR79r+xTUaLOSA0GW/egpO3SQ=
|
||||
@@ -177,13 +182,12 @@ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMn
|
||||
github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmEg9bt0VpxxWqJlO4iwu3FBdHUzV7wQVg=
|
||||
github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cloudflare/cfssl v0.0.0-20180223231731-4e2dcbde5004 h1:lkAMpLVBDaj17e85keuznYcH5rqI438v41pKcBl4ZxQ=
|
||||
github.com/cloudflare/cfssl v0.0.0-20180223231731-4e2dcbde5004/go.mod h1:yMWuSON2oQp+43nFtAV/uvKQIFpSPerB57DCt9t8sSA=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
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-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/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko=
|
||||
github.com/containerd/cgroups v0.0.0-20200217135630-d732e370d46d h1:UKAt78F1OvM4ceTn1VvXuYuatXohsFU1eSI2IBtTw9g=
|
||||
@@ -255,6 +259,7 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
|
||||
github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd/go.mod h1:dv4zxwHi5C/8AeI+4gX4dCWOIvNi7I6JCSX0HvlKPgE=
|
||||
github.com/deislabs/oras v0.8.1/go.mod h1:Mx0rMSbBNaNfY9hjpccEnxkOqJL6KGjtxNHPLC4G4As=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20191001013358-cfbb681360f0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20191128021309-1d7a30a10f73 h1:OGNva6WhsKst5OZf7eZOklDztV3hwtTHovdrLHV+MsA=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20191128021309-1d7a30a10f73/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
|
||||
github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0=
|
||||
github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
@@ -315,6 +320,7 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y=
|
||||
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0=
|
||||
github.com/evanphx/json-patch v0.0.0-20200808040245-162e5629780b/go.mod h1:NAJj0yf/KaRKURN6nyi7A9IZydMivZEm9oQLWNjfKDc=
|
||||
github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4=
|
||||
@@ -400,6 +406,7 @@ github.com/go-openapi/validate v0.19.5/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85n
|
||||
github.com/go-sql-driver/mysql v1.3.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
|
||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
@@ -432,6 +439,7 @@ github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5
|
||||
github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||
github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
|
||||
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
|
||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
@@ -470,6 +478,7 @@ github.com/golangplus/fmt v0.0.0-20150411045040-2a5d6d7d2995/go.mod h1:lJgMEyOkY
|
||||
github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e/go.mod h1:0AA//k/eakGydO4jKRoRL2j92ZKSzTgj9tclaCrvXHk=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/certificate-transparency-go v1.0.10-0.20180222191210-5ab67e519c93 h1:jc2UWq7CbdszqeH6qu1ougXMIUBfSy8Pbh/anURYbGI=
|
||||
github.com/google/certificate-transparency-go v1.0.10-0.20180222191210-5ab67e519c93/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg=
|
||||
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
@@ -532,6 +541,7 @@ github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 h1:MJG/KsmcqMwFAkh8mTnAwhyKoB+sTAnY4CACC110tbU=
|
||||
github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645/go.mod h1:6iZfnjpejD4L/4DwD7NryNaJyCQdzwWwH2MWhCA90Kw=
|
||||
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8=
|
||||
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4=
|
||||
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
|
||||
github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=
|
||||
@@ -591,8 +601,11 @@ github.com/jedib0t/go-pretty/v6 v6.0.5/go.mod h1:MTr6FgcfNdnN5wPVBzJ6mhJeDyiF0yB
|
||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/jinzhu/copier v0.0.0-20180308034124-7e38e58719c3 h1:sHsPfNMAG70QAvKbddQ0uScZCHQoZsT5NykGRCeeeIs=
|
||||
github.com/jinzhu/copier v0.0.0-20180308034124-7e38e58719c3/go.mod h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s=
|
||||
github.com/jinzhu/gorm v0.0.0-20170222002820-5409931a1bb8 h1:CZkYfurY6KGhVtlalI4QwQ6T0Cu6iuY3e0x5RLu96WE=
|
||||
github.com/jinzhu/gorm v0.0.0-20170222002820-5409931a1bb8/go.mod h1:Vla75njaFJ8clLU1W44h34PjIkijhjHIYnZxMqCdxqo=
|
||||
github.com/jinzhu/inflection v0.0.0-20170102125226-1c35d901db3d h1:jRQLvyVGL+iVtDElaEIDdKwpPqUIZJfzkNLV34htpEc=
|
||||
github.com/jinzhu/inflection v0.0.0-20170102125226-1c35d901db3d/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
github.com/jinzhu/now v1.1.1 h1:g39TucaRWyV3dwDO++eEc6qf8TVIQ/Da48WmqjZ3i7E=
|
||||
github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
@@ -613,6 +626,7 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/juju/loggo v0.0.0-20190526231331-6e530bcce5d8 h1:UUHMLvzt/31azWTN/ifGWef4WUqvXk0iRqdhdy/2uzI=
|
||||
github.com/juju/loggo v0.0.0-20190526231331-6e530bcce5d8/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw=
|
||||
@@ -649,6 +663,7 @@ github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6Fm
|
||||
github.com/lib/pq v0.0.0-20150723085316-0dad96c0b94f/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.7.0 h1:h93mCPfUSkaul3Ka/VG8uZdmW1uMHDGxzu0NWHuJmHY=
|
||||
github.com/lib/pq v1.7.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
|
||||
github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
|
||||
@@ -713,6 +728,8 @@ github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS4
|
||||
github.com/mitchellh/hashstructure v0.0.0-20170609045927-2bca23e0e452/go.mod h1:QjSHrPWS+BGUVBYkbTZWEnOh3G1DutKwClXU/ABz6AQ=
|
||||
github.com/mitchellh/hashstructure v1.0.0 h1:ZkRJX1CyOoTkar7p/mLS5TZU4nJ1Rn/F8u9dGS02Q3Y=
|
||||
github.com/mitchellh/hashstructure v1.0.0/go.mod h1:QjSHrPWS+BGUVBYkbTZWEnOh3G1DutKwClXU/ABz6AQ=
|
||||
github.com/mitchellh/hashstructure/v2 v2.0.1 h1:L60q1+q7cXE4JeEJJKMnh2brFIe3rZxCihYAB61ypAY=
|
||||
github.com/mitchellh/hashstructure/v2 v2.0.1/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE=
|
||||
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
|
||||
github.com/mitchellh/mapstructure v0.0.0-20150613213606-2caf8efc9366/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
@@ -743,8 +760,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/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/go-pluggable v0.0.0-20201113184918-d36448fc8f82 h1:Hkefw2tzoKATVUTFsCtDlUnY180+OE851qGbq45ATxk=
|
||||
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 h1:jixIxEgLSqu24eMiyzfCI+roa5IaOUhF546ePSFyHeY=
|
||||
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/go.mod h1:uP5BBgFxq2wNWo7n1vnY5SSbgL0WDshVJrOO12tZ/lA=
|
||||
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
@@ -1450,6 +1467,7 @@ google.golang.org/protobuf v1.24.0 h1:UhZDfRO8JRQru4/+LlLE0BRKGF8L+PICnvYZmx/fEG
|
||||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/cenkalti/backoff.v2 v2.2.1 h1:eJ9UAg01/HIHG987TwxvnzK2MgxXq97YY6rYDpY9aII=
|
||||
gopkg.in/cenkalti/backoff.v2 v2.2.1/go.mod h1:S0QdOvT2AlerfSBkp0O+dk+bbIMaNbEmVk876gPCthU=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
@@ -1472,6 +1490,7 @@ gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
|
||||
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
|
||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||
gopkg.in/rethinkdb/rethinkdb-go.v6 v6.2.1 h1:d4KQkxAaAiRY2h5Zqis161Pv91A37uZyJOx73duwUwM=
|
||||
gopkg.in/rethinkdb/rethinkdb-go.v6 v6.2.1/go.mod h1:WbjuEoo1oadwzQ4apSDU+JTvmllEHtsNHS6y7vFc7iw=
|
||||
gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
|
@@ -1,6 +1,8 @@
|
||||
package bus
|
||||
|
||||
import (
|
||||
. "github.com/mudler/luet/pkg/logger"
|
||||
|
||||
"github.com/mudler/go-pluggable"
|
||||
)
|
||||
|
||||
@@ -47,21 +49,47 @@ var (
|
||||
)
|
||||
|
||||
// Manager is the bus instance manager, which subscribes plugins to events emitted by Luet
|
||||
var Manager *pluggable.Manager = pluggable.NewManager(
|
||||
[]pluggable.EventType{
|
||||
EventPackageInstall,
|
||||
EventPackageUnInstall,
|
||||
EventPackagePreBuild,
|
||||
EventPackagePreBuildArtifact,
|
||||
EventPackagePostBuildArtifact,
|
||||
EventPackagePostBuild,
|
||||
EventRepositoryPreBuild,
|
||||
EventRepositoryPostBuild,
|
||||
EventImagePreBuild,
|
||||
EventImagePrePull,
|
||||
EventImagePrePush,
|
||||
EventImagePostBuild,
|
||||
EventImagePostPull,
|
||||
EventImagePostPush,
|
||||
},
|
||||
)
|
||||
var Manager *Bus = &Bus{
|
||||
Manager: pluggable.NewManager(
|
||||
[]pluggable.EventType{
|
||||
EventPackageInstall,
|
||||
EventPackageUnInstall,
|
||||
EventPackagePreBuild,
|
||||
EventPackagePreBuildArtifact,
|
||||
EventPackagePostBuildArtifact,
|
||||
EventPackagePostBuild,
|
||||
EventRepositoryPreBuild,
|
||||
EventRepositoryPostBuild,
|
||||
EventImagePreBuild,
|
||||
EventImagePrePull,
|
||||
EventImagePrePush,
|
||||
EventImagePostBuild,
|
||||
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,
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@@ -25,7 +25,6 @@ import (
|
||||
|
||||
bus "github.com/mudler/luet/pkg/bus"
|
||||
|
||||
docker "github.com/fsouza/go-dockerclient"
|
||||
capi "github.com/mudler/docker-companion/api"
|
||||
|
||||
"github.com/mudler/luet/pkg/helpers"
|
||||
@@ -56,24 +55,6 @@ func (*SimpleDocker) BuildImage(opts Options) error {
|
||||
|
||||
Info(":whale: Building image " + name + " done")
|
||||
|
||||
if os.Getenv("DOCKER_SQUASH") == "true" {
|
||||
Info(":whale: Squashing image " + name)
|
||||
var client *docker.Client
|
||||
|
||||
Spinner(22)
|
||||
defer SpinnerStop()
|
||||
client, err = docker.NewClientFromEnv()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not connect to the Docker daemon")
|
||||
}
|
||||
err = capi.Squash(client, name, name)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Failed squashing image")
|
||||
}
|
||||
|
||||
Info(":whale: Squashing image " + name + " done")
|
||||
}
|
||||
|
||||
bus.Manager.Publish(bus.EventImagePostBuild, opts)
|
||||
|
||||
return nil
|
||||
@@ -200,6 +181,12 @@ func (b *SimpleDocker) ExtractRootfs(opts Options, keepPerms bool) error {
|
||||
name := opts.ImageName
|
||||
dst := opts.Destination
|
||||
|
||||
if !b.ImageExists(name) {
|
||||
if err := b.DownloadImage(opts); err != nil {
|
||||
return errors.Wrap(err, "failed pulling image "+name+" during extraction")
|
||||
}
|
||||
}
|
||||
|
||||
tempexport, err := ioutil.TempDir(dst, "tmprootfs")
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Error met while creating tempdir for rootfs")
|
||||
|
@@ -16,7 +16,9 @@
|
||||
package compiler
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
@@ -89,7 +91,7 @@ func (cs *LuetCompiler) compilerWorker(i int, wg *sync.WaitGroup, cspecs chan *c
|
||||
defer wg.Done()
|
||||
|
||||
for s := range cspecs {
|
||||
ar, err := cs.compile(concurrency, keepPermissions, s)
|
||||
ar, err := cs.compile(concurrency, keepPermissions, nil, nil, s)
|
||||
if err != nil {
|
||||
errors <- err
|
||||
}
|
||||
@@ -146,11 +148,6 @@ func (cs *LuetCompiler) CompileParallel(keepPermissions bool, ps *compilerspec.L
|
||||
}
|
||||
|
||||
for _, p := range ps.All() {
|
||||
asserts, err := cs.ComputeDepTree(p)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
p.SetSourceAssertion(asserts)
|
||||
all <- p
|
||||
}
|
||||
|
||||
@@ -303,20 +300,6 @@ func (cs *LuetCompiler) buildPackageImage(image, buildertaggedImage, packageImag
|
||||
|
||||
pkgTag := ":package: " + p.GetPackage().HumanReadableString()
|
||||
|
||||
// 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.
|
||||
|
||||
fp := p.GetPackage().HashFingerprint(helpers.StripRegistryFromImage(packageImage))
|
||||
|
||||
if buildertaggedImage == "" {
|
||||
buildertaggedImage = cs.Options.PushImageRepository + ":builder-" + fp
|
||||
Debug(pkgTag, "Creating intermediary image", buildertaggedImage, "from", image)
|
||||
}
|
||||
|
||||
// TODO: Cleanup, not actually hit
|
||||
if packageImage == "" {
|
||||
return runnerOpts, builderOpts, errors.New("no package image given")
|
||||
@@ -354,9 +337,15 @@ func (cs *LuetCompiler) buildPackageImage(image, buildertaggedImage, packageImag
|
||||
return builderOpts, runnerOpts, errors.Wrap(err, "Could not generate image definition")
|
||||
}
|
||||
|
||||
if len(p.GetPreBuildSteps()) == 0 {
|
||||
buildertaggedImage = image
|
||||
}
|
||||
// Even if we don't have prelude steps, we want to push
|
||||
// An intermediate image to tag images which are outside of the tree.
|
||||
// Those don't have an hash otherwise, and thus makes build unreproducible
|
||||
// see SKIPBUILD for the other logic
|
||||
// if len(p.GetPreBuildSteps()) == 0 {
|
||||
// buildertaggedImage = image
|
||||
// }
|
||||
// We might want to skip this phase but replacing with a tag that we push. But in case
|
||||
// steps in prelude are == 0 those are equivalent.
|
||||
|
||||
// Then we write the step image, which uses the builder one
|
||||
if err := p.WriteStepImageDefinition(buildertaggedImage, filepath.Join(buildDir, p.GetPackage().GetFingerPrint()+".dockerfile")); err != nil {
|
||||
@@ -401,12 +390,13 @@ func (cs *LuetCompiler) buildPackageImage(image, buildertaggedImage, packageImag
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if len(p.GetPreBuildSteps()) != 0 {
|
||||
Info(pkgTag, ":whale: Generating 'builder' image from", image, "as", buildertaggedImage, "with prelude steps")
|
||||
if err := buildAndPush(builderOpts); err != nil {
|
||||
return builderOpts, runnerOpts, errors.Wrapf(err, "Could not push image: %s %s", image, builderOpts.DockerFileName)
|
||||
}
|
||||
// SKIPBUILD
|
||||
// if len(p.GetPreBuildSteps()) != 0 {
|
||||
Info(pkgTag, ":whale: Generating 'builder' image from", image, "as", buildertaggedImage, "with prelude steps")
|
||||
if err := buildAndPush(builderOpts); err != nil {
|
||||
return builderOpts, runnerOpts, errors.Wrapf(err, "Could not push image: %s %s", image, builderOpts.DockerFileName)
|
||||
}
|
||||
//}
|
||||
|
||||
// Even if we might not have any steps to build, we do that so we can tag the image used in this moment and use that to cache it in a registry, or in the system.
|
||||
// acting as a docker tag.
|
||||
@@ -425,7 +415,7 @@ func (cs *LuetCompiler) genArtifact(p *compilerspec.LuetCompilationSpec, builder
|
||||
var rootfs string
|
||||
var err error
|
||||
pkgTag := ":package: " + p.GetPackage().HumanReadableString()
|
||||
|
||||
Debug(pkgTag, "Generating artifact")
|
||||
// We can't generate delta in this case. It implies the package is a virtual, and nothing has to be done really
|
||||
if p.EmptyPackage() {
|
||||
fakePackage := p.Rel(p.GetPackage().GetFingerPrint() + ".package.tar")
|
||||
@@ -470,7 +460,7 @@ func (cs *LuetCompiler) genArtifact(p *compilerspec.LuetCompilationSpec, builder
|
||||
|
||||
filelist, err := a.FileList()
|
||||
if err != nil {
|
||||
return a, errors.Wrap(err, "Failed getting package list")
|
||||
return a, errors.Wrapf(err, "Failed getting package list for '%s' '%s'", a.Path, a.CompileSpec.Package.HumanReadableString())
|
||||
}
|
||||
|
||||
a.Files = filelist
|
||||
@@ -518,10 +508,11 @@ func oneOfImagesAvailable(images []string, b CompilerBackend) (bool, string) {
|
||||
return false, ""
|
||||
}
|
||||
|
||||
func (cs *LuetCompiler) resolveExistingImageHash(imageHash string) string {
|
||||
func (cs *LuetCompiler) findImageHash(imageHash string, p *compilerspec.LuetCompilationSpec) string {
|
||||
var resolvedImage string
|
||||
Debug("Resolving image hash for", p.Package.HumanReadableString(), "hash", imageHash, "Pull repositories", p.BuildOptions.PullImageRepository)
|
||||
toChecklist := append([]string{fmt.Sprintf("%s:%s", cs.Options.PushImageRepository, imageHash)},
|
||||
genImageList(cs.Options.PullImageRepository, imageHash)...)
|
||||
genImageList(p.BuildOptions.PullImageRepository, imageHash)...)
|
||||
if exists, which := oneOfImagesExists(toChecklist, cs.Backend); exists {
|
||||
resolvedImage = which
|
||||
}
|
||||
@@ -530,6 +521,11 @@ func (cs *LuetCompiler) resolveExistingImageHash(imageHash string) string {
|
||||
resolvedImage = which
|
||||
}
|
||||
}
|
||||
return resolvedImage
|
||||
}
|
||||
|
||||
func (cs *LuetCompiler) resolveExistingImageHash(imageHash string, p *compilerspec.LuetCompilationSpec) string {
|
||||
resolvedImage := cs.findImageHash(imageHash, p)
|
||||
|
||||
if resolvedImage == "" {
|
||||
resolvedImage = fmt.Sprintf("%s:%s", cs.Options.PushImageRepository, imageHash)
|
||||
@@ -555,9 +551,10 @@ func LoadArtifactFromYaml(spec *compilerspec.LuetCompilationSpec) (*artifact.Pac
|
||||
func (cs *LuetCompiler) getImageArtifact(hash string, p *compilerspec.LuetCompilationSpec) (*artifact.PackageArtifact, error) {
|
||||
// we check if there is an available image with the given hash and
|
||||
// we return a full artifact if can be loaded locally.
|
||||
Debug("Get image artifact for", p.Package.HumanReadableString(), "hash", hash, "Pull repositories", p.BuildOptions.PullImageRepository)
|
||||
|
||||
toChecklist := append([]string{fmt.Sprintf("%s:%s", cs.Options.PushImageRepository, hash)},
|
||||
genImageList(cs.Options.PullImageRepository, hash)...)
|
||||
genImageList(p.BuildOptions.PullImageRepository, hash)...)
|
||||
|
||||
exists, _ := oneOfImagesExists(toChecklist, cs.Backend)
|
||||
if art, err := LoadArtifactFromYaml(p); err == nil && exists { // If YAML is correctly loaded, and both images exists, no reason to rebuild.
|
||||
@@ -578,7 +575,7 @@ func (cs *LuetCompiler) getImageArtifact(hash string, p *compilerspec.LuetCompil
|
||||
// image buildertaggedImage.
|
||||
// Images that can be resolved from repositories are prefered over the local ones if PullFirst is set to true
|
||||
// avoiding to rebuild images as much as possible
|
||||
func (cs *LuetCompiler) compileWithImage(image, buildertaggedImage string, packageTagHash string,
|
||||
func (cs *LuetCompiler) compileWithImage(image, builderHash string, packageTagHash string,
|
||||
concurrency int,
|
||||
keepPermissions, keepImg bool,
|
||||
p *compilerspec.LuetCompilationSpec, generateArtifact bool) (*artifact.PackageArtifact, error) {
|
||||
@@ -591,17 +588,52 @@ func (cs *LuetCompiler) compileWithImage(image, buildertaggedImage string, packa
|
||||
}
|
||||
|
||||
if !generateArtifact {
|
||||
// try to avoid regenerating the image if possible by checking the hash in the
|
||||
// given repositories
|
||||
// It is best effort. If we fail resolving, we will generate the images and keep going
|
||||
if art, err := cs.getImageArtifact(packageTagHash, p); err == nil {
|
||||
// try to avoid regenerating the image if possible by checking the hash in the
|
||||
// given repositories
|
||||
// It is best effort. If we fail resolving, we will generate the images and keep going
|
||||
return art, nil
|
||||
}
|
||||
}
|
||||
|
||||
// always going to point at the destination from the repo defined
|
||||
packageImage := fmt.Sprintf("%s:%s", cs.Options.PushImageRepository, packageTagHash)
|
||||
builderOpts, runnerOpts, err := cs.buildPackageImage(image, buildertaggedImage, packageImage, concurrency, keepPermissions, p)
|
||||
remoteBuildertaggedImage := fmt.Sprintf("%s:%s", cs.Options.PushImageRepository, builderHash)
|
||||
builderResolved := cs.resolveExistingImageHash(builderHash, p)
|
||||
//generated := false
|
||||
// if buildertaggedImage == "" {
|
||||
// buildertaggedImage = fmt.Sprintf("%s:%s", cs.Options.PushImageRepository, buildertaggedImage)
|
||||
// generated = true
|
||||
// // Debug(pkgTag, "Creating intermediary image", buildertaggedImage, "from", image)
|
||||
// }
|
||||
|
||||
if cs.Options.PullFirst && !cs.Options.Rebuild {
|
||||
Debug("Checking if an image is already available")
|
||||
// FIXUP here. If packageimage hash exists and pull is true, generate package
|
||||
resolved := cs.resolveExistingImageHash(packageTagHash, p)
|
||||
Debug("Resolved: " + resolved)
|
||||
Debug("Expected remote: " + resolved)
|
||||
Debug("Package image: " + packageImage)
|
||||
Debug("Resolved builder image: " + builderResolved)
|
||||
|
||||
// a remote image is there already
|
||||
remoteImageAvailable := resolved != packageImage && remoteBuildertaggedImage != builderResolved
|
||||
// or a local one is available
|
||||
localImageAvailable := cs.Backend.ImageExists(remoteBuildertaggedImage) && cs.Backend.ImageExists(packageImage)
|
||||
|
||||
switch {
|
||||
case remoteImageAvailable:
|
||||
Debug("Images available remotely for", p.Package.HumanReadableString(), "generating artifact from remote images:", resolved)
|
||||
return cs.genArtifact(p, backend.Options{ImageName: builderResolved}, backend.Options{ImageName: resolved}, concurrency, keepPermissions)
|
||||
case localImageAvailable:
|
||||
Debug("Images locally available for", p.Package.HumanReadableString(), "generating artifact from image:", resolved)
|
||||
return cs.genArtifact(p, backend.Options{ImageName: remoteBuildertaggedImage}, backend.Options{ImageName: packageImage}, concurrency, keepPermissions)
|
||||
default:
|
||||
Debug("Images not available for", p.Package.HumanReadableString())
|
||||
}
|
||||
}
|
||||
|
||||
// always going to point at the destination from the repo defined
|
||||
builderOpts, runnerOpts, err := cs.buildPackageImage(image, builderResolved, packageImage, concurrency, keepPermissions, p)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed building package image")
|
||||
}
|
||||
@@ -651,33 +683,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) {
|
||||
|
||||
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()})
|
||||
@@ -689,31 +695,35 @@ func (cs *LuetCompiler) ComputeDepTree(p *compilerspec.LuetCompilationSpec) (sol
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "While order a solution for "+p.GetPackage().HumanReadableString())
|
||||
}
|
||||
return dependencies, nil
|
||||
}
|
||||
|
||||
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(),
|
||||
}
|
||||
assertions = append(assertions, assertion)
|
||||
// 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 {
|
||||
sol, err := cs.ComputeDepTree(spec)
|
||||
if err != nil {
|
||||
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 assertions, nil
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Compile is a non-parallel version of CompileParallel. It builds the compilation specs and generates
|
||||
// an artifact
|
||||
func (cs *LuetCompiler) Compile(keepPermissions bool, p *compilerspec.LuetCompilationSpec) (*artifact.PackageArtifact, error) {
|
||||
asserts, err := cs.ComputeDepTree(p)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
p.SetSourceAssertion(asserts)
|
||||
return cs.compile(cs.Options.Concurrency, keepPermissions, p)
|
||||
return cs.compile(cs.Options.Concurrency, keepPermissions, nil, nil, p)
|
||||
}
|
||||
|
||||
func genImageList(refs []string, hash string) []string {
|
||||
@@ -724,15 +734,203 @@ func genImageList(refs []string, hash string) []string {
|
||||
return res
|
||||
}
|
||||
|
||||
func (cs *LuetCompiler) compile(concurrency int, keepPermissions bool, p *compilerspec.LuetCompilationSpec) (*artifact.PackageArtifact, error) {
|
||||
if len(p.BuildOptions.PullImageRepository) != 0 {
|
||||
orig := cs.Options.PullImageRepository
|
||||
cs.Options.PullImageRepository = append(orig, p.BuildOptions.PullImageRepository...)
|
||||
defer func() { cs.Options.PullImageRepository = orig }()
|
||||
func (cs *LuetCompiler) inheritSpecBuildOptions(p *compilerspec.LuetCompilationSpec) {
|
||||
Debug(p.GetPackage().HumanReadableString(), "Build options before inherit", p.BuildOptions)
|
||||
|
||||
// Append push repositories from buildpsec buildoptions as pull if found.
|
||||
// This allows to resolve the hash automatically if we pulled the metadata from
|
||||
// repositories that are advertizing their cache.
|
||||
if len(p.BuildOptions.PushImageRepository) != 0 {
|
||||
p.BuildOptions.PullImageRepository = append(p.BuildOptions.PullImageRepository, p.BuildOptions.PushImageRepository)
|
||||
Debug("Inheriting pull repository from PushImageRepository buildoptions", p.BuildOptions.PullImageRepository)
|
||||
}
|
||||
|
||||
if len(cs.Options.PullImageRepository) != 0 {
|
||||
p.BuildOptions.PullImageRepository = append(p.BuildOptions.PullImageRepository, cs.Options.PullImageRepository...)
|
||||
Debug("Inheriting pull repository from PullImageRepository buildoptions", p.BuildOptions.PullImageRepository)
|
||||
}
|
||||
Debug(p.GetPackage().HumanReadableString(), "Build options after inherit", p.BuildOptions)
|
||||
}
|
||||
|
||||
func (cs *LuetCompiler) getSpecHash(pkgs pkg.DefaultPackages, salt string) (string, error) {
|
||||
ht := NewHashTree(cs.Database)
|
||||
overallFp := ""
|
||||
|
||||
for _, p := range pkgs {
|
||||
compileSpec, err := cs.FromPackage(p)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "Error while generating compilespec for "+p.GetName())
|
||||
}
|
||||
packageHashTree, err := ht.Query(cs, compileSpec)
|
||||
if err != nil {
|
||||
return "nil", errors.Wrap(err, "failed querying hashtree")
|
||||
}
|
||||
overallFp = overallFp + packageHashTree.Target.Hash.PackageHash + p.GetFingerPrint()
|
||||
}
|
||||
|
||||
h := md5.New()
|
||||
io.WriteString(h, fmt.Sprintf("%s-%s", overallFp, salt))
|
||||
return fmt.Sprintf("%x", h.Sum(nil)), nil
|
||||
}
|
||||
|
||||
func (cs *LuetCompiler) resolveJoinImages(concurrency int, keepPermissions bool, p *compilerspec.LuetCompilationSpec) error {
|
||||
|
||||
joinTag := ">:loop: join<"
|
||||
if len(p.Join) != 0 {
|
||||
Info(joinTag, "Generating a joint parent image from final packages")
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
|
||||
// First compute a hash and check if image is available. if it is, then directly consume that
|
||||
overallFp, err := cs.getSpecHash(p.Join, "join")
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not generate image hash")
|
||||
}
|
||||
|
||||
Info(joinTag, "Searching existing image with hash ", overallFp)
|
||||
|
||||
image := cs.findImageHash(overallFp, p)
|
||||
if image != "" {
|
||||
Info("Image already found", image)
|
||||
p.SetImage(image)
|
||||
return nil
|
||||
}
|
||||
Info(joinTag, "Image not found. Generating image join with hash ", overallFp)
|
||||
|
||||
// Make sure there is an output path
|
||||
if err := os.MkdirAll(p.GetOutputPath(), os.ModePerm); err != nil {
|
||||
return errors.Wrap(err, "while creating output path")
|
||||
}
|
||||
|
||||
// otherwise, generate it and push it aside
|
||||
joinDir, err := ioutil.TempDir(p.GetOutputPath(), "join")
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not create tempdir for joining images")
|
||||
}
|
||||
defer os.RemoveAll(joinDir) // clean up
|
||||
|
||||
for _, p := range p.Join { //highly dependent on the order
|
||||
Info(joinTag, ":arrow_right_hook:", p.HumanReadableString(), ":leaves:")
|
||||
}
|
||||
|
||||
current := 0
|
||||
for _, c := range p.Join {
|
||||
current++
|
||||
if c != nil && c.Name != "" && c.Version != "" {
|
||||
joinTag2 := fmt.Sprintf("%s %d/%d ⤑ :hammer: build %s", joinTag, current, len(p.Join), c.HumanReadableString())
|
||||
|
||||
Info(joinTag2, "compilation starts")
|
||||
spec, err := cs.FromPackage(c)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "while generating images to join from")
|
||||
}
|
||||
wantsArtifact := true
|
||||
genDepsArtifact := !cs.Options.PackageTargetOnly
|
||||
|
||||
spec.SetOutputPath(p.GetOutputPath())
|
||||
|
||||
artifact, err := cs.compile(concurrency, keepPermissions, &wantsArtifact, &genDepsArtifact, spec)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed building join image")
|
||||
}
|
||||
|
||||
err = artifact.Unpack(joinDir, keepPermissions)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed building join image")
|
||||
}
|
||||
Info(joinTag2, ":white_check_mark: Done")
|
||||
}
|
||||
}
|
||||
|
||||
artifactDir, err := ioutil.TempDir(p.GetOutputPath(), "artifact")
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not create tempdir for final artifact")
|
||||
}
|
||||
defer os.RemoveAll(joinDir) // clean up
|
||||
|
||||
Info(joinTag, ":droplet: generating artifact for source image of", p.GetPackage().HumanReadableString())
|
||||
|
||||
// After unpack, create a new artifact and a new final image from it.
|
||||
// no need to compress, as we are going to toss it away.
|
||||
a := artifact.NewPackageArtifact(filepath.Join(artifactDir, p.GetPackage().GetFingerPrint()+".join.tar"))
|
||||
if err := a.Compress(joinDir, concurrency); err != nil {
|
||||
return errors.Wrap(err, "error met while creating package archive")
|
||||
}
|
||||
|
||||
joinImageName := fmt.Sprintf("%s:%s", cs.Options.PushImageRepository, overallFp)
|
||||
Info(joinTag, ":droplet: generating image from artifact", joinImageName)
|
||||
opts, err := a.GenerateFinalImage(joinImageName, cs.Backend, keepPermissions)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not create final image")
|
||||
}
|
||||
if cs.Options.Push {
|
||||
Info(joinTag, ":droplet: pushing image from artifact", joinImageName)
|
||||
if err = cs.Backend.Push(opts); err != nil {
|
||||
return errors.Wrapf(err, "Could not push image: %s %s", image, opts.DockerFileName)
|
||||
}
|
||||
}
|
||||
Info(joinTag, ":droplet: Consuming image", joinImageName)
|
||||
p.SetImage(joinImageName)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cs *LuetCompiler) resolveMultiStageImages(concurrency int, keepPermissions bool, p *compilerspec.LuetCompilationSpec) error {
|
||||
resolvedCopyFields := []compilerspec.CopyField{}
|
||||
copyTag := ">:droplet: copy<"
|
||||
|
||||
if len(p.Copy) != 0 {
|
||||
Info(copyTag, "Package has multi-stage copy, generating required images")
|
||||
}
|
||||
|
||||
current := 0
|
||||
// TODO: we should run this only if we are going to build the image
|
||||
for _, c := range p.Copy {
|
||||
current++
|
||||
if c.Package != nil && c.Package.Name != "" && c.Package.Version != "" {
|
||||
copyTag2 := fmt.Sprintf("%s %d/%d ⤑ :hammer: build %s", copyTag, current, len(p.Copy), c.Package.HumanReadableString())
|
||||
|
||||
Info(copyTag2, "generating multi-stage images for", c.Package.HumanReadableString())
|
||||
spec, err := cs.FromPackage(c.Package)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "while generating images to copy from")
|
||||
}
|
||||
|
||||
// If we specify --only-target package, we don't want any artifact, otherwise we do
|
||||
genArtifact := !cs.Options.PackageTargetOnly
|
||||
spec.SetOutputPath(p.GetOutputPath())
|
||||
artifact, err := cs.compile(concurrency, keepPermissions, &genArtifact, &genArtifact, spec)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed building multi-stage image")
|
||||
}
|
||||
|
||||
resolvedCopyFields = append(resolvedCopyFields, compilerspec.CopyField{
|
||||
Image: cs.resolveExistingImageHash(artifact.PackageCacheImage, spec),
|
||||
Source: c.Source,
|
||||
Destination: c.Destination,
|
||||
})
|
||||
Info(copyTag2, ":white_check_mark: Done")
|
||||
} else {
|
||||
resolvedCopyFields = append(resolvedCopyFields, c)
|
||||
}
|
||||
}
|
||||
p.Copy = resolvedCopyFields
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cs *LuetCompiler) compile(concurrency int, keepPermissions bool, generateFinalArtifact *bool, generateDependenciesFinalArtifact *bool, p *compilerspec.LuetCompilationSpec) (*artifact.PackageArtifact, error) {
|
||||
Info(":package: Compiling", p.GetPackage().HumanReadableString(), ".... :coffee:")
|
||||
|
||||
//Before multistage : join - same as multistage, but keep artifacts, join them, create a new one and generate a final image.
|
||||
// When the image is there, use it as a source here, in place of GetImage().
|
||||
if err := cs.resolveJoinImages(concurrency, keepPermissions, p); err != nil {
|
||||
return nil, errors.Wrap(err, "while resolving join images")
|
||||
}
|
||||
|
||||
if err := cs.resolveMultiStageImages(concurrency, keepPermissions, p); err != nil {
|
||||
return nil, errors.Wrap(err, "while resolving multi-stage images")
|
||||
}
|
||||
|
||||
Debug(fmt.Sprintf("%s: has images %t, empty package: %t", p.GetPackage().HumanReadableString(), p.HasImageSource(), p.EmptyPackage()))
|
||||
if !p.HasImageSource() && !p.EmptyPackage() {
|
||||
return nil,
|
||||
@@ -742,38 +940,66 @@ 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 {
|
||||
CompileSpec *compilerspec.LuetCompilationSpec
|
||||
Assert solver.PackageAssert
|
||||
CompileSpec *compilerspec.LuetCompilationSpec
|
||||
Assert solver.PackageAssert
|
||||
PackageHashTree *PackageImageHashTree
|
||||
}{
|
||||
CompileSpec: p,
|
||||
Assert: *targetAssertion,
|
||||
CompileSpec: p,
|
||||
Assert: *targetAssertion,
|
||||
PackageHashTree: packageHashTree,
|
||||
})
|
||||
|
||||
// Update compilespec build options - it will be then serialized into the compilation metadata file
|
||||
p.SetBuildOptions(cs.Options)
|
||||
p.BuildOptions.PushImageRepository = cs.Options.PushImageRepository
|
||||
|
||||
// - 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
|
||||
if p.GetImage() != "" {
|
||||
return cs.compileWithImage(p.GetImage(), "", targetAssertion.Hash.PackageHash, concurrency, keepPermissions, cs.Options.KeepImg, p, true)
|
||||
localGenerateArtifact := true
|
||||
if generateFinalArtifact != nil {
|
||||
localGenerateArtifact = *generateFinalArtifact
|
||||
}
|
||||
|
||||
a, err := cs.compileWithImage(p.GetImage(), packageHashTree.BuilderImageHash, targetAssertion.Hash.PackageHash, concurrency, keepPermissions, cs.Options.KeepImg, p, localGenerateArtifact)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "building direct image")
|
||||
}
|
||||
a.SourceAssertion = p.GetSourceAssertion()
|
||||
|
||||
a.PackageCacheImage = targetAssertion.Hash.PackageHash
|
||||
return a, nil
|
||||
}
|
||||
|
||||
// - 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.
|
||||
// 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.
|
||||
|
||||
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
|
||||
var lastHash string
|
||||
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)
|
||||
departifacts := []*artifact.PackageArtifact{} // TODO: Return this somehow
|
||||
depsN := 0
|
||||
currentN := 0
|
||||
|
||||
packageDeps := !cs.Options.PackageTargetOnly
|
||||
if !cs.Options.NoDeps {
|
||||
if generateDependenciesFinalArtifact != nil {
|
||||
packageDeps = *generateDependenciesFinalArtifact
|
||||
}
|
||||
|
||||
buildDeps := !cs.Options.NoDeps
|
||||
buildTarget := !cs.Options.OnlyDeps
|
||||
|
||||
if buildDeps {
|
||||
Info(":deciduous_tree: Build dependencies for " + p.GetPackage().HumanReadableString())
|
||||
for _, assertion := range dependencies { //highly dependent on the order
|
||||
depsN++
|
||||
@@ -788,9 +1014,10 @@ func (cs *LuetCompiler) compile(concurrency int, keepPermissions bool, p *compil
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Error while generating compilespec for "+assertion.Package.GetName())
|
||||
}
|
||||
compileSpec.BuildOptions.PullImageRepository = append(compileSpec.BuildOptions.PullImageRepository, p.BuildOptions.PullImageRepository...)
|
||||
Debug("PullImage repos:", compileSpec.BuildOptions.PullImageRepository)
|
||||
|
||||
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 {
|
||||
CompileSpec *compilerspec.LuetCompilationSpec
|
||||
@@ -800,29 +1027,53 @@ func (cs *LuetCompiler) compile(concurrency int, keepPermissions bool, p *compil
|
||||
Assert: assertion,
|
||||
})
|
||||
|
||||
lastHash = assertion.Hash.PackageHash
|
||||
// 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
|
||||
resolvedBuildImage := cs.resolveExistingImageHash(assertion.Hash.BuildHash)
|
||||
if compileSpec.GetImage() != "" {
|
||||
Debug(pkgTag, " :wrench: Compiling "+compileSpec.GetPackage().HumanReadableString()+" from image")
|
||||
|
||||
a, err := cs.compileWithImage(compileSpec.GetImage(), resolvedBuildImage, 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
|
||||
if err := cs.resolveJoinImages(concurrency, keepPermissions, compileSpec); err != nil {
|
||||
return nil, errors.Wrap(err, "while resolving join images")
|
||||
}
|
||||
|
||||
Debug(pkgTag, " :wrench: Compiling "+compileSpec.GetPackage().HumanReadableString()+" from tree")
|
||||
a, err := cs.compileWithImage(resolvedBuildImage, "", assertion.Hash.PackageHash, concurrency, keepPermissions, cs.Options.KeepImg, compileSpec, packageDeps)
|
||||
if err := cs.resolveMultiStageImages(concurrency, keepPermissions, compileSpec); err != nil {
|
||||
return nil, errors.Wrap(err, "while resolving multi-stage images")
|
||||
}
|
||||
|
||||
buildHash, err := packageHashTree.DependencyBuildImage(assertion.Package)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed looking for dependency in hashtree")
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
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 {
|
||||
return nil, errors.Wrap(err, "Failed compiling "+compileSpec.GetPackage().HumanReadableString())
|
||||
}
|
||||
|
||||
a.PackageCacheImage = assertion.Hash.PackageHash
|
||||
|
||||
Info(pkgTag, ":white_check_mark: Done")
|
||||
|
||||
bus.Manager.Publish(bus.EventPackagePostBuild, struct {
|
||||
CompileSpec *compilerspec.LuetCompilationSpec
|
||||
Artifact *artifact.PackageArtifact
|
||||
@@ -832,24 +1083,24 @@ func (cs *LuetCompiler) compile(concurrency int, keepPermissions bool, p *compil
|
||||
})
|
||||
|
||||
departifacts = append(departifacts, a)
|
||||
Info(pkgTag, ":white_check_mark: Done")
|
||||
}
|
||||
|
||||
} else if len(dependencies) > 0 {
|
||||
lastHash = dependencies[len(dependencies)-1].Hash.PackageHash
|
||||
}
|
||||
|
||||
if !cs.Options.OnlyDeps {
|
||||
resolvedBuildImage := cs.resolveExistingImageHash(lastHash)
|
||||
if buildTarget {
|
||||
localGenerateArtifact := true
|
||||
if generateFinalArtifact != nil {
|
||||
localGenerateArtifact = *generateFinalArtifact
|
||||
}
|
||||
resolvedSourceImage := cs.resolveExistingImageHash(packageHashTree.SourceHash, p)
|
||||
Info(":rocket: All dependencies are satisfied, building package requested by the user", p.GetPackage().HumanReadableString())
|
||||
Info(":package:", p.GetPackage().HumanReadableString(), " Using image: ", resolvedBuildImage)
|
||||
a, err := cs.compileWithImage(resolvedBuildImage, "", targetAssertion.Hash.PackageHash, concurrency, keepPermissions, cs.Options.KeepImg, p, true)
|
||||
Info(":package:", p.GetPackage().HumanReadableString(), " Using image: ", resolvedSourceImage)
|
||||
a, err := cs.compileWithImage(resolvedSourceImage, packageHashTree.BuilderImageHash, targetAssertion.Hash.PackageHash, concurrency, keepPermissions, cs.Options.KeepImg, p, localGenerateArtifact)
|
||||
if err != nil {
|
||||
return a, err
|
||||
}
|
||||
a.Dependencies = departifacts
|
||||
a.SourceAssertion = p.GetSourceAssertion()
|
||||
|
||||
a.PackageCacheImage = targetAssertion.Hash.PackageHash
|
||||
bus.Manager.Publish(bus.EventPackagePostBuild, struct {
|
||||
CompileSpec *compilerspec.LuetCompilationSpec
|
||||
Artifact *artifact.PackageArtifact
|
||||
@@ -866,18 +1117,11 @@ func (cs *LuetCompiler) compile(concurrency int, keepPermissions bool, p *compil
|
||||
|
||||
type templatedata map[string]interface{}
|
||||
|
||||
func (cs *LuetCompiler) templatePackage(vals []map[string]interface{}, pack pkg.Package) ([]byte, error) {
|
||||
func (cs *LuetCompiler) templatePackage(vals []map[string]interface{}, pack pkg.Package, dst templatedata) ([]byte, error) {
|
||||
|
||||
var dataresult []byte
|
||||
val := pack.Rel(DefinitionFile)
|
||||
|
||||
// Update processed build values
|
||||
dst, err := helpers.UnMarshalValues(cs.Options.BuildValuesFile)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "unmarshalling values")
|
||||
}
|
||||
cs.Options.BuildValues = append(vals, (map[string]interface{})(dst))
|
||||
|
||||
if _, err := os.Stat(pack.Rel(CollectionFile)); err == nil {
|
||||
val = pack.Rel(CollectionFile)
|
||||
|
||||
@@ -956,7 +1200,7 @@ func (cs *LuetCompiler) FromPackage(p pkg.Package) (*compilerspec.LuetCompilatio
|
||||
|
||||
opts := options.Compiler{}
|
||||
|
||||
artifactMetadataFile := filepath.Join(p.GetTreeDir(), "..", p.GetMetadataFilePath())
|
||||
artifactMetadataFile := filepath.Join(pack.GetTreeDir(), "..", pack.GetMetadataFilePath())
|
||||
Debug("Checking if metadata file is present", artifactMetadataFile)
|
||||
if _, err := os.Stat(artifactMetadataFile); err == nil {
|
||||
f, err := os.Open(artifactMetadataFile)
|
||||
@@ -972,17 +1216,24 @@ func (cs *LuetCompiler) FromPackage(p pkg.Package) (*compilerspec.LuetCompilatio
|
||||
return nil, errors.Wrap(err, "could not decode package from yaml")
|
||||
}
|
||||
|
||||
Debug("Read build options:", art.CompileSpec.BuildOptions)
|
||||
opts = art.CompileSpec.BuildOptions
|
||||
opts.PushImageRepository = ""
|
||||
|
||||
Debug("Read build options:", art.CompileSpec.BuildOptions, "from", artifactMetadataFile)
|
||||
if art.CompileSpec.BuildOptions != nil {
|
||||
opts = *art.CompileSpec.BuildOptions
|
||||
}
|
||||
} else if !os.IsNotExist(err) {
|
||||
Debug("error reading already existing artifact metadata file: ", err.Error())
|
||||
Debug("error reading artifact metadata file: ", err.Error())
|
||||
} else if os.IsNotExist(err) {
|
||||
Debug("metadata file not present, skipping", artifactMetadataFile)
|
||||
}
|
||||
|
||||
bytes, err := cs.templatePackage(opts.BuildValues, pack)
|
||||
// Update processed build values
|
||||
dst, err := helpers.UnMarshalValues(cs.Options.BuildValuesFile)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "unmarshalling values")
|
||||
}
|
||||
opts.BuildValues = append(opts.BuildValues, (map[string]interface{})(dst))
|
||||
|
||||
bytes, err := cs.templatePackage(opts.BuildValues, pack, templatedata(dst))
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "while rendering package template")
|
||||
}
|
||||
@@ -991,7 +1242,9 @@ func (cs *LuetCompiler) FromPackage(p pkg.Package) (*compilerspec.LuetCompilatio
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
newSpec.BuildOptions = opts
|
||||
newSpec.BuildOptions = &opts
|
||||
|
||||
cs.inheritSpecBuildOptions(newSpec)
|
||||
|
||||
return newSpec, err
|
||||
}
|
||||
|
@@ -75,6 +75,68 @@ var _ = Describe("Compiler", func() {
|
||||
})
|
||||
})
|
||||
|
||||
Context("Copy and Join", func() {
|
||||
It("Compiles it correctly with Copy", func() {
|
||||
generalRecipe := tree.NewCompilerRecipe(pkg.NewInMemoryDatabase(false))
|
||||
|
||||
err := generalRecipe.Load("../../tests/fixtures/copy")
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(len(generalRecipe.GetDatabase().GetPackages())).To(Equal(3))
|
||||
|
||||
compiler := NewLuetCompiler(sd.NewSimpleDockerBackend(), generalRecipe.GetDatabase(), options.Concurrency(2))
|
||||
|
||||
spec, err := compiler.FromPackage(&pkg.DefaultPackage{Name: "c", Category: "test", Version: "1.2"})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(spec.GetPackage().GetPath()).ToNot(Equal(""))
|
||||
|
||||
tmpdir, err := ioutil.TempDir("", "tree")
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
defer os.RemoveAll(tmpdir) // clean up
|
||||
|
||||
spec.SetOutputPath(tmpdir)
|
||||
|
||||
artifact, err := compiler.Compile(false, spec)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(helpers.Exists(artifact.Path)).To(BeTrue())
|
||||
Expect(helpers.Untar(artifact.Path, tmpdir, false)).ToNot(HaveOccurred())
|
||||
|
||||
Expect(helpers.Exists(spec.Rel("result"))).To(BeTrue())
|
||||
Expect(helpers.Exists(spec.Rel("bina/busybox"))).To(BeTrue())
|
||||
})
|
||||
|
||||
It("Compiles it correctly with Join", func() {
|
||||
generalRecipe := tree.NewCompilerRecipe(pkg.NewInMemoryDatabase(false))
|
||||
|
||||
err := generalRecipe.Load("../../tests/fixtures/join")
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(len(generalRecipe.GetDatabase().GetPackages())).To(Equal(3))
|
||||
|
||||
compiler := NewLuetCompiler(sd.NewSimpleDockerBackend(), generalRecipe.GetDatabase(), options.Concurrency(2))
|
||||
|
||||
spec, err := compiler.FromPackage(&pkg.DefaultPackage{Name: "c", Category: "test", Version: "1.2"})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(spec.GetPackage().GetPath()).ToNot(Equal(""))
|
||||
|
||||
tmpdir, err := ioutil.TempDir("", "tree")
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
defer os.RemoveAll(tmpdir) // clean up
|
||||
|
||||
spec.SetOutputPath(tmpdir)
|
||||
|
||||
artifact, err := compiler.Compile(false, spec)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(helpers.Exists(artifact.Path)).To(BeTrue())
|
||||
Expect(helpers.Untar(artifact.Path, tmpdir, false)).ToNot(HaveOccurred())
|
||||
Expect(helpers.Exists(spec.Rel("newc"))).To(BeTrue())
|
||||
Expect(helpers.Exists(spec.Rel("test4"))).To(BeTrue())
|
||||
Expect(helpers.Exists(spec.Rel("test3"))).To(BeTrue())
|
||||
})
|
||||
})
|
||||
|
||||
Context("Simple package build definition", func() {
|
||||
It("Compiles it in parallel", func() {
|
||||
generalRecipe := tree.NewCompilerRecipe(pkg.NewInMemoryDatabase(false))
|
||||
|
161
pkg/compiler/imagehashtree.go
Normal file
161
pkg/compiler/imagehashtree.go
Normal file
@@ -0,0 +1,161 @@
|
||||
// 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"
|
||||
)
|
||||
|
||||
// ImageHashTree is holding the Database
|
||||
// and the options to resolve PackageImageHashTrees
|
||||
// for a given specfile
|
||||
// It is responsible of returning a concrete result
|
||||
// which identifies a Package in a HashTree
|
||||
type ImageHashTree struct {
|
||||
Database pkg.PackageDatabase
|
||||
SolverOptions config.LuetSolverOptions
|
||||
}
|
||||
|
||||
// PackageImageHashTree represent the Package into a given image hash tree
|
||||
// The hash tree is constructed by a set of images representing
|
||||
// the package during its build stage. A Hash is assigned to each image
|
||||
// from the package fingerprint, plus the SAT solver assertion result (which is hashed as well)
|
||||
// and the specfile signatures. This guarantees that each image of the build stage
|
||||
// is unique and can be identified later on.
|
||||
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
|
||||
}
|
||||
|
||||
func (ht *PackageImageHashTree) String() string {
|
||||
return fmt.Sprintf(
|
||||
"Target buildhash: %s\nTarget packagehash: %s\nBuilder Imagehash: %s\nSource Imagehash: %s\n",
|
||||
ht.Target.Hash.BuildHash,
|
||||
ht.Target.Hash.PackageHash,
|
||||
ht.BuilderImageHash,
|
||||
ht.SourceHash,
|
||||
)
|
||||
}
|
||||
|
||||
// Query takes a compiler and a compilation spec and returns a PackageImageHashTree tied to it.
|
||||
// PackageImageHashTree contains all the informations to resolve the spec build images in order to
|
||||
// reproducibly re-build images from packages
|
||||
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())
|
||||
}
|
||||
|
||||
// Get hash from buildpsecs
|
||||
salts := map[string]string{}
|
||||
for _, assertion := range dependencies { //highly dependent on the order
|
||||
if assertion.Value {
|
||||
spec, err := cs.FromPackage(assertion.Package)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "while computing hash buildspecs")
|
||||
}
|
||||
hash, err := spec.Hash()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed computing hash")
|
||||
}
|
||||
salts[assertion.Package.GetFingerPrint()] = hash
|
||||
}
|
||||
}
|
||||
|
||||
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.SaltedHashFrom(assertion.Package, salts),
|
||||
PackageHash: nthsolution.SaltedAssertionHash(salts),
|
||||
}
|
||||
assertion.Package.SetTreeDir(p.Package.GetTreeDir())
|
||||
assertions = append(assertions, assertion)
|
||||
}
|
||||
}
|
||||
|
||||
return assertions, nil
|
||||
}
|
145
pkg/compiler/imagehashtree_test.go
Normal file
145
pkg/compiler/imagehashtree_test.go
Normal file
@@ -0,0 +1,145 @@
|
||||
// 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("4db24406e8db30a3310a1cf8c4d4e19597745e6d41b189dc51a73ac4a50cc9e6"))
|
||||
Expect(packageHash.Target.Hash.PackageHash).To(Equal("4c867c9bab6c71d9420df75806e7a2f171dbc08487852ab4e2487bab04066cf2"))
|
||||
Expect(packageHash.BuilderImageHash).To(Equal("builder-e6f9c5552a67c463215b0a9e4f7c7fc8"))
|
||||
})
|
||||
})
|
||||
|
||||
expectedPackageHash := "15811d83d0f8360318c54d91dcae3714f8efb39bf872572294834880f00ee7a8"
|
||||
|
||||
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(expectedPackageHash))
|
||||
Expect(packageHash.SourceHash).To(Equal(expectedPackageHash))
|
||||
Expect(packageHash.BuilderImageHash).To(Equal("builder-3d739cab442aec15a6da238481df73c5"))
|
||||
|
||||
//Expect(packageHash.Target.Hash.BuildHash).To(Equal("79d7107d13d578b362e6a7bf10ec850efce26316405b8d732ce8f9e004d64281"))
|
||||
Expect(packageHash.Target.Hash.PackageHash).To(Equal("99c4ebb4bc4754985fcc28677badf90f525aa231b1db0fe75659f11b86dc20e8"))
|
||||
a := &pkg.DefaultPackage{Name: "a", Category: "test", Version: "1.1"}
|
||||
hash, err := packageHash.DependencyBuildImage(a)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(hash).To(Equal("f48f28ab62f1379a4247ec763681ccede68ea1e5c25aae8fb72459c0b2f8742e"))
|
||||
|
||||
assertionA := packageHash.Dependencies.Search(a.GetFingerPrint())
|
||||
Expect(assertionA.Hash.PackageHash).To(Equal(expectedPackageHash))
|
||||
b := &pkg.DefaultPackage{Name: "b", Category: "test", Version: "1.0"}
|
||||
assertionB := packageHash.Dependencies.Search(b.GetFingerPrint())
|
||||
Expect(assertionB.Hash.PackageHash).To(Equal("f48f28ab62f1379a4247ec763681ccede68ea1e5c25aae8fb72459c0b2f8742e"))
|
||||
hashB, err := packageHash.DependencyBuildImage(b)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(hashB).To(Equal("2668e418eab6861404834ad617713e39b8e58f68016a1fbfcc9384efdd037376"))
|
||||
})
|
||||
})
|
||||
|
||||
Context("complex package definition, with small change in build.yaml", func() {
|
||||
BeforeEach(func() {
|
||||
generalRecipe = tree.NewCompilerRecipe(pkg.NewInMemoryDatabase(false))
|
||||
|
||||
//Definition of A here is slightly changed in the steps build.yaml file (1 character only)
|
||||
err := generalRecipe.Load("../../tests/fixtures/upgrade_old_repo_revision_content_changed")
|
||||
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).ToNot(Equal(expectedPackageHash))
|
||||
sourceHash := "1d91b13d0246fa000085a1071c63397d21546300b17f69493f22315a64b717d4"
|
||||
Expect(packageHash.Dependencies[len(packageHash.Dependencies)-1].Hash.PackageHash).To(Equal(sourceHash))
|
||||
Expect(packageHash.SourceHash).To(Equal(sourceHash))
|
||||
Expect(packageHash.SourceHash).ToNot(Equal(expectedPackageHash))
|
||||
|
||||
Expect(packageHash.BuilderImageHash).To(Equal("builder-03ee108a7c56b17ee568ace0800dd16d"))
|
||||
|
||||
//Expect(packageHash.Target.Hash.BuildHash).To(Equal("79d7107d13d578b362e6a7bf10ec850efce26316405b8d732ce8f9e004d64281"))
|
||||
Expect(packageHash.Target.Hash.PackageHash).To(Equal("7677da23b2cc866c2d07aa4a58fbf703340f2f78c0efbb1ba9faf8979f250c87"))
|
||||
a := &pkg.DefaultPackage{Name: "a", Category: "test", Version: "1.1"}
|
||||
hash, err := packageHash.DependencyBuildImage(a)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(hash).To(Equal("f48f28ab62f1379a4247ec763681ccede68ea1e5c25aae8fb72459c0b2f8742e"))
|
||||
|
||||
assertionA := packageHash.Dependencies.Search(a.GetFingerPrint())
|
||||
|
||||
Expect(assertionA.Hash.PackageHash).To(Equal("1d91b13d0246fa000085a1071c63397d21546300b17f69493f22315a64b717d4"))
|
||||
Expect(assertionA.Hash.PackageHash).ToNot(Equal(expectedPackageHash))
|
||||
|
||||
b := &pkg.DefaultPackage{Name: "b", Category: "test", Version: "1.0"}
|
||||
assertionB := packageHash.Dependencies.Search(b.GetFingerPrint())
|
||||
|
||||
Expect(assertionB.Hash.PackageHash).To(Equal("f48f28ab62f1379a4247ec763681ccede68ea1e5c25aae8fb72459c0b2f8742e"))
|
||||
hashB, err := packageHash.DependencyBuildImage(b)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(hashB).To(Equal("2668e418eab6861404834ad617713e39b8e58f68016a1fbfcc9384efdd037376"))
|
||||
})
|
||||
})
|
||||
|
||||
})
|
@@ -19,6 +19,8 @@ import (
|
||||
"archive/tar"
|
||||
"bufio"
|
||||
"bytes"
|
||||
"crypto/sha1"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
@@ -27,7 +29,6 @@ import (
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
|
||||
system "github.com/docker/docker/pkg/system"
|
||||
zstd "github.com/klauspost/compress/zstd"
|
||||
gzip "github.com/klauspost/pgzip"
|
||||
|
||||
@@ -54,12 +55,13 @@ import (
|
||||
type PackageArtifact struct {
|
||||
Path string `json:"path"`
|
||||
|
||||
Dependencies []*PackageArtifact `json:"dependencies"`
|
||||
CompileSpec *compilerspec.LuetCompilationSpec `json:"compilationspec"`
|
||||
Checksums Checksums `json:"checksums"`
|
||||
SourceAssertion solver.PackagesAssertions `json:"-"`
|
||||
CompressionType compression.Implementation `json:"compressiontype"`
|
||||
Files []string `json:"files"`
|
||||
Dependencies []*PackageArtifact `json:"dependencies"`
|
||||
CompileSpec *compilerspec.LuetCompilationSpec `json:"compilationspec"`
|
||||
Checksums Checksums `json:"checksums"`
|
||||
SourceAssertion solver.PackagesAssertions `json:"-"`
|
||||
CompressionType compression.Implementation `json:"compressiontype"`
|
||||
Files []string `json:"files"`
|
||||
PackageCacheImage string `json:"package_cacheimage"`
|
||||
}
|
||||
|
||||
func (p *PackageArtifact) ShallowCopy() *PackageArtifact {
|
||||
@@ -317,7 +319,6 @@ func (a *PackageArtifact) Compress(src string, concurrency int) error {
|
||||
default:
|
||||
return helpers.Tar(src, a.getCompressedName())
|
||||
}
|
||||
return errors.New("Compression type must be supplied")
|
||||
}
|
||||
|
||||
func (a *PackageArtifact) getCompressedName() string {
|
||||
@@ -340,6 +341,28 @@ func (a *PackageArtifact) GetUncompressedName() string {
|
||||
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) {
|
||||
// If the destination path already exists I rename target file name with postfix.
|
||||
var destPath string
|
||||
@@ -351,6 +374,7 @@ func tarModifierWrapperFunc(dst, path string, header *tar.Header, content io.Rea
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
tarHash := hashContent(buffer.Bytes())
|
||||
|
||||
// If file is not present on archive but is defined on mods
|
||||
// I receive the callback. Prevent nil exception.
|
||||
@@ -363,8 +387,21 @@ func tarModifierWrapperFunc(dst, path string, header *tar.Header, content io.Rea
|
||||
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
|
||||
if helpers.Exists(destPath) {
|
||||
if helpers.Exists(destPath) && differs {
|
||||
for i := 1; i < 1000; i++ {
|
||||
name := filepath.Join(filepath.Join(filepath.Dir(path),
|
||||
fmt.Sprintf("._cfg%04d_%s", i, filepath.Base(path))))
|
||||
@@ -584,47 +621,16 @@ type CopyJob struct {
|
||||
Artifact string
|
||||
}
|
||||
|
||||
func copyXattr(srcPath, dstPath, attr string) error {
|
||||
data, err := system.Lgetxattr(srcPath, attr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if data != nil {
|
||||
if err := system.Lsetxattr(dstPath, attr, data, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func doCopyXattrs(srcPath, dstPath string) error {
|
||||
if err := copyXattr(srcPath, dstPath, "security.capability"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return copyXattr(srcPath, dstPath, "trusted.overlay.opaque")
|
||||
}
|
||||
|
||||
func worker(i int, wg *sync.WaitGroup, s <-chan CopyJob) {
|
||||
defer wg.Done()
|
||||
|
||||
for job := range s {
|
||||
//Info("#"+strconv.Itoa(i), "copying", job.Src, "to", job.Dst)
|
||||
// if dir, err := helpers.IsDirectory(job.Src); err == nil && dir {
|
||||
// err = helpers.CopyDir(job.Src, job.Dst)
|
||||
// if err != nil {
|
||||
// Warning("Error copying dir", job, err)
|
||||
// }
|
||||
// continue
|
||||
// }
|
||||
|
||||
_, err := os.Lstat(job.Dst)
|
||||
if err != nil {
|
||||
Debug("Copying ", job.Src)
|
||||
if err := helpers.CopyFile(job.Src, job.Dst); err != nil {
|
||||
if err := helpers.DeepCopyFile(job.Src, job.Dst); err != nil {
|
||||
Warning("Error copying", job, err)
|
||||
}
|
||||
doCopyXattrs(job.Src, job.Dst)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
32
pkg/compiler/types/artifact/artifact_suite_test.go
Normal file
32
pkg/compiler/types/artifact/artifact_suite_test.go
Normal file
@@ -0,0 +1,32 @@
|
||||
// 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 artifact_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "github.com/mudler/luet/cmd"
|
||||
config "github.com/mudler/luet/pkg/config"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
func TestArtifact(t *testing.T) {
|
||||
RegisterFailHandler(Fail)
|
||||
LoadConfig(config.LuetCfg)
|
||||
RunSpecs(t, "Artifact Suite")
|
||||
}
|
@@ -41,7 +41,7 @@ var _ = Describe("Artifact", func() {
|
||||
|
||||
generalRecipe := tree.NewGeneralRecipe(pkg.NewInMemoryDatabase(false))
|
||||
|
||||
err := generalRecipe.Load("../../tests/fixtures/buildtree")
|
||||
err := generalRecipe.Load("../../../../tests/fixtures/buildtree")
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(len(generalRecipe.GetDatabase().GetPackages())).To(Equal(1))
|
||||
|
@@ -40,13 +40,13 @@ var _ = Describe("Checksum", func() {
|
||||
Expect(len(definitionsum)).To(Equal(0))
|
||||
Expect(len(definitionsum2)).To(Equal(0))
|
||||
|
||||
err = buildsum.Generate(NewPackageArtifact("../../tests/fixtures/layers/alpine/build.yaml"))
|
||||
err = buildsum.Generate(NewPackageArtifact("../../../../tests/fixtures/layers/alpine/build.yaml"))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
err = definitionsum.Generate(NewPackageArtifact("../../tests/fixtures/layers/alpine/definition.yaml"))
|
||||
err = definitionsum.Generate(NewPackageArtifact("../../../../tests/fixtures/layers/alpine/definition.yaml"))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
err = definitionsum2.Generate(NewPackageArtifact("../../tests/fixtures/layers/alpine/definition.yaml"))
|
||||
err = definitionsum2.Generate(NewPackageArtifact("../../../../tests/fixtures/layers/alpine/definition.yaml"))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(len(buildsum)).To(Equal(1))
|
||||
|
@@ -38,6 +38,7 @@ type Compiler struct {
|
||||
BuildValues []map[string]interface{}
|
||||
|
||||
PackageTargetOnly bool
|
||||
Rebuild bool
|
||||
|
||||
BackendArgs []string
|
||||
|
||||
@@ -131,6 +132,13 @@ func KeepImg(b bool) func(cfg *Compiler) error {
|
||||
}
|
||||
}
|
||||
|
||||
func Rebuild(b bool) func(cfg *Compiler) error {
|
||||
return func(cfg *Compiler) error {
|
||||
cfg.Rebuild = b
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func PushImages(b bool) func(cfg *Compiler) error {
|
||||
return func(cfg *Compiler) error {
|
||||
cfg.Push = b
|
||||
|
@@ -16,9 +16,11 @@
|
||||
package compilerspec
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/mitchellh/hashstructure/v2"
|
||||
options "github.com/mudler/luet/pkg/compiler/types/options"
|
||||
|
||||
pkg "github.com/mudler/luet/pkg/package"
|
||||
@@ -85,6 +87,13 @@ func (specs *LuetCompilationspecs) Unique() *LuetCompilationspecs {
|
||||
return &newSpecs
|
||||
}
|
||||
|
||||
type CopyField struct {
|
||||
Package *pkg.DefaultPackage `json:"package"`
|
||||
Image string `json:"image"`
|
||||
Source string `json:"source"`
|
||||
Destination string `json:"destination"`
|
||||
}
|
||||
|
||||
type LuetCompilationSpec struct {
|
||||
Steps []string `json:"steps"` // Are run inside a container and the result layer diff is saved
|
||||
Env []string `json:"env"`
|
||||
@@ -102,7 +111,44 @@ type LuetCompilationSpec struct {
|
||||
Includes []string `json:"includes"`
|
||||
Excludes []string `json:"excludes"`
|
||||
|
||||
BuildOptions options.Compiler `json:"build_options"`
|
||||
BuildOptions *options.Compiler `json:"build_options"`
|
||||
|
||||
Copy []CopyField `json:"copy"`
|
||||
|
||||
Join pkg.DefaultPackages `json:"join"`
|
||||
}
|
||||
|
||||
// Signature is a portion of the spec that yields a signature for the hash
|
||||
type Signature struct {
|
||||
Image string
|
||||
Steps []string
|
||||
PackageDir string
|
||||
Prelude []string
|
||||
Seed string
|
||||
Env []string
|
||||
Retrieve []string
|
||||
Unpack bool
|
||||
Includes []string
|
||||
Excludes []string
|
||||
Copy []CopyField
|
||||
Join pkg.DefaultPackages
|
||||
}
|
||||
|
||||
func (cs *LuetCompilationSpec) signature() Signature {
|
||||
return Signature{
|
||||
Image: cs.Image,
|
||||
Steps: cs.Steps,
|
||||
PackageDir: cs.PackageDir,
|
||||
Prelude: cs.Prelude,
|
||||
Seed: cs.Seed,
|
||||
Env: cs.Env,
|
||||
Retrieve: cs.Retrieve,
|
||||
Unpack: cs.Unpack,
|
||||
Includes: cs.Includes,
|
||||
Excludes: cs.Excludes,
|
||||
Copy: cs.Copy,
|
||||
Join: cs.Join,
|
||||
}
|
||||
}
|
||||
|
||||
func NewLuetCompilationSpec(b []byte, p pkg.Package) (*LuetCompilationSpec, error) {
|
||||
@@ -119,7 +165,7 @@ func (cs *LuetCompilationSpec) GetSourceAssertion() solver.PackagesAssertions {
|
||||
}
|
||||
|
||||
func (cs *LuetCompilationSpec) SetBuildOptions(b options.Compiler) {
|
||||
cs.BuildOptions = b
|
||||
cs.BuildOptions = &b
|
||||
}
|
||||
|
||||
func (cs *LuetCompilationSpec) SetSourceAssertion(as solver.PackagesAssertions) {
|
||||
@@ -213,7 +259,14 @@ func (cs *LuetCompilationSpec) UnpackedPackage() bool {
|
||||
// a compilation spec has an image source when it depends on other packages or have a source image
|
||||
// explictly supplied
|
||||
func (cs *LuetCompilationSpec) HasImageSource() bool {
|
||||
return (cs.Package != nil && len(cs.GetPackage().GetRequires()) != 0) || cs.GetImage() != ""
|
||||
return (cs.Package != nil && len(cs.GetPackage().GetRequires()) != 0) || cs.GetImage() != "" || len(cs.Join) != 0
|
||||
}
|
||||
|
||||
func (cs *LuetCompilationSpec) Hash() (string, error) {
|
||||
// build a signature, we want to be part of the hash only the fields that are relevant for build purposes
|
||||
signature := cs.signature()
|
||||
h, err := hashstructure.Hash(signature, hashstructure.FormatV2, nil)
|
||||
return fmt.Sprint(h), err
|
||||
}
|
||||
|
||||
func (cs *LuetCompilationSpec) CopyRetrieves(dest string) error {
|
||||
@@ -256,6 +309,13 @@ ADD ` + s + ` /luetbuild/`
|
||||
}
|
||||
}
|
||||
|
||||
for _, c := range cs.Copy {
|
||||
if c.Image != "" {
|
||||
copyLine := fmt.Sprintf("\nCOPY --from=%s %s %s\n", c.Image, c.Source, c.Destination)
|
||||
spec = spec + copyLine
|
||||
}
|
||||
}
|
||||
|
||||
for _, s := range cs.Env {
|
||||
spec = spec + `
|
||||
ENV ` + s
|
||||
|
32
pkg/compiler/types/spec/spec_suite_test.go
Normal file
32
pkg/compiler/types/spec/spec_suite_test.go
Normal file
@@ -0,0 +1,32 @@
|
||||
// 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 compilerspec_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "github.com/mudler/luet/cmd"
|
||||
config "github.com/mudler/luet/pkg/config"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
func TestSpec(t *testing.T) {
|
||||
RegisterFailHandler(Fail)
|
||||
LoadConfig(config.LuetCfg)
|
||||
RunSpecs(t, "Spec Suite")
|
||||
}
|
@@ -20,6 +20,7 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
options "github.com/mudler/luet/pkg/compiler/types/options"
|
||||
compilerspec "github.com/mudler/luet/pkg/compiler/types/spec"
|
||||
|
||||
. "github.com/mudler/luet/pkg/compiler"
|
||||
@@ -74,11 +75,67 @@ var _ = Describe("Spec", func() {
|
||||
})
|
||||
})
|
||||
|
||||
Context("Image hashing", func() {
|
||||
It("is stable", func() {
|
||||
spec1 := &compilerspec.LuetCompilationSpec{
|
||||
Image: "foo",
|
||||
BuildOptions: &options.Compiler{BuildValues: []map[string]interface{}{{"foo": "bar", "baz": true}}},
|
||||
|
||||
Package: &pkg.DefaultPackage{
|
||||
Name: "foo",
|
||||
Category: "Bar",
|
||||
Labels: map[string]string{
|
||||
"foo": "bar",
|
||||
"baz": "foo",
|
||||
},
|
||||
},
|
||||
}
|
||||
spec2 := &compilerspec.LuetCompilationSpec{
|
||||
Image: "foo",
|
||||
BuildOptions: &options.Compiler{BuildValues: []map[string]interface{}{{"foo": "bar", "baz": true}}},
|
||||
Package: &pkg.DefaultPackage{
|
||||
Name: "foo",
|
||||
Category: "Bar",
|
||||
Labels: map[string]string{
|
||||
"foo": "bar",
|
||||
"baz": "foo",
|
||||
},
|
||||
},
|
||||
}
|
||||
spec3 := &compilerspec.LuetCompilationSpec{
|
||||
Image: "foo",
|
||||
Steps: []string{"foo"},
|
||||
Package: &pkg.DefaultPackage{
|
||||
Name: "foo",
|
||||
Category: "Bar",
|
||||
Labels: map[string]string{
|
||||
"foo": "bar",
|
||||
"baz": "foo",
|
||||
},
|
||||
},
|
||||
}
|
||||
hash, err := spec1.Hash()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
hash2, err := spec2.Hash()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
hash3, err := spec3.Hash()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(hash).To(Equal(hash2))
|
||||
hashagain, err := spec2.Hash()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(hash).ToNot(Equal(hash3))
|
||||
Expect(hash).To(Equal(hashagain))
|
||||
})
|
||||
})
|
||||
|
||||
Context("Simple package build definition", func() {
|
||||
It("Loads it correctly", func() {
|
||||
generalRecipe := tree.NewGeneralRecipe(pkg.NewInMemoryDatabase(false))
|
||||
|
||||
err := generalRecipe.Load("../../tests/fixtures/buildtree")
|
||||
err := generalRecipe.Load("../../../../tests/fixtures/buildtree")
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(len(generalRecipe.GetDatabase().GetPackages())).To(Equal(1))
|
||||
@@ -130,7 +187,7 @@ RUN echo bar > /test2`))
|
||||
It("Renders retrieve and env fields", func() {
|
||||
generalRecipe := tree.NewGeneralRecipe(pkg.NewInMemoryDatabase(false))
|
||||
|
||||
err := generalRecipe.Load("../../tests/fixtures/retrieve")
|
||||
err := generalRecipe.Load("../../../../tests/fixtures/retrieve")
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(len(generalRecipe.GetDatabase().GetPackages())).To(Equal(1))
|
||||
|
@@ -90,8 +90,7 @@ func UntarProtect(src, dst string, sameOwner bool, protectedFiles []string, modi
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
opts := &archive.TarOptions{
|
||||
|
@@ -19,6 +19,7 @@ import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/cli/cli/trust"
|
||||
"github.com/docker/distribution/reference"
|
||||
@@ -122,3 +123,7 @@ func DownloadAndExtractDockerImage(temp, image, dest string, auth *types.AuthCon
|
||||
err = c.Unpack(image, dest)
|
||||
return listedImage, err
|
||||
}
|
||||
|
||||
func StripInvalidStringsFromImage(s string) string {
|
||||
return strings.ReplaceAll(s, "+", "-")
|
||||
}
|
||||
|
30
pkg/helpers/docker_test.go
Normal file
30
pkg/helpers/docker_test.go
Normal file
@@ -0,0 +1,30 @@
|
||||
// Copyright © 2021 Ettore Di Giacinto <mudler@sabayon.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 helpers_test
|
||||
|
||||
import (
|
||||
. "github.com/mudler/luet/pkg/helpers"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("StripInvalidStringsFromImage", func() {
|
||||
Context("Image names", func() {
|
||||
It("strips invalid chars", func() {
|
||||
Expect(StripInvalidStringsFromImage("foo+bar")).To(Equal("foo-bar"))
|
||||
})
|
||||
})
|
||||
})
|
@@ -27,6 +27,7 @@ import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/pkg/system"
|
||||
"github.com/google/renameio"
|
||||
copy "github.com/otiai10/copy"
|
||||
"github.com/pkg/errors"
|
||||
@@ -167,9 +168,27 @@ func Read(file string) (string, error) {
|
||||
return string(dat), nil
|
||||
}
|
||||
|
||||
func EnsureDirPerm(src, dst string) {
|
||||
if info, err := os.Lstat(filepath.Dir(src)); err == nil {
|
||||
if _, err := os.Lstat(filepath.Dir(dst)); os.IsNotExist(err) {
|
||||
err := os.MkdirAll(filepath.Dir(dst), info.Mode().Perm())
|
||||
if err != nil {
|
||||
fmt.Println("warning: failed creating", filepath.Dir(dst), err.Error())
|
||||
}
|
||||
if stat, ok := info.Sys().(*syscall.Stat_t); ok {
|
||||
if err := os.Lchown(filepath.Dir(dst), int(stat.Uid), int(stat.Gid)); err != nil {
|
||||
fmt.Println("warning: failed chowning", filepath.Dir(dst), err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
EnsureDir(dst)
|
||||
}
|
||||
}
|
||||
|
||||
func EnsureDir(fileName string) error {
|
||||
dirName := filepath.Dir(fileName)
|
||||
if _, serr := os.Stat(dirName); serr != nil {
|
||||
if _, serr := os.Stat(dirName); os.IsNotExist(serr) {
|
||||
merr := os.MkdirAll(dirName, os.ModePerm) // FIXME: It should preserve permissions from src to dst instead
|
||||
if merr != nil {
|
||||
return merr
|
||||
@@ -178,12 +197,39 @@ func EnsureDir(fileName string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// CopyFile copies the contents of the file named src to the file named
|
||||
func CopyFile(src, dst string) (err error) {
|
||||
return copy.Copy(src, dst, copy.Options{
|
||||
Sync: true,
|
||||
OnSymlink: func(string) copy.SymlinkAction { return copy.Shallow }})
|
||||
}
|
||||
|
||||
func copyXattr(srcPath, dstPath, attr string) error {
|
||||
data, err := system.Lgetxattr(srcPath, attr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if data != nil {
|
||||
if err := system.Lsetxattr(dstPath, attr, data, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func doCopyXattrs(srcPath, dstPath string) error {
|
||||
if err := copyXattr(srcPath, dstPath, "security.capability"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return copyXattr(srcPath, dstPath, "trusted.overlay.opaque")
|
||||
}
|
||||
|
||||
// DeepCopyFile copies the contents of the file named src to the file named
|
||||
// by dst. The file will be created if it does not already exist. If the
|
||||
// destination file exists, all it's contents will be replaced by the contents
|
||||
// of the source file. The file mode will be copied from the source and
|
||||
// the copied data is synced/flushed to stable storage.
|
||||
func CopyFile(src, dst string) (err error) {
|
||||
func DeepCopyFile(src, dst string) (err error) {
|
||||
// Workaround for https://github.com/otiai10/copy/issues/47
|
||||
fi, err := os.Lstat(src)
|
||||
if err != nil {
|
||||
@@ -193,7 +239,7 @@ func CopyFile(src, dst string) (err error) {
|
||||
fm := fi.Mode()
|
||||
switch {
|
||||
case fm&os.ModeNamedPipe != 0:
|
||||
EnsureDir(dst)
|
||||
EnsureDirPerm(src, dst)
|
||||
if err := syscall.Mkfifo(dst, uint32(fi.Mode())); err != nil {
|
||||
return errors.Wrap(err, "failed creating pipe")
|
||||
}
|
||||
@@ -205,6 +251,9 @@ func CopyFile(src, dst string) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
//filepath.Dir(src)
|
||||
EnsureDirPerm(src, dst)
|
||||
|
||||
err = copy.Copy(src, dst, copy.Options{
|
||||
Sync: true,
|
||||
OnSymlink: func(string) copy.SymlinkAction { return copy.Shallow }})
|
||||
@@ -216,7 +265,8 @@ func CopyFile(src, dst string) (err error) {
|
||||
fmt.Println("warning: failed chowning", dst, err.Error())
|
||||
}
|
||||
}
|
||||
return err
|
||||
|
||||
return doCopyXattrs(src, dst)
|
||||
}
|
||||
|
||||
func IsDirectory(path string) (bool, error) {
|
||||
|
@@ -17,9 +17,18 @@
|
||||
package helpers
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
func ReverseAny(s interface{}) {
|
||||
n := reflect.ValueOf(s).Len()
|
||||
swap := reflect.Swapper(s)
|
||||
for i, j := 0, n-1; i < j; i, j = i+1, j-1 {
|
||||
swap(i, j)
|
||||
}
|
||||
}
|
||||
|
||||
func MapMatchRegex(m *map[string]string, r *regexp.Regexp) bool {
|
||||
ans := false
|
||||
|
||||
|
@@ -29,6 +29,7 @@ import (
|
||||
"github.com/mudler/luet/pkg/compiler/types/artifact"
|
||||
"github.com/mudler/luet/pkg/config"
|
||||
"github.com/mudler/luet/pkg/helpers"
|
||||
"github.com/mudler/luet/pkg/helpers/imgworker"
|
||||
. "github.com/mudler/luet/pkg/logger"
|
||||
)
|
||||
|
||||
@@ -138,8 +139,8 @@ func (c *DockerClient) DownloadArtifact(a *artifact.PackageArtifact) (*artifact.
|
||||
func (c *DockerClient) DownloadFile(name string) (string, error) {
|
||||
var file *os.File = nil
|
||||
var err error
|
||||
var temp string
|
||||
|
||||
var temp, contentstore string
|
||||
var info *imgworker.ListedImage
|
||||
// Files should be in URI/repository:<file>
|
||||
ok := false
|
||||
|
||||
@@ -149,22 +150,21 @@ func (c *DockerClient) DownloadFile(name string) (string, error) {
|
||||
}
|
||||
|
||||
for _, uri := range c.RepoData.Urls {
|
||||
|
||||
file, err = config.LuetCfg.GetSystem().TempFile("DockerClient")
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
contentstore, err := config.LuetCfg.GetSystem().TempDir("contentstore")
|
||||
contentstore, err = config.LuetCfg.GetSystem().TempDir("contentstore")
|
||||
if err != nil {
|
||||
Warning("Cannot create contentstore", err.Error())
|
||||
continue
|
||||
}
|
||||
|
||||
imageName := fmt.Sprintf("%s:%s", uri, name)
|
||||
imageName := fmt.Sprintf("%s:%s", uri, helpers.StripInvalidStringsFromImage(name))
|
||||
Info("Downloading", imageName)
|
||||
|
||||
info, err := helpers.DownloadAndExtractDockerImage(contentstore, imageName, temp, c.auth, c.RepoData.Verify)
|
||||
info, err = helpers.DownloadAndExtractDockerImage(contentstore, imageName, temp, c.auth, c.RepoData.Verify)
|
||||
if err != nil {
|
||||
Warning(fmt.Sprintf(errImageDownloadMsg, imageName, err.Error()))
|
||||
continue
|
||||
@@ -175,7 +175,6 @@ func (c *DockerClient) DownloadFile(name string) (string, error) {
|
||||
|
||||
Debug("\nCopying file ", filepath.Join(temp, name), "to", file.Name())
|
||||
err = helpers.CopyFile(filepath.Join(temp, name), file.Name())
|
||||
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
@@ -128,6 +128,8 @@ func packsToList(p pkg.Packages) string {
|
||||
for _, pp := range p {
|
||||
packs = append(packs, pp.HumanReadableString())
|
||||
}
|
||||
|
||||
sort.Strings(packs)
|
||||
return strings.Join(packs, " ")
|
||||
}
|
||||
|
||||
@@ -137,6 +139,7 @@ func matchesToList(artefacts map[string]ArtifactMatch) string {
|
||||
for fingerprint, match := range artefacts {
|
||||
packs = append(packs, fmt.Sprintf("%s (%s)", fingerprint, match.Repository.GetName()))
|
||||
}
|
||||
sort.Strings(packs)
|
||||
return strings.Join(packs, " ")
|
||||
}
|
||||
|
||||
@@ -153,39 +156,7 @@ func (l *LuetInstaller) Upgrade(s *System) error {
|
||||
Info(":memo: note: will consider new build revisions while upgrading")
|
||||
}
|
||||
|
||||
Spinner(32)
|
||||
uninstall, toInstall, err := l.computeUpgrade(syncedRepos, s)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed computing upgrade")
|
||||
}
|
||||
SpinnerStop()
|
||||
|
||||
if len(uninstall) > 0 {
|
||||
Info(":recycle: Packages that are going to be removed from the system:\n ", Yellow(packsToList(uninstall)).BgBlack().String())
|
||||
}
|
||||
|
||||
if len(toInstall) > 0 {
|
||||
Info(":zap:Packages that are going to be installed in the system:\n ", Green(packsToList(toInstall)).BgBlack().String())
|
||||
}
|
||||
|
||||
if len(toInstall) == 0 && len(uninstall) == 0 {
|
||||
Info("Nothing to do")
|
||||
return nil
|
||||
}
|
||||
|
||||
if l.Options.Ask {
|
||||
Info("By going forward, you are also accepting the licenses of the packages that you are going to install in your system.")
|
||||
if Ask() {
|
||||
l.Options.Ask = false // Don't prompt anymore
|
||||
return l.swap(syncedRepos, uninstall, toInstall, s, true)
|
||||
} else {
|
||||
return errors.New("Aborted by user")
|
||||
}
|
||||
}
|
||||
|
||||
Spinner(32)
|
||||
defer SpinnerStop()
|
||||
return l.swap(syncedRepos, uninstall, toInstall, s, true)
|
||||
return l.checkAndUpgrade(syncedRepos, s)
|
||||
}
|
||||
|
||||
func (l *LuetInstaller) SyncRepositories(inMemory bool) (Repositories, error) {
|
||||
@@ -226,11 +197,19 @@ func (l *LuetInstaller) Swap(toRemove pkg.Packages, toInstall pkg.Packages, s *S
|
||||
toRemoveFinal = append(toRemoveFinal, pp)
|
||||
}
|
||||
}
|
||||
o := Option{
|
||||
FullUninstall: false,
|
||||
Force: true,
|
||||
CheckConflicts: false,
|
||||
FullCleanUninstall: false,
|
||||
NoDeps: l.Options.NoDeps,
|
||||
OnlyDeps: false,
|
||||
}
|
||||
|
||||
return l.swap(syncedRepos, toRemoveFinal, toInstall, s, false)
|
||||
return l.swap(o, syncedRepos, toRemoveFinal, toInstall, s)
|
||||
}
|
||||
|
||||
func (l *LuetInstaller) computeSwap(syncedRepos Repositories, toRemove pkg.Packages, toInstall pkg.Packages, s *System) (map[string]ArtifactMatch, pkg.Packages, solver.PackagesAssertions, pkg.PackageDatabase, error) {
|
||||
func (l *LuetInstaller) computeSwap(o Option, syncedRepos Repositories, toRemove pkg.Packages, toInstall pkg.Packages, s *System) (map[string]ArtifactMatch, pkg.Packages, solver.PackagesAssertions, pkg.PackageDatabase, error) {
|
||||
|
||||
allRepos := pkg.NewInMemoryDatabase(false)
|
||||
syncedRepos.SyncDatabase(allRepos)
|
||||
@@ -245,8 +224,8 @@ func (l *LuetInstaller) computeSwap(syncedRepos Repositories, toRemove pkg.Packa
|
||||
|
||||
systemAfterChanges := &System{Database: installedtmp}
|
||||
|
||||
packs, err := l.computeUninstall(systemAfterChanges, toRemove...)
|
||||
if err != nil && !l.Options.Force {
|
||||
packs, err := l.computeUninstall(o, systemAfterChanges, toRemove...)
|
||||
if err != nil && !o.Force {
|
||||
Error("Failed computing uninstall for ", packsToList(toRemove))
|
||||
return nil, nil, nil, nil, errors.Wrap(err, "computing uninstall "+packsToList(toRemove))
|
||||
}
|
||||
@@ -257,30 +236,16 @@ func (l *LuetInstaller) computeSwap(syncedRepos Repositories, toRemove pkg.Packa
|
||||
}
|
||||
}
|
||||
|
||||
match, packages, assertions, allRepos, err := l.computeInstall(syncedRepos, toInstall, systemAfterChanges)
|
||||
match, packages, assertions, allRepos, err := l.computeInstall(o, syncedRepos, toInstall, systemAfterChanges)
|
||||
for _, p := range toInstall {
|
||||
assertions = append(assertions, solver.PackageAssert{Package: p.(*pkg.DefaultPackage), Value: true})
|
||||
}
|
||||
return match, packages, assertions, allRepos, err
|
||||
}
|
||||
|
||||
func (l *LuetInstaller) swap(syncedRepos Repositories, toRemove pkg.Packages, toInstall pkg.Packages, s *System, forceNodeps bool) error {
|
||||
forced := l.Options.Force
|
||||
nodeps := l.Options.NoDeps
|
||||
func (l *LuetInstaller) swap(o Option, syncedRepos Repositories, toRemove pkg.Packages, toInstall pkg.Packages, s *System) error {
|
||||
|
||||
// We don't want any conflict with the installed to raise during the upgrade.
|
||||
// In this way we both force uninstalls and we avoid to check with conflicts
|
||||
// against the current system state which is pending to deletion
|
||||
// E.g. you can't check for conflicts for an upgrade of a new version of A
|
||||
// if the old A results installed in the system. This is due to the fact that
|
||||
// now the solver enforces the constraints and explictly denies two packages
|
||||
// of the same version installed.
|
||||
l.Options.Force = true
|
||||
if forceNodeps {
|
||||
l.Options.NoDeps = true
|
||||
}
|
||||
|
||||
match, packages, assertions, allRepos, err := l.computeSwap(syncedRepos, toRemove, toInstall, s)
|
||||
match, packages, assertions, allRepos, err := l.computeSwap(o, syncedRepos, toRemove, toInstall, s)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed computing package replacement")
|
||||
}
|
||||
@@ -310,15 +275,223 @@ func (l *LuetInstaller) swap(syncedRepos Repositories, toRemove pkg.Packages, to
|
||||
return nil
|
||||
}
|
||||
|
||||
err = l.Uninstall(s, toRemove...)
|
||||
if err != nil && !l.Options.Force {
|
||||
Error("Failed uninstall for ", packsToList(toRemove))
|
||||
return errors.Wrap(err, "uninstalling "+packsToList(toRemove))
|
||||
ops := l.getOpsWithOptions(toRemove, match, Option{
|
||||
Force: o.Force,
|
||||
NoDeps: false,
|
||||
OnlyDeps: o.OnlyDeps,
|
||||
RunFinalizers: false,
|
||||
}, o, syncedRepos, packages, assertions, allRepos)
|
||||
|
||||
err = l.runOps(ops, s)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed running installer options")
|
||||
}
|
||||
|
||||
l.Options.Force = forced
|
||||
l.Options.NoDeps = nodeps
|
||||
return l.install(syncedRepos, match, packages, assertions, allRepos, s)
|
||||
toFinalize, err := l.getFinalizers(allRepos, assertions, match, o.NoDeps)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed getting package to finalize")
|
||||
}
|
||||
|
||||
return s.ExecuteFinalizers(toFinalize)
|
||||
}
|
||||
|
||||
type Option struct {
|
||||
Force bool
|
||||
NoDeps bool
|
||||
CheckConflicts bool
|
||||
FullUninstall bool
|
||||
FullCleanUninstall bool
|
||||
OnlyDeps bool
|
||||
RunFinalizers bool
|
||||
}
|
||||
|
||||
type operation struct {
|
||||
Option Option
|
||||
Package pkg.Package
|
||||
}
|
||||
|
||||
type installOperation struct {
|
||||
operation
|
||||
Reposiories Repositories
|
||||
Packages pkg.Packages
|
||||
Assertions solver.PackagesAssertions
|
||||
Database pkg.PackageDatabase
|
||||
Matches map[string]ArtifactMatch
|
||||
}
|
||||
|
||||
// installerOp is the operation that is sent to the
|
||||
// upgradeWorker's channel (todo)
|
||||
type installerOp struct {
|
||||
Uninstall operation
|
||||
Install installOperation
|
||||
}
|
||||
|
||||
func (l *LuetInstaller) runOps(ops []installerOp, s *System) error {
|
||||
all := make(chan installerOp)
|
||||
|
||||
wg := new(sync.WaitGroup)
|
||||
|
||||
// Do the real install
|
||||
for i := 0; i < l.Options.Concurrency; i++ {
|
||||
wg.Add(1)
|
||||
go l.installerOpWorker(i, wg, all, s)
|
||||
}
|
||||
|
||||
for _, c := range ops {
|
||||
all <- c
|
||||
}
|
||||
close(all)
|
||||
wg.Wait()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO: use installerOpWorker in place of all the other workers.
|
||||
// This one is general enough to read a list of operations and execute them.
|
||||
func (l *LuetInstaller) installerOpWorker(i int, wg *sync.WaitGroup, c <-chan installerOp, s *System) error {
|
||||
defer wg.Done()
|
||||
|
||||
for p := range c {
|
||||
if p.Uninstall.Package != nil {
|
||||
Debug("Replacing package inplace")
|
||||
toUninstall, uninstall, err := l.generateUninstallFn(p.Uninstall.Option, s, p.Uninstall.Package)
|
||||
if err != nil {
|
||||
Error("Failed to generate Uninstall function for" + err.Error())
|
||||
continue
|
||||
//return errors.Wrap(err, "while computing uninstall")
|
||||
}
|
||||
|
||||
err = uninstall()
|
||||
if err != nil {
|
||||
Error("Failed uninstall for ", packsToList(toUninstall))
|
||||
continue
|
||||
//return errors.Wrap(err, "uninstalling "+packsToList(toUninstall))
|
||||
}
|
||||
}
|
||||
if p.Install.Package != nil {
|
||||
artMatch := p.Install.Matches[p.Install.Package.GetFingerPrint()]
|
||||
ass := p.Install.Assertions.Search(p.Install.Package.GetFingerPrint())
|
||||
packageToInstall, _ := p.Install.Packages.Find(p.Install.Package.GetPackageName())
|
||||
|
||||
err := l.install(
|
||||
p.Install.Option,
|
||||
p.Install.Reposiories,
|
||||
map[string]ArtifactMatch{p.Install.Package.GetFingerPrint(): artMatch},
|
||||
pkg.Packages{packageToInstall},
|
||||
solver.PackagesAssertions{*ass},
|
||||
p.Install.Database,
|
||||
s,
|
||||
)
|
||||
if err != nil {
|
||||
Error(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// checks wheter we can uninstall and install in place and compose installer worker ops
|
||||
func (l *LuetInstaller) getOpsWithOptions(
|
||||
toUninstall pkg.Packages, installMatch map[string]ArtifactMatch, installOpt, uninstallOpt Option,
|
||||
syncedRepos Repositories, toInstall pkg.Packages, solution solver.PackagesAssertions, allRepos pkg.PackageDatabase) []installerOp {
|
||||
resOps := []installerOp{}
|
||||
for _, match := range installMatch {
|
||||
if pack, err := toUninstall.Find(match.Package.GetPackageName()); err == nil {
|
||||
resOps = append(resOps, installerOp{
|
||||
Uninstall: operation{Package: pack, Option: uninstallOpt},
|
||||
Install: installOperation{
|
||||
operation: operation{
|
||||
Package: match.Package,
|
||||
Option: installOpt,
|
||||
},
|
||||
Matches: installMatch,
|
||||
Packages: toInstall,
|
||||
Reposiories: syncedRepos,
|
||||
Assertions: solution,
|
||||
Database: allRepos,
|
||||
},
|
||||
})
|
||||
} else {
|
||||
resOps = append(resOps, installerOp{
|
||||
Install: installOperation{
|
||||
operation: operation{Package: match.Package, Option: installOpt},
|
||||
Matches: installMatch,
|
||||
Reposiories: syncedRepos,
|
||||
Packages: toInstall,
|
||||
Assertions: solution,
|
||||
Database: allRepos,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
for _, p := range toUninstall {
|
||||
found := false
|
||||
|
||||
for _, match := range installMatch {
|
||||
if match.Package.GetPackageName() == p.GetPackageName() {
|
||||
found = true
|
||||
}
|
||||
|
||||
}
|
||||
if !found {
|
||||
resOps = append(resOps, installerOp{
|
||||
Uninstall: operation{Package: p, Option: uninstallOpt},
|
||||
})
|
||||
}
|
||||
}
|
||||
return resOps
|
||||
}
|
||||
|
||||
func (l *LuetInstaller) checkAndUpgrade(r Repositories, s *System) error {
|
||||
Spinner(32)
|
||||
uninstall, toInstall, err := l.computeUpgrade(r, s)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed computing upgrade")
|
||||
}
|
||||
SpinnerStop()
|
||||
|
||||
if len(uninstall) > 0 {
|
||||
Info(":recycle: Packages that are going to be removed from the system:\n ", Yellow(packsToList(uninstall)).BgBlack().String())
|
||||
}
|
||||
|
||||
if len(toInstall) > 0 {
|
||||
Info(":zap:Packages that are going to be installed in the system:\n ", Green(packsToList(toInstall)).BgBlack().String())
|
||||
}
|
||||
|
||||
if len(toInstall) == 0 && len(uninstall) == 0 {
|
||||
Info("Nothing to do")
|
||||
return nil
|
||||
}
|
||||
|
||||
// We don't want any conflict with the installed to raise during the upgrade.
|
||||
// In this way we both force uninstalls and we avoid to check with conflicts
|
||||
// against the current system state which is pending to deletion
|
||||
// E.g. you can't check for conflicts for an upgrade of a new version of A
|
||||
// if the old A results installed in the system. This is due to the fact that
|
||||
// now the solver enforces the constraints and explictly denies two packages
|
||||
// of the same version installed.
|
||||
o := Option{
|
||||
FullUninstall: false,
|
||||
Force: true,
|
||||
CheckConflicts: false,
|
||||
FullCleanUninstall: false,
|
||||
NoDeps: true,
|
||||
OnlyDeps: false,
|
||||
}
|
||||
|
||||
if l.Options.Ask {
|
||||
Info("By going forward, you are also accepting the licenses of the packages that you are going to install in your system.")
|
||||
if Ask() {
|
||||
l.Options.Ask = false // Don't prompt anymore
|
||||
return l.swap(o, r, uninstall, toInstall, s)
|
||||
} else {
|
||||
return errors.New("Aborted by user")
|
||||
}
|
||||
}
|
||||
|
||||
return l.swap(o, r, uninstall, toInstall, s)
|
||||
}
|
||||
|
||||
func (l *LuetInstaller) Install(cp pkg.Packages, s *System) error {
|
||||
@@ -327,7 +500,20 @@ func (l *LuetInstaller) Install(cp pkg.Packages, s *System) error {
|
||||
return err
|
||||
}
|
||||
|
||||
match, packages, assertions, allRepos, err := l.computeInstall(syncedRepos, cp, s)
|
||||
if len(s.Database.World()) > 0 {
|
||||
Info(":thinking: Checking for available upgrades")
|
||||
if err := l.checkAndUpgrade(syncedRepos, s); err != nil {
|
||||
return errors.Wrap(err, "while checking upgrades before install")
|
||||
}
|
||||
}
|
||||
|
||||
o := Option{
|
||||
NoDeps: l.Options.NoDeps,
|
||||
Force: l.Options.Force,
|
||||
OnlyDeps: l.Options.OnlyDeps,
|
||||
RunFinalizers: true,
|
||||
}
|
||||
match, packages, assertions, allRepos, err := l.computeInstall(o, syncedRepos, cp, s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -364,12 +550,12 @@ func (l *LuetInstaller) Install(cp pkg.Packages, s *System) error {
|
||||
Info("By going forward, you are also accepting the licenses of the packages that you are going to install in your system.")
|
||||
if Ask() {
|
||||
l.Options.Ask = false // Don't prompt anymore
|
||||
return l.install(syncedRepos, match, packages, assertions, allRepos, s)
|
||||
return l.install(o, syncedRepos, match, packages, assertions, allRepos, s)
|
||||
} else {
|
||||
return errors.New("Aborted by user")
|
||||
}
|
||||
}
|
||||
return l.install(syncedRepos, match, packages, assertions, allRepos, s)
|
||||
return l.install(o, syncedRepos, match, packages, assertions, allRepos, s)
|
||||
}
|
||||
|
||||
func (l *LuetInstaller) download(syncedRepos Repositories, toDownload map[string]ArtifactMatch) error {
|
||||
@@ -444,7 +630,7 @@ func (l *LuetInstaller) Reclaim(s *System) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *LuetInstaller) computeInstall(syncedRepos Repositories, cp pkg.Packages, s *System) (map[string]ArtifactMatch, pkg.Packages, solver.PackagesAssertions, pkg.PackageDatabase, error) {
|
||||
func (l *LuetInstaller) computeInstall(o Option, syncedRepos Repositories, cp pkg.Packages, s *System) (map[string]ArtifactMatch, pkg.Packages, solver.PackagesAssertions, pkg.PackageDatabase, error) {
|
||||
var p pkg.Packages
|
||||
toInstall := map[string]ArtifactMatch{}
|
||||
allRepos := pkg.NewInMemoryDatabase(false)
|
||||
@@ -477,11 +663,11 @@ func (l *LuetInstaller) computeInstall(syncedRepos Repositories, cp pkg.Packages
|
||||
var packagesToInstall pkg.Packages
|
||||
var err error
|
||||
|
||||
if !l.Options.NoDeps {
|
||||
if !o.NoDeps {
|
||||
solv := solver.NewResolver(solver.Options{Type: l.Options.SolverOptions.Implementation, Concurrency: l.Options.Concurrency}, s.Database, allRepos, pkg.NewInMemoryDatabase(false), l.Options.SolverOptions.Resolver())
|
||||
solution, err = solv.Install(p)
|
||||
/// TODO: PackageAssertions needs to be a map[fingerprint]pack so lookup is in O(1)
|
||||
if err != nil && !l.Options.Force {
|
||||
if err != nil && !o.Force {
|
||||
return toInstall, p, solution, allRepos, errors.Wrap(err, "Failed solving solution for package")
|
||||
}
|
||||
// Gathers things to install
|
||||
@@ -494,7 +680,7 @@ func (l *LuetInstaller) computeInstall(syncedRepos Repositories, cp pkg.Packages
|
||||
packagesToInstall = append(packagesToInstall, assertion.Package)
|
||||
}
|
||||
}
|
||||
} else if !l.Options.OnlyDeps {
|
||||
} else if !o.OnlyDeps {
|
||||
for _, currentPack := range p {
|
||||
if _, err := s.Database.FindPackage(currentPack); err == nil {
|
||||
// skip matching if it is installed already
|
||||
@@ -529,7 +715,47 @@ func (l *LuetInstaller) computeInstall(syncedRepos Repositories, cp pkg.Packages
|
||||
return toInstall, p, solution, allRepos, nil
|
||||
}
|
||||
|
||||
func (l *LuetInstaller) install(syncedRepos Repositories, toInstall map[string]ArtifactMatch, p pkg.Packages, solution solver.PackagesAssertions, allRepos pkg.PackageDatabase, s *System) error {
|
||||
func (l *LuetInstaller) getFinalizers(allRepos pkg.PackageDatabase, solution solver.PackagesAssertions, toInstall map[string]ArtifactMatch, nodeps bool) ([]pkg.Package, error) {
|
||||
var toFinalize []pkg.Package
|
||||
if !nodeps {
|
||||
// TODO: Lower those errors as warning
|
||||
for _, w := range toInstall {
|
||||
// Finalizers needs to run in order and in sequence.
|
||||
ordered, err := solution.Order(allRepos, w.Package.GetFingerPrint())
|
||||
if err != nil {
|
||||
return toFinalize, errors.Wrap(err, "While order a solution for "+w.Package.HumanReadableString())
|
||||
}
|
||||
ORDER:
|
||||
for _, ass := range ordered {
|
||||
if ass.Value {
|
||||
installed, ok := toInstall[ass.Package.GetFingerPrint()]
|
||||
if !ok {
|
||||
// It was a dep already installed in the system, so we can skip it safely
|
||||
continue ORDER
|
||||
}
|
||||
treePackage, err := installed.Repository.GetTree().GetDatabase().FindPackage(ass.Package)
|
||||
if err != nil {
|
||||
return toFinalize, errors.Wrap(err, "Error getting package "+ass.Package.HumanReadableString())
|
||||
}
|
||||
|
||||
toFinalize = append(toFinalize, treePackage)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
for _, c := range toInstall {
|
||||
treePackage, err := c.Repository.GetTree().GetDatabase().FindPackage(c.Package)
|
||||
if err != nil {
|
||||
return toFinalize, errors.Wrap(err, "Error getting package "+c.Package.HumanReadableString())
|
||||
}
|
||||
toFinalize = append(toFinalize, treePackage)
|
||||
}
|
||||
}
|
||||
return toFinalize, nil
|
||||
}
|
||||
|
||||
func (l *LuetInstaller) install(o Option, syncedRepos Repositories, toInstall map[string]ArtifactMatch, p pkg.Packages, solution solver.PackagesAssertions, allRepos pkg.PackageDatabase, s *System) error {
|
||||
// Install packages into rootfs in parallel.
|
||||
if err := l.download(syncedRepos, toInstall); err != nil {
|
||||
return errors.Wrap(err, "Downloading packages")
|
||||
@@ -558,46 +784,19 @@ func (l *LuetInstaller) install(syncedRepos Repositories, toInstall map[string]A
|
||||
for _, c := range toInstall {
|
||||
// Annotate to the system that the package was installed
|
||||
_, err := s.Database.CreatePackage(c.Package)
|
||||
if err != nil && !l.Options.Force {
|
||||
if err != nil && !o.Force {
|
||||
return errors.Wrap(err, "Failed creating package")
|
||||
}
|
||||
bus.Manager.Publish(bus.EventPackageInstall, c)
|
||||
}
|
||||
var toFinalize []pkg.Package
|
||||
if !l.Options.NoDeps {
|
||||
// TODO: Lower those errors as warning
|
||||
for _, w := range p {
|
||||
// Finalizers needs to run in order and in sequence.
|
||||
ordered, err := solution.Order(allRepos, w.GetFingerPrint())
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "While order a solution for "+w.HumanReadableString())
|
||||
}
|
||||
ORDER:
|
||||
for _, ass := range ordered {
|
||||
if ass.Value {
|
||||
installed, ok := toInstall[ass.Package.GetFingerPrint()]
|
||||
if !ok {
|
||||
// It was a dep already installed in the system, so we can skip it safely
|
||||
continue ORDER
|
||||
}
|
||||
treePackage, err := installed.Repository.GetTree().GetDatabase().FindPackage(ass.Package)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Error getting package "+ass.Package.HumanReadableString())
|
||||
}
|
||||
|
||||
toFinalize = append(toFinalize, treePackage)
|
||||
}
|
||||
}
|
||||
if !o.RunFinalizers {
|
||||
return nil
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
for _, c := range toInstall {
|
||||
treePackage, err := c.Repository.GetTree().GetDatabase().FindPackage(c.Package)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Error getting package "+c.Package.HumanReadableString())
|
||||
}
|
||||
toFinalize = append(toFinalize, treePackage)
|
||||
}
|
||||
toFinalize, err := l.getFinalizers(allRepos, solution, toInstall, o.NoDeps)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed getting package to finalize")
|
||||
}
|
||||
|
||||
return s.ExecuteFinalizers(toFinalize)
|
||||
@@ -677,6 +876,51 @@ func (l *LuetInstaller) installerWorker(i int, wg *sync.WaitGroup, c <-chan Arti
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkAndPrunePath(path string) {
|
||||
// check if now the target path is empty
|
||||
targetPath := filepath.Dir(path)
|
||||
|
||||
fi, err := os.Lstat(targetPath)
|
||||
if err != nil {
|
||||
// Warning("Dir not found (it was before?) ", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
switch mode := fi.Mode(); {
|
||||
case mode.IsDir():
|
||||
files, err := ioutil.ReadDir(targetPath)
|
||||
if err != nil {
|
||||
Warning("Failed reading folder", targetPath, err.Error())
|
||||
}
|
||||
if len(files) != 0 {
|
||||
Debug("Preserving not-empty folder", targetPath)
|
||||
return
|
||||
}
|
||||
}
|
||||
if err = os.Remove(targetPath); err != nil {
|
||||
Warning("Failed removing file (maybe not present in the system target anymore ?)", targetPath, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// We will try to cleanup every path from the file, if the folders left behind are empty
|
||||
func pruneEmptyFilePath(path string) {
|
||||
checkAndPrunePath(path)
|
||||
|
||||
// A path is for e.g. /usr/bin/bar
|
||||
// we want to create an array as "/usr", "/usr/bin", "/usr/bin/bar"
|
||||
paths := strings.Split(path, string(os.PathSeparator))
|
||||
currentPath := filepath.Join(string(os.PathSeparator), paths[0])
|
||||
allPaths := []string{currentPath}
|
||||
for _, p := range paths[1:] {
|
||||
currentPath = filepath.Join(currentPath, p)
|
||||
allPaths = append(allPaths, currentPath)
|
||||
}
|
||||
helpers.ReverseAny(allPaths)
|
||||
for _, p := range allPaths {
|
||||
checkAndPrunePath(p)
|
||||
}
|
||||
}
|
||||
|
||||
func (l *LuetInstaller) uninstall(p pkg.Package, s *System) error {
|
||||
var cp *config.ConfigProtect
|
||||
annotationDir := ""
|
||||
@@ -738,6 +982,8 @@ func (l *LuetInstaller) uninstall(p pkg.Package, s *System) error {
|
||||
if err = os.Remove(target); err != nil {
|
||||
Warning("Failed removing file (maybe not present in the system target anymore ?)", target, err.Error())
|
||||
}
|
||||
|
||||
pruneEmptyFilePath(target)
|
||||
}
|
||||
|
||||
for _, f := range notPresent {
|
||||
@@ -751,6 +997,8 @@ func (l *LuetInstaller) uninstall(p pkg.Package, s *System) error {
|
||||
if err = os.Remove(target); err != nil {
|
||||
Debug("Failed removing file (not present in the system target)", target, err.Error())
|
||||
}
|
||||
|
||||
pruneEmptyFilePath(target)
|
||||
}
|
||||
|
||||
err = s.Database.RemovePackageFiles(p)
|
||||
@@ -768,17 +1016,17 @@ func (l *LuetInstaller) uninstall(p pkg.Package, s *System) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *LuetInstaller) computeUninstall(s *System, packs ...pkg.Package) (pkg.Packages, error) {
|
||||
func (l *LuetInstaller) computeUninstall(o Option, s *System, packs ...pkg.Package) (pkg.Packages, error) {
|
||||
|
||||
var toUninstall pkg.Packages
|
||||
// compute uninstall from all world - remove packages in parallel - run uninstall finalizer (in order) TODO - mark the uninstallation in db
|
||||
// Get installed definition
|
||||
checkConflicts := l.Options.CheckConflicts
|
||||
full := l.Options.FullUninstall
|
||||
if l.Options.Force == true { // IF forced, we want to remove the package and all its requires
|
||||
checkConflicts = false
|
||||
full = false
|
||||
}
|
||||
checkConflicts := o.CheckConflicts
|
||||
full := o.FullUninstall
|
||||
// if o.Force == true { // IF forced, we want to remove the package and all its requires
|
||||
// checkConflicts = false
|
||||
// full = false
|
||||
// }
|
||||
|
||||
// Create a temporary DB with the installed packages
|
||||
// so the solver is much faster finding the deptree
|
||||
@@ -788,11 +1036,11 @@ func (l *LuetInstaller) computeUninstall(s *System, packs ...pkg.Package) (pkg.P
|
||||
return toUninstall, errors.Wrap(err, "Failed create temporary in-memory db")
|
||||
}
|
||||
|
||||
if !l.Options.NoDeps {
|
||||
if !o.NoDeps {
|
||||
solv := solver.NewResolver(solver.Options{Type: l.Options.SolverOptions.Implementation, Concurrency: l.Options.Concurrency}, installedtmp, installedtmp, pkg.NewInMemoryDatabase(false), l.Options.SolverOptions.Resolver())
|
||||
var solution pkg.Packages
|
||||
var err error
|
||||
if l.Options.FullCleanUninstall {
|
||||
if o.FullCleanUninstall {
|
||||
solution, err = solv.UninstallUniverse(packs)
|
||||
if err != nil {
|
||||
return toUninstall, errors.Wrap(err, "Could not solve the uninstall constraints. Tip: try with --solver-type qlearning or with --force, or by removing packages excluding their dependencies with --nodeps")
|
||||
@@ -813,32 +1061,47 @@ func (l *LuetInstaller) computeUninstall(s *System, packs ...pkg.Package) (pkg.P
|
||||
|
||||
return toUninstall, nil
|
||||
}
|
||||
func (l *LuetInstaller) Uninstall(s *System, packs ...pkg.Package) error {
|
||||
|
||||
func (l *LuetInstaller) generateUninstallFn(o Option, s *System, packs ...pkg.Package) (pkg.Packages, func() error, error) {
|
||||
for _, p := range packs {
|
||||
if packs, _ := s.Database.FindPackages(p); len(packs) == 0 {
|
||||
return errors.New("Package not found in the system")
|
||||
return nil, nil, errors.New("Package not found in the system")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Spinner(32)
|
||||
toUninstall, err := l.computeUninstall(s, packs...)
|
||||
toUninstall, err := l.computeUninstall(o, s, packs...)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "while computing uninstall")
|
||||
return nil, nil, errors.Wrap(err, "while computing uninstall")
|
||||
}
|
||||
SpinnerStop()
|
||||
|
||||
uninstall := func() error {
|
||||
for _, p := range toUninstall {
|
||||
err := l.uninstall(p, s)
|
||||
if err != nil && !l.Options.Force {
|
||||
if err != nil && !o.Force {
|
||||
return errors.Wrap(err, "Uninstall failed")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
return toUninstall, uninstall, nil
|
||||
}
|
||||
|
||||
func (l *LuetInstaller) Uninstall(s *System, packs ...pkg.Package) error {
|
||||
|
||||
Spinner(32)
|
||||
o := Option{
|
||||
FullUninstall: l.Options.FullUninstall,
|
||||
Force: l.Options.Force,
|
||||
CheckConflicts: l.Options.CheckConflicts,
|
||||
FullCleanUninstall: l.Options.FullCleanUninstall,
|
||||
}
|
||||
toUninstall, uninstall, err := l.generateUninstallFn(o, s, packs...)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "while computing uninstall")
|
||||
}
|
||||
SpinnerStop()
|
||||
|
||||
if len(toUninstall) == 0 {
|
||||
Info("Nothing to do")
|
||||
return nil
|
||||
|
@@ -61,7 +61,7 @@ func (l *dockerRepositoryGenerator) Initialize(path string, db pkg.PackageDataba
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := l.pushImageFromArtifact(artifact.NewPackageArtifact(currentpath), l.b); err != nil {
|
||||
if err := l.pushImageFromArtifact(artifact.NewPackageArtifact(currentpath), l.b, true); err != nil {
|
||||
return errors.Wrap(err, "while pushing metadata file associated to the artifact")
|
||||
}
|
||||
|
||||
@@ -159,16 +159,20 @@ func (d *dockerRepositoryGenerator) pushRepoMetadata(repospec string, r *LuetSys
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *dockerRepositoryGenerator) pushImageFromArtifact(a *artifact.PackageArtifact, b compiler.CompilerBackend) error {
|
||||
func (d *dockerRepositoryGenerator) pushImageFromArtifact(a *artifact.PackageArtifact, b compiler.CompilerBackend, checkIfExists bool) error {
|
||||
// we generate a new archive containing the required compressed file.
|
||||
// TODO: Bundle all the extra files in 1 docker image only, instead of an image for each file
|
||||
treeArchive, err := artifact.CreateArtifactForFile(a.Path)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed generating checksums for tree")
|
||||
}
|
||||
imageTree := fmt.Sprintf("%s:%s", d.imagePrefix, a.GetFileName())
|
||||
|
||||
return d.pushFileFromArtifact(treeArchive, imageTree)
|
||||
imageTree := fmt.Sprintf("%s:%s", d.imagePrefix, helpers.StripInvalidStringsFromImage(a.GetFileName()))
|
||||
if checkIfExists && d.imagePush && d.b.ImageAvailable(imageTree) && !d.force {
|
||||
Info("Image", imageTree, "already present, skipping. use --force-push to override")
|
||||
return nil
|
||||
} else {
|
||||
return d.pushFileFromArtifact(treeArchive, imageTree)
|
||||
}
|
||||
}
|
||||
|
||||
// Generate creates a Docker luet repository
|
||||
@@ -225,7 +229,7 @@ func (d *dockerRepositoryGenerator) Generate(r *LuetSystemRepository, imagePrefi
|
||||
|
||||
// we generate a new archive containing the required compressed file.
|
||||
// TODO: Bundle all the extra files in 1 docker image only, instead of an image for each file
|
||||
if err := d.pushImageFromArtifact(a, d.b); err != nil {
|
||||
if err := d.pushImageFromArtifact(a, d.b, false); err != nil {
|
||||
return errors.Wrap(err, "error met while pushing runtime tree")
|
||||
}
|
||||
|
||||
@@ -235,7 +239,7 @@ func (d *dockerRepositoryGenerator) Generate(r *LuetSystemRepository, imagePrefi
|
||||
}
|
||||
// we generate a new archive containing the required compressed file.
|
||||
// TODO: Bundle all the extra files in 1 docker image only, instead of an image for each file
|
||||
if err := d.pushImageFromArtifact(a, d.b); err != nil {
|
||||
if err := d.pushImageFromArtifact(a, d.b, false); err != nil {
|
||||
return errors.Wrap(err, "error met while pushing compiler tree")
|
||||
}
|
||||
|
||||
@@ -251,7 +255,7 @@ func (d *dockerRepositoryGenerator) Generate(r *LuetSystemRepository, imagePrefi
|
||||
return errors.Wrap(err, "failed adding Metadata file to repository")
|
||||
}
|
||||
|
||||
if err := d.pushImageFromArtifact(a, d.b); err != nil {
|
||||
if err := d.pushImageFromArtifact(a, d.b, false); err != nil {
|
||||
return errors.Wrap(err, "error met while pushing docker image from artifact")
|
||||
}
|
||||
|
||||
|
@@ -118,6 +118,8 @@ type Package interface {
|
||||
SetTreeDir(s string)
|
||||
GetTreeDir() string
|
||||
|
||||
Mark() Package
|
||||
|
||||
JSON() ([]byte, error)
|
||||
}
|
||||
|
||||
@@ -131,6 +133,19 @@ type Tree interface {
|
||||
|
||||
type Packages []Package
|
||||
|
||||
type DefaultPackages []*DefaultPackage
|
||||
|
||||
func (d DefaultPackages) Hash(salt string) string {
|
||||
|
||||
overallFp := ""
|
||||
for _, c := range d {
|
||||
overallFp = overallFp + c.HashFingerprint("join")
|
||||
}
|
||||
h := md5.New()
|
||||
io.WriteString(h, fmt.Sprintf("%s-%s", overallFp, salt))
|
||||
return fmt.Sprintf("%x", h.Sum(nil))
|
||||
}
|
||||
|
||||
// >> Unmarshallers
|
||||
// DefaultPackageFromYaml decodes a package from yaml bytes
|
||||
func DefaultPackageFromYaml(yml []byte) (DefaultPackage, error) {
|
||||
@@ -309,7 +324,7 @@ func (p *DefaultPackage) GetPackageName() string {
|
||||
}
|
||||
|
||||
func (p *DefaultPackage) ImageID() string {
|
||||
return strings.ReplaceAll(p.GetFingerPrint(), "+", "-")
|
||||
return helpers.StripInvalidStringsFromImage(p.GetFingerPrint())
|
||||
}
|
||||
|
||||
// GetBuildTimestamp returns the package build timestamp
|
||||
@@ -492,6 +507,12 @@ func (p *DefaultPackage) Matches(m Package) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (p *DefaultPackage) Mark() Package {
|
||||
marked := p.Clone()
|
||||
marked.SetName("@@" + marked.GetName())
|
||||
return marked
|
||||
}
|
||||
|
||||
func (p *DefaultPackage) Expand(definitiondb PackageDatabase) (Packages, error) {
|
||||
var versionsInWorld Packages
|
||||
|
||||
@@ -645,6 +666,16 @@ func (set Packages) Best(v version.Versioner) Package {
|
||||
return versionsMap[sorted[len(sorted)-1]]
|
||||
}
|
||||
|
||||
func (set Packages) Find(packageName string) (Package, error) {
|
||||
for _, p := range set {
|
||||
if p.GetPackageName() == packageName {
|
||||
return p, nil
|
||||
}
|
||||
}
|
||||
|
||||
return &DefaultPackage{}, errors.New("package not found")
|
||||
}
|
||||
|
||||
func (set Packages) Unique() Packages {
|
||||
var result Packages
|
||||
uniq := make(map[string]Package)
|
||||
|
@@ -260,24 +260,42 @@ func (a PackagesAssertions) TrueLen() int {
|
||||
// and checks it's not the only one. if it's unique it marks it specially - so the hash
|
||||
// which is generated is unique for the selected package
|
||||
func (assertions PackagesAssertions) HashFrom(p pkg.Package) string {
|
||||
return assertions.SaltedHashFrom(p, map[string]string{})
|
||||
}
|
||||
|
||||
func (assertions PackagesAssertions) AssertionHash() string {
|
||||
return assertions.SaltedAssertionHash(map[string]string{})
|
||||
}
|
||||
|
||||
func (assertions PackagesAssertions) SaltedHashFrom(p pkg.Package, salts map[string]string) string {
|
||||
var assertionhash string
|
||||
|
||||
// When we don't have any solution to hash for, we need to generate an UUID by ourselves
|
||||
latestsolution := assertions.Drop(p)
|
||||
if latestsolution.TrueLen() == 0 {
|
||||
assertionhash = assertions.Mark(p).AssertionHash()
|
||||
// Preserve the hash if supplied of marked packages
|
||||
marked := p.Mark()
|
||||
if markedHash, exists := salts[p.GetFingerPrint()]; exists {
|
||||
salts[marked.GetFingerPrint()] = markedHash
|
||||
}
|
||||
assertionhash = assertions.Mark(p).SaltedAssertionHash(salts)
|
||||
} else {
|
||||
assertionhash = latestsolution.AssertionHash()
|
||||
assertionhash = latestsolution.SaltedAssertionHash(salts)
|
||||
}
|
||||
return assertionhash
|
||||
}
|
||||
|
||||
func (assertions PackagesAssertions) AssertionHash() string {
|
||||
func (assertions PackagesAssertions) SaltedAssertionHash(salts map[string]string) string {
|
||||
var fingerprint string
|
||||
for _, assertion := range assertions { // Note: Always order them first!
|
||||
if assertion.Value { // Tke into account only dependencies installed (get fingerprint of subgraph)
|
||||
fingerprint += assertion.ToString() + "\n"
|
||||
salt, exists := salts[assertion.Package.GetFingerPrint()]
|
||||
if exists {
|
||||
fingerprint += assertion.ToString() + salt + "\n"
|
||||
|
||||
} else {
|
||||
fingerprint += assertion.ToString() + "\n"
|
||||
}
|
||||
}
|
||||
}
|
||||
hash := sha256.Sum256([]byte(fingerprint))
|
||||
@@ -316,8 +334,7 @@ func (assertions PackagesAssertions) Mark(p pkg.Package) PackagesAssertions {
|
||||
|
||||
for _, a := range assertions {
|
||||
if a.Package.Matches(p) {
|
||||
marked := a.Package.Clone()
|
||||
marked.SetName("@@" + marked.GetName())
|
||||
marked := a.Package.Mark()
|
||||
a = PackageAssert{Package: marked.(*pkg.DefaultPackage), Value: a.Value, Hash: a.Hash}
|
||||
}
|
||||
ass = append(ass, a)
|
||||
|
@@ -382,6 +382,9 @@ var _ = Describe("Decoder", func() {
|
||||
|
||||
Expect(solution.HashFrom(X)).ToNot(Equal(solution2.HashFrom(F)))
|
||||
Expect(solution3.HashFrom(D)).To(Equal(solution.HashFrom(X)))
|
||||
Expect(solution3.SaltedHashFrom(D, map[string]string{D.GetFingerPrint(): "foo"})).ToNot(Equal(solution3.HashFrom(D)))
|
||||
|
||||
Expect(solution4.SaltedHashFrom(Y, map[string]string{X.GetFingerPrint(): "foo"})).ToNot(Equal(solution4.HashFrom(Y)))
|
||||
|
||||
Expect(empty.AssertionHash()).ToNot(Equal(solution3.HashFrom(D)))
|
||||
Expect(empty.AssertionHash()).ToNot(Equal(solution2.HashFrom(F)))
|
||||
|
17
tests/fixtures/copy/c/a/build.yaml
vendored
Normal file
17
tests/fixtures/copy/c/a/build.yaml
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
image: "alpine"
|
||||
|
||||
copy:
|
||||
- package:
|
||||
name: "a"
|
||||
category: "test"
|
||||
version: ">=0"
|
||||
source: /test3
|
||||
destination: /test3
|
||||
- image: "busybox"
|
||||
source: /bin/busybox
|
||||
destination: /busybox
|
||||
|
||||
steps:
|
||||
- mkdir /bina
|
||||
- cp /test3 /result
|
||||
- cp -rf /busybox /bina/busybox
|
3
tests/fixtures/copy/c/a/definition.yaml
vendored
Normal file
3
tests/fixtures/copy/c/a/definition.yaml
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
category: "test"
|
||||
name: "c"
|
||||
version: "1.2"
|
7
tests/fixtures/copy/cat/a/a/build.yaml
vendored
Normal file
7
tests/fixtures/copy/cat/a/a/build.yaml
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
image: "alpine"
|
||||
prelude:
|
||||
- echo foo > /test
|
||||
- echo bar > /test2
|
||||
steps:
|
||||
- echo artifact3 > /test3
|
||||
- echo artifact4 > /test4
|
3
tests/fixtures/copy/cat/a/a/definition.yaml
vendored
Normal file
3
tests/fixtures/copy/cat/a/a/definition.yaml
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
category: "test"
|
||||
name: "a"
|
||||
version: "1.2"
|
13
tests/fixtures/copy/cat/b-1.1/build.yaml
vendored
Normal file
13
tests/fixtures/copy/cat/b-1.1/build.yaml
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
requires:
|
||||
- category: "test"
|
||||
name: "a"
|
||||
version: ">=0"
|
||||
|
||||
prelude:
|
||||
- echo foo > /test
|
||||
- echo bar > /test2
|
||||
steps:
|
||||
- echo artifact5 > /newc
|
||||
- echo artifact6 > /newnewc
|
||||
- chmod +x generate.sh
|
||||
- ./generate.sh
|
3
tests/fixtures/copy/cat/b-1.1/definition.yaml
vendored
Normal file
3
tests/fixtures/copy/cat/b-1.1/definition.yaml
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
category: "test"
|
||||
name: "b"
|
||||
version: "1.1"
|
1
tests/fixtures/copy/cat/b-1.1/generate.sh
vendored
Normal file
1
tests/fixtures/copy/cat/b-1.1/generate.sh
vendored
Normal file
@@ -0,0 +1 @@
|
||||
echo generated > /sonewc
|
11
tests/fixtures/docker_repo/c/build.yaml
vendored
Normal file
11
tests/fixtures/docker_repo/c/build.yaml
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
prelude:
|
||||
- echo foo > /test
|
||||
- echo bar > /test2
|
||||
steps:
|
||||
- echo c > /c
|
||||
- echo c > /cd
|
||||
requires:
|
||||
- category: "test"
|
||||
name: "b"
|
||||
version: "1.0"
|
||||
|
3
tests/fixtures/docker_repo/c/definition.yaml
vendored
Normal file
3
tests/fixtures/docker_repo/c/definition.yaml
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
category: "test"
|
||||
name: "c"
|
||||
version: "1.0"
|
9
tests/fixtures/docker_repo/cat/b/build.yaml
vendored
Normal file
9
tests/fixtures/docker_repo/cat/b/build.yaml
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
image: "alpine"
|
||||
prelude:
|
||||
- echo foo > /test
|
||||
- echo bar > /test2
|
||||
steps:
|
||||
- echo artifact5 > /test5
|
||||
- echo artifact6 > /test6
|
||||
- chmod +x generate.sh
|
||||
- ./generate.sh
|
3
tests/fixtures/docker_repo/cat/b/definition.yaml
vendored
Normal file
3
tests/fixtures/docker_repo/cat/b/definition.yaml
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
category: "test"
|
||||
name: "b"
|
||||
version: "1.0"
|
1
tests/fixtures/docker_repo/cat/b/generate.sh
vendored
Normal file
1
tests/fixtures/docker_repo/cat/b/generate.sh
vendored
Normal file
@@ -0,0 +1 @@
|
||||
echo generated > /artifact42
|
10
tests/fixtures/docker_repo/cat/cat2/a/build.yaml
vendored
Normal file
10
tests/fixtures/docker_repo/cat/cat2/a/build.yaml
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
prelude:
|
||||
- echo foo > /test
|
||||
- echo bar > /test2
|
||||
steps:
|
||||
- echo artifact3 > /test3
|
||||
- echo artifact4 > /test4
|
||||
requires:
|
||||
- category: "test"
|
||||
name: "b"
|
||||
version: "1.0"
|
8
tests/fixtures/docker_repo/cat/cat2/a/definition.yaml
vendored
Normal file
8
tests/fixtures/docker_repo/cat/cat2/a/definition.yaml
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
category: "test"
|
||||
name: "a"
|
||||
version: "1.0"
|
||||
requires:
|
||||
- category: "test"
|
||||
name: "b"
|
||||
version: "1.0"
|
||||
|
11
tests/fixtures/docker_repo/d/build.yaml
vendored
Normal file
11
tests/fixtures/docker_repo/d/build.yaml
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
prelude:
|
||||
- echo foo > /test
|
||||
- echo bar > /test2
|
||||
steps:
|
||||
- echo s > /d
|
||||
- echo dd > /dd
|
||||
requires:
|
||||
- category: "test"
|
||||
name: "c"
|
||||
version: "1.0"
|
||||
|
3
tests/fixtures/docker_repo/d/definition.yaml
vendored
Normal file
3
tests/fixtures/docker_repo/d/definition.yaml
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
category: "test"
|
||||
name: "d"
|
||||
version: "1.0"
|
3
tests/fixtures/docker_repo/interpolated/build.yaml
vendored
Normal file
3
tests/fixtures/docker_repo/interpolated/build.yaml
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
steps:
|
||||
- echo s > /interpolated-{{.Values.foo}}-{{.Values.extra}}
|
||||
image: "alpine"
|
4
tests/fixtures/docker_repo/interpolated/definition.yaml
vendored
Normal file
4
tests/fixtures/docker_repo/interpolated/definition.yaml
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
category: "test"
|
||||
name: "interpolated"
|
||||
version: "1.0+2"
|
||||
foo: "bar"
|
3
tests/fixtures/docker_repo/z/build.yaml
vendored
Normal file
3
tests/fixtures/docker_repo/z/build.yaml
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
steps:
|
||||
- echo s > /z
|
||||
image: "alpine"
|
3
tests/fixtures/docker_repo/z/definition.yaml
vendored
Normal file
3
tests/fixtures/docker_repo/z/definition.yaml
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
category: "test"
|
||||
name: "z"
|
||||
version: "1.0+2"
|
8
tests/fixtures/join/c/a/build.yaml
vendored
Normal file
8
tests/fixtures/join/c/a/build.yaml
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
join:
|
||||
- name: "a"
|
||||
category: "test"
|
||||
version: ">=0"
|
||||
- name: "b"
|
||||
category: "test"
|
||||
version: ">=0"
|
||||
unpack: true
|
3
tests/fixtures/join/c/a/definition.yaml
vendored
Normal file
3
tests/fixtures/join/c/a/definition.yaml
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
category: "test"
|
||||
name: "c"
|
||||
version: "1.2"
|
7
tests/fixtures/join/cat/a/a/build.yaml
vendored
Normal file
7
tests/fixtures/join/cat/a/a/build.yaml
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
image: "alpine"
|
||||
prelude:
|
||||
- echo foo > /test
|
||||
- echo bar > /test2
|
||||
steps:
|
||||
- echo artifact3 > /test3
|
||||
- echo artifact4 > /test4
|
3
tests/fixtures/join/cat/a/a/definition.yaml
vendored
Normal file
3
tests/fixtures/join/cat/a/a/definition.yaml
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
category: "test"
|
||||
name: "a"
|
||||
version: "1.2"
|
13
tests/fixtures/join/cat/b-1.1/build.yaml
vendored
Normal file
13
tests/fixtures/join/cat/b-1.1/build.yaml
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
requires:
|
||||
- category: "test"
|
||||
name: "a"
|
||||
version: ">=0"
|
||||
|
||||
prelude:
|
||||
- echo foo > /test
|
||||
- echo bar > /test2
|
||||
steps:
|
||||
- echo artifact5 > /newc
|
||||
- echo artifact6 > /newnewc
|
||||
- chmod +x generate.sh
|
||||
- ./generate.sh
|
3
tests/fixtures/join/cat/b-1.1/definition.yaml
vendored
Normal file
3
tests/fixtures/join/cat/b-1.1/definition.yaml
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
category: "test"
|
||||
name: "b"
|
||||
version: "1.1"
|
1
tests/fixtures/join/cat/b-1.1/generate.sh
vendored
Normal file
1
tests/fixtures/join/cat/b-1.1/generate.sh
vendored
Normal file
@@ -0,0 +1 @@
|
||||
echo generated > /sonewc
|
7
tests/fixtures/join_complex/c/c1/build.yaml
vendored
Normal file
7
tests/fixtures/join_complex/c/c1/build.yaml
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
join:
|
||||
- name: "a"
|
||||
category: "test"
|
||||
version: ">=0"
|
||||
- name: "b"
|
||||
category: "test"
|
||||
version: ">=0"
|
3
tests/fixtures/join_complex/c/c1/definition.yaml
vendored
Normal file
3
tests/fixtures/join_complex/c/c1/definition.yaml
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
category: "test"
|
||||
name: "c"
|
||||
version: "1.2"
|
8
tests/fixtures/join_complex/c/f/build.yaml
vendored
Normal file
8
tests/fixtures/join_complex/c/f/build.yaml
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
join:
|
||||
- name: "a"
|
||||
category: "test"
|
||||
version: ">=0"
|
||||
- name: "b"
|
||||
category: "test"
|
||||
version: ">=0"
|
||||
unpack: true
|
3
tests/fixtures/join_complex/c/f/definition.yaml
vendored
Normal file
3
tests/fixtures/join_complex/c/f/definition.yaml
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
category: "test"
|
||||
name: "f"
|
||||
version: "1.2"
|
2
tests/fixtures/join_complex/cat/a/a/build.yaml
vendored
Normal file
2
tests/fixtures/join_complex/cat/a/a/build.yaml
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
image: "alpine"
|
||||
unpack: true
|
3
tests/fixtures/join_complex/cat/a/a/definition.yaml
vendored
Normal file
3
tests/fixtures/join_complex/cat/a/a/definition.yaml
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
category: "test"
|
||||
name: "a"
|
||||
version: "1.2"
|
13
tests/fixtures/join_complex/cat/b-1.1/build.yaml
vendored
Normal file
13
tests/fixtures/join_complex/cat/b-1.1/build.yaml
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
requires:
|
||||
- category: "test"
|
||||
name: "a"
|
||||
version: ">=0"
|
||||
|
||||
prelude:
|
||||
- echo foo > /test
|
||||
- echo bar > /test2
|
||||
steps:
|
||||
- echo artifact5 > /newc
|
||||
- echo artifact6 > /newnewc
|
||||
- chmod +x generate.sh
|
||||
- ./generate.sh
|
3
tests/fixtures/join_complex/cat/b-1.1/definition.yaml
vendored
Normal file
3
tests/fixtures/join_complex/cat/b-1.1/definition.yaml
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
category: "test"
|
||||
name: "b"
|
||||
version: "1.1"
|
1
tests/fixtures/join_complex/cat/b-1.1/generate.sh
vendored
Normal file
1
tests/fixtures/join_complex/cat/b-1.1/generate.sh
vendored
Normal file
@@ -0,0 +1 @@
|
||||
echo generated > /sonewc
|
10
tests/fixtures/join_complex/x/build.yaml
vendored
Normal file
10
tests/fixtures/join_complex/x/build.yaml
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
join:
|
||||
- category: "test"
|
||||
name: "f"
|
||||
version: ">=0"
|
||||
# this is actually a virtual, no files shipped in c
|
||||
- category: "test"
|
||||
name: "c"
|
||||
version: ">=0"
|
||||
steps:
|
||||
- mv /newnewc /x
|
3
tests/fixtures/join_complex/x/definition.yaml
vendored
Normal file
3
tests/fixtures/join_complex/x/definition.yaml
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
name: "x"
|
||||
category: "test"
|
||||
version: "0.1"
|
6
tests/fixtures/join_complex/z/build.yaml
vendored
Normal file
6
tests/fixtures/join_complex/z/build.yaml
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
requires:
|
||||
- category: "test"
|
||||
name: "c"
|
||||
version: ">=0"
|
||||
steps:
|
||||
- mv /newnewc /z
|
3
tests/fixtures/join_complex/z/definition.yaml
vendored
Normal file
3
tests/fixtures/join_complex/z/definition.yaml
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
name: "z"
|
||||
category: "test"
|
||||
version: "0.1"
|
11
tests/fixtures/perms/pkgA/0.1/build.yaml
vendored
Normal file
11
tests/fixtures/perms/pkgA/0.1/build.yaml
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
image: "alpine"
|
||||
unpack: true
|
||||
includes:
|
||||
- /foo
|
||||
- /foo/bar
|
||||
- /foo/bar/.keep
|
||||
steps:
|
||||
- mkdir -p /foo/bar
|
||||
- touch /foo/bar/.keep
|
||||
- chown 100:100 /foo/bar
|
||||
- chown 101:101 /foo/bar/.keep
|
3
tests/fixtures/perms/pkgA/0.1/definition.yaml
vendored
Normal file
3
tests/fixtures/perms/pkgA/0.1/definition.yaml
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
category: "test"
|
||||
name: "perms"
|
||||
version: "0.1"
|
7
tests/fixtures/perms/pkgB/0.1/build.yaml
vendored
Normal file
7
tests/fixtures/perms/pkgB/0.1/build.yaml
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
image: "alpine"
|
||||
|
||||
steps:
|
||||
- mkdir -p /foo/baz
|
||||
- touch /foo/baz/.keep
|
||||
- chown 100:100 /foo/baz
|
||||
- chown 101:101 /foo/baz/.keep
|
3
tests/fixtures/perms/pkgB/0.1/definition.yaml
vendored
Normal file
3
tests/fixtures/perms/pkgB/0.1/definition.yaml
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
category: "test"
|
||||
name: "perms2"
|
||||
version: "0.1"
|
4
tests/fixtures/plugin/test-foo
vendored
4
tests/fixtures/plugin/test-foo
vendored
@@ -1,3 +1,5 @@
|
||||
#!/bin/bash
|
||||
echo "$1" >> $EVENT_FILE
|
||||
echo "$2" >> $PAYLOAD_FILE
|
||||
echo "$2" >> $PAYLOAD_FILE
|
||||
|
||||
echo "{}"
|
10
tests/fixtures/upgrade_old_repo_revision_content_changed/c/build.yaml
vendored
Normal file
10
tests/fixtures/upgrade_old_repo_revision_content_changed/c/build.yaml
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
prelude:
|
||||
- echo foo > /test
|
||||
- echo bar > /test2
|
||||
steps:
|
||||
- echo c > /c
|
||||
- echo c > /cd
|
||||
requires:
|
||||
- category: "test"
|
||||
name: "a"
|
||||
version: ">=1.0"
|
3
tests/fixtures/upgrade_old_repo_revision_content_changed/c/definition.yaml
vendored
Normal file
3
tests/fixtures/upgrade_old_repo_revision_content_changed/c/definition.yaml
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
category: "test"
|
||||
name: "c"
|
||||
version: "1.0"
|
11
tests/fixtures/upgrade_old_repo_revision_content_changed/cat/a/a/build.yaml
vendored
Normal file
11
tests/fixtures/upgrade_old_repo_revision_content_changed/cat/a/a/build.yaml
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
image: "alpine"
|
||||
prelude:
|
||||
- echo fozo > /test
|
||||
- echo bar > /test2
|
||||
steps:
|
||||
- echo artifact3 > /test3
|
||||
- echo artifact4 > /test4
|
||||
requires:
|
||||
- category: "test"
|
||||
name: "b"
|
||||
version: "1.0"
|
8
tests/fixtures/upgrade_old_repo_revision_content_changed/cat/a/a/definition.yaml
vendored
Normal file
8
tests/fixtures/upgrade_old_repo_revision_content_changed/cat/a/a/definition.yaml
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
category: "test"
|
||||
name: "a"
|
||||
version: "1.1"
|
||||
requires:
|
||||
- category: "test2"
|
||||
name: "b"
|
||||
version: "1.0"
|
||||
|
9
tests/fixtures/upgrade_old_repo_revision_content_changed/cat/b-1.1/build.yaml
vendored
Normal file
9
tests/fixtures/upgrade_old_repo_revision_content_changed/cat/b-1.1/build.yaml
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
image: "alpine"
|
||||
prelude:
|
||||
- echo foo > /test
|
||||
- echo bar > /test2
|
||||
steps:
|
||||
- echo artifact5 > /newc
|
||||
- echo artifact6 > /newnewc
|
||||
- chmod +x generate.sh
|
||||
- ./generate.sh
|
3
tests/fixtures/upgrade_old_repo_revision_content_changed/cat/b-1.1/definition.yaml
vendored
Normal file
3
tests/fixtures/upgrade_old_repo_revision_content_changed/cat/b-1.1/definition.yaml
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
category: "test"
|
||||
name: "b"
|
||||
version: "1.0"
|
1
tests/fixtures/upgrade_old_repo_revision_content_changed/cat/b-1.1/generate.sh
vendored
Normal file
1
tests/fixtures/upgrade_old_repo_revision_content_changed/cat/b-1.1/generate.sh
vendored
Normal file
@@ -0,0 +1 @@
|
||||
echo generated > /sonewc
|
@@ -3,27 +3,41 @@
|
||||
export LUET_NOLOCK=true
|
||||
|
||||
oneTimeSetUp() {
|
||||
export tmpdir="$(mktemp -d)"
|
||||
export tmpdir="$(mktemp -d)"
|
||||
docker images --filter='reference=luet/cache' --format='{{.Repository}}:{{.Tag}}' | xargs -r docker rmi
|
||||
}
|
||||
|
||||
oneTimeTearDown() {
|
||||
rm -rf "$tmpdir"
|
||||
docker images --filter='reference=luet/cache' --format='{{.Repository}}:{{.Tag}}' | xargs -r docker rmi
|
||||
}
|
||||
|
||||
testBuild() {
|
||||
# Disable tests which require a DOCKER registry
|
||||
[ -z "${TEST_DOCKER_IMAGE:-}" ] && startSkipping
|
||||
cat <<EOF > $tmpdir/default.yaml
|
||||
extra: "bar"
|
||||
foo: "baz"
|
||||
EOF
|
||||
mkdir $tmpdir/testbuild
|
||||
luet build --tree "$ROOT_DIR/tests/fixtures/buildableseed" --destination $tmpdir/testbuild --compression zstd test/c@1.0 > /dev/null
|
||||
luet build --tree "$ROOT_DIR/tests/fixtures/docker_repo" \
|
||||
--destination $tmpdir/testbuild --concurrency 1 \
|
||||
--image-repository "${TEST_DOCKER_IMAGE}-cache" --push \
|
||||
--compression zstd --values $tmpdir/default.yaml \
|
||||
test/c@1.0 test/z test/interpolated #> /dev/null
|
||||
buildst=$?
|
||||
assertEquals 'builds successfully' "$buildst" "0"
|
||||
assertTrue 'create package dep B' "[ -e '$tmpdir/testbuild/b-test-1.0.package.tar.zst' ]"
|
||||
assertTrue 'create package' "[ -e '$tmpdir/testbuild/c-test-1.0.package.tar.zst' ]"
|
||||
assertTrue 'create package z' "[ -e '$tmpdir/testbuild/z-test-1.0+2.package.tar.zst' ]"
|
||||
assertTrue 'create package interpolated' "[ -e '$tmpdir/testbuild/interpolated-test-1.0+2.package.tar.zst' ]"
|
||||
}
|
||||
|
||||
testRepo() {
|
||||
# Disable tests which require a DOCKER registry
|
||||
[ -z "${TEST_DOCKER_IMAGE:-}" ] && startSkipping
|
||||
|
||||
luet create-repo --tree "$ROOT_DIR/tests/fixtures/buildableseed" \
|
||||
createres=$(luet create-repo --tree "$ROOT_DIR/tests/fixtures/docker_repo" \
|
||||
--output "${TEST_DOCKER_IMAGE}" \
|
||||
--packages $tmpdir/testbuild \
|
||||
--name "test" \
|
||||
@@ -33,10 +47,11 @@ testRepo() {
|
||||
--tree-filename foo.tar \
|
||||
--meta-filename repository.meta.tar \
|
||||
--meta-compression zstd \
|
||||
--type docker --push-images --force-push
|
||||
--type docker --push-images --force-push)
|
||||
|
||||
createst=$?
|
||||
assertEquals 'create repo successfully' "$createst" "0"
|
||||
assertContains 'contains image push' "$createres" 'Pushed image: quay.io/mocaccinoos/integration-test:z-test-1.0-2'
|
||||
}
|
||||
|
||||
testConfig() {
|
||||
@@ -65,10 +80,12 @@ testInstall() {
|
||||
# Disable tests which require a DOCKER registry
|
||||
[ -z "${TEST_DOCKER_IMAGE:-}" ] && startSkipping
|
||||
|
||||
luet install -y --config $tmpdir/luet.yaml test/c@1.0
|
||||
luet install -y --config $tmpdir/luet.yaml test/c@1.0 test/z test/interpolated
|
||||
installst=$?
|
||||
assertEquals 'install test successfully' "$installst" "0"
|
||||
assertTrue 'package installed' "[ -e '$tmpdir/testrootfs/c' ]"
|
||||
assertTrue 'package Z installed' "[ -e '$tmpdir/testrootfs/z' ]"
|
||||
assertTrue 'package interpolated installed' "[ -e '$tmpdir/testrootfs/interpolated-baz-bar' ]"
|
||||
}
|
||||
|
||||
testReInstall() {
|
||||
@@ -85,10 +102,11 @@ testUnInstall() {
|
||||
# Disable tests which require a DOCKER registry
|
||||
[ -z "${TEST_DOCKER_IMAGE:-}" ] && startSkipping
|
||||
|
||||
luet uninstall -y --config $tmpdir/luet.yaml test/c@1.0
|
||||
luet uninstall -y --config $tmpdir/luet.yaml test/c@1.0 test/z
|
||||
installst=$?
|
||||
assertEquals 'uninstall test successfully' "$installst" "0"
|
||||
assertTrue 'package uninstalled' "[ ! -e '$tmpdir/testrootfs/c' ]"
|
||||
assertTrue 'package Z uninstalled' "[ ! -e '$tmpdir/testrootfs/z' ]"
|
||||
}
|
||||
|
||||
testInstallAgain() {
|
||||
@@ -96,11 +114,13 @@ testInstallAgain() {
|
||||
[ -z "${TEST_DOCKER_IMAGE:-}" ] && startSkipping
|
||||
|
||||
assertTrue 'package uninstalled' "[ ! -e '$tmpdir/testrootfs/c' ]"
|
||||
output=$(luet install -y --config $tmpdir/luet.yaml test/c@1.0)
|
||||
output=$(luet install -y --config $tmpdir/luet.yaml test/c@1.0 test/z)
|
||||
installst=$?
|
||||
assertEquals 'install test successfully' "$installst" "0"
|
||||
assertNotContains 'contains warning' "$output" 'No packages to install'
|
||||
assertTrue 'package installed' "[ -e '$tmpdir/testrootfs/c' ]"
|
||||
assertTrue 'package Z installed' "[ -e '$tmpdir/testrootfs/z' ]"
|
||||
assertTrue 'package Z in cache' "[ -e '$tmpdir/testrootfs/packages/z-test-1.0+2.package.tar.zst' ]"
|
||||
assertTrue 'package in cache' "[ -e '$tmpdir/testrootfs/packages/c-test-1.0.package.tar.zst' ]"
|
||||
}
|
||||
|
||||
|
@@ -95,13 +95,6 @@ testInstall() {
|
||||
installst=$?
|
||||
assertEquals 'install test successfully' "$installst" "0"
|
||||
|
||||
luet install -y --config $tmpdir/luet.yaml test/a@1.1
|
||||
assertTrue 'package installed A' "[ -e '$tmpdir/testrootfs/testaa' ]"
|
||||
installst=$?
|
||||
assertEquals 'install test successfully' "$installst" "0"
|
||||
assertTrue 'package keeps old A' "[ -e '$tmpdir/testrootfs/testaa' ]"
|
||||
assertTrue 'package new A was not installed' "[ ! -e '$tmpdir/testrootfs/testlatest' ]"
|
||||
|
||||
luet install -y --config $tmpdir/luet.yaml test/c@1.0
|
||||
installst=$?
|
||||
assertEquals 'install test successfully' "$installst" "0"
|
||||
|
@@ -84,26 +84,11 @@ EOF
|
||||
}
|
||||
|
||||
testInstall() {
|
||||
luet install -y --config $tmpdir/luet.yaml test/b@1.0
|
||||
luet install -y --config $tmpdir/luet.yaml test/b@1.0 test/a@1.0 test/c@1.0
|
||||
installst=$?
|
||||
assertEquals 'install test successfully' "$installst" "0"
|
||||
assertTrue 'package installed B' "[ -e '$tmpdir/testrootfs/test5' ]"
|
||||
|
||||
luet install -y --config $tmpdir/luet.yaml test/a@1.0
|
||||
assertTrue 'package installed A' "[ -e '$tmpdir/testrootfs/testaa' ]"
|
||||
installst=$?
|
||||
assertEquals 'install test successfully' "$installst" "0"
|
||||
|
||||
luet install -y --config $tmpdir/luet.yaml test/a@1.1
|
||||
assertTrue 'package installed A' "[ -e '$tmpdir/testrootfs/testaa' ]"
|
||||
installst=$?
|
||||
assertEquals 'install test successfully' "$installst" "0"
|
||||
assertTrue 'package keeps old A' "[ -e '$tmpdir/testrootfs/testaa' ]"
|
||||
assertTrue 'package new A was not installed' "[ ! -e '$tmpdir/testrootfs/testlatest' ]"
|
||||
|
||||
luet install -y --config $tmpdir/luet.yaml test/c@1.0
|
||||
installst=$?
|
||||
assertEquals 'install test successfully' "$installst" "0"
|
||||
assertTrue 'package installed C' "[ -e '$tmpdir/testrootfs/c' ]"
|
||||
}
|
||||
|
||||
|
@@ -85,26 +85,11 @@ EOF
|
||||
}
|
||||
|
||||
testInstall() {
|
||||
luet install -y --config $tmpdir/luet.yaml test/b@1.0
|
||||
luet install -y --config $tmpdir/luet.yaml test/b@1.0 test/a@1.0 test/c@1.0
|
||||
installst=$?
|
||||
assertEquals 'install test successfully' "$installst" "0"
|
||||
assertTrue 'package installed B' "[ -e '$tmpdir/testrootfs/test5' ]"
|
||||
|
||||
luet install -y --config $tmpdir/luet.yaml test/a@1.0
|
||||
assertTrue 'package installed A' "[ -e '$tmpdir/testrootfs/testaa' ]"
|
||||
installst=$?
|
||||
assertEquals 'install test successfully' "$installst" "0"
|
||||
|
||||
luet install -y --config $tmpdir/luet.yaml test/a@1.1
|
||||
assertTrue 'package installed A' "[ -e '$tmpdir/testrootfs/testaa' ]"
|
||||
installst=$?
|
||||
assertEquals 'install test successfully' "$installst" "0"
|
||||
assertTrue 'package keeps old A' "[ -e '$tmpdir/testrootfs/testaa' ]"
|
||||
assertTrue 'package new A was not installed' "[ ! -e '$tmpdir/testrootfs/testlatest' ]"
|
||||
|
||||
luet install -y --config $tmpdir/luet.yaml test/c@1.0
|
||||
installst=$?
|
||||
assertEquals 'install test successfully' "$installst" "0"
|
||||
assertTrue 'package installed C' "[ -e '$tmpdir/testrootfs/c' ]"
|
||||
}
|
||||
|
||||
|
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
|
||||
|
79
tests/integration/16_perms.sh
Executable file
79
tests/integration/16_perms.sh
Executable file
@@ -0,0 +1,79 @@
|
||||
#!/bin/bash
|
||||
|
||||
export LUET_NOLOCK=true
|
||||
|
||||
oneTimeSetUp() {
|
||||
export tmpdir="$(mktemp -d)"
|
||||
}
|
||||
|
||||
oneTimeTearDown() {
|
||||
rm -rf "$tmpdir"
|
||||
}
|
||||
|
||||
testBuild() {
|
||||
[ "$LUET_BACKEND" == "img" ] && startSkipping
|
||||
mkdir $tmpdir/testbuild
|
||||
luet build -d --tree "$ROOT_DIR/tests/fixtures/perms" --same-owner=true --destination $tmpdir/testbuild --compression gzip --full
|
||||
buildst=$?
|
||||
assertTrue 'create package perms 0.1' "[ -e '$tmpdir/testbuild/perms-test-0.1.package.tar.gz' ]"
|
||||
assertEquals 'builds successfully' "$buildst" "0"
|
||||
}
|
||||
|
||||
testRepo() {
|
||||
[ "$LUET_BACKEND" == "img" ] && startSkipping
|
||||
assertTrue 'no repository' "[ ! -e '$tmpdir/testbuild/repository.yaml' ]"
|
||||
luet create-repo --tree "$ROOT_DIR/tests/fixtures/perms" \
|
||||
--output $tmpdir/testbuild \
|
||||
--packages $tmpdir/testbuild \
|
||||
--name "test" \
|
||||
--descr "Test Repo" \
|
||||
--urls $tmpdir/testrootfs \
|
||||
--type http
|
||||
|
||||
createst=$?
|
||||
assertEquals 'create repo successfully' "$createst" "0"
|
||||
assertTrue 'create repository' "[ -e '$tmpdir/testbuild/repository.yaml' ]"
|
||||
}
|
||||
|
||||
testConfig() {
|
||||
[ "$LUET_BACKEND" == "img" ] && startSkipping
|
||||
mkdir $tmpdir/testrootfs
|
||||
cat <<EOF > $tmpdir/luet.yaml
|
||||
general:
|
||||
debug: true
|
||||
system:
|
||||
rootfs: $tmpdir/testrootfs
|
||||
database_path: "/"
|
||||
database_engine: "boltdb"
|
||||
config_from_host: true
|
||||
repositories:
|
||||
- name: "main"
|
||||
type: "disk"
|
||||
enable: true
|
||||
urls:
|
||||
- "$tmpdir/testbuild"
|
||||
EOF
|
||||
luet config --config $tmpdir/luet.yaml
|
||||
res=$?
|
||||
assertEquals 'config test successfully' "$res" "0"
|
||||
}
|
||||
|
||||
testInstall() {
|
||||
[ "$LUET_BACKEND" == "img" ] && startSkipping
|
||||
$ROOT_DIR/tests/integration/bin/luet install -y --config $tmpdir/luet.yaml test/perms@0.1 test/perms2@0.1
|
||||
installst=$?
|
||||
assertEquals 'install test successfully' "$installst" "0"
|
||||
|
||||
assertTrue 'package installed perms baz' "[ -d '$tmpdir/testrootfs/foo/baz' ]"
|
||||
assertTrue 'package installed perms bar' "[ -d '$tmpdir/testrootfs/foo/bar' ]"
|
||||
|
||||
assertContains 'perms1' "$(stat -c %u:%g $tmpdir/testrootfs/foo/baz)" "100:100"
|
||||
assertContains 'perms2' "$(stat -c %u:%g $tmpdir/testrootfs/foo/bar)" "100:100"
|
||||
assertContains 'perms11' "$(stat -c %u:%g $tmpdir/testrootfs/foo/baz/.keep)" "101:101"
|
||||
assertContains 'perms22' "$(stat -c %u:%g $tmpdir/testrootfs/foo/bar/.keep)" "101:101"
|
||||
}
|
||||
|
||||
|
||||
# Load shUnit2.
|
||||
. "$ROOT_DIR/tests/integration/shunit2"/shunit2
|
||||
|
@@ -3,11 +3,13 @@
|
||||
export LUET_NOLOCK=true
|
||||
|
||||
oneTimeSetUp() {
|
||||
export tmpdir="$(mktemp -d)"
|
||||
export tmpdir="$(mktemp -d)"
|
||||
docker images --filter='reference=luet/cache' --format='{{.Repository}}:{{.Tag}}' | xargs -r docker rmi
|
||||
}
|
||||
|
||||
oneTimeTearDown() {
|
||||
rm -rf "$tmpdir"
|
||||
docker images --filter='reference=luet/cache' --format='{{.Repository}}:{{.Tag}}' | xargs -r docker rmi
|
||||
}
|
||||
|
||||
testBuild() {
|
||||
@@ -15,7 +17,7 @@ testBuild() {
|
||||
bb: "ttt"
|
||||
EOF
|
||||
mkdir $tmpdir/testbuild
|
||||
luet build --tree "$ROOT_DIR/tests/fixtures/build_values" --values $tmpdir/default.yaml --destination $tmpdir/testbuild --compression gzip --all
|
||||
luet build --tree "$ROOT_DIR/tests/fixtures/build_values" --values $tmpdir/default.yaml --destination $tmpdir/testbuild --compression gzip distro/a distro/b test/foo distro/c
|
||||
buildst=$?
|
||||
assertEquals 'builds successfully' "$buildst" "0"
|
||||
assertTrue 'create package B' "[ -e '$tmpdir/testbuild/b-distro-0.3.package.tar.gz' ]"
|
||||
@@ -63,7 +65,7 @@ EOF
|
||||
testBuildWithNoTree() {
|
||||
mkdir $tmpdir/testbuild2
|
||||
mkdir $tmpdir/emptytree
|
||||
luet build --from-repositories --tree $tmpdir/emptytree --config $tmpdir/luet.yaml test/c --destination $tmpdir/testbuild2 --compression gzip --all
|
||||
luet build --from-repositories --tree $tmpdir/emptytree --config $tmpdir/luet.yaml distro/c --destination $tmpdir/testbuild2 --compression gzip distro/a distro/b test/foo distro/c
|
||||
buildst=$?
|
||||
assertEquals 'builds successfully' "$buildst" "0"
|
||||
assertTrue 'create package B' "[ -e '$tmpdir/testbuild2/b-distro-0.3.package.tar.gz' ]"
|
||||
@@ -187,7 +189,7 @@ foo: "sq"
|
||||
EOF
|
||||
mkdir $tmpdir/testbuild3
|
||||
mkdir $tmpdir/emptytree
|
||||
luet build --from-repositories --values $tmpdir/default.yaml --tree $tmpdir/emptytree --config $tmpdir/luet.yaml test/c --destination $tmpdir/testbuild3 --compression gzip --all
|
||||
luet build --from-repositories --values $tmpdir/default.yaml --tree $tmpdir/emptytree --config $tmpdir/luet.yaml distro/c --destination $tmpdir/testbuild3 --compression gzip distro/a distro/b test/foo
|
||||
buildst=$?
|
||||
assertEquals 'builds successfully' "$buildst" "0"
|
||||
assertTrue 'create package B' "[ -e '$tmpdir/testbuild3/b-distro-0.3.package.tar.gz' ]"
|
||||
@@ -239,7 +241,6 @@ EOF
|
||||
assertTrue 'package installed A interpolated with values' "[ -e '$tmpdir/testrootfs3/a-newinterpolation' ]"
|
||||
# Finalizers can interpolate only on package field. No extra fields are allowed at this time.
|
||||
assertTrue 'finalizer executed on A' "[ -e '$tmpdir/testrootfs3/finalize-a' ]"
|
||||
|
||||
installed=$(luet --config $tmpdir/luet2.yaml search --installed .)
|
||||
searchst=$?
|
||||
assertEquals 'search exists successfully' "$searchst" "0"
|
||||
|
@@ -3,11 +3,13 @@
|
||||
export LUET_NOLOCK=true
|
||||
|
||||
oneTimeSetUp() {
|
||||
export tmpdir="$(mktemp -d)"
|
||||
export tmpdir="$(mktemp -d)"
|
||||
docker images --filter='reference=luet/cache' --format='{{.Repository}}:{{.Tag}}' | xargs -r docker rmi
|
||||
}
|
||||
|
||||
oneTimeTearDown() {
|
||||
rm -rf "$tmpdir"
|
||||
docker images --filter='reference=luet/cache' --format='{{.Repository}}:{{.Tag}}' | xargs -r docker rmi
|
||||
}
|
||||
|
||||
testConfig() {
|
||||
@@ -39,11 +41,19 @@ testBuild() {
|
||||
|
||||
mkdir $tmpdir/testbuild
|
||||
mkdir $tmpdir/empty
|
||||
luet build --tree "$tmpdir/empty" --config $tmpdir/luet.yaml --from-repositories --destination $tmpdir/testbuild --compression zstd test/c@1.0 > /dev/null
|
||||
build_output=$(luet build --pull --tree "$tmpdir/empty" \
|
||||
--config $tmpdir/luet.yaml --concurrency 1 \
|
||||
--from-repositories --destination $tmpdir/testbuild --compression zstd test/c@1.0 test/z test/interpolated)
|
||||
buildst=$?
|
||||
echo "$build_output"
|
||||
assertEquals 'builds successfully' "$buildst" "0"
|
||||
assertTrue 'create package dep B' "[ -e '$tmpdir/testbuild/b-test-1.0.package.tar.zst' ]"
|
||||
assertTrue 'create package' "[ -e '$tmpdir/testbuild/c-test-1.0.package.tar.zst' ]"
|
||||
assertTrue 'create package Z' "[ -e '$tmpdir/testbuild/z-test-1.0+2.package.tar.zst' ]"
|
||||
assertTrue 'create package interpolated' "[ -e '$tmpdir/testbuild/interpolated-test-1.0+2.package.tar.zst' ]"
|
||||
assertContains 'Does use the upstream cache without specifying it test/c' "$build_output" "Images available remotely for test/c-1.0 generating artifact from remote images: quay.io/mocaccinoos/integration-test-cache:ac34beb3fc2752bab54549db095dd6994d7531b88e1ff7f902d01ae80fdd030d"
|
||||
assertContains 'Does use the upstream cache without specifying it test/z' "$build_output" "Images available remotely for test/z-1.0+2 generating artifact from remote images: quay.io/mocaccinoos/integration-test-cache:d8b8881d50ae83646728bb28ad678fc14e4e003e4b0d0a66f8e6167c6116e024"
|
||||
assertContains 'Does use the upstream cache without specifying it test/interpolated' "$build_output" "Images available remotely for test/interpolated-1.0+2 generating artifact from remote images: quay.io/mocaccinoos/integration-test-cache:2aaccd929ebe5683f95c70c6ec8d68f240ceea8633f3350b94904ad73da5fd47"
|
||||
}
|
||||
|
||||
testRepo() {
|
||||
@@ -94,10 +104,12 @@ testInstall() {
|
||||
# Disable tests which require a DOCKER registry
|
||||
[ -z "${TEST_DOCKER_IMAGE:-}" ] && startSkipping
|
||||
|
||||
luet install -y --config $tmpdir/luet-client.yaml test/c@1.0
|
||||
luet install -y --config $tmpdir/luet-client.yaml test/c@1.0 test/z test/interpolated
|
||||
installst=$?
|
||||
assertEquals 'install test successfully' "$installst" "0"
|
||||
assertTrue 'package installed' "[ -e '$tmpdir/testrootfs/c' ]"
|
||||
assertTrue 'package Z installed' "[ -e '$tmpdir/testrootfs/z' ]"
|
||||
assertTrue 'package interpolated installed' "[ -e '$tmpdir/testrootfs/interpolated-baz-bar' ]"
|
||||
}
|
||||
|
||||
testReInstall() {
|
||||
|
163
tests/integration/29_nobuildtreeinheritvalues.sh
Executable file
163
tests/integration/29_nobuildtreeinheritvalues.sh
Executable file
@@ -0,0 +1,163 @@
|
||||
#!/bin/bash
|
||||
|
||||
export LUET_NOLOCK=true
|
||||
|
||||
oneTimeSetUp() {
|
||||
export tmpdir="$(mktemp -d)"
|
||||
docker images --filter='reference=luet/cache' --format='{{.Repository}}:{{.Tag}}' | xargs -r docker rmi
|
||||
}
|
||||
|
||||
oneTimeTearDown() {
|
||||
rm -rf "$tmpdir"
|
||||
docker images --filter='reference=luet/cache' --format='{{.Repository}}:{{.Tag}}' | xargs -r docker rmi
|
||||
}
|
||||
|
||||
testConfig() {
|
||||
[ -z "${TEST_DOCKER_IMAGE:-}" ] && startSkipping
|
||||
|
||||
mkdir $tmpdir/testrootfs
|
||||
cat <<EOF > $tmpdir/luet.yaml
|
||||
general:
|
||||
debug: true
|
||||
system:
|
||||
rootfs: $tmpdir/testrootfs
|
||||
database_path: "/"
|
||||
database_engine: "boltdb"
|
||||
config_from_host: true
|
||||
repositories:
|
||||
- name: "main"
|
||||
type: "docker"
|
||||
enable: true
|
||||
urls:
|
||||
- "${TEST_DOCKER_IMAGE}"
|
||||
EOF
|
||||
luet config --config $tmpdir/luet.yaml
|
||||
res=$?
|
||||
assertEquals 'config test successfully' "$res" "0"
|
||||
}
|
||||
|
||||
testBuild() {
|
||||
[ -z "${TEST_DOCKER_IMAGE:-}" ] && startSkipping
|
||||
cat <<EOF > $tmpdir/default.yaml
|
||||
extra: "an"
|
||||
EOF
|
||||
|
||||
mkdir $tmpdir/testbuild
|
||||
mkdir $tmpdir/empty
|
||||
|
||||
# Without --rebuild, the package gets ignored
|
||||
build_output=$(luet build --pull --tree "$tmpdir/empty" \
|
||||
--config $tmpdir/luet.yaml --values $tmpdir/default.yaml --concurrency 1 \
|
||||
--from-repositories --destination $tmpdir/testbuild --compression zstd test/c@1.0 test/z test/interpolated)
|
||||
buildst=$?
|
||||
echo "$build_output"
|
||||
assertEquals 'builds successfully' "$buildst" "0"
|
||||
assertTrue 'create package dep B' "[ -e '$tmpdir/testbuild/b-test-1.0.package.tar.zst' ]"
|
||||
assertTrue 'create package' "[ -e '$tmpdir/testbuild/c-test-1.0.package.tar.zst' ]"
|
||||
assertTrue 'create package Z' "[ -e '$tmpdir/testbuild/z-test-1.0+2.package.tar.zst' ]"
|
||||
assertTrue 'create package interpolated' "[ -e '$tmpdir/testbuild/interpolated-test-1.0+2.package.tar.zst' ]"
|
||||
assertNotContains 'Does NOT use the upstream cache without specifying it' "$build_output" "Images available remotely for test/interpolated-1.0+2 generating artifact from remote images: quay.io/mocaccinoos/integration-test-cache:2aaccd929ebe5683f95c70c6ec8d68f240ceea8633f3350b94904ad73da5fd47"
|
||||
assertContains 'Does generate a new hash as values changed build.yaml for test/interpolated-1.0+2 package image' "$build_output" "Building image luet/cache:c34b533cf76886c332fe9b2d3208f04265360a465a90c996cb4fcdaf959dee36 done"
|
||||
}
|
||||
|
||||
testRepo() {
|
||||
# Disable tests which require a DOCKER registry
|
||||
[ -z "${TEST_DOCKER_IMAGE:-}" ] && startSkipping
|
||||
|
||||
luet create-repo \
|
||||
--output "${TEST_DOCKER_IMAGE}-2" \
|
||||
--packages $tmpdir/testbuild \
|
||||
--name "test" \
|
||||
--descr "Test Repo" \
|
||||
--urls $tmpdir/testrootfs \
|
||||
--tree-compression zstd \
|
||||
--tree-filename foo.tar \
|
||||
--tree "$tmpdir/empty" --config $tmpdir/luet.yaml --from-repositories \
|
||||
--meta-filename repository.meta.tar \
|
||||
--meta-compression zstd \
|
||||
--type docker --push-images --force-push --debug
|
||||
|
||||
createst=$?
|
||||
assertEquals 'create repo successfully' "$createst" "0"
|
||||
}
|
||||
|
||||
testConfigClient() {
|
||||
[ -z "${TEST_DOCKER_IMAGE:-}" ] && startSkipping
|
||||
|
||||
cat <<EOF > $tmpdir/luet-client.yaml
|
||||
general:
|
||||
debug: true
|
||||
system:
|
||||
rootfs: $tmpdir/testrootfs
|
||||
database_path: "/"
|
||||
database_engine: "boltdb"
|
||||
config_from_host: true
|
||||
repositories:
|
||||
- name: "main"
|
||||
type: "docker"
|
||||
enable: true
|
||||
urls:
|
||||
- "${TEST_DOCKER_IMAGE}-2"
|
||||
EOF
|
||||
luet config --config $tmpdir/luet-client.yaml
|
||||
res=$?
|
||||
assertEquals 'config test successfully' "$res" "0"
|
||||
}
|
||||
|
||||
testInstall() {
|
||||
# Disable tests which require a DOCKER registry
|
||||
[ -z "${TEST_DOCKER_IMAGE:-}" ] && startSkipping
|
||||
|
||||
luet install -y --config $tmpdir/luet-client.yaml test/c@1.0 test/z test/interpolated
|
||||
installst=$?
|
||||
assertEquals 'install test successfully' "$installst" "0"
|
||||
assertTrue 'package installed' "[ -e '$tmpdir/testrootfs/c' ]"
|
||||
assertTrue 'package Z installed' "[ -e '$tmpdir/testrootfs/z' ]"
|
||||
ls -liah $tmpdir/testrootfs/
|
||||
assertTrue 'package interpolated installed' "[ -e '$tmpdir/testrootfs/interpolated-baz-an' ]"
|
||||
}
|
||||
|
||||
testReInstall() {
|
||||
# Disable tests which require a DOCKER registry
|
||||
[ -z "${TEST_DOCKER_IMAGE:-}" ] && startSkipping
|
||||
|
||||
output=$(luet install -y --config $tmpdir/luet-client.yaml test/c@1.0)
|
||||
installst=$?
|
||||
assertEquals 'install test successfully' "$installst" "0"
|
||||
assertContains 'contains warning' "$output" 'No packages to install'
|
||||
}
|
||||
|
||||
testUnInstall() {
|
||||
# Disable tests which require a DOCKER registry
|
||||
[ -z "${TEST_DOCKER_IMAGE:-}" ] && startSkipping
|
||||
|
||||
luet uninstall -y --config $tmpdir/luet-client.yaml test/c@1.0
|
||||
installst=$?
|
||||
assertEquals 'uninstall test successfully' "$installst" "0"
|
||||
assertTrue 'package uninstalled' "[ ! -e '$tmpdir/testrootfs/c' ]"
|
||||
}
|
||||
|
||||
testInstallAgain() {
|
||||
# Disable tests which require a DOCKER registry
|
||||
[ -z "${TEST_DOCKER_IMAGE:-}" ] && startSkipping
|
||||
|
||||
assertTrue 'package uninstalled' "[ ! -e '$tmpdir/testrootfs/c' ]"
|
||||
output=$(luet install -y --config $tmpdir/luet-client.yaml test/c@1.0)
|
||||
installst=$?
|
||||
assertEquals 'install test successfully' "$installst" "0"
|
||||
assertNotContains 'contains warning' "$output" 'No packages to install'
|
||||
assertTrue 'package installed' "[ -e '$tmpdir/testrootfs/c' ]"
|
||||
assertTrue 'package in cache' "[ -e '$tmpdir/testrootfs/packages/c-test-1.0.package.tar.zst' ]"
|
||||
}
|
||||
|
||||
testCleanup() {
|
||||
[ -z "${TEST_DOCKER_IMAGE:-}" ] && startSkipping
|
||||
|
||||
luet cleanup --config $tmpdir/luet-client.yaml
|
||||
installst=$?
|
||||
assertEquals 'cleanup test successfully' "$installst" "0"
|
||||
}
|
||||
|
||||
# Load shUnit2.
|
||||
. "$ROOT_DIR/tests/integration/shunit2"/shunit2
|
||||
|
162
tests/integration/29_nobuildtreeinheritvalues_noignored.sh
Executable file
162
tests/integration/29_nobuildtreeinheritvalues_noignored.sh
Executable file
@@ -0,0 +1,162 @@
|
||||
#!/bin/bash
|
||||
|
||||
export LUET_NOLOCK=true
|
||||
|
||||
oneTimeSetUp() {
|
||||
export tmpdir="$(mktemp -d)"
|
||||
docker images --filter='reference=luet/cache' --format='{{.Repository}}:{{.Tag}}' | xargs -r docker rmi
|
||||
}
|
||||
|
||||
oneTimeTearDown() {
|
||||
rm -rf "$tmpdir"
|
||||
docker images --filter='reference=luet/cache' --format='{{.Repository}}:{{.Tag}}' | xargs -r docker rmi
|
||||
}
|
||||
|
||||
testConfig() {
|
||||
[ -z "${TEST_DOCKER_IMAGE:-}" ] && startSkipping
|
||||
|
||||
mkdir $tmpdir/testrootfs
|
||||
cat <<EOF > $tmpdir/luet.yaml
|
||||
general:
|
||||
debug: true
|
||||
system:
|
||||
rootfs: $tmpdir/testrootfs
|
||||
database_path: "/"
|
||||
database_engine: "boltdb"
|
||||
config_from_host: true
|
||||
repositories:
|
||||
- name: "main"
|
||||
type: "docker"
|
||||
enable: true
|
||||
urls:
|
||||
- "${TEST_DOCKER_IMAGE}"
|
||||
EOF
|
||||
luet config --config $tmpdir/luet.yaml
|
||||
res=$?
|
||||
assertEquals 'config test successfully' "$res" "0"
|
||||
}
|
||||
|
||||
testBuild() {
|
||||
[ -z "${TEST_DOCKER_IMAGE:-}" ] && startSkipping
|
||||
cat <<EOF > $tmpdir/default.yaml
|
||||
extra: "an"
|
||||
EOF
|
||||
|
||||
mkdir $tmpdir/testbuild
|
||||
mkdir $tmpdir/empty
|
||||
|
||||
# With --rebuild, the package gets rebuild with the values applied
|
||||
build_output=$(luet build --pull --rebuild --tree "$tmpdir/empty" \
|
||||
--config $tmpdir/luet.yaml --values $tmpdir/default.yaml --concurrency 1 \
|
||||
--from-repositories --destination $tmpdir/testbuild --compression zstd test/c@1.0 test/z test/interpolated)
|
||||
buildst=$?
|
||||
echo "$build_output"
|
||||
assertEquals 'builds successfully' "$buildst" "0"
|
||||
assertTrue 'create package dep B' "[ -e '$tmpdir/testbuild/b-test-1.0.package.tar.zst' ]"
|
||||
assertTrue 'create package' "[ -e '$tmpdir/testbuild/c-test-1.0.package.tar.zst' ]"
|
||||
assertTrue 'create package Z' "[ -e '$tmpdir/testbuild/z-test-1.0+2.package.tar.zst' ]"
|
||||
assertTrue 'create package interpolated' "[ -e '$tmpdir/testbuild/interpolated-test-1.0+2.package.tar.zst' ]"
|
||||
assertContains 'Does use the upstream cache without specifying it' "$build_output" "Downloading image quay.io/mocaccinoos/integration-test-cache:4db24406e8db30a3310a1cf8c4d4e19597745e6d41b189dc51a73ac4a50cc9e6"
|
||||
}
|
||||
|
||||
testRepo() {
|
||||
# Disable tests which require a DOCKER registry
|
||||
[ -z "${TEST_DOCKER_IMAGE:-}" ] && startSkipping
|
||||
|
||||
luet create-repo \
|
||||
--output "${TEST_DOCKER_IMAGE}-2" \
|
||||
--packages $tmpdir/testbuild \
|
||||
--name "test" \
|
||||
--descr "Test Repo" \
|
||||
--urls $tmpdir/testrootfs \
|
||||
--tree-compression zstd \
|
||||
--tree-filename foo.tar \
|
||||
--tree "$tmpdir/empty" --config $tmpdir/luet.yaml --from-repositories \
|
||||
--meta-filename repository.meta.tar \
|
||||
--meta-compression zstd \
|
||||
--type docker --push-images --force-push --debug
|
||||
|
||||
createst=$?
|
||||
assertEquals 'create repo successfully' "$createst" "0"
|
||||
}
|
||||
|
||||
testConfigClient() {
|
||||
[ -z "${TEST_DOCKER_IMAGE:-}" ] && startSkipping
|
||||
|
||||
cat <<EOF > $tmpdir/luet-client.yaml
|
||||
general:
|
||||
debug: true
|
||||
system:
|
||||
rootfs: $tmpdir/testrootfs
|
||||
database_path: "/"
|
||||
database_engine: "boltdb"
|
||||
config_from_host: true
|
||||
repositories:
|
||||
- name: "main"
|
||||
type: "docker"
|
||||
enable: true
|
||||
urls:
|
||||
- "${TEST_DOCKER_IMAGE}-2"
|
||||
EOF
|
||||
luet config --config $tmpdir/luet-client.yaml
|
||||
res=$?
|
||||
assertEquals 'config test successfully' "$res" "0"
|
||||
}
|
||||
|
||||
testInstall() {
|
||||
# Disable tests which require a DOCKER registry
|
||||
[ -z "${TEST_DOCKER_IMAGE:-}" ] && startSkipping
|
||||
|
||||
luet install -y --config $tmpdir/luet-client.yaml test/c@1.0 test/z test/interpolated
|
||||
installst=$?
|
||||
assertEquals 'install test successfully' "$installst" "0"
|
||||
assertTrue 'package installed' "[ -e '$tmpdir/testrootfs/c' ]"
|
||||
assertTrue 'package Z installed' "[ -e '$tmpdir/testrootfs/z' ]"
|
||||
ls -liah $tmpdir/testrootfs/
|
||||
assertTrue 'package interpolated installed' "[ -e '$tmpdir/testrootfs/interpolated-baz-an' ]"
|
||||
}
|
||||
|
||||
testReInstall() {
|
||||
# Disable tests which require a DOCKER registry
|
||||
[ -z "${TEST_DOCKER_IMAGE:-}" ] && startSkipping
|
||||
|
||||
output=$(luet install -y --config $tmpdir/luet-client.yaml test/c@1.0)
|
||||
installst=$?
|
||||
assertEquals 'install test successfully' "$installst" "0"
|
||||
assertContains 'contains warning' "$output" 'No packages to install'
|
||||
}
|
||||
|
||||
testUnInstall() {
|
||||
# Disable tests which require a DOCKER registry
|
||||
[ -z "${TEST_DOCKER_IMAGE:-}" ] && startSkipping
|
||||
|
||||
luet uninstall -y --config $tmpdir/luet-client.yaml test/c@1.0
|
||||
installst=$?
|
||||
assertEquals 'uninstall test successfully' "$installst" "0"
|
||||
assertTrue 'package uninstalled' "[ ! -e '$tmpdir/testrootfs/c' ]"
|
||||
}
|
||||
|
||||
testInstallAgain() {
|
||||
# Disable tests which require a DOCKER registry
|
||||
[ -z "${TEST_DOCKER_IMAGE:-}" ] && startSkipping
|
||||
|
||||
assertTrue 'package uninstalled' "[ ! -e '$tmpdir/testrootfs/c' ]"
|
||||
output=$(luet install -y --config $tmpdir/luet-client.yaml test/c@1.0)
|
||||
installst=$?
|
||||
assertEquals 'install test successfully' "$installst" "0"
|
||||
assertNotContains 'contains warning' "$output" 'No packages to install'
|
||||
assertTrue 'package installed' "[ -e '$tmpdir/testrootfs/c' ]"
|
||||
assertTrue 'package in cache' "[ -e '$tmpdir/testrootfs/packages/c-test-1.0.package.tar.zst' ]"
|
||||
}
|
||||
|
||||
testCleanup() {
|
||||
[ -z "${TEST_DOCKER_IMAGE:-}" ] && startSkipping
|
||||
|
||||
luet cleanup --config $tmpdir/luet-client.yaml
|
||||
installst=$?
|
||||
assertEquals 'cleanup test successfully' "$installst" "0"
|
||||
}
|
||||
|
||||
# Load shUnit2.
|
||||
. "$ROOT_DIR/tests/integration/shunit2"/shunit2
|
||||
|
170
tests/integration/29_nobuildtreeinheritvalues_norebuild.sh
Executable file
170
tests/integration/29_nobuildtreeinheritvalues_norebuild.sh
Executable file
@@ -0,0 +1,170 @@
|
||||
#!/bin/bash
|
||||
|
||||
export LUET_NOLOCK=true
|
||||
|
||||
oneTimeSetUp() {
|
||||
export tmpdir="$(mktemp -d)"
|
||||
docker images --filter='reference=luet/cache' --format='{{.Repository}}:{{.Tag}}' | xargs -r docker rmi
|
||||
}
|
||||
|
||||
oneTimeTearDown() {
|
||||
rm -rf "$tmpdir"
|
||||
docker images --filter='reference=luet/cache' --format='{{.Repository}}:{{.Tag}}' | xargs -r docker rmi
|
||||
}
|
||||
|
||||
testConfig() {
|
||||
[ -z "${TEST_DOCKER_IMAGE:-}" ] && startSkipping
|
||||
|
||||
mkdir $tmpdir/testrootfs
|
||||
cat <<EOF > $tmpdir/luet.yaml
|
||||
general:
|
||||
debug: true
|
||||
system:
|
||||
rootfs: $tmpdir/testrootfs
|
||||
database_path: "/"
|
||||
database_engine: "boltdb"
|
||||
config_from_host: true
|
||||
repositories:
|
||||
- name: "main"
|
||||
type: "docker"
|
||||
enable: true
|
||||
urls:
|
||||
- "${TEST_DOCKER_IMAGE}"
|
||||
EOF
|
||||
luet config --config $tmpdir/luet.yaml
|
||||
res=$?
|
||||
assertEquals 'config test successfully' "$res" "0"
|
||||
}
|
||||
|
||||
testBuild() {
|
||||
[ -z "${TEST_DOCKER_IMAGE:-}" ] && startSkipping
|
||||
|
||||
# This will be ignored, as no --rebuild is supplied
|
||||
cat <<EOF > $tmpdir/default.yaml
|
||||
extra: "an"
|
||||
EOF
|
||||
|
||||
mkdir $tmpdir/testbuild
|
||||
mkdir $tmpdir/empty
|
||||
cp -rf "$ROOT_DIR/tests/fixtures/docker_repo/interpolated" $tmpdir/empty/
|
||||
|
||||
cat <<EOF > $tmpdir/empty/interpolated/definition.yaml
|
||||
category: "test"
|
||||
name: "interpolated"
|
||||
version: "1.1"
|
||||
foo: "bar"
|
||||
EOF
|
||||
|
||||
build_output=$(luet build --pull --tree "$tmpdir/empty" \
|
||||
--config $tmpdir/luet.yaml --values $tmpdir/default.yaml --concurrency 1 \
|
||||
--from-repositories --destination $tmpdir/testbuild --compression zstd test/c@1.0 test/z test/interpolated)
|
||||
buildst=$?
|
||||
echo "$build_output"
|
||||
assertEquals 'builds successfully' "$buildst" "0"
|
||||
assertTrue 'create package dep B' "[ -e '$tmpdir/testbuild/b-test-1.0.package.tar.zst' ]"
|
||||
assertTrue 'create package' "[ -e '$tmpdir/testbuild/c-test-1.0.package.tar.zst' ]"
|
||||
assertTrue 'create package Z' "[ -e '$tmpdir/testbuild/z-test-1.0+2.package.tar.zst' ]"
|
||||
assertTrue 'create package interpolated' "[ -e '$tmpdir/testbuild/interpolated-test-1.1.package.tar.zst' ]"
|
||||
}
|
||||
|
||||
testRepo() {
|
||||
# Disable tests which require a DOCKER registry
|
||||
[ -z "${TEST_DOCKER_IMAGE:-}" ] && startSkipping
|
||||
|
||||
luet create-repo \
|
||||
--output "${TEST_DOCKER_IMAGE}-2" \
|
||||
--packages $tmpdir/testbuild \
|
||||
--name "test" \
|
||||
--descr "Test Repo" \
|
||||
--urls $tmpdir/testrootfs \
|
||||
--tree-compression zstd \
|
||||
--tree-filename foo.tar \
|
||||
--tree "$tmpdir/empty" --config $tmpdir/luet.yaml --from-repositories \
|
||||
--meta-filename repository.meta.tar \
|
||||
--meta-compression zstd \
|
||||
--type docker --push-images --force-push --debug
|
||||
|
||||
createst=$?
|
||||
assertEquals 'create repo successfully' "$createst" "0"
|
||||
}
|
||||
|
||||
testConfigClient() {
|
||||
[ -z "${TEST_DOCKER_IMAGE:-}" ] && startSkipping
|
||||
|
||||
cat <<EOF > $tmpdir/luet-client.yaml
|
||||
general:
|
||||
debug: true
|
||||
system:
|
||||
rootfs: $tmpdir/testrootfs
|
||||
database_path: "/"
|
||||
database_engine: "boltdb"
|
||||
config_from_host: true
|
||||
repositories:
|
||||
- name: "main"
|
||||
type: "docker"
|
||||
enable: true
|
||||
urls:
|
||||
- "${TEST_DOCKER_IMAGE}-2"
|
||||
EOF
|
||||
luet config --config $tmpdir/luet-client.yaml
|
||||
res=$?
|
||||
assertEquals 'config test successfully' "$res" "0"
|
||||
}
|
||||
|
||||
testInstall() {
|
||||
# Disable tests which require a DOCKER registry
|
||||
[ -z "${TEST_DOCKER_IMAGE:-}" ] && startSkipping
|
||||
|
||||
luet install -y --config $tmpdir/luet-client.yaml test/c@1.0 test/z test/interpolated
|
||||
installst=$?
|
||||
assertEquals 'install test successfully' "$installst" "0"
|
||||
assertTrue 'package installed' "[ -e '$tmpdir/testrootfs/c' ]"
|
||||
assertTrue 'package Z installed' "[ -e '$tmpdir/testrootfs/z' ]"
|
||||
ls -liah $tmpdir/testrootfs/
|
||||
assertTrue 'package interpolated installed' "[ -e '$tmpdir/testrootfs/interpolated-bar-an' ]"
|
||||
}
|
||||
|
||||
testReInstall() {
|
||||
# Disable tests which require a DOCKER registry
|
||||
[ -z "${TEST_DOCKER_IMAGE:-}" ] && startSkipping
|
||||
|
||||
output=$(luet install -y --config $tmpdir/luet-client.yaml test/c@1.0)
|
||||
installst=$?
|
||||
assertEquals 'install test successfully' "$installst" "0"
|
||||
assertContains 'contains warning' "$output" 'No packages to install'
|
||||
}
|
||||
|
||||
testUnInstall() {
|
||||
# Disable tests which require a DOCKER registry
|
||||
[ -z "${TEST_DOCKER_IMAGE:-}" ] && startSkipping
|
||||
|
||||
luet uninstall -y --config $tmpdir/luet-client.yaml test/c@1.0
|
||||
installst=$?
|
||||
assertEquals 'uninstall test successfully' "$installst" "0"
|
||||
assertTrue 'package uninstalled' "[ ! -e '$tmpdir/testrootfs/c' ]"
|
||||
}
|
||||
|
||||
testInstallAgain() {
|
||||
# Disable tests which require a DOCKER registry
|
||||
[ -z "${TEST_DOCKER_IMAGE:-}" ] && startSkipping
|
||||
|
||||
assertTrue 'package uninstalled' "[ ! -e '$tmpdir/testrootfs/c' ]"
|
||||
output=$(luet install -y --config $tmpdir/luet-client.yaml test/c@1.0)
|
||||
installst=$?
|
||||
assertEquals 'install test successfully' "$installst" "0"
|
||||
assertNotContains 'contains warning' "$output" 'No packages to install'
|
||||
assertTrue 'package installed' "[ -e '$tmpdir/testrootfs/c' ]"
|
||||
assertTrue 'package in cache' "[ -e '$tmpdir/testrootfs/packages/c-test-1.0.package.tar.zst' ]"
|
||||
}
|
||||
|
||||
testCleanup() {
|
||||
[ -z "${TEST_DOCKER_IMAGE:-}" ] && startSkipping
|
||||
|
||||
luet cleanup --config $tmpdir/luet-client.yaml
|
||||
installst=$?
|
||||
assertEquals 'cleanup test successfully' "$installst" "0"
|
||||
}
|
||||
|
||||
# Load shUnit2.
|
||||
. "$ROOT_DIR/tests/integration/shunit2"/shunit2
|
||||
|
38
tests/integration/30_copy.sh
Executable file
38
tests/integration/30_copy.sh
Executable file
@@ -0,0 +1,38 @@
|
||||
#!/bin/bash
|
||||
|
||||
export LUET_NOLOCK=true
|
||||
|
||||
oneTimeSetUp() {
|
||||
export tmpdir="$(mktemp -d)"
|
||||
docker images --filter='reference=luet/cache' --format='{{.Repository}}:{{.Tag}}' | xargs -r docker rmi
|
||||
}
|
||||
|
||||
oneTimeTearDown() {
|
||||
rm -rf "$tmpdir"
|
||||
docker images --filter='reference=luet/cache' --format='{{.Repository}}:{{.Tag}}' | xargs -r docker rmi
|
||||
}
|
||||
|
||||
testBuild() {
|
||||
[ "$LUET_BACKEND" == "img" ] && startSkipping
|
||||
cat <<EOF > $tmpdir/default.yaml
|
||||
extra: "bar"
|
||||
foo: "baz"
|
||||
EOF
|
||||
mkdir $tmpdir/testbuild
|
||||
luet build --tree "$ROOT_DIR/tests/fixtures/copy" \
|
||||
--destination $tmpdir/testbuild --concurrency 1 \
|
||||
--compression gzip --values $tmpdir/default.yaml \
|
||||
test/c
|
||||
buildst=$?
|
||||
assertEquals 'builds successfully' "$buildst" "0"
|
||||
assertTrue 'create package c' "[ -e '$tmpdir/testbuild/c-test-1.2.package.tar.gz' ]"
|
||||
mkdir $tmpdir/extract
|
||||
tar -xvf $tmpdir/testbuild/c-test-1.2.package.tar.gz -C $tmpdir/extract
|
||||
assertTrue 'create result in package c' "[ -e '$tmpdir/extract/result' ]"
|
||||
assertTrue 'create busybox in package c' "[ -f '$tmpdir/extract/bina/busybox' ]"
|
||||
}
|
||||
|
||||
|
||||
# Load shUnit2.
|
||||
. "$ROOT_DIR/tests/integration/shunit2"/shunit2
|
||||
|
39
tests/integration/31_join.sh
Executable file
39
tests/integration/31_join.sh
Executable file
@@ -0,0 +1,39 @@
|
||||
#!/bin/bash
|
||||
|
||||
export LUET_NOLOCK=true
|
||||
|
||||
oneTimeSetUp() {
|
||||
export tmpdir="$(mktemp -d)"
|
||||
docker images --filter='reference=luet/cache' --format='{{.Repository}}:{{.Tag}}' | xargs -r docker rmi
|
||||
}
|
||||
|
||||
oneTimeTearDown() {
|
||||
rm -rf "$tmpdir"
|
||||
docker images --filter='reference=luet/cache' --format='{{.Repository}}:{{.Tag}}' | xargs -r docker rmi
|
||||
}
|
||||
|
||||
testBuild() {
|
||||
[ "$LUET_BACKEND" == "img" ] && startSkipping
|
||||
cat <<EOF > $tmpdir/default.yaml
|
||||
extra: "bar"
|
||||
foo: "baz"
|
||||
EOF
|
||||
mkdir $tmpdir/testbuild
|
||||
luet build --tree "$ROOT_DIR/tests/fixtures/join" \
|
||||
--destination $tmpdir/testbuild --concurrency 1 \
|
||||
--compression gzip --values $tmpdir/default.yaml \
|
||||
test/c
|
||||
buildst=$?
|
||||
assertEquals 'builds successfully' "$buildst" "0"
|
||||
assertTrue 'create package c' "[ -e '$tmpdir/testbuild/c-test-1.2.package.tar.gz' ]"
|
||||
mkdir $tmpdir/extract
|
||||
tar -xvf $tmpdir/testbuild/c-test-1.2.package.tar.gz -C $tmpdir/extract
|
||||
assertTrue 'create result from join' "[ -e '$tmpdir/extract/test3' ]"
|
||||
assertTrue 'create result from join' "[ -f '$tmpdir/extract/newc' ]"
|
||||
assertTrue 'create result from join' "[ -e '$tmpdir/extract/test4' ]"
|
||||
}
|
||||
|
||||
|
||||
# Load shUnit2.
|
||||
. "$ROOT_DIR/tests/integration/shunit2"/shunit2
|
||||
|
37
tests/integration/31_join_complex.sh
Executable file
37
tests/integration/31_join_complex.sh
Executable file
@@ -0,0 +1,37 @@
|
||||
#!/bin/bash
|
||||
|
||||
export LUET_NOLOCK=true
|
||||
|
||||
oneTimeSetUp() {
|
||||
export tmpdir="$(mktemp -d)"
|
||||
docker images --filter='reference=luet/cache' --format='{{.Repository}}:{{.Tag}}' | xargs -r docker rmi
|
||||
}
|
||||
|
||||
oneTimeTearDown() {
|
||||
rm -rf "$tmpdir"
|
||||
docker images --filter='reference=luet/cache' --format='{{.Repository}}:{{.Tag}}' | xargs -r docker rmi
|
||||
}
|
||||
|
||||
testBuild() {
|
||||
[ "$LUET_BACKEND" == "img" ] && startSkipping
|
||||
mkdir $tmpdir/testbuild
|
||||
luet build --tree "$ROOT_DIR/tests/fixtures/join_complex" \
|
||||
--destination $tmpdir/testbuild --concurrency 1 \
|
||||
--compression gzip \
|
||||
test/z test/x
|
||||
buildst=$?
|
||||
assertEquals 'builds successfully' "$buildst" "0"
|
||||
assertTrue 'create package z' "[ -e '$tmpdir/testbuild/z-test-0.1.package.tar.gz' ]"
|
||||
assertTrue 'create package z' "[ -e '$tmpdir/testbuild/x-test-0.1.package.tar.gz' ]"
|
||||
|
||||
mkdir $tmpdir/extract
|
||||
tar -xvf $tmpdir/testbuild/x-test-0.1.package.tar.gz -C $tmpdir/extract
|
||||
tar -xvf $tmpdir/testbuild/z-test-0.1.package.tar.gz -C $tmpdir/extract
|
||||
assertTrue 'create result from a package that requires a join' "[ -e '$tmpdir/extract/z' ]"
|
||||
assertTrue 'create result from join of a join' "[ -e '$tmpdir/extract/x' ]"
|
||||
}
|
||||
|
||||
|
||||
# Load shUnit2.
|
||||
. "$ROOT_DIR/tests/integration/shunit2"/shunit2
|
||||
|
@@ -1,6 +1,6 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
export LUET_NO_SPINNER=true
|
||||
export LUET_YES=true
|
||||
export ROOT_DIR="$(git rev-parse --show-toplevel)"
|
||||
|
||||
|
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.
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user