mirror of
https://github.com/mudler/luet.git
synced 2025-09-05 01:00:44 +00:00
Compare commits
34 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
02653e03d8 | ||
|
2c48fe0524 | ||
|
a0113dcd13 | ||
|
d45536505b | ||
|
92d335d5d1 | ||
|
49d7b4e2bf | ||
|
f15ed3fda1 | ||
|
2ad16fa875 | ||
|
416be23a46 | ||
|
98c7d5c450 | ||
|
50091b2a4b | ||
|
0067fa82a5 | ||
|
117554792d | ||
|
d0b7552aca | ||
|
454e9d934e | ||
|
dd91a61caf | ||
|
bc5d01c3df | ||
|
af7f1de9f1 | ||
|
3f5aa7db22 | ||
|
a0f9222068 | ||
|
520768d0ca | ||
|
4f002ab40f | ||
|
60635a03eb | ||
|
202ed2651a | ||
|
4e461fd6be | ||
|
6bd8fe6789 | ||
|
7cf6d51355 | ||
|
d5166c55ab | ||
|
7de5f6656d | ||
|
9e62111e1a | ||
|
655da7e883 | ||
|
8dbc266b39 | ||
|
5942e2f20c | ||
|
1a8fb77771 |
2
Makefile
2
Makefile
@@ -19,7 +19,7 @@ fmt:
|
|||||||
test:
|
test:
|
||||||
GO111MODULE=off go get github.com/onsi/ginkgo/ginkgo
|
GO111MODULE=off go get github.com/onsi/ginkgo/ginkgo
|
||||||
GO111MODULE=off go get github.com/onsi/gomega/...
|
GO111MODULE=off go get github.com/onsi/gomega/...
|
||||||
ginkgo -race -r ./...
|
ginkgo -race -r -flakeAttempts 3 ./...
|
||||||
|
|
||||||
.PHONY: test-integration
|
.PHONY: test-integration
|
||||||
test-integration:
|
test-integration:
|
||||||
|
@@ -40,7 +40,9 @@ var createrepoCmd = &cobra.Command{
|
|||||||
viper.BindPFlag("urls", cmd.Flags().Lookup("urls"))
|
viper.BindPFlag("urls", cmd.Flags().Lookup("urls"))
|
||||||
viper.BindPFlag("type", cmd.Flags().Lookup("type"))
|
viper.BindPFlag("type", cmd.Flags().Lookup("type"))
|
||||||
viper.BindPFlag("tree-compression", cmd.Flags().Lookup("tree-compression"))
|
viper.BindPFlag("tree-compression", cmd.Flags().Lookup("tree-compression"))
|
||||||
viper.BindPFlag("tree-path", cmd.Flags().Lookup("tree-path"))
|
viper.BindPFlag("tree-filename", cmd.Flags().Lookup("tree-filename"))
|
||||||
|
viper.BindPFlag("meta-compression", cmd.Flags().Lookup("meta-compression"))
|
||||||
|
viper.BindPFlag("meta-filename", cmd.Flags().Lookup("meta-filename"))
|
||||||
viper.BindPFlag("reset-revision", cmd.Flags().Lookup("reset-revision"))
|
viper.BindPFlag("reset-revision", cmd.Flags().Lookup("reset-revision"))
|
||||||
viper.BindPFlag("repo", cmd.Flags().Lookup("repo"))
|
viper.BindPFlag("repo", cmd.Flags().Lookup("repo"))
|
||||||
},
|
},
|
||||||
@@ -57,9 +59,14 @@ var createrepoCmd = &cobra.Command{
|
|||||||
t := viper.GetString("type")
|
t := viper.GetString("type")
|
||||||
reset := viper.GetBool("reset-revision")
|
reset := viper.GetBool("reset-revision")
|
||||||
treetype := viper.GetString("tree-compression")
|
treetype := viper.GetString("tree-compression")
|
||||||
treepath := viper.GetString("tree-path")
|
treeName := viper.GetString("tree-filename")
|
||||||
|
metatype := viper.GetString("meta-compression")
|
||||||
|
metaName := viper.GetString("meta-filename")
|
||||||
source_repo := viper.GetString("repo")
|
source_repo := viper.GetString("repo")
|
||||||
|
|
||||||
|
treeFile := installer.NewDefaultTreeRepositoryFile()
|
||||||
|
metaFile := installer.NewDefaultMetaRepositoryFile()
|
||||||
|
|
||||||
if source_repo != "" {
|
if source_repo != "" {
|
||||||
// Search for system repository
|
// Search for system repository
|
||||||
lrepo, err := LuetCfg.GetSystemRepository(source_repo)
|
lrepo, err := LuetCfg.GetSystemRepository(source_repo)
|
||||||
@@ -93,13 +100,24 @@ var createrepoCmd = &cobra.Command{
|
|||||||
}
|
}
|
||||||
|
|
||||||
if treetype != "" {
|
if treetype != "" {
|
||||||
repo.SetTreeCompressionType(compiler.CompressionImplementation(treetype))
|
treeFile.SetCompressionType(compiler.CompressionImplementation(treetype))
|
||||||
}
|
}
|
||||||
|
|
||||||
if treepath != "" {
|
if treeName != "" {
|
||||||
repo.SetTreePath(treepath)
|
treeFile.SetFileName(treeName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if metatype != "" {
|
||||||
|
metaFile.SetCompressionType(compiler.CompressionImplementation(metatype))
|
||||||
|
}
|
||||||
|
|
||||||
|
if metaName != "" {
|
||||||
|
metaFile.SetFileName(metaName)
|
||||||
|
}
|
||||||
|
|
||||||
|
repo.SetRepositoryFile(installer.REPOFILE_TREE_KEY, treeFile)
|
||||||
|
repo.SetRepositoryFile(installer.REPOFILE_META_KEY, metaFile)
|
||||||
|
|
||||||
err = repo.Write(dst, reset)
|
err = repo.Write(dst, reset)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Fatal("Error: " + err.Error())
|
Fatal("Error: " + err.Error())
|
||||||
@@ -122,8 +140,10 @@ func init() {
|
|||||||
createrepoCmd.Flags().Bool("reset-revision", false, "Reset repository revision.")
|
createrepoCmd.Flags().Bool("reset-revision", false, "Reset repository revision.")
|
||||||
createrepoCmd.Flags().String("repo", "", "Use repository defined in configuration.")
|
createrepoCmd.Flags().String("repo", "", "Use repository defined in configuration.")
|
||||||
|
|
||||||
createrepoCmd.Flags().String("tree-compression", "none", "Compression alg: none, gzip")
|
createrepoCmd.Flags().String("tree-compression", "gzip", "Compression alg: none, gzip")
|
||||||
createrepoCmd.Flags().String("tree-path", installer.TREE_TARBALL, "Repository tree filename")
|
createrepoCmd.Flags().String("tree-filename", installer.TREE_TARBALL, "Repository tree filename")
|
||||||
|
createrepoCmd.Flags().String("meta-compression", "none", "Compression alg: none, gzip")
|
||||||
|
createrepoCmd.Flags().String("meta-filename", installer.REPOSITORY_METAFILE+".tar", "Repository metadata filename")
|
||||||
|
|
||||||
RootCmd.AddCommand(createrepoCmd)
|
RootCmd.AddCommand(createrepoCmd)
|
||||||
}
|
}
|
||||||
|
86
cmd/exec.go
Normal file
86
cmd/exec.go
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
// Copyright © 2020 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 cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
|
||||||
|
b64 "encoding/base64"
|
||||||
|
|
||||||
|
"github.com/mudler/luet/pkg/box"
|
||||||
|
. "github.com/mudler/luet/pkg/logger"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
)
|
||||||
|
|
||||||
|
var execCmd = &cobra.Command{
|
||||||
|
Use: "exec --rootfs /path [command]",
|
||||||
|
Short: "Execute a command in the rootfs context",
|
||||||
|
Long: `Uses unshare technique and pivot root to execute a command inside a folder containing a valid rootfs`,
|
||||||
|
PreRun: func(cmd *cobra.Command, args []string) {
|
||||||
|
viper.BindPFlag("stdin", cmd.Flags().Lookup("stdin"))
|
||||||
|
viper.BindPFlag("stdout", cmd.Flags().Lookup("stdout"))
|
||||||
|
viper.BindPFlag("stderr", cmd.Flags().Lookup("stderr"))
|
||||||
|
viper.BindPFlag("rootfs", cmd.Flags().Lookup("rootfs"))
|
||||||
|
viper.BindPFlag("decode", cmd.Flags().Lookup("decode"))
|
||||||
|
viper.BindPFlag("entrypoint", cmd.Flags().Lookup("entrypoint"))
|
||||||
|
|
||||||
|
},
|
||||||
|
// If you change this, look at pkg/box/exec that runs this command and adapt
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
|
||||||
|
stdin := viper.GetBool("stdin")
|
||||||
|
stdout := viper.GetBool("stdout")
|
||||||
|
stderr := viper.GetBool("stderr")
|
||||||
|
rootfs := viper.GetString("rootfs")
|
||||||
|
base := viper.GetBool("decode")
|
||||||
|
|
||||||
|
entrypoint := viper.GetString("entrypoint")
|
||||||
|
if base {
|
||||||
|
var ss []string
|
||||||
|
for _, a := range args {
|
||||||
|
sDec, _ := b64.StdEncoding.DecodeString(a)
|
||||||
|
ss = append(ss, string(sDec))
|
||||||
|
}
|
||||||
|
//If the command to run is complex,using base64 to avoid bad input
|
||||||
|
|
||||||
|
args = ss
|
||||||
|
}
|
||||||
|
Info("Executing", args, "in", rootfs)
|
||||||
|
|
||||||
|
b := box.NewBox(entrypoint, args, rootfs, stdin, stdout, stderr)
|
||||||
|
err := b.Exec()
|
||||||
|
if err != nil {
|
||||||
|
Fatal(err)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
path, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
Fatal(err)
|
||||||
|
}
|
||||||
|
execCmd.Hidden = true
|
||||||
|
execCmd.Flags().String("rootfs", path, "Rootfs path")
|
||||||
|
execCmd.Flags().Bool("stdin", false, "Attach to stdin")
|
||||||
|
execCmd.Flags().Bool("stdout", false, "Attach to stdout")
|
||||||
|
execCmd.Flags().Bool("stderr", false, "Attach to stderr")
|
||||||
|
execCmd.Flags().Bool("decode", false, "Base64 decode")
|
||||||
|
|
||||||
|
execCmd.Flags().String("entrypoint", "/bin/sh", "Entrypoint command (/bin/sh)")
|
||||||
|
|
||||||
|
RootCmd.AddCommand(execCmd)
|
||||||
|
}
|
@@ -62,7 +62,7 @@ $> luet repo update repo1 repo2
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
for _, repo := range LuetCfg.SystemRepositories {
|
for _, repo := range LuetCfg.SystemRepositories {
|
||||||
if repo.Cached {
|
if repo.Cached && repo.Enable {
|
||||||
r := installer.NewSystemRepository(repo)
|
r := installer.NewSystemRepository(repo)
|
||||||
Spinner(32)
|
Spinner(32)
|
||||||
_, err := r.Sync(force)
|
_, err := r.Sync(force)
|
||||||
|
24
cmd/root.go
24
cmd/root.go
@@ -35,9 +35,10 @@ import (
|
|||||||
|
|
||||||
var cfgFile string
|
var cfgFile string
|
||||||
var Verbose bool
|
var Verbose bool
|
||||||
|
var LockedCommands = []string{"install", "uninstall", "upgrade"}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
LuetCLIVersion = "0.7.1"
|
LuetCLIVersion = "0.7.2"
|
||||||
LuetEnvPrefix = "LUET"
|
LuetEnvPrefix = "LUET"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -91,16 +92,21 @@ func LoadConfig(c *config.LuetConfig) error {
|
|||||||
// Execute adds all child commands to the root command sets flags appropriately.
|
// Execute adds all child commands to the root command sets flags appropriately.
|
||||||
// This is called by main.main(). It only needs to happen once to the rootCmd.
|
// This is called by main.main(). It only needs to happen once to the rootCmd.
|
||||||
func Execute() {
|
func Execute() {
|
||||||
// XXX: This is mostly from scratch images.
|
|
||||||
if os.Getenv("LUET_NOLOCK") != "true" {
|
if os.Getenv("LUET_NOLOCK") != "true" {
|
||||||
s := single.New("luet")
|
for _, lockedCmd := range LockedCommands {
|
||||||
if err := s.CheckLock(); err != nil && err == single.ErrAlreadyRunning {
|
if os.Args[1] == lockedCmd {
|
||||||
Fatal("another instance of the app is already running, exiting")
|
s := single.New("luet")
|
||||||
} else if err != nil {
|
if err := s.CheckLock(); err != nil && err == single.ErrAlreadyRunning {
|
||||||
// Another error occurred, might be worth handling it as well
|
Fatal("another instance of the app is already running, exiting")
|
||||||
Fatal("failed to acquire exclusive app lock:", err.Error())
|
} else if err != nil {
|
||||||
|
// Another error occurred, might be worth handling it as well
|
||||||
|
Fatal("failed to acquire exclusive app lock:", err.Error())
|
||||||
|
}
|
||||||
|
defer s.TryUnlock()
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
defer s.TryUnlock()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := RootCmd.Execute(); err != nil {
|
if err := RootCmd.Execute(); err != nil {
|
||||||
|
@@ -96,8 +96,11 @@
|
|||||||
# packages. By default caching is disable.
|
# packages. By default caching is disable.
|
||||||
# cached: false
|
# cached: false
|
||||||
#
|
#
|
||||||
# Path where store tree of the specifications. Default path is $database_path/repos/$repo_name
|
# Path where store tree of the specifications. Default path is $database_path/repos/$repo_name/treefs
|
||||||
# tree_path: "/var/cache/luet/repos/local"
|
# tree_path: "/var/cache/luet/repos/local/treefs"
|
||||||
|
#
|
||||||
|
# Path where store repository metadata. Default path is $database_path/repos/$repo_name/meta
|
||||||
|
# meta_path: "/var/cache/luet/repos/local/meta"
|
||||||
#
|
#
|
||||||
# Define the list of the URL where retrieve tree and packages.
|
# Define the list of the URL where retrieve tree and packages.
|
||||||
# urls:
|
# urls:
|
||||||
|
157
pkg/box/exec.go
Normal file
157
pkg/box/exec.go
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
// Copyright © 2020 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 box
|
||||||
|
|
||||||
|
import (
|
||||||
|
b64 "encoding/base64"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
|
helpers "github.com/mudler/luet/pkg/helpers"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Box interface {
|
||||||
|
Run() error
|
||||||
|
Exec() error
|
||||||
|
}
|
||||||
|
|
||||||
|
type DefaultBox struct {
|
||||||
|
Name string
|
||||||
|
Root string
|
||||||
|
Env []string
|
||||||
|
Cmd string
|
||||||
|
Args []string
|
||||||
|
|
||||||
|
Stdin, Stdout, Stderr bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewBox(cmd string, args []string, rootfs string, stdin, stdout, stderr bool) Box {
|
||||||
|
return &DefaultBox{
|
||||||
|
Stdin: stdin,
|
||||||
|
Stdout: stdout,
|
||||||
|
Stderr: stderr,
|
||||||
|
Cmd: cmd,
|
||||||
|
Args: args,
|
||||||
|
Root: rootfs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *DefaultBox) Exec() error {
|
||||||
|
|
||||||
|
if err := mountProc(b.Root); err != nil {
|
||||||
|
return errors.Wrap(err, "Failed mounting proc on rootfs")
|
||||||
|
}
|
||||||
|
if err := mountDev(b.Root); err != nil {
|
||||||
|
return errors.Wrap(err, "Failed mounting dev on rootfs")
|
||||||
|
}
|
||||||
|
if err := PivotRoot(b.Root); err != nil {
|
||||||
|
return errors.Wrap(err, "Failed switching pivot on rootfs")
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := exec.Command(b.Cmd, b.Args...)
|
||||||
|
|
||||||
|
if b.Stdin {
|
||||||
|
cmd.Stdin = os.Stdin
|
||||||
|
}
|
||||||
|
|
||||||
|
if b.Stderr {
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
}
|
||||||
|
|
||||||
|
if b.Stdout {
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.Env = b.Env
|
||||||
|
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
return errors.Wrap(err, fmt.Sprintf("Error running the %s command", b.Cmd))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *DefaultBox) Run() error {
|
||||||
|
|
||||||
|
if !helpers.Exists(b.Root) {
|
||||||
|
return errors.New(b.Root + " does not exist")
|
||||||
|
}
|
||||||
|
|
||||||
|
// This matches with exec CLI command in luet
|
||||||
|
// TODO: Pass by env var as well
|
||||||
|
execCmd := []string{"exec", "--rootfs", b.Root, "--entrypoint", b.Cmd}
|
||||||
|
|
||||||
|
if b.Stdin {
|
||||||
|
execCmd = append(execCmd, "--stdin")
|
||||||
|
}
|
||||||
|
|
||||||
|
if b.Stderr {
|
||||||
|
execCmd = append(execCmd, "--stderr")
|
||||||
|
}
|
||||||
|
|
||||||
|
if b.Stdout {
|
||||||
|
execCmd = append(execCmd, "--stdout")
|
||||||
|
}
|
||||||
|
// Encode the command in base64 to avoid bad input from the args given
|
||||||
|
execCmd = append(execCmd, "--decode")
|
||||||
|
|
||||||
|
for _, a := range b.Args {
|
||||||
|
execCmd = append(execCmd, b64.StdEncoding.EncodeToString([]byte(a)))
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := exec.Command("/proc/self/exe", execCmd...)
|
||||||
|
if b.Stdin {
|
||||||
|
cmd.Stdin = os.Stdin
|
||||||
|
}
|
||||||
|
|
||||||
|
if b.Stderr {
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
}
|
||||||
|
|
||||||
|
if b.Stdout {
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
}
|
||||||
|
cmd.SysProcAttr = &syscall.SysProcAttr{
|
||||||
|
Cloneflags: syscall.CLONE_NEWNS |
|
||||||
|
syscall.CLONE_NEWUTS |
|
||||||
|
syscall.CLONE_NEWIPC |
|
||||||
|
syscall.CLONE_NEWPID |
|
||||||
|
syscall.CLONE_NEWNET |
|
||||||
|
syscall.CLONE_NEWUSER,
|
||||||
|
UidMappings: []syscall.SysProcIDMap{
|
||||||
|
{
|
||||||
|
ContainerID: 0,
|
||||||
|
HostID: os.Getuid(),
|
||||||
|
Size: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
GidMappings: []syscall.SysProcIDMap{
|
||||||
|
{
|
||||||
|
ContainerID: 0,
|
||||||
|
HostID: os.Getgid(),
|
||||||
|
Size: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
return errors.Wrap(err, "Failed running Box command")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
91
pkg/box/rootfs.go
Normal file
91
pkg/box/rootfs.go
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
// Copyright © 2020 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 box
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
func PivotRoot(newroot string) error {
|
||||||
|
putold := filepath.Join(newroot, "/.pivot_root")
|
||||||
|
|
||||||
|
// bind mount newroot to itself - this is a slight hack needed to satisfy the
|
||||||
|
// pivot_root requirement that newroot and putold must not be on the same
|
||||||
|
// filesystem as the current root
|
||||||
|
if err := syscall.Mount(newroot, newroot, "", syscall.MS_BIND|syscall.MS_REC, ""); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// create putold directory
|
||||||
|
if err := os.MkdirAll(putold, 0700); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// call pivot_root
|
||||||
|
if err := syscall.PivotRoot(newroot, putold); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ensure current working directory is set to new root
|
||||||
|
if err := os.Chdir("/"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// umount putold, which now lives at /.pivot_root
|
||||||
|
putold = "/.pivot_root"
|
||||||
|
if err := syscall.Unmount(putold, syscall.MNT_DETACH); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove putold
|
||||||
|
if err := os.RemoveAll(putold); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func mountProc(newroot string) error {
|
||||||
|
source := "proc"
|
||||||
|
target := filepath.Join(newroot, "/proc")
|
||||||
|
fstype := "proc"
|
||||||
|
flags := 0
|
||||||
|
data := ""
|
||||||
|
|
||||||
|
os.MkdirAll(target, 0755)
|
||||||
|
if err := syscall.Mount(source, target, fstype, uintptr(flags), data); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func mountDev(newroot string) error {
|
||||||
|
|
||||||
|
source := "/dev"
|
||||||
|
target := filepath.Join(newroot, "/dev")
|
||||||
|
fstype := "bind"
|
||||||
|
data := ""
|
||||||
|
|
||||||
|
os.MkdirAll(target, 0755)
|
||||||
|
if err := syscall.Mount(source, target, fstype, syscall.MS_BIND|syscall.MS_REC, data); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
@@ -131,6 +131,7 @@ type LuetRepository struct {
|
|||||||
Cached bool `json:"cached,omitempty" yaml:"cached,omitempty" mapstructure:"cached,omitempty"`
|
Cached bool `json:"cached,omitempty" yaml:"cached,omitempty" mapstructure:"cached,omitempty"`
|
||||||
Authentication map[string]string `json:"auth,omitempty" yaml:"auth,omitempty" mapstructure:"auth,omitempty"`
|
Authentication map[string]string `json:"auth,omitempty" yaml:"auth,omitempty" mapstructure:"auth,omitempty"`
|
||||||
TreePath string `json:"tree_path,omitempty" yaml:"tree_path,omitempty" mapstructure:"tree_path"`
|
TreePath string `json:"tree_path,omitempty" yaml:"tree_path,omitempty" mapstructure:"tree_path"`
|
||||||
|
MetaPath string `json:"meta_path,omitempty" yaml:"meta_path,omitempty" mapstructure:"meta_path"`
|
||||||
|
|
||||||
// Serialized options not used in repository configuration
|
// Serialized options not used in repository configuration
|
||||||
|
|
||||||
@@ -153,6 +154,7 @@ func NewLuetRepository(name, t, descr string, urls []string, priority int, enabl
|
|||||||
Cached: cached,
|
Cached: cached,
|
||||||
Authentication: make(map[string]string, 0),
|
Authentication: make(map[string]string, 0),
|
||||||
TreePath: "",
|
TreePath: "",
|
||||||
|
MetaPath: "",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,6 +166,7 @@ func NewEmptyLuetRepository() *LuetRepository {
|
|||||||
Type: "",
|
Type: "",
|
||||||
Priority: 9999,
|
Priority: 9999,
|
||||||
TreePath: "",
|
TreePath: "",
|
||||||
|
MetaPath: "",
|
||||||
Enable: false,
|
Enable: false,
|
||||||
Cached: false,
|
Cached: false,
|
||||||
Authentication: make(map[string]string, 0),
|
Authentication: make(map[string]string, 0),
|
||||||
|
@@ -23,6 +23,22 @@ import (
|
|||||||
copy "github.com/otiai10/copy"
|
copy "github.com/otiai10/copy"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func ListDir(dir string) ([]string, error) {
|
||||||
|
content := []string{}
|
||||||
|
|
||||||
|
err := filepath.Walk(dir,
|
||||||
|
func(path string, info os.FileInfo, err error) error {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
content = append(content, path)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
return content, err
|
||||||
|
}
|
||||||
|
|
||||||
// Exists reports whether the named file or directory exists.
|
// Exists reports whether the named file or directory exists.
|
||||||
func Exists(name string) bool {
|
func Exists(name string) bool {
|
||||||
if _, err := os.Stat(name); err != nil {
|
if _, err := os.Stat(name); err != nil {
|
||||||
|
76
pkg/installer/finalizer.go
Normal file
76
pkg/installer/finalizer.go
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
// 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 installer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os/exec"
|
||||||
|
|
||||||
|
"github.com/ghodss/yaml"
|
||||||
|
box "github.com/mudler/luet/pkg/box"
|
||||||
|
. "github.com/mudler/luet/pkg/logger"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type LuetFinalizer struct {
|
||||||
|
Install []string `json:"install"`
|
||||||
|
Uninstall []string `json:"uninstall"` // TODO: Where to store?
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *LuetFinalizer) RunInstall(s *System) error {
|
||||||
|
for _, c := range f.Install {
|
||||||
|
if s.Target == "/" {
|
||||||
|
|
||||||
|
Info("finalizer on / :", "sh", "-c", c)
|
||||||
|
cmd := exec.Command("sh", "-c", c)
|
||||||
|
stdoutStderr, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "Failed running command: "+string(stdoutStderr))
|
||||||
|
}
|
||||||
|
Info(string(stdoutStderr))
|
||||||
|
} else {
|
||||||
|
b := box.NewBox("sh", []string{"-c", c}, s.Target, false, true, true)
|
||||||
|
err := b.Run()
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "Failed running command ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: We don't store uninstall finalizers ?!
|
||||||
|
func (f *LuetFinalizer) RunUnInstall() error {
|
||||||
|
for _, c := range f.Uninstall {
|
||||||
|
Debug("finalizer:", "sh", "-c", c)
|
||||||
|
cmd := exec.Command("sh", "-c", c)
|
||||||
|
stdoutStderr, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "Failed running command: "+string(stdoutStderr))
|
||||||
|
}
|
||||||
|
Info(string(stdoutStderr))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewLuetFinalizerFromYaml(data []byte) (*LuetFinalizer, error) {
|
||||||
|
var p LuetFinalizer
|
||||||
|
err := yaml.Unmarshal(data, &p)
|
||||||
|
if err != nil {
|
||||||
|
return &p, err
|
||||||
|
}
|
||||||
|
return &p, err
|
||||||
|
}
|
@@ -18,13 +18,11 @@ package installer
|
|||||||
import (
|
import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/ghodss/yaml"
|
|
||||||
compiler "github.com/mudler/luet/pkg/compiler"
|
compiler "github.com/mudler/luet/pkg/compiler"
|
||||||
"github.com/mudler/luet/pkg/config"
|
"github.com/mudler/luet/pkg/config"
|
||||||
"github.com/mudler/luet/pkg/helpers"
|
"github.com/mudler/luet/pkg/helpers"
|
||||||
@@ -57,47 +55,6 @@ type ArtifactMatch struct {
|
|||||||
Repository Repository
|
Repository Repository
|
||||||
}
|
}
|
||||||
|
|
||||||
type LuetFinalizer struct {
|
|
||||||
Install []string `json:"install"`
|
|
||||||
Uninstall []string `json:"uninstall"` // TODO: Where to store?
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *LuetFinalizer) RunInstall() error {
|
|
||||||
for _, c := range f.Install {
|
|
||||||
Debug("finalizer:", "sh", "-c", c)
|
|
||||||
cmd := exec.Command("sh", "-c", c)
|
|
||||||
stdoutStderr, err := cmd.CombinedOutput()
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "Failed running command: "+string(stdoutStderr))
|
|
||||||
}
|
|
||||||
Info(string(stdoutStderr))
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: We don't store uninstall finalizers ?!
|
|
||||||
func (f *LuetFinalizer) RunUnInstall() error {
|
|
||||||
for _, c := range f.Install {
|
|
||||||
Debug("finalizer:", "sh", "-c", c)
|
|
||||||
cmd := exec.Command("sh", "-c", c)
|
|
||||||
stdoutStderr, err := cmd.CombinedOutput()
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "Failed running command: "+string(stdoutStderr))
|
|
||||||
}
|
|
||||||
Info(string(stdoutStderr))
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewLuetFinalizerFromYaml(data []byte) (*LuetFinalizer, error) {
|
|
||||||
var p LuetFinalizer
|
|
||||||
err := yaml.Unmarshal(data, &p)
|
|
||||||
if err != nil {
|
|
||||||
return &p, err
|
|
||||||
}
|
|
||||||
return &p, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewLuetInstaller(opts LuetInstallerOptions) Installer {
|
func NewLuetInstaller(opts LuetInstallerOptions) Installer {
|
||||||
return &LuetInstaller{Options: opts}
|
return &LuetInstaller{Options: opts}
|
||||||
}
|
}
|
||||||
@@ -119,7 +76,8 @@ func (l *LuetInstaller) Upgrade(s *System) error {
|
|||||||
|
|
||||||
toInstall := []pkg.Package{}
|
toInstall := []pkg.Package{}
|
||||||
for _, assertion := range solution {
|
for _, assertion := range solution {
|
||||||
if assertion.Value {
|
// Be sure to filter from solutions packages already installed in the system
|
||||||
|
if _, err := s.Database.FindPackage(assertion.Package); err != nil && assertion.Value {
|
||||||
toInstall = append(toInstall, assertion.Package)
|
toInstall = append(toInstall, assertion.Package)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -158,13 +116,12 @@ func (l *LuetInstaller) Swap(toRemove []pkg.Package, toInstall []pkg.Package, s
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (l *LuetInstaller) swap(syncedRepos Repositories, toRemove []pkg.Package, toInstall []pkg.Package, s *System) error {
|
func (l *LuetInstaller) swap(syncedRepos Repositories, toRemove []pkg.Package, toInstall []pkg.Package, s *System) error {
|
||||||
|
|
||||||
// First match packages against repositories by priority
|
// First match packages against repositories by priority
|
||||||
allRepos := pkg.NewInMemoryDatabase(false)
|
allRepos := pkg.NewInMemoryDatabase(false)
|
||||||
syncedRepos.SyncDatabase(allRepos)
|
syncedRepos.SyncDatabase(allRepos)
|
||||||
toInstall = syncedRepos.ResolveSelectors(toInstall)
|
toInstall = syncedRepos.ResolveSelectors(toInstall)
|
||||||
|
|
||||||
if err := l.install(syncedRepos, toInstall, s, true); err != nil {
|
if err := l.download(syncedRepos, toInstall); err != nil {
|
||||||
return errors.Wrap(err, "Pre-downloading packages")
|
return errors.Wrap(err, "Pre-downloading packages")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,7 +150,7 @@ func (l *LuetInstaller) swap(syncedRepos Repositories, toRemove []pkg.Package, t
|
|||||||
}
|
}
|
||||||
l.Options.Force = forced
|
l.Options.Force = forced
|
||||||
|
|
||||||
return l.install(syncedRepos, toInstall, s, false)
|
return l.install(syncedRepos, toInstall, s)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *LuetInstaller) Install(cp []pkg.Package, s *System, downloadOnly bool) error {
|
func (l *LuetInstaller) Install(cp []pkg.Package, s *System, downloadOnly bool) error {
|
||||||
@@ -201,10 +158,55 @@ func (l *LuetInstaller) Install(cp []pkg.Package, s *System, downloadOnly bool)
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return l.install(syncedRepos, cp, s, downloadOnly)
|
return l.install(syncedRepos, cp, s)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *LuetInstaller) install(syncedRepos Repositories, cp []pkg.Package, s *System, downloadOnly bool) error {
|
func (l *LuetInstaller) download(syncedRepos Repositories, cp []pkg.Package) error {
|
||||||
|
toDownload := map[string]ArtifactMatch{}
|
||||||
|
|
||||||
|
// FIXME: This can be optimized. We don't need to re-match this to the repository
|
||||||
|
// But we could just do it once
|
||||||
|
|
||||||
|
// Gathers things to download
|
||||||
|
for _, currentPack := range cp {
|
||||||
|
matches := syncedRepos.PackageMatches([]pkg.Package{currentPack})
|
||||||
|
if len(matches) == 0 {
|
||||||
|
return errors.New("Failed matching solutions against repository for " + currentPack.HumanReadableString() + " where are definitions coming from?!")
|
||||||
|
}
|
||||||
|
A:
|
||||||
|
for _, artefact := range matches[0].Repo.GetIndex() {
|
||||||
|
if artefact.GetCompileSpec().GetPackage() == nil {
|
||||||
|
return errors.New("Package in compilespec empty")
|
||||||
|
|
||||||
|
}
|
||||||
|
if matches[0].Package.Matches(artefact.GetCompileSpec().GetPackage()) {
|
||||||
|
|
||||||
|
toDownload[currentPack.GetFingerPrint()] = ArtifactMatch{Package: currentPack, Artifact: artefact, Repository: matches[0].Repo}
|
||||||
|
|
||||||
|
break A
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Download packages into cache in parallel.
|
||||||
|
all := make(chan ArtifactMatch)
|
||||||
|
|
||||||
|
var wg = new(sync.WaitGroup)
|
||||||
|
|
||||||
|
// Download
|
||||||
|
for i := 0; i < l.Options.Concurrency; i++ {
|
||||||
|
wg.Add(1)
|
||||||
|
go l.downloadWorker(i, wg, all)
|
||||||
|
}
|
||||||
|
for _, c := range toDownload {
|
||||||
|
all <- c
|
||||||
|
}
|
||||||
|
close(all)
|
||||||
|
wg.Wait()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *LuetInstaller) install(syncedRepos Repositories, cp []pkg.Package, s *System) error {
|
||||||
var p []pkg.Package
|
var p []pkg.Package
|
||||||
|
|
||||||
// Check if the package is installed first
|
// Check if the package is installed first
|
||||||
@@ -283,50 +285,33 @@ func (l *LuetInstaller) install(syncedRepos Repositories, cp []pkg.Package, s *S
|
|||||||
|
|
||||||
var wg = new(sync.WaitGroup)
|
var wg = new(sync.WaitGroup)
|
||||||
|
|
||||||
if !downloadOnly {
|
// Download first
|
||||||
// Download first
|
for i := 0; i < l.Options.Concurrency; i++ {
|
||||||
for i := 0; i < l.Options.Concurrency; i++ {
|
wg.Add(1)
|
||||||
wg.Add(1)
|
go l.downloadWorker(i, wg, all)
|
||||||
go l.installerWorker(i, wg, all, s, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, c := range toInstall {
|
|
||||||
all <- c
|
|
||||||
}
|
|
||||||
close(all)
|
|
||||||
wg.Wait()
|
|
||||||
|
|
||||||
all = make(chan ArtifactMatch)
|
|
||||||
|
|
||||||
wg = new(sync.WaitGroup)
|
|
||||||
|
|
||||||
// Do the real install
|
|
||||||
for i := 0; i < l.Options.Concurrency; i++ {
|
|
||||||
wg.Add(1)
|
|
||||||
go l.installerWorker(i, wg, all, s, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, c := range toInstall {
|
|
||||||
all <- c
|
|
||||||
}
|
|
||||||
close(all)
|
|
||||||
wg.Wait()
|
|
||||||
} else {
|
|
||||||
for i := 0; i < l.Options.Concurrency; i++ {
|
|
||||||
wg.Add(1)
|
|
||||||
go l.installerWorker(i, wg, all, s, downloadOnly)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, c := range toInstall {
|
|
||||||
all <- c
|
|
||||||
}
|
|
||||||
close(all)
|
|
||||||
wg.Wait()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if downloadOnly {
|
for _, c := range toInstall {
|
||||||
return nil
|
all <- c
|
||||||
}
|
}
|
||||||
|
close(all)
|
||||||
|
wg.Wait()
|
||||||
|
|
||||||
|
all = make(chan ArtifactMatch)
|
||||||
|
|
||||||
|
wg = new(sync.WaitGroup)
|
||||||
|
|
||||||
|
// Do the real install
|
||||||
|
for i := 0; i < l.Options.Concurrency; i++ {
|
||||||
|
wg.Add(1)
|
||||||
|
go l.installerWorker(i, wg, all, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range toInstall {
|
||||||
|
all <- c
|
||||||
|
}
|
||||||
|
close(all)
|
||||||
|
wg.Wait()
|
||||||
|
|
||||||
for _, c := range toInstall {
|
for _, c := range toInstall {
|
||||||
// Annotate to the system that the package was installed
|
// Annotate to the system that the package was installed
|
||||||
@@ -367,13 +352,14 @@ func (l *LuetInstaller) install(syncedRepos Repositories, cp []pkg.Package, s *S
|
|||||||
if err != nil && !l.Options.Force {
|
if err != nil && !l.Options.Force {
|
||||||
return errors.Wrap(err, "Error reading finalizer "+treePackage.Rel(tree.FinalizerFile))
|
return errors.Wrap(err, "Error reading finalizer "+treePackage.Rel(tree.FinalizerFile))
|
||||||
}
|
}
|
||||||
err = finalizer.RunInstall()
|
err = finalizer.RunInstall(s)
|
||||||
if err != nil && !l.Options.Force {
|
if err != nil && !l.Options.Force {
|
||||||
return errors.Wrap(err, "Error executing install finalizer "+treePackage.Rel(tree.FinalizerFile))
|
return errors.Wrap(err, "Error executing install finalizer "+treePackage.Rel(tree.FinalizerFile))
|
||||||
}
|
}
|
||||||
executedFinalizer[ass.Package.GetFingerPrint()] = true
|
executedFinalizer[ass.Package.GetFingerPrint()] = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -395,7 +381,7 @@ func (l *LuetInstaller) install(syncedRepos Repositories, cp []pkg.Package, s *S
|
|||||||
if err != nil && !l.Options.Force {
|
if err != nil && !l.Options.Force {
|
||||||
return errors.Wrap(err, "Error reading finalizer "+treePackage.Rel(tree.FinalizerFile))
|
return errors.Wrap(err, "Error reading finalizer "+treePackage.Rel(tree.FinalizerFile))
|
||||||
}
|
}
|
||||||
err = finalizer.RunInstall()
|
err = finalizer.RunInstall(s)
|
||||||
if err != nil && !l.Options.Force {
|
if err != nil && !l.Options.Force {
|
||||||
return errors.Wrap(err, "Error executing install finalizer "+treePackage.Rel(tree.FinalizerFile))
|
return errors.Wrap(err, "Error executing install finalizer "+treePackage.Rel(tree.FinalizerFile))
|
||||||
}
|
}
|
||||||
@@ -404,23 +390,30 @@ func (l *LuetInstaller) install(syncedRepos Repositories, cp []pkg.Package, s *S
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *LuetInstaller) installPackage(a ArtifactMatch, s *System, downloadOnly bool) error {
|
func (l *LuetInstaller) downloadPackage(a ArtifactMatch) (compiler.Artifact, error) {
|
||||||
|
|
||||||
artifact, err := a.Repository.Client().DownloadArtifact(a.Artifact)
|
artifact, err := a.Repository.Client().DownloadArtifact(a.Artifact)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "Error on download artifact")
|
return nil, errors.Wrap(err, "Error on download artifact")
|
||||||
}
|
}
|
||||||
|
|
||||||
err = artifact.Verify()
|
err = artifact.Verify()
|
||||||
if err != nil && !l.Options.Force {
|
if err != nil && !l.Options.Force {
|
||||||
return errors.Wrap(err, "Artifact integrity check failure")
|
return nil, errors.Wrap(err, "Artifact integrity check failure")
|
||||||
}
|
}
|
||||||
if downloadOnly {
|
return artifact, nil
|
||||||
return nil
|
}
|
||||||
|
|
||||||
|
func (l *LuetInstaller) installPackage(a ArtifactMatch, s *System) error {
|
||||||
|
|
||||||
|
artifact, err := l.downloadPackage(a)
|
||||||
|
if err != nil && !l.Options.Force {
|
||||||
|
return errors.Wrap(err, "Failed downloading package")
|
||||||
}
|
}
|
||||||
|
|
||||||
files, err := artifact.FileList()
|
files, err := artifact.FileList()
|
||||||
@@ -438,20 +431,39 @@ func (l *LuetInstaller) installPackage(a ArtifactMatch, s *System, downloadOnly
|
|||||||
return s.Database.SetPackageFiles(&pkg.PackageFile{PackageFingerprint: a.Package.GetFingerPrint(), Files: files})
|
return s.Database.SetPackageFiles(&pkg.PackageFile{PackageFingerprint: a.Package.GetFingerPrint(), Files: files})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *LuetInstaller) installerWorker(i int, wg *sync.WaitGroup, c <-chan ArtifactMatch, s *System, downloadOnly bool) error {
|
func (l *LuetInstaller) downloadWorker(i int, wg *sync.WaitGroup, c <-chan ArtifactMatch) error {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
|
|
||||||
for p := range c {
|
for p := range c {
|
||||||
// TODO: Keep trace of what was added from the tar, and save it into system
|
// TODO: Keep trace of what was added from the tar, and save it into system
|
||||||
err := l.installPackage(p, s, downloadOnly)
|
_, err := l.downloadPackage(p)
|
||||||
if err != nil && !l.Options.Force {
|
if err != nil && !l.Options.Force {
|
||||||
//TODO: Uninstall, rollback.
|
//TODO: Uninstall, rollback.
|
||||||
Fatal("Failed installing package "+p.Package.GetName(), err.Error())
|
Fatal("Failed installing package "+p.Package.GetName(), err.Error())
|
||||||
return errors.Wrap(err, "Failed installing package "+p.Package.GetName())
|
return errors.Wrap(err, "Failed installing package "+p.Package.GetName())
|
||||||
}
|
}
|
||||||
if err == nil && downloadOnly {
|
if err == nil {
|
||||||
Info(":package: ", p.Package.HumanReadableString(), "downloaded")
|
Info(":package: ", p.Package.HumanReadableString(), "downloaded")
|
||||||
} else if err == nil {
|
} else if err != nil && l.Options.Force {
|
||||||
|
Info(":package: ", p.Package.HumanReadableString(), "downloaded with failures (force download)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *LuetInstaller) installerWorker(i int, wg *sync.WaitGroup, c <-chan ArtifactMatch, s *System) error {
|
||||||
|
defer wg.Done()
|
||||||
|
|
||||||
|
for p := range c {
|
||||||
|
// TODO: Keep trace of what was added from the tar, and save it into system
|
||||||
|
err := l.installPackage(p, s)
|
||||||
|
if err != nil && !l.Options.Force {
|
||||||
|
//TODO: Uninstall, rollback.
|
||||||
|
Fatal("Failed installing package "+p.Package.GetName(), err.Error())
|
||||||
|
return errors.Wrap(err, "Failed installing package "+p.Package.GetName())
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
Info(":package: ", p.Package.HumanReadableString(), "installed")
|
Info(":package: ", p.Package.HumanReadableString(), "installed")
|
||||||
} else if err != nil && l.Options.Force {
|
} else if err != nil && l.Options.Force {
|
||||||
Info(":package: ", p.Package.HumanReadableString(), "installed with failures (force install)")
|
Info(":package: ", p.Package.HumanReadableString(), "installed with failures (force install)")
|
||||||
|
@@ -47,9 +47,9 @@ var _ = Describe("Installer", func() {
|
|||||||
|
|
||||||
Expect(len(generalRecipe.GetDatabase().GetPackages())).To(Equal(3))
|
Expect(len(generalRecipe.GetDatabase().GetPackages())).To(Equal(3))
|
||||||
|
|
||||||
compiler := compiler.NewLuetCompiler(backend.NewSimpleDockerBackend(), generalRecipe.GetDatabase(), compiler.NewDefaultCompilerOptions())
|
c := compiler.NewLuetCompiler(backend.NewSimpleDockerBackend(), generalRecipe.GetDatabase(), compiler.NewDefaultCompilerOptions())
|
||||||
|
|
||||||
spec, err := compiler.FromPackage(&pkg.DefaultPackage{Name: "b", Category: "test", Version: "1.0"})
|
spec, err := c.FromPackage(&pkg.DefaultPackage{Name: "b", Category: "test", Version: "1.0"})
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
Expect(spec.GetPackage().GetPath()).ToNot(Equal(""))
|
Expect(spec.GetPackage().GetPath()).ToNot(Equal(""))
|
||||||
@@ -62,9 +62,9 @@ var _ = Describe("Installer", func() {
|
|||||||
Expect(spec.GetPreBuildSteps()).To(Equal([]string{"echo foo > /test", "echo bar > /test2", "chmod +x generate.sh"}))
|
Expect(spec.GetPreBuildSteps()).To(Equal([]string{"echo foo > /test", "echo bar > /test2", "chmod +x generate.sh"}))
|
||||||
|
|
||||||
spec.SetOutputPath(tmpdir)
|
spec.SetOutputPath(tmpdir)
|
||||||
compiler.SetConcurrency(2)
|
c.SetConcurrency(2)
|
||||||
|
|
||||||
artifact, err := compiler.Compile(false, spec)
|
artifact, err := c.Compile(false, spec)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(helpers.Exists(artifact.GetPath())).To(BeTrue())
|
Expect(helpers.Exists(artifact.GetPath())).To(BeTrue())
|
||||||
Expect(helpers.Untar(artifact.GetPath(), tmpdir, false)).ToNot(HaveOccurred())
|
Expect(helpers.Untar(artifact.GetPath(), tmpdir, false)).ToNot(HaveOccurred())
|
||||||
@@ -86,12 +86,133 @@ var _ = Describe("Installer", func() {
|
|||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(repo.GetName()).To(Equal("test"))
|
Expect(repo.GetName()).To(Equal("test"))
|
||||||
Expect(helpers.Exists(spec.Rel("repository.yaml"))).ToNot(BeTrue())
|
Expect(helpers.Exists(spec.Rel("repository.yaml"))).ToNot(BeTrue())
|
||||||
Expect(helpers.Exists(spec.Rel(TREE_TARBALL))).ToNot(BeTrue())
|
Expect(helpers.Exists(spec.Rel(TREE_TARBALL + ".gz"))).ToNot(BeTrue())
|
||||||
|
Expect(helpers.Exists(spec.Rel(REPOSITORY_METAFILE + ".tar"))).ToNot(BeTrue())
|
||||||
|
err = repo.Write(tmpdir, false)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
Expect(helpers.Exists(spec.Rel("repository.yaml"))).To(BeTrue())
|
||||||
|
Expect(helpers.Exists(spec.Rel(TREE_TARBALL + ".gz"))).To(BeTrue())
|
||||||
|
Expect(helpers.Exists(spec.Rel(REPOSITORY_METAFILE + ".tar"))).To(BeTrue())
|
||||||
|
Expect(repo.GetUrls()[0]).To(Equal(tmpdir))
|
||||||
|
Expect(repo.GetType()).To(Equal("disk"))
|
||||||
|
|
||||||
|
fakeroot, err := ioutil.TempDir("", "fakeroot")
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
defer os.RemoveAll(fakeroot) // clean up
|
||||||
|
|
||||||
|
inst := NewLuetInstaller(LuetInstallerOptions{Concurrency: 1})
|
||||||
|
repo2, err := NewLuetSystemRepositoryFromYaml([]byte(`
|
||||||
|
name: "test"
|
||||||
|
type: "disk"
|
||||||
|
urls:
|
||||||
|
- "`+tmpdir+`"
|
||||||
|
`), pkg.NewInMemoryDatabase(false))
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
inst.Repositories(Repositories{repo2})
|
||||||
|
Expect(repo.GetUrls()[0]).To(Equal(tmpdir))
|
||||||
|
Expect(repo.GetType()).To(Equal("disk"))
|
||||||
|
systemDB := pkg.NewInMemoryDatabase(false)
|
||||||
|
system := &System{Database: systemDB, Target: fakeroot}
|
||||||
|
err = inst.Install([]pkg.Package{&pkg.DefaultPackage{Name: "b", Category: "test", Version: "1.0"}}, system, false)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
Expect(helpers.Exists(filepath.Join(fakeroot, "test5"))).To(BeTrue())
|
||||||
|
Expect(helpers.Exists(filepath.Join(fakeroot, "test6"))).To(BeTrue())
|
||||||
|
_, err = systemDB.FindPackage(&pkg.DefaultPackage{Name: "b", Category: "test", Version: "1.0"})
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
files, err := systemDB.GetPackageFiles(&pkg.DefaultPackage{Name: "b", Category: "test", Version: "1.0"})
|
||||||
|
Expect(files).To(Equal([]string{"artifact42", "test5", "test6"}))
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
Expect(len(system.Database.GetPackages())).To(Equal(1))
|
||||||
|
p, err := system.Database.GetPackage(system.Database.GetPackages()[0])
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(p.GetName()).To(Equal("b"))
|
||||||
|
|
||||||
|
err = inst.Uninstall(&pkg.DefaultPackage{Name: "b", Category: "test", Version: "1.0"}, system)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
// Nothing should be there anymore (files, packagedb entry)
|
||||||
|
Expect(helpers.Exists(filepath.Join(fakeroot, "test5"))).ToNot(BeTrue())
|
||||||
|
Expect(helpers.Exists(filepath.Join(fakeroot, "test6"))).ToNot(BeTrue())
|
||||||
|
|
||||||
|
_, err = systemDB.FindPackage(&pkg.DefaultPackage{Name: "b", Category: "test", Version: "1.0"})
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
_, err = systemDB.GetPackageFiles(&pkg.DefaultPackage{Name: "b", Category: "test", Version: "1.0"})
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
Context("Writes a repository definition without compression", func() {
|
||||||
|
It("Writes a repo and can install packages from it", func() {
|
||||||
|
//repo:=NewLuetSystemRepository()
|
||||||
|
|
||||||
|
tmpdir, err := ioutil.TempDir("", "tree")
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
defer os.RemoveAll(tmpdir) // clean up
|
||||||
|
|
||||||
|
generalRecipe := tree.NewCompilerRecipe(pkg.NewInMemoryDatabase(false))
|
||||||
|
|
||||||
|
err = generalRecipe.Load("../../tests/fixtures/buildable")
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
Expect(len(generalRecipe.GetDatabase().GetPackages())).To(Equal(3))
|
||||||
|
|
||||||
|
c := compiler.NewLuetCompiler(backend.NewSimpleDockerBackend(),
|
||||||
|
generalRecipe.GetDatabase(), compiler.NewDefaultCompilerOptions())
|
||||||
|
|
||||||
|
spec, err := c.FromPackage(&pkg.DefaultPackage{Name: "b", Category: "test", Version: "1.0"})
|
||||||
|
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
|
||||||
|
|
||||||
|
Expect(spec.BuildSteps()).To(Equal([]string{"echo artifact5 > /test5", "echo artifact6 > /test6", "./generate.sh"}))
|
||||||
|
Expect(spec.GetPreBuildSteps()).To(Equal([]string{"echo foo > /test", "echo bar > /test2", "chmod +x generate.sh"}))
|
||||||
|
|
||||||
|
spec.SetOutputPath(tmpdir)
|
||||||
|
c.SetConcurrency(2)
|
||||||
|
|
||||||
|
artifact, err := c.Compile(false, spec)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(helpers.Exists(artifact.GetPath())).To(BeTrue())
|
||||||
|
Expect(helpers.Untar(artifact.GetPath(), tmpdir, false)).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
Expect(helpers.Exists(spec.Rel("test5"))).To(BeTrue())
|
||||||
|
Expect(helpers.Exists(spec.Rel("test6"))).To(BeTrue())
|
||||||
|
|
||||||
|
content1, err := helpers.Read(spec.Rel("test5"))
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
content2, err := helpers.Read(spec.Rel("test6"))
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(content1).To(Equal("artifact5\n"))
|
||||||
|
Expect(content2).To(Equal("artifact6\n"))
|
||||||
|
|
||||||
|
Expect(helpers.Exists(spec.Rel("b-test-1.0.package.tar"))).To(BeTrue())
|
||||||
|
Expect(helpers.Exists(spec.Rel("b-test-1.0.metadata.yaml"))).To(BeTrue())
|
||||||
|
|
||||||
|
repo, err := GenerateRepository("test", "description", "disk", []string{tmpdir}, 1, tmpdir, "../../tests/fixtures/buildable", pkg.NewInMemoryDatabase(false))
|
||||||
|
treeFile := NewDefaultTreeRepositoryFile()
|
||||||
|
treeFile.SetCompressionType(compiler.None)
|
||||||
|
repo.SetRepositoryFile(REPOFILE_TREE_KEY, treeFile)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(repo.GetName()).To(Equal("test"))
|
||||||
|
Expect(helpers.Exists(spec.Rel("repository.yaml"))).ToNot(BeTrue())
|
||||||
|
Expect(helpers.Exists(spec.Rel(TREE_TARBALL + ".gz"))).ToNot(BeTrue())
|
||||||
|
Expect(helpers.Exists(spec.Rel(REPOSITORY_METAFILE + ".tar"))).ToNot(BeTrue())
|
||||||
err = repo.Write(tmpdir, false)
|
err = repo.Write(tmpdir, false)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
Expect(helpers.Exists(spec.Rel("repository.yaml"))).To(BeTrue())
|
Expect(helpers.Exists(spec.Rel("repository.yaml"))).To(BeTrue())
|
||||||
Expect(helpers.Exists(spec.Rel(TREE_TARBALL))).To(BeTrue())
|
Expect(helpers.Exists(spec.Rel(TREE_TARBALL))).To(BeTrue())
|
||||||
|
Expect(helpers.Exists(spec.Rel(REPOSITORY_METAFILE + ".tar"))).To(BeTrue())
|
||||||
Expect(repo.GetUrls()[0]).To(Equal(tmpdir))
|
Expect(repo.GetUrls()[0]).To(Equal(tmpdir))
|
||||||
Expect(repo.GetType()).To(Equal("disk"))
|
Expect(repo.GetType()).To(Equal("disk"))
|
||||||
|
|
||||||
@@ -160,9 +281,9 @@ urls:
|
|||||||
|
|
||||||
Expect(len(generalRecipe.GetDatabase().GetPackages())).To(Equal(3))
|
Expect(len(generalRecipe.GetDatabase().GetPackages())).To(Equal(3))
|
||||||
|
|
||||||
compiler := compiler.NewLuetCompiler(backend.NewSimpleDockerBackend(), generalRecipe.GetDatabase(), compiler.NewDefaultCompilerOptions())
|
c := compiler.NewLuetCompiler(backend.NewSimpleDockerBackend(), generalRecipe.GetDatabase(), compiler.NewDefaultCompilerOptions())
|
||||||
|
|
||||||
spec, err := compiler.FromPackage(&pkg.DefaultPackage{Name: "b", Category: "test", Version: "1.0"})
|
spec, err := c.FromPackage(&pkg.DefaultPackage{Name: "b", Category: "test", Version: "1.0"})
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
Expect(spec.GetPackage().GetPath()).ToNot(Equal(""))
|
Expect(spec.GetPackage().GetPath()).ToNot(Equal(""))
|
||||||
@@ -175,9 +296,9 @@ urls:
|
|||||||
Expect(spec.GetPreBuildSteps()).To(Equal([]string{"echo foo > /test", "echo bar > /test2", "chmod +x generate.sh"}))
|
Expect(spec.GetPreBuildSteps()).To(Equal([]string{"echo foo > /test", "echo bar > /test2", "chmod +x generate.sh"}))
|
||||||
|
|
||||||
spec.SetOutputPath(tmpdir)
|
spec.SetOutputPath(tmpdir)
|
||||||
compiler.SetConcurrency(2)
|
c.SetConcurrency(2)
|
||||||
|
|
||||||
artifact, err := compiler.Compile(false, spec)
|
artifact, err := c.Compile(false, spec)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(helpers.Exists(artifact.GetPath())).To(BeTrue())
|
Expect(helpers.Exists(artifact.GetPath())).To(BeTrue())
|
||||||
Expect(helpers.Untar(artifact.GetPath(), tmpdir, false)).ToNot(HaveOccurred())
|
Expect(helpers.Untar(artifact.GetPath(), tmpdir, false)).ToNot(HaveOccurred())
|
||||||
@@ -199,12 +320,14 @@ urls:
|
|||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(repo.GetName()).To(Equal("test"))
|
Expect(repo.GetName()).To(Equal("test"))
|
||||||
Expect(helpers.Exists(spec.Rel("repository.yaml"))).ToNot(BeTrue())
|
Expect(helpers.Exists(spec.Rel("repository.yaml"))).ToNot(BeTrue())
|
||||||
Expect(helpers.Exists(spec.Rel(TREE_TARBALL))).ToNot(BeTrue())
|
Expect(helpers.Exists(spec.Rel(TREE_TARBALL + ".gz"))).ToNot(BeTrue())
|
||||||
|
Expect(helpers.Exists(spec.Rel(REPOSITORY_METAFILE + ".tar"))).ToNot(BeTrue())
|
||||||
err = repo.Write(tmpdir, false)
|
err = repo.Write(tmpdir, false)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
Expect(helpers.Exists(spec.Rel("repository.yaml"))).To(BeTrue())
|
Expect(helpers.Exists(spec.Rel("repository.yaml"))).To(BeTrue())
|
||||||
Expect(helpers.Exists(spec.Rel(TREE_TARBALL))).To(BeTrue())
|
Expect(helpers.Exists(spec.Rel(TREE_TARBALL + ".gz"))).To(BeTrue())
|
||||||
|
Expect(helpers.Exists(spec.Rel(REPOSITORY_METAFILE + ".tar"))).To(BeTrue())
|
||||||
Expect(repo.GetUrls()[0]).To(Equal(tmpdir))
|
Expect(repo.GetUrls()[0]).To(Equal(tmpdir))
|
||||||
Expect(repo.GetType()).To(Equal("disk"))
|
Expect(repo.GetType()).To(Equal("disk"))
|
||||||
|
|
||||||
@@ -307,12 +430,14 @@ urls:
|
|||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(repo.GetName()).To(Equal("test"))
|
Expect(repo.GetName()).To(Equal("test"))
|
||||||
Expect(helpers.Exists(spec.Rel("repository.yaml"))).ToNot(BeTrue())
|
Expect(helpers.Exists(spec.Rel("repository.yaml"))).ToNot(BeTrue())
|
||||||
Expect(helpers.Exists(spec.Rel(TREE_TARBALL))).ToNot(BeTrue())
|
Expect(helpers.Exists(spec.Rel(TREE_TARBALL + ".gz"))).ToNot(BeTrue())
|
||||||
|
Expect(helpers.Exists(spec.Rel(REPOSITORY_METAFILE + ".tar"))).ToNot(BeTrue())
|
||||||
err = repo.Write(tmpdir, false)
|
err = repo.Write(tmpdir, false)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
Expect(helpers.Exists(spec.Rel("repository.yaml"))).To(BeTrue())
|
Expect(helpers.Exists(spec.Rel("repository.yaml"))).To(BeTrue())
|
||||||
Expect(helpers.Exists(spec.Rel(TREE_TARBALL))).To(BeTrue())
|
Expect(helpers.Exists(spec.Rel(TREE_TARBALL + ".gz"))).To(BeTrue())
|
||||||
|
Expect(helpers.Exists(spec.Rel(REPOSITORY_METAFILE + ".tar"))).To(BeTrue())
|
||||||
Expect(repo.GetUrls()[0]).To(Equal(tmpdir))
|
Expect(repo.GetUrls()[0]).To(Equal(tmpdir))
|
||||||
Expect(repo.GetType()).To(Equal("disk"))
|
Expect(repo.GetType()).To(Equal("disk"))
|
||||||
|
|
||||||
@@ -420,14 +545,16 @@ urls:
|
|||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(repo.GetName()).To(Equal("test"))
|
Expect(repo.GetName()).To(Equal("test"))
|
||||||
Expect(helpers.Exists(spec.Rel("repository.yaml"))).ToNot(BeTrue())
|
Expect(helpers.Exists(spec.Rel("repository.yaml"))).ToNot(BeTrue())
|
||||||
Expect(helpers.Exists(spec.Rel(TREE_TARBALL))).ToNot(BeTrue())
|
Expect(helpers.Exists(spec.Rel(TREE_TARBALL + ".gz"))).ToNot(BeTrue())
|
||||||
|
Expect(helpers.Exists(spec.Rel(REPOSITORY_METAFILE + ".tar"))).ToNot(BeTrue())
|
||||||
err = repo.Write(tmpdir, false)
|
err = repo.Write(tmpdir, false)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(helpers.Exists(spec.Rel("b-test-1.1.package.tar.gz"))).To(BeTrue())
|
Expect(helpers.Exists(spec.Rel("b-test-1.1.package.tar.gz"))).To(BeTrue())
|
||||||
Expect(helpers.Exists(spec.Rel("b-test-1.1.package.tar"))).ToNot(BeTrue())
|
Expect(helpers.Exists(spec.Rel("b-test-1.1.package.tar"))).ToNot(BeTrue())
|
||||||
|
|
||||||
Expect(helpers.Exists(spec.Rel("repository.yaml"))).To(BeTrue())
|
Expect(helpers.Exists(spec.Rel("repository.yaml"))).To(BeTrue())
|
||||||
Expect(helpers.Exists(spec.Rel(TREE_TARBALL))).To(BeTrue())
|
Expect(helpers.Exists(spec.Rel(TREE_TARBALL + ".gz"))).To(BeTrue())
|
||||||
|
Expect(helpers.Exists(spec.Rel(REPOSITORY_METAFILE + ".tar"))).To(BeTrue())
|
||||||
Expect(repo.GetUrls()[0]).To(Equal(tmpdir))
|
Expect(repo.GetUrls()[0]).To(Equal(tmpdir))
|
||||||
Expect(repo.GetType()).To(Equal("disk"))
|
Expect(repo.GetType()).To(Equal("disk"))
|
||||||
|
|
||||||
|
@@ -46,12 +46,15 @@ type Repository interface {
|
|||||||
AddUrl(string)
|
AddUrl(string)
|
||||||
GetPriority() int
|
GetPriority() int
|
||||||
GetIndex() compiler.ArtifactIndex
|
GetIndex() compiler.ArtifactIndex
|
||||||
|
SetIndex(i compiler.ArtifactIndex)
|
||||||
GetTree() tree.Builder
|
GetTree() tree.Builder
|
||||||
SetTree(tree.Builder)
|
SetTree(tree.Builder)
|
||||||
Write(path string, resetRevision bool) error
|
Write(path string, resetRevision bool) error
|
||||||
Sync(bool) (Repository, error)
|
Sync(bool) (Repository, error)
|
||||||
GetTreePath() string
|
GetTreePath() string
|
||||||
SetTreePath(string)
|
SetTreePath(string)
|
||||||
|
GetMetaPath() string
|
||||||
|
SetMetaPath(string)
|
||||||
GetType() string
|
GetType() string
|
||||||
SetType(string)
|
SetType(string)
|
||||||
SetAuthentication(map[string]string)
|
SetAuthentication(map[string]string)
|
||||||
@@ -62,8 +65,8 @@ type Repository interface {
|
|||||||
SetLastUpdate(string)
|
SetLastUpdate(string)
|
||||||
Client() Client
|
Client() Client
|
||||||
|
|
||||||
GetTreeChecksums() compiler.Checksums
|
GetRepositoryFile(string) (LuetRepositoryFile, error)
|
||||||
GetTreeCompressionType() compiler.CompressionImplementation
|
SetRepositoryFile(string, LuetRepositoryFile)
|
||||||
SetTreeCompressionType(c compiler.CompressionImplementation)
|
|
||||||
SetTreeChecksums(c compiler.Checksums)
|
Serialize() (*LuetSystemRepositoryMetadata, LuetSystemRepositorySerialized)
|
||||||
}
|
}
|
||||||
|
@@ -40,32 +40,43 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
REPOSITORY_METAFILE = "repository.meta.yaml"
|
||||||
REPOSITORY_SPECFILE = "repository.yaml"
|
REPOSITORY_SPECFILE = "repository.yaml"
|
||||||
TREE_TARBALL = "tree.tar"
|
TREE_TARBALL = "tree.tar"
|
||||||
|
|
||||||
|
REPOFILE_TREE_KEY = "tree"
|
||||||
|
REPOFILE_META_KEY = "meta"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type LuetRepositoryFile struct {
|
||||||
|
FileName string `json:"filename"`
|
||||||
|
CompressionType compiler.CompressionImplementation `json:"compressiontype,omitempty"`
|
||||||
|
Checksums compiler.Checksums `json:"checksums,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
type LuetSystemRepository struct {
|
type LuetSystemRepository struct {
|
||||||
*config.LuetRepository
|
*config.LuetRepository
|
||||||
|
|
||||||
Index compiler.ArtifactIndex `json:"index"`
|
Index compiler.ArtifactIndex `json:"index"`
|
||||||
Tree tree.Builder `json:"-"`
|
Tree tree.Builder `json:"-"`
|
||||||
TreePath string `json:"treepath"`
|
RepositoryFiles map[string]LuetRepositoryFile `json:"repo_files"`
|
||||||
TreeCompressionType compiler.CompressionImplementation `json:"treecompressiontype"`
|
|
||||||
TreeChecksums compiler.Checksums `json:"treechecksums"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type LuetSystemRepositorySerialized struct {
|
type LuetSystemRepositorySerialized struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Description string `json:"description,omitempty"`
|
Description string `json:"description,omitempty"`
|
||||||
Urls []string `json:"urls"`
|
Urls []string `json:"urls"`
|
||||||
Priority int `json:"priority"`
|
Priority int `json:"priority"`
|
||||||
Index []*compiler.PackageArtifact `json:"index"`
|
Type string `json:"type"`
|
||||||
Type string `json:"type"`
|
Revision int `json:"revision,omitempty"`
|
||||||
Revision int `json:"revision,omitempty"`
|
LastUpdate string `json:"last_update,omitempty"`
|
||||||
LastUpdate string `json:"last_update,omitempty"`
|
TreePath string `json:"treepath"`
|
||||||
TreePath string `json:"treepath"`
|
MetaPath string `json:"metapath"`
|
||||||
TreeCompressionType compiler.CompressionImplementation `json:"treecompressiontype"`
|
RepositoryFiles map[string]LuetRepositoryFile `json:"repo_files"`
|
||||||
TreeChecksums compiler.Checksums `json:"treechecksums"`
|
}
|
||||||
|
|
||||||
|
type LuetSystemRepositoryMetadata struct {
|
||||||
|
Index []*compiler.PackageArtifact `json:"index,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type LuetSearchModeType string
|
type LuetSearchModeType string
|
||||||
@@ -81,6 +92,90 @@ type LuetSearchOpts struct {
|
|||||||
Mode LuetSearchModeType
|
Mode LuetSearchModeType
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewLuetSystemRepositoryMetadata(file string, removeFile bool) (*LuetSystemRepositoryMetadata, error) {
|
||||||
|
ans := &LuetSystemRepositoryMetadata{}
|
||||||
|
err := ans.ReadFile(file, removeFile)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return ans, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *LuetSystemRepositoryMetadata) WriteFile(path string) error {
|
||||||
|
data, err := yaml.Marshal(m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = ioutil.WriteFile(path, data, os.ModePerm)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *LuetSystemRepositoryMetadata) ReadFile(file string, removeFile bool) error {
|
||||||
|
if file == "" {
|
||||||
|
return errors.New("Invalid path for repository metadata")
|
||||||
|
}
|
||||||
|
|
||||||
|
dat, err := ioutil.ReadFile(file)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if removeFile {
|
||||||
|
defer os.Remove(file)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = yaml.Unmarshal(dat, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *LuetSystemRepositoryMetadata) ToArtificatIndex() (ans compiler.ArtifactIndex) {
|
||||||
|
for _, a := range m.Index {
|
||||||
|
ans = append(ans, a)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDefaultTreeRepositoryFile() LuetRepositoryFile {
|
||||||
|
return LuetRepositoryFile{
|
||||||
|
FileName: TREE_TARBALL,
|
||||||
|
CompressionType: compiler.GZip,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDefaultMetaRepositoryFile() LuetRepositoryFile {
|
||||||
|
return LuetRepositoryFile{
|
||||||
|
FileName: REPOSITORY_METAFILE + ".tar",
|
||||||
|
CompressionType: compiler.None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *LuetRepositoryFile) SetFileName(n string) {
|
||||||
|
f.FileName = n
|
||||||
|
}
|
||||||
|
func (f *LuetRepositoryFile) GetFileName() string {
|
||||||
|
return f.FileName
|
||||||
|
}
|
||||||
|
func (f *LuetRepositoryFile) SetCompressionType(c compiler.CompressionImplementation) {
|
||||||
|
f.CompressionType = c
|
||||||
|
}
|
||||||
|
func (f *LuetRepositoryFile) GetCompressionType() compiler.CompressionImplementation {
|
||||||
|
return f.CompressionType
|
||||||
|
}
|
||||||
|
func (f *LuetRepositoryFile) SetChecksums(c compiler.Checksums) {
|
||||||
|
f.Checksums = c
|
||||||
|
}
|
||||||
|
func (f *LuetRepositoryFile) GetChecksums() compiler.Checksums {
|
||||||
|
return f.Checksums
|
||||||
|
}
|
||||||
|
|
||||||
func GenerateRepository(name, descr, t string, urls []string, priority int, src, treeDir string, db pkg.PackageDatabase) (Repository, error) {
|
func GenerateRepository(name, descr, t string, urls []string, priority int, src, treeDir string, db pkg.PackageDatabase) (Repository, error) {
|
||||||
|
|
||||||
art, err := buildPackageIndex(src)
|
art, err := buildPackageIndex(src)
|
||||||
@@ -100,15 +195,17 @@ func GenerateRepository(name, descr, t string, urls []string, priority int, src,
|
|||||||
|
|
||||||
func NewSystemRepository(repo config.LuetRepository) Repository {
|
func NewSystemRepository(repo config.LuetRepository) Repository {
|
||||||
return &LuetSystemRepository{
|
return &LuetSystemRepository{
|
||||||
LuetRepository: &repo,
|
LuetRepository: &repo,
|
||||||
|
RepositoryFiles: map[string]LuetRepositoryFile{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewLuetSystemRepository(repo *config.LuetRepository, art []compiler.Artifact, builder tree.Builder) Repository {
|
func NewLuetSystemRepository(repo *config.LuetRepository, art []compiler.Artifact, builder tree.Builder) Repository {
|
||||||
return &LuetSystemRepository{
|
return &LuetSystemRepository{
|
||||||
LuetRepository: repo,
|
LuetRepository: repo,
|
||||||
Index: art,
|
Index: art,
|
||||||
Tree: builder,
|
Tree: builder,
|
||||||
|
RepositoryFiles: map[string]LuetRepositoryFile{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,6 +215,7 @@ func NewLuetSystemRepositoryFromYaml(data []byte, db pkg.PackageDatabase) (Repos
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
r := &LuetSystemRepository{
|
r := &LuetSystemRepository{
|
||||||
LuetRepository: config.NewLuetRepository(
|
LuetRepository: config.NewLuetRepository(
|
||||||
p.Name,
|
p.Name,
|
||||||
@@ -128,9 +226,7 @@ func NewLuetSystemRepositoryFromYaml(data []byte, db pkg.PackageDatabase) (Repos
|
|||||||
true,
|
true,
|
||||||
false,
|
false,
|
||||||
),
|
),
|
||||||
TreeCompressionType: p.TreeCompressionType,
|
RepositoryFiles: p.RepositoryFiles,
|
||||||
TreeChecksums: p.TreeChecksums,
|
|
||||||
TreePath: p.TreePath,
|
|
||||||
}
|
}
|
||||||
if p.Revision > 0 {
|
if p.Revision > 0 {
|
||||||
r.Revision = p.Revision
|
r.Revision = p.Revision
|
||||||
@@ -138,11 +234,6 @@ func NewLuetSystemRepositoryFromYaml(data []byte, db pkg.PackageDatabase) (Repos
|
|||||||
if p.LastUpdate != "" {
|
if p.LastUpdate != "" {
|
||||||
r.LastUpdate = p.LastUpdate
|
r.LastUpdate = p.LastUpdate
|
||||||
}
|
}
|
||||||
i := compiler.ArtifactIndex{}
|
|
||||||
for _, ii := range p.Index {
|
|
||||||
i = append(i, ii)
|
|
||||||
}
|
|
||||||
r.Index = i
|
|
||||||
r.Tree = tree.NewInstallerRecipe(db)
|
r.Tree = tree.NewInstallerRecipe(db)
|
||||||
|
|
||||||
return r, err
|
return r, err
|
||||||
@@ -190,22 +281,6 @@ func (r *LuetSystemRepository) GetAuthentication() map[string]string {
|
|||||||
return r.LuetRepository.Authentication
|
return r.LuetRepository.Authentication
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *LuetSystemRepository) GetTreeCompressionType() compiler.CompressionImplementation {
|
|
||||||
return r.TreeCompressionType
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *LuetSystemRepository) GetTreeChecksums() compiler.Checksums {
|
|
||||||
return r.TreeChecksums
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *LuetSystemRepository) SetTreeCompressionType(c compiler.CompressionImplementation) {
|
|
||||||
r.TreeCompressionType = c
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *LuetSystemRepository) SetTreeChecksums(c compiler.Checksums) {
|
|
||||||
r.TreeChecksums = c
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *LuetSystemRepository) GetType() string {
|
func (r *LuetSystemRepository) GetType() string {
|
||||||
return r.LuetRepository.Type
|
return r.LuetRepository.Type
|
||||||
}
|
}
|
||||||
@@ -230,12 +305,21 @@ func (r *LuetSystemRepository) GetTreePath() string {
|
|||||||
func (r *LuetSystemRepository) SetTreePath(p string) {
|
func (r *LuetSystemRepository) SetTreePath(p string) {
|
||||||
r.TreePath = p
|
r.TreePath = p
|
||||||
}
|
}
|
||||||
|
func (r *LuetSystemRepository) GetMetaPath() string {
|
||||||
|
return r.MetaPath
|
||||||
|
}
|
||||||
|
func (r *LuetSystemRepository) SetMetaPath(p string) {
|
||||||
|
r.MetaPath = p
|
||||||
|
}
|
||||||
func (r *LuetSystemRepository) SetTree(b tree.Builder) {
|
func (r *LuetSystemRepository) SetTree(b tree.Builder) {
|
||||||
r.Tree = b
|
r.Tree = b
|
||||||
}
|
}
|
||||||
func (r *LuetSystemRepository) GetIndex() compiler.ArtifactIndex {
|
func (r *LuetSystemRepository) GetIndex() compiler.ArtifactIndex {
|
||||||
return r.Index
|
return r.Index
|
||||||
}
|
}
|
||||||
|
func (r *LuetSystemRepository) SetIndex(i compiler.ArtifactIndex) {
|
||||||
|
r.Index = i
|
||||||
|
}
|
||||||
func (r *LuetSystemRepository) GetTree() tree.Builder {
|
func (r *LuetSystemRepository) GetTree() tree.Builder {
|
||||||
return r.Tree
|
return r.Tree
|
||||||
}
|
}
|
||||||
@@ -251,10 +335,19 @@ func (r *LuetSystemRepository) SetLastUpdate(u string) {
|
|||||||
func (r *LuetSystemRepository) IncrementRevision() {
|
func (r *LuetSystemRepository) IncrementRevision() {
|
||||||
r.LuetRepository.Revision++
|
r.LuetRepository.Revision++
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *LuetSystemRepository) SetAuthentication(auth map[string]string) {
|
func (r *LuetSystemRepository) SetAuthentication(auth map[string]string) {
|
||||||
r.LuetRepository.Authentication = auth
|
r.LuetRepository.Authentication = auth
|
||||||
}
|
}
|
||||||
|
func (r *LuetSystemRepository) GetRepositoryFile(name string) (LuetRepositoryFile, error) {
|
||||||
|
ans, ok := r.RepositoryFiles[name]
|
||||||
|
if ok {
|
||||||
|
return ans, nil
|
||||||
|
}
|
||||||
|
return ans, errors.New("Repository file " + name + " not found!")
|
||||||
|
}
|
||||||
|
func (r *LuetSystemRepository) SetRepositoryFile(name string, f LuetRepositoryFile) {
|
||||||
|
r.RepositoryFiles[name] = f
|
||||||
|
}
|
||||||
|
|
||||||
func (r *LuetSystemRepository) ReadSpecFile(file string, removeFile bool) (Repository, error) {
|
func (r *LuetSystemRepository) ReadSpecFile(file string, removeFile bool) (Repository, error) {
|
||||||
dat, err := ioutil.ReadFile(file)
|
dat, err := ioutil.ReadFile(file)
|
||||||
@@ -271,6 +364,16 @@ func (r *LuetSystemRepository) ReadSpecFile(file string, removeFile bool) (Repos
|
|||||||
return nil, errors.Wrap(err, "Error reading repository from file "+file)
|
return nil, errors.Wrap(err, "Error reading repository from file "+file)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if mandatory key are present
|
||||||
|
_, err = repo.GetRepositoryFile(REPOFILE_TREE_KEY)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("Invalid repository without the " + REPOFILE_TREE_KEY + " key file.")
|
||||||
|
}
|
||||||
|
_, err = repo.GetRepositoryFile(REPOFILE_META_KEY)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("Invalid repository without the " + REPOFILE_META_KEY + " key file.")
|
||||||
|
}
|
||||||
|
|
||||||
return repo, err
|
return repo, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -279,7 +382,6 @@ func (r *LuetSystemRepository) Write(dst string, resetRevision bool) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
r.Index = r.Index.CleanPath()
|
|
||||||
r.LastUpdate = strconv.FormatInt(time.Now().Unix(), 10)
|
r.LastUpdate = strconv.FormatInt(time.Now().Unix(), 10)
|
||||||
|
|
||||||
repospec := filepath.Join(dst, REPOSITORY_SPECFILE)
|
repospec := filepath.Join(dst, REPOSITORY_SPECFILE)
|
||||||
@@ -302,6 +404,7 @@ func (r *LuetSystemRepository) Write(dst string, resetRevision bool) error {
|
|||||||
r.Name, r.Revision, r.LastUpdate,
|
r.Name, r.Revision, r.LastUpdate,
|
||||||
))
|
))
|
||||||
|
|
||||||
|
// Create tree and repository file
|
||||||
archive, err := ioutil.TempDir(os.TempDir(), "archive")
|
archive, err := ioutil.TempDir(os.TempDir(), "archive")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "Error met while creating tempdir for archive")
|
return errors.Wrap(err, "Error met while creating tempdir for archive")
|
||||||
@@ -311,26 +414,68 @@ func (r *LuetSystemRepository) Write(dst string, resetRevision bool) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "Error met while saving the tree")
|
return errors.Wrap(err, "Error met while saving the tree")
|
||||||
}
|
}
|
||||||
tpath := r.GetTreePath()
|
|
||||||
if tpath == "" {
|
treeFile, err := r.GetRepositoryFile(REPOFILE_TREE_KEY)
|
||||||
tpath = TREE_TARBALL
|
if err != nil {
|
||||||
|
treeFile = NewDefaultTreeRepositoryFile()
|
||||||
|
r.SetRepositoryFile(REPOFILE_TREE_KEY, treeFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
a := compiler.NewPackageArtifact(filepath.Join(dst, tpath))
|
a := compiler.NewPackageArtifact(filepath.Join(dst, treeFile.GetFileName()))
|
||||||
a.SetCompressionType(r.TreeCompressionType)
|
a.SetCompressionType(treeFile.GetCompressionType())
|
||||||
err = a.Compress(archive, 1)
|
err = a.Compress(archive, 1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "Error met while creating package archive")
|
return errors.Wrap(err, "Error met while creating package archive")
|
||||||
}
|
}
|
||||||
|
|
||||||
r.TreePath = path.Base(a.GetPath())
|
// Update the tree name with the name created by compression selected.
|
||||||
|
treeFile.SetFileName(path.Base(a.GetPath()))
|
||||||
err = a.Hash()
|
err = a.Hash()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "Failed generating checksums for tree")
|
return errors.Wrap(err, "Failed generating checksums for tree")
|
||||||
}
|
}
|
||||||
r.TreeChecksums = a.GetChecksums()
|
treeFile.SetChecksums(a.GetChecksums())
|
||||||
|
r.SetRepositoryFile(REPOFILE_TREE_KEY, treeFile)
|
||||||
|
|
||||||
data, err := yaml.Marshal(r)
|
// Create Metadata struct and serialized repository
|
||||||
|
meta, serialized := r.Serialize()
|
||||||
|
|
||||||
|
// Create metadata file and repository file
|
||||||
|
metaTmpDir, err := ioutil.TempDir(os.TempDir(), "metadata")
|
||||||
|
defer os.RemoveAll(metaTmpDir) // clean up
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "Error met while creating tempdir for metadata")
|
||||||
|
}
|
||||||
|
|
||||||
|
metaFile, err := r.GetRepositoryFile(REPOFILE_META_KEY)
|
||||||
|
if err != nil {
|
||||||
|
metaFile = NewDefaultMetaRepositoryFile()
|
||||||
|
r.SetRepositoryFile(REPOFILE_META_KEY, metaFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
repoMetaSpec := filepath.Join(metaTmpDir, REPOSITORY_METAFILE)
|
||||||
|
// Create repository.meta.yaml file
|
||||||
|
err = meta.WriteFile(repoMetaSpec)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
a = compiler.NewPackageArtifact(filepath.Join(dst, metaFile.GetFileName()))
|
||||||
|
a.SetCompressionType(metaFile.GetCompressionType())
|
||||||
|
err = a.Compress(metaTmpDir, 1)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "Error met while archiving repository metadata")
|
||||||
|
}
|
||||||
|
|
||||||
|
metaFile.SetFileName(path.Base(a.GetPath()))
|
||||||
|
r.SetRepositoryFile(REPOFILE_META_KEY, metaFile)
|
||||||
|
err = a.Hash()
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "Failed generating checksums for metadata")
|
||||||
|
}
|
||||||
|
metaFile.SetChecksums(a.GetChecksums())
|
||||||
|
|
||||||
|
data, err := yaml.Marshal(serialized)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -358,7 +503,7 @@ func (r *LuetSystemRepository) Client() Client {
|
|||||||
}
|
}
|
||||||
func (r *LuetSystemRepository) Sync(force bool) (Repository, error) {
|
func (r *LuetSystemRepository) Sync(force bool) (Repository, error) {
|
||||||
var repoUpdated bool = false
|
var repoUpdated bool = false
|
||||||
var treefs string
|
var treefs, metafs string
|
||||||
|
|
||||||
Debug("Sync of the repository", r.Name, "in progress...")
|
Debug("Sync of the repository", r.Name, "in progress...")
|
||||||
c := r.Client()
|
c := r.Client()
|
||||||
@@ -396,37 +541,72 @@ func (r *LuetSystemRepository) Sync(force bool) (Repository, error) {
|
|||||||
} else {
|
} else {
|
||||||
treefs = r.GetTreePath()
|
treefs = r.GetTreePath()
|
||||||
}
|
}
|
||||||
|
if r.GetMetaPath() == "" {
|
||||||
|
metafs = filepath.Join(repobasedir, "metafs")
|
||||||
|
} else {
|
||||||
|
metafs = r.GetMetaPath()
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
treefs, err = ioutil.TempDir(os.TempDir(), "treefs")
|
treefs, err = ioutil.TempDir(os.TempDir(), "treefs")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "Error met while creating tempdir for rootfs")
|
return nil, errors.Wrap(err, "Error met while creating tempdir for rootfs")
|
||||||
}
|
}
|
||||||
|
// If we always remove them, later on, no other structure can access
|
||||||
|
// to the tree for e.g. to retrieve finalizers
|
||||||
|
//defer os.RemoveAll(treefs)
|
||||||
|
|
||||||
|
metafs, err = ioutil.TempDir(os.TempDir(), "metafs")
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error met whilte creating tempdir for metafs")
|
||||||
|
}
|
||||||
|
//defer os.RemoveAll(metafs)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// POST: treeFile and metaFile are present. I check this inside
|
||||||
|
// ReadSpecFile and NewLuetSystemRepositoryFromYaml
|
||||||
|
treeFile, _ := repo.GetRepositoryFile(REPOFILE_TREE_KEY)
|
||||||
|
metaFile, _ := repo.GetRepositoryFile(REPOFILE_META_KEY)
|
||||||
|
|
||||||
if !repoUpdated {
|
if !repoUpdated {
|
||||||
tpath := repo.GetTreePath()
|
|
||||||
if tpath == "" {
|
|
||||||
tpath = TREE_TARBALL
|
|
||||||
}
|
|
||||||
a := compiler.NewPackageArtifact(tpath)
|
|
||||||
|
|
||||||
artifact, err := c.DownloadArtifact(a)
|
// Get Tree
|
||||||
|
a := compiler.NewPackageArtifact(treeFile.GetFileName())
|
||||||
|
artifactTree, err := c.DownloadArtifact(a)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "While downloading "+tpath)
|
return nil, errors.Wrap(err, "While downloading "+treeFile.GetFileName())
|
||||||
}
|
}
|
||||||
defer os.Remove(artifact.GetPath())
|
defer os.Remove(artifactTree.GetPath())
|
||||||
|
|
||||||
artifact.SetChecksums(repo.GetTreeChecksums())
|
artifactTree.SetChecksums(treeFile.GetChecksums())
|
||||||
artifact.SetCompressionType(repo.GetTreeCompressionType())
|
artifactTree.SetCompressionType(treeFile.GetCompressionType())
|
||||||
|
|
||||||
err = artifact.Verify()
|
err = artifactTree.Verify()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "Tree integrity check failure")
|
return nil, errors.Wrap(err, "Tree integrity check failure")
|
||||||
}
|
}
|
||||||
|
|
||||||
Debug("Tree tarball for the repository " + r.GetName() + " downloaded correctly.")
|
Debug("Tree tarball for the repository " + r.GetName() + " downloaded correctly.")
|
||||||
|
|
||||||
|
// Get Repository Metadata
|
||||||
|
a = compiler.NewPackageArtifact(metaFile.GetFileName())
|
||||||
|
artifactMeta, err := c.DownloadArtifact(a)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "While downloading "+metaFile.GetFileName())
|
||||||
|
}
|
||||||
|
defer os.Remove(artifactMeta.GetPath())
|
||||||
|
|
||||||
|
artifactMeta.SetChecksums(metaFile.GetChecksums())
|
||||||
|
artifactMeta.SetCompressionType(metaFile.GetCompressionType())
|
||||||
|
|
||||||
|
err = artifactMeta.Verify()
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Metadata integrity check failure")
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug("Metadata tarball for the repository " + r.GetName() + " downloaded correctly.")
|
||||||
|
|
||||||
if r.Cached {
|
if r.Cached {
|
||||||
// Copy updated repository.yaml file to repo dir now that the tree is synced.
|
// Copy updated repository.yaml file to repo dir now that the tree is synced.
|
||||||
err = helpers.CopyFile(file, filepath.Join(repobasedir, REPOSITORY_SPECFILE))
|
err = helpers.CopyFile(file, filepath.Join(repobasedir, REPOSITORY_SPECFILE))
|
||||||
@@ -435,14 +615,24 @@ func (r *LuetSystemRepository) Sync(force bool) (Repository, error) {
|
|||||||
}
|
}
|
||||||
// Remove previous tree
|
// Remove previous tree
|
||||||
os.RemoveAll(treefs)
|
os.RemoveAll(treefs)
|
||||||
|
// Remove previous meta dir
|
||||||
|
os.RemoveAll(metafs)
|
||||||
}
|
}
|
||||||
Debug("Decompress tree of the repository " + r.Name + "...")
|
Debug("Decompress tree of the repository " + r.Name + "...")
|
||||||
|
|
||||||
err = artifact.Unpack(treefs, true)
|
err = artifactTree.Unpack(treefs, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "Error met while unpacking tree")
|
return nil, errors.Wrap(err, "Error met while unpacking tree")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: It seems that tar with only one file doesn't create destination
|
||||||
|
// directory. I create directory directly for now.
|
||||||
|
os.MkdirAll(metafs, os.ModePerm)
|
||||||
|
err = artifactMeta.Unpack(metafs, true)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error met while unpacking metadata")
|
||||||
|
}
|
||||||
|
|
||||||
tsec, _ := strconv.ParseInt(repo.GetLastUpdate(), 10, 64)
|
tsec, _ := strconv.ParseInt(repo.GetLastUpdate(), 10, 64)
|
||||||
|
|
||||||
InfoC(
|
InfoC(
|
||||||
@@ -455,6 +645,14 @@ func (r *LuetSystemRepository) Sync(force bool) (Repository, error) {
|
|||||||
Info("Repository", r.GetName(), "is already up to date.")
|
Info("Repository", r.GetName(), "is already up to date.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
meta, err := NewLuetSystemRepositoryMetadata(
|
||||||
|
filepath.Join(metafs, REPOSITORY_METAFILE), false,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "While processing "+REPOSITORY_METAFILE)
|
||||||
|
}
|
||||||
|
repo.SetIndex(meta.ToArtificatIndex())
|
||||||
|
|
||||||
reciper := tree.NewInstallerRecipe(pkg.NewInMemoryDatabase(false))
|
reciper := tree.NewInstallerRecipe(pkg.NewInMemoryDatabase(false))
|
||||||
err = reciper.Load(treefs)
|
err = reciper.Load(treefs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -469,6 +667,34 @@ func (r *LuetSystemRepository) Sync(force bool) (Repository, error) {
|
|||||||
return repo, nil
|
return repo, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *LuetSystemRepository) Serialize() (*LuetSystemRepositoryMetadata, LuetSystemRepositorySerialized) {
|
||||||
|
|
||||||
|
serialized := LuetSystemRepositorySerialized{
|
||||||
|
Name: r.Name,
|
||||||
|
Description: r.Description,
|
||||||
|
Urls: r.Urls,
|
||||||
|
Priority: r.Priority,
|
||||||
|
Type: r.Type,
|
||||||
|
Revision: r.Revision,
|
||||||
|
LastUpdate: r.LastUpdate,
|
||||||
|
RepositoryFiles: r.RepositoryFiles,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if is needed set the index or simply use
|
||||||
|
// value returned by CleanPath
|
||||||
|
r.Index = r.Index.CleanPath()
|
||||||
|
|
||||||
|
meta := &LuetSystemRepositoryMetadata{
|
||||||
|
Index: []*compiler.PackageArtifact{},
|
||||||
|
}
|
||||||
|
for _, a := range r.Index {
|
||||||
|
art := a.(*compiler.PackageArtifact)
|
||||||
|
meta.Index = append(meta.Index, art)
|
||||||
|
}
|
||||||
|
|
||||||
|
return meta, serialized
|
||||||
|
}
|
||||||
|
|
||||||
func (r Repositories) Len() int { return len(r) }
|
func (r Repositories) Len() int { return len(r) }
|
||||||
func (r Repositories) Swap(i, j int) { r[i], r[j] = r[j], r[i] }
|
func (r Repositories) Swap(i, j int) { r[i], r[j] = r[j], r[i] }
|
||||||
func (r Repositories) Less(i, j int) bool {
|
func (r Repositories) Less(i, j int) bool {
|
||||||
|
@@ -86,12 +86,14 @@ var _ = Describe("Repository", func() {
|
|||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(repo.GetName()).To(Equal("test"))
|
Expect(repo.GetName()).To(Equal("test"))
|
||||||
Expect(helpers.Exists(spec.Rel(REPOSITORY_SPECFILE))).ToNot(BeTrue())
|
Expect(helpers.Exists(spec.Rel(REPOSITORY_SPECFILE))).ToNot(BeTrue())
|
||||||
Expect(helpers.Exists(spec.Rel(TREE_TARBALL))).ToNot(BeTrue())
|
Expect(helpers.Exists(spec.Rel(TREE_TARBALL + ".gz"))).ToNot(BeTrue())
|
||||||
|
Expect(helpers.Exists(spec.Rel(REPOSITORY_METAFILE + ".tar"))).ToNot(BeTrue())
|
||||||
err = repo.Write(tmpdir, false)
|
err = repo.Write(tmpdir, false)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
Expect(helpers.Exists(spec.Rel(REPOSITORY_SPECFILE))).To(BeTrue())
|
Expect(helpers.Exists(spec.Rel(REPOSITORY_SPECFILE))).To(BeTrue())
|
||||||
Expect(helpers.Exists(spec.Rel(TREE_TARBALL))).To(BeTrue())
|
Expect(helpers.Exists(spec.Rel(TREE_TARBALL + ".gz"))).To(BeTrue())
|
||||||
|
Expect(helpers.Exists(spec.Rel(REPOSITORY_METAFILE + ".tar"))).To(BeTrue())
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
Context("Matching packages", func() {
|
Context("Matching packages", func() {
|
||||||
|
@@ -141,16 +141,16 @@ func (t *DefaultPackage) JSON() ([]byte, error) {
|
|||||||
|
|
||||||
// DefaultPackage represent a standard package definition
|
// DefaultPackage represent a standard package definition
|
||||||
type DefaultPackage struct {
|
type DefaultPackage struct {
|
||||||
ID int `storm:"id,increment" json:"id"` // primary key with auto increment
|
ID int `storm:"id,increment" json:"id"` // primary key with auto increment
|
||||||
Name string `json:"name"` // Affects YAML field names too.
|
Name string `json:"name"` // Affects YAML field names too.
|
||||||
Version string `json:"version"` // Affects YAML field names too.
|
Version string `json:"version"` // Affects YAML field names too.
|
||||||
Category string `json:"category"` // Affects YAML field names too.
|
Category string `json:"category"` // Affects YAML field names too.
|
||||||
UseFlags []string `json:"use_flags"` // Affects YAML field names too.
|
UseFlags []string `json:"use_flags,omitempty"` // Affects YAML field names too.
|
||||||
State State
|
State State `json:"state,omitempty"`
|
||||||
PackageRequires []*DefaultPackage `json:"requires"` // Affects YAML field names too.
|
PackageRequires []*DefaultPackage `json:"requires"` // Affects YAML field names too.
|
||||||
PackageConflicts []*DefaultPackage `json:"conflicts"` // Affects YAML field names too.
|
PackageConflicts []*DefaultPackage `json:"conflicts"` // Affects YAML field names too.
|
||||||
IsSet bool `json:"set"` // Affects YAML field names too.
|
IsSet bool `json:"set,omitempty"` // Affects YAML field names too.
|
||||||
Provides []*DefaultPackage `json:"provides"` // Affects YAML field names too.
|
Provides []*DefaultPackage `json:"provides,omitempty"` // Affects YAML field names too.
|
||||||
|
|
||||||
// TODO: Annotations?
|
// TODO: Annotations?
|
||||||
|
|
||||||
|
@@ -23,7 +23,7 @@ coveragetxt="coverage.txt"
|
|||||||
|
|
||||||
|
|
||||||
generate_cover_data() {
|
generate_cover_data() {
|
||||||
ginkgo -failFast -cover -r .
|
ginkgo -flakeAttempts=3 -race -failFast -cover -r .
|
||||||
echo "" > ${coveragetxt}
|
echo "" > ${coveragetxt}
|
||||||
find . -type f -name "*.coverprofile" | while read -r file; do cat "$file" >> ${coveragetxt} && mv "$file" "${coverdir}"; done
|
find . -type f -name "*.coverprofile" | while read -r file; do cat "$file" >> ${coveragetxt} && mv "$file" "${coverdir}"; done
|
||||||
echo "mode: $covermode" >"$profile"
|
echo "mode: $covermode" >"$profile"
|
||||||
|
2
tests/fixtures/finalizers/alpine/build.yaml
vendored
Normal file
2
tests/fixtures/finalizers/alpine/build.yaml
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
image: "alpine"
|
||||||
|
unpack: true
|
3
tests/fixtures/finalizers/alpine/definition.yaml
vendored
Normal file
3
tests/fixtures/finalizers/alpine/definition.yaml
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
category: "seed"
|
||||||
|
name: "alpine"
|
||||||
|
version: "1.0"
|
2
tests/fixtures/finalizers/alpine/finalize.yaml
vendored
Normal file
2
tests/fixtures/finalizers/alpine/finalize.yaml
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
install:
|
||||||
|
- touch /tmp/foo
|
@@ -28,7 +28,7 @@ testRepo() {
|
|||||||
--descr "Test Repo" \
|
--descr "Test Repo" \
|
||||||
--urls $tmpdir/testrootfs \
|
--urls $tmpdir/testrootfs \
|
||||||
--tree-compression gzip \
|
--tree-compression gzip \
|
||||||
--tree-path foo.tar \
|
--tree-filename foo.tar \
|
||||||
--type disk > /dev/null
|
--type disk > /dev/null
|
||||||
|
|
||||||
createst=$?
|
createst=$?
|
||||||
|
107
tests/integration/01_simple_meta_gzip.sh
Executable file
107
tests/integration/01_simple_meta_gzip.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/testbuild
|
||||||
|
luet build --tree "$ROOT_DIR/tests/fixtures/buildableseed" --destination $tmpdir/testbuild --compression gzip test/c-1.0 > /dev/null
|
||||||
|
buildst=$?
|
||||||
|
assertEquals 'builds successfully' "$buildst" "0"
|
||||||
|
assertTrue 'create package dep B' "[ -e '$tmpdir/testbuild/b-test-1.0.package.tar.gz' ]"
|
||||||
|
assertTrue 'create package' "[ -e '$tmpdir/testbuild/c-test-1.0.package.tar.gz' ]"
|
||||||
|
}
|
||||||
|
|
||||||
|
testRepo() {
|
||||||
|
assertTrue 'no repository' "[ ! -e '$tmpdir/testbuild/repository.yaml' ]"
|
||||||
|
luet create-repo --tree "$ROOT_DIR/tests/fixtures/buildableseed" \
|
||||||
|
--output $tmpdir/testbuild \
|
||||||
|
--packages $tmpdir/testbuild \
|
||||||
|
--name "test" \
|
||||||
|
--descr "Test Repo" \
|
||||||
|
--urls $tmpdir/testrootfs \
|
||||||
|
--tree-compression gzip \
|
||||||
|
--tree-filename foo.tar \
|
||||||
|
--meta-filename repository.meta.tar \
|
||||||
|
--meta-compression gzip \
|
||||||
|
--type disk > /dev/null
|
||||||
|
|
||||||
|
createst=$?
|
||||||
|
assertEquals 'create repo successfully' "$createst" "0"
|
||||||
|
assertTrue 'create repository' "[ -e '$tmpdir/testbuild/repository.yaml' ]"
|
||||||
|
assertTrue 'create named tree in gzip' "[ -e '$tmpdir/testbuild/foo.tar.gz' ]"
|
||||||
|
assertTrue 'create tree in gzip-only' "[ ! -e '$tmpdir/testbuild/foo.tar' ]"
|
||||||
|
assertTrue 'create named meta in gzip' "[ -e '$tmpdir/testbuild/repository.meta.tar.gz' ]"
|
||||||
|
assertTrue 'create meta in gzip-only' "[ ! -e '$tmpdir/testbuild/repository.meta.tar' ]"
|
||||||
|
}
|
||||||
|
|
||||||
|
testConfig() {
|
||||||
|
mkdir $tmpdir/testrootfs
|
||||||
|
cat <<EOF > $tmpdir/luet.yaml
|
||||||
|
general:
|
||||||
|
debug: true
|
||||||
|
system:
|
||||||
|
rootfs: $tmpdir/testrootfs
|
||||||
|
database_path: "/"
|
||||||
|
database_engine: "boltdb"
|
||||||
|
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 install --config $tmpdir/luet.yaml test/c-1.0
|
||||||
|
#luet install --config $tmpdir/luet.yaml test/c-1.0 > /dev/null
|
||||||
|
installst=$?
|
||||||
|
assertEquals 'install test successfully' "$installst" "0"
|
||||||
|
assertTrue 'package installed' "[ -e '$tmpdir/testrootfs/c' ]"
|
||||||
|
}
|
||||||
|
|
||||||
|
testReInstall() {
|
||||||
|
output=$(luet install --config $tmpdir/luet.yaml test/c-1.0)
|
||||||
|
installst=$?
|
||||||
|
assertEquals 'install test successfully' "$installst" "0"
|
||||||
|
assertContains 'contains warning' "$output" 'Filtering out'
|
||||||
|
}
|
||||||
|
|
||||||
|
testUnInstall() {
|
||||||
|
luet uninstall --config $tmpdir/luet.yaml test/c-1.0
|
||||||
|
installst=$?
|
||||||
|
assertEquals 'uninstall test successfully' "$installst" "0"
|
||||||
|
assertTrue 'package uninstalled' "[ ! -e '$tmpdir/testrootfs/c' ]"
|
||||||
|
}
|
||||||
|
|
||||||
|
testInstallAgain() {
|
||||||
|
assertTrue 'package uninstalled' "[ ! -e '$tmpdir/testrootfs/c' ]"
|
||||||
|
output=$(luet install --config $tmpdir/luet.yaml test/c-1.0)
|
||||||
|
installst=$?
|
||||||
|
assertEquals 'install test successfully' "$installst" "0"
|
||||||
|
assertNotContains 'contains warning' "$output" 'Filtering out'
|
||||||
|
assertTrue 'package installed' "[ -e '$tmpdir/testrootfs/c' ]"
|
||||||
|
assertTrue 'package in cache' "[ -e '$tmpdir/testrootfs/packages/c-test-1.0.package.tar.gz' ]"
|
||||||
|
}
|
||||||
|
|
||||||
|
testCleanup() {
|
||||||
|
luet cleanup --config $tmpdir/luet.yaml
|
||||||
|
installst=$?
|
||||||
|
assertEquals 'install test successfully' "$installst" "0"
|
||||||
|
assertTrue 'package installed' "[ ! -e '$tmpdir/testrootfs/packages/c-test-1.0.package.tar.gz' ]"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Load shUnit2.
|
||||||
|
. "$ROOT_DIR/tests/integration/shunit2"/shunit2
|
||||||
|
|
@@ -108,13 +108,15 @@ testInstall() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
testUpgrade() {
|
testUpgrade() {
|
||||||
luet --config $tmpdir/luet.yaml upgrade
|
upgrade=$(luet --config $tmpdir/luet.yaml upgrade)
|
||||||
installst=$?
|
installst=$?
|
||||||
assertEquals 'install test successfully' "$installst" "0"
|
assertEquals 'install test successfully' "$installst" "0"
|
||||||
assertTrue 'package uninstalled B' "[ ! -e '$tmpdir/testrootfs/test5' ]"
|
assertTrue 'package uninstalled B' "[ ! -e '$tmpdir/testrootfs/test5' ]"
|
||||||
assertTrue 'package installed B' "[ -e '$tmpdir/testrootfs/newc' ]"
|
assertTrue 'package installed B' "[ -e '$tmpdir/testrootfs/newc' ]"
|
||||||
assertTrue 'package uninstalled A' "[ ! -e '$tmpdir/testrootfs/testaa' ]"
|
assertTrue 'package uninstalled A' "[ ! -e '$tmpdir/testrootfs/testaa' ]"
|
||||||
assertTrue 'package installed new A' "[ -e '$tmpdir/testrootfs/testlatest' ]"
|
assertTrue 'package installed new A' "[ -e '$tmpdir/testrootfs/testlatest' ]"
|
||||||
|
assertNotContains 'does not contain test/c-1.0' "$upgrade" 'test/c-1.0'
|
||||||
|
assertNotContains 'does not attempt to download test/c-1.0' "$upgrade" 'test/c-1.0 downloaded'
|
||||||
}
|
}
|
||||||
|
|
||||||
# Load shUnit2.
|
# Load shUnit2.
|
||||||
|
121
tests/integration/06_search.sh
Executable file
121
tests/integration/06_search.sh
Executable file
@@ -0,0 +1,121 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
export LUET_NOLOCK=true
|
||||||
|
oneTimeSetUp() {
|
||||||
|
export tmpdir="$(mktemp -d)"
|
||||||
|
}
|
||||||
|
|
||||||
|
oneTimeTearDown() {
|
||||||
|
rm -rf "$tmpdir"
|
||||||
|
}
|
||||||
|
|
||||||
|
testBuild() {
|
||||||
|
mkdir $tmpdir/testbuild
|
||||||
|
luet build --tree "$ROOT_DIR/tests/fixtures/upgrade_integration" --destination $tmpdir/testbuild --compression gzip test/b-1.0
|
||||||
|
buildst=$?
|
||||||
|
assertTrue 'create package B 1.0' "[ -e '$tmpdir/testbuild/b-test-1.0.package.tar.gz' ]"
|
||||||
|
assertEquals 'builds successfully' "$buildst" "0"
|
||||||
|
|
||||||
|
luet build --tree "$ROOT_DIR/tests/fixtures/upgrade_integration" --destination $tmpdir/testbuild --compression gzip test/b-1.1
|
||||||
|
buildst=$?
|
||||||
|
assertEquals 'builds successfully' "$buildst" "0"
|
||||||
|
assertTrue 'create package B 1.1' "[ -e '$tmpdir/testbuild/b-test-1.1.package.tar.gz' ]"
|
||||||
|
|
||||||
|
luet build --tree "$ROOT_DIR/tests/fixtures/upgrade_integration" --destination $tmpdir/testbuild --compression gzip test/a-1.0
|
||||||
|
buildst=$?
|
||||||
|
assertEquals 'builds successfully' "$buildst" "0"
|
||||||
|
assertTrue 'create package A 1.0' "[ -e '$tmpdir/testbuild/a-test-1.0.package.tar.gz' ]"
|
||||||
|
|
||||||
|
luet build --tree "$ROOT_DIR/tests/fixtures/upgrade_integration" --destination $tmpdir/testbuild --compression gzip test/a-1.1
|
||||||
|
buildst=$?
|
||||||
|
assertEquals 'builds successfully' "$buildst" "0"
|
||||||
|
|
||||||
|
assertTrue 'create package A 1.1' "[ -e '$tmpdir/testbuild/a-test-1.1.package.tar.gz' ]"
|
||||||
|
|
||||||
|
luet build --tree "$ROOT_DIR/tests/fixtures/upgrade_integration" --destination $tmpdir/testbuild --compression gzip test/a-1.2
|
||||||
|
buildst=$?
|
||||||
|
assertEquals 'builds successfully' "$buildst" "0"
|
||||||
|
|
||||||
|
assertTrue 'create package A 1.2' "[ -e '$tmpdir/testbuild/a-test-1.2.package.tar.gz' ]"
|
||||||
|
|
||||||
|
|
||||||
|
luet build --tree "$ROOT_DIR/tests/fixtures/upgrade_integration" --destination $tmpdir/testbuild --compression gzip test/c-1.0
|
||||||
|
buildst=$?
|
||||||
|
assertEquals 'builds successfully' "$buildst" "0"
|
||||||
|
assertTrue 'create package C 1.0' "[ -e '$tmpdir/testbuild/c-test-1.0.package.tar.gz' ]"
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
testRepo() {
|
||||||
|
assertTrue 'no repository' "[ ! -e '$tmpdir/testbuild/repository.yaml' ]"
|
||||||
|
luet create-repo --tree "$ROOT_DIR/tests/fixtures/upgrade_integration" \
|
||||||
|
--output $tmpdir/testbuild \
|
||||||
|
--packages $tmpdir/testbuild \
|
||||||
|
--name "test" \
|
||||||
|
--descr "Test Repo" \
|
||||||
|
--urls $tmpdir/testrootfs \
|
||||||
|
--type disk
|
||||||
|
|
||||||
|
createst=$?
|
||||||
|
assertEquals 'create repo successfully' "$createst" "0"
|
||||||
|
assertTrue 'create repository' "[ -e '$tmpdir/testbuild/repository.yaml' ]"
|
||||||
|
}
|
||||||
|
|
||||||
|
testConfig() {
|
||||||
|
mkdir $tmpdir/testrootfs
|
||||||
|
cat <<EOF > $tmpdir/luet.yaml
|
||||||
|
general:
|
||||||
|
debug: true
|
||||||
|
system:
|
||||||
|
rootfs: $tmpdir/testrootfs
|
||||||
|
database_path: "/"
|
||||||
|
database_engine: "boltdb"
|
||||||
|
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 install --config $tmpdir/luet.yaml test/b-1.0
|
||||||
|
installst=$?
|
||||||
|
assertEquals 'install test successfully' "$installst" "0"
|
||||||
|
assertTrue 'package installed B' "[ -e '$tmpdir/testrootfs/test5' ]"
|
||||||
|
|
||||||
|
luet install --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 --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 --config $tmpdir/luet.yaml test/c-1.0
|
||||||
|
installst=$?
|
||||||
|
assertEquals 'install test successfully' "$installst" "0"
|
||||||
|
assertTrue 'package installed C' "[ -e '$tmpdir/testrootfs/c' ]"
|
||||||
|
}
|
||||||
|
|
||||||
|
testSearch() {
|
||||||
|
installed=$(luet --config $tmpdir/luet.yaml search --installed .)
|
||||||
|
searchst=$?
|
||||||
|
assertEquals 'search exists successfully' "$searchst" "0"
|
||||||
|
|
||||||
|
assertContains 'contains test/b-1.0' "$installed" 'test b 1.0'
|
||||||
|
assertContains 'contains test/a-1.0' "$installed" 'test a 1.0'
|
||||||
|
assertContains 'contains test/c-1.0' "$installed" 'test c 1.0'
|
||||||
|
}
|
||||||
|
|
||||||
|
# Load shUnit2.
|
||||||
|
. "$ROOT_DIR/tests/integration/shunit2"/shunit2
|
||||||
|
|
75
tests/integration/07_finalizer.sh
Executable file
75
tests/integration/07_finalizer.sh
Executable file
@@ -0,0 +1,75 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
export LUET_NOLOCK=true
|
||||||
|
|
||||||
|
oneTimeSetUp() {
|
||||||
|
export tmpdir="$(mktemp -d)"
|
||||||
|
}
|
||||||
|
|
||||||
|
oneTimeTearDown() {
|
||||||
|
rm -rf "$tmpdir"
|
||||||
|
}
|
||||||
|
|
||||||
|
testBuild() {
|
||||||
|
mkdir $tmpdir/testbuild
|
||||||
|
luet build --tree "$ROOT_DIR/tests/fixtures/finalizers" --destination $tmpdir/testbuild --compression gzip --all > /dev/null
|
||||||
|
buildst=$?
|
||||||
|
assertEquals 'builds successfully' "$buildst" "0"
|
||||||
|
assertTrue 'create package' "[ -e '$tmpdir/testbuild/alpine-seed-1.0.package.tar.gz' ]"
|
||||||
|
}
|
||||||
|
|
||||||
|
testRepo() {
|
||||||
|
assertTrue 'no repository' "[ ! -e '$tmpdir/testbuild/repository.yaml' ]"
|
||||||
|
luet create-repo --tree "$ROOT_DIR/tests/fixtures/finalizers" \
|
||||||
|
--output $tmpdir/testbuild \
|
||||||
|
--packages $tmpdir/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/testbuild/repository.yaml' ]"
|
||||||
|
}
|
||||||
|
|
||||||
|
testConfig() {
|
||||||
|
mkdir $tmpdir/testrootfs
|
||||||
|
cat <<EOF > $tmpdir/luet.yaml
|
||||||
|
general:
|
||||||
|
debug: true
|
||||||
|
system:
|
||||||
|
rootfs: $tmpdir/testrootfs
|
||||||
|
database_path: "/"
|
||||||
|
database_engine: "boltdb"
|
||||||
|
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 install --config $tmpdir/luet.yaml seed/alpine
|
||||||
|
#luet install --config $tmpdir/luet.yaml test/c-1.0 > /dev/null
|
||||||
|
installst=$?
|
||||||
|
assertEquals 'install test successfully' "$installst" "0"
|
||||||
|
assertTrue 'package installed' "[ -e '$tmpdir/testrootfs/bin/busybox' ]"
|
||||||
|
assertTrue 'finalizer runs' "[ -e '$tmpdir/testrootfs/tmp/foo' ]"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
testCleanup() {
|
||||||
|
luet cleanup --config $tmpdir/luet.yaml
|
||||||
|
installst=$?
|
||||||
|
assertEquals 'install test successfully' "$installst" "0"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Load shUnit2.
|
||||||
|
. "$ROOT_DIR/tests/integration/shunit2"/shunit2
|
||||||
|
|
Reference in New Issue
Block a user