Merge pull request #6 from d4s/docs

actions: add description of actions
This commit is contained in:
Sjoerd Simons
2017-10-12 13:43:50 +02:00
committed by GitHub
16 changed files with 923 additions and 64 deletions

51
.gitignore vendored Normal file
View File

@@ -0,0 +1,51 @@
# Created by https://www.gitignore.io/api/vim,linux,go
### Go ###
# Binaries for programs and plugins
*.exe
*.dll
*.so
*.dylib
# Test binary, build with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
.glide/
# Golang project vendor packages which should be ignored
vendor/
### Linux ###
*~
# temporary files which can be created if a process still has a handle open of a deleted file
.fuse_hidden*
# KDE directory preferences
.directory
# Linux trash folder which might appear on any partition or disk
.Trash-*
# .nfs files are created when an open file is removed but is still being accessed
.nfs*
### Vim ###
# swap
[._]*.s[a-v][a-z]
[._]*.sw[a-p]
[._]s[a-v][a-z]
[._]sw[a-p]
# session
Session.vim
# temporary
.netrwhist
# auto-generated tag files
tags
# End of https://www.gitignore.io/api/vim,linux,go

6
actions/actions_doc.go Normal file
View File

@@ -0,0 +1,6 @@
// Copyright 2017, Collabora Ltd.
/*
Package 'actions' implements 'debos' modules used for OS creation.
*/
package actions

View File

@@ -1,3 +1,23 @@
/*
Apt Action
Install packages and their dependencies to the target rootfs with 'apt'.
Yaml syntax:
- action: apt
recommends: bool
packages:
- package1
- package2
Mandatory properties:
- packages -- list of packages to install
Optional properties:
- recommends -- boolean indicating if suggested packages will be installed
*/
package actions
import (
@@ -6,8 +26,8 @@ import (
type AptAction struct {
debos.BaseAction `yaml:",inline"`
Recommends bool
Packages []string
Recommends bool
Packages []string
}
func (apt *AptAction) Run(context *debos.DebosContext) error {

View File

@@ -1,3 +1,32 @@
/*
Debootstrap Action
Construct the target rootfs with debootstrap tool.
Yaml syntax:
- action: debootstrap
mirror: URL
suite: "name"
components: <list of components>
variant: "name"
keyring-package:
Mandatory properties:
- suite -- release code name or symbolic name (e.g. "stable")
Optional properties:
- mirror -- URL with Debian-compatible repository
- variant -- name of the bootstrap script variant to use
- components -- list of components to use for packages selection.
Example:
components: [ main, contrib ]
- keyring-package -- keyring for packages validation. Currently ignored.
*/
package actions
import (
@@ -11,13 +40,13 @@ import (
)
type DebootstrapAction struct {
debos.BaseAction `yaml:",inline"`
Suite string
Mirror string
Variant string
KeyringPackage string `yaml:"keyring-package"`
Components []string
MergedUsr bool `yaml:"merged-usr"`
debos.BaseAction `yaml:",inline"`
Suite string
Mirror string
Variant string
KeyringPackage string `yaml:"keyring-package"`
Components []string
MergedUsr bool `yaml:"merged-usr"`
}
func NewDebootstrapAction() *DebootstrapAction {
@@ -25,6 +54,7 @@ func NewDebootstrapAction() *DebootstrapAction {
// Use filesystem with merged '/usr' by default
d.MergedUsr = true
return &d
}
func (d *DebootstrapAction) RunSecondStage(context debos.DebosContext) error {

View File

@@ -1,3 +1,35 @@
/*
Download Action
Download a single file from Internet and unpack it in place if needed.
Yaml syntax:
- action: download
url: http://example.domain/path/filename.ext
name: firmware
filename: output_name
unpack: bool
compression: gz
Mandatory properties:
- url -- URL to an object for download
- name -- string which allow to use downloaded object in other actions
via 'origin' property. If 'unpack' property is set to 'true' name will
refer to temporary directory with extracted content.
Optional properties:
- filename -- use this property as the name for saved file. Useful if URL does not
contain file name in path, for example it is possible to download files from URLs without path part.
- unpack -- hint for action to extract all files from downloaded archive.
See the 'Unpack' action for more information.
- compression -- optional hint for unpack allowing to use proper compression method.
See the 'Unpack' action for more information.
*/
package actions
import (
@@ -37,13 +69,58 @@ func (d *DownloadAction) validateUrl() (*url.URL, error) {
return url, nil
}
func (d *DownloadAction) validateFilename(context *debos.DebosContext, url *url.URL) (filename string, err error) {
if len(d.Filename) == 0 {
// Trying to guess the name from URL Path
filename = path.Base(url.Path)
} else {
filename = path.Base(d.Filename)
}
if len(filename) == 0 {
return "", fmt.Errorf("Incorrect filename is provided for '%s'", d.Url)
}
filename = path.Join(context.Scratchdir, filename)
return filename, nil
}
func (d *DownloadAction) archive(filename string) (debos.Archive, error) {
archive, err := debos.NewArchive(filename)
if err != nil {
return archive, err
}
switch archive.Type() {
case debos.Tar:
if len(d.Compression) > 0 {
if err := archive.AddOption("tarcompression", d.Compression); err != nil {
return archive, err
}
}
default:
}
return archive, nil
}
func (d *DownloadAction) Verify(context *debos.DebosContext) error {
var filename string
if len(d.Name) == 0 {
return fmt.Errorf("Property 'name' is mandatory for download action\n")
}
_, err := d.validateUrl()
return err
url, err := d.validateUrl()
if err != nil {
return err
}
filename, err = d.validateFilename(context, url)
if err != nil {
return err
}
if d.Unpack == true {
if _, err := d.archive(filename); err != nil {
return err
}
}
return nil
}
func (d *DownloadAction) Run(context *debos.DebosContext) error {
@@ -55,16 +132,10 @@ func (d *DownloadAction) Run(context *debos.DebosContext) error {
return err
}
if len(d.Filename) == 0 {
// Trying to guess the name from URL Path
filename = path.Base(url.Path)
} else {
filename = path.Base(d.Filename)
filename, err = d.validateFilename(context, url)
if err != nil {
return err
}
if len(filename) == 0 {
return fmt.Errorf("Incorrect filename is provided for '%s'", d.Url)
}
filename = path.Join(context.Scratchdir, filename)
originPath := filename
switch url.Scheme {
@@ -78,8 +149,13 @@ func (d *DownloadAction) Run(context *debos.DebosContext) error {
}
if d.Unpack == true {
archive, err := d.archive(filename)
if err != nil {
return err
}
targetdir := filename + ".d"
err := debos.UnpackTarArchive(filename, targetdir, d.Compression, "--no-same-owner", "--no-same-permissions")
err = archive.RelaxedUnpack(targetdir)
if err != nil {
return err
}

View File

@@ -1,3 +1,22 @@
/*
FilesystemDeploy Action
Deploy prepared root filesystem to output image. This action requires
'image-partition' action to be executed before it.
Yaml syntax:
- action: filesystem-deploy
setup-fstab: bool
setup-kernel-cmdline: bool
Optional properties:
- setup-fstab -- generate '/etc/fstab' file according to information provided
by 'image-partition' action. By default is 'true'.
- setup-kernel-cmdline -- add location of root partition to '/etc/kernel/cmdline'
file on target image. By default is 'true'.
*/
package actions
import (
@@ -14,7 +33,7 @@ import (
)
type FilesystemDeployAction struct {
debos.BaseAction `yaml:",inline"`
debos.BaseAction `yaml:",inline"`
SetupFSTab bool `yaml:"setup-fstab"`
SetupKernelCmdline bool `yaml:"setup-kernel-cmdline"`
}

View File

@@ -1,3 +1,105 @@
/*
ImagePartition Action
This action creates an image file, partitions it and formats the filesystems.
Yaml syntax:
- action: image-partition
imagename: image_name
imagesize: size
partitiontype: gpt
partitions:
<list of partitions>
mountpoints:
<list of mount points>
Mandatory properties:
- imagename -- the name of the image file.
- imagesize -- generated image size in human-readable form, examples: 100MB, 1GB, etc.
- partitiontype -- partition table type. Currently only 'gpt' and 'msdos'
partition tables are supported.
- partitions -- list of partitions, at least one partition is needed.
Partition properties are described below.
- mountpoints -- list of mount points for partitions.
Properties for mount points are described below.
Yaml syntax for partitions:
partitions:
- name: label
name: partition name
fs: filesystem
start: offset
end: offset
flags: list of flags
Mandatory properties:
- name -- is used for referencing named partition for mount points
configuration (below) and label the filesystem located on this partition.
- fs -- filesystem type used for formatting.
NB: the FAT (vfat) filesystem is named 'fat32' in configuration file.
- start -- offset from beginning of the disk there the partition starts.
- end -- offset from beginning of the disk there the partition ends.
For 'start' and 'end' properties offset can be written in human readable
form -- '32MB', '1GB' or as disk percentage -- '100%'.
Optional properties:
- flags -- list of additional flags for partition compatible with parted(8)
'set' command.
Yaml syntax for mount points:
mountpoints:
- mountpoint: path
partition: partition label
options: list of options
Mandatory properties:
- partition -- partition name for mounting.
- mountpoint -- path in the target root filesystem where the named partition
should be mounted.
Optional properties:
- options -- list of options to be added to appropriate entry in fstab file.
Layout example for Raspberry PI 3:
- action: image-partition
imagename: "debian-rpi3.img"
imagesize: 1GB
partitiontype: msdos
mountpoints:
- mountpoint: /
partition: root
- mountpoint: /boot/firmware
partition: firmware
options: [ x-systemd.automount ]
partitions:
- name: firmware
fs: fat32
start: 0%
end: 64MB
- name: root
fs: ext4
start: 64MB
end: 100%
flags: [ boot ]
*/
package actions
import (
@@ -32,14 +134,14 @@ type Mountpoint struct {
}
type ImagePartitionAction struct {
debos.BaseAction `yaml:",inline"`
ImageName string
ImageSize string
PartitionType string
Partitions []Partition
Mountpoints []Mountpoint
size int64
usingLoop bool
debos.BaseAction `yaml:",inline"`
ImageName string
ImageSize string
PartitionType string
Partitions []Partition
Mountpoints []Mountpoint
size int64
usingLoop bool
}
func (i *ImagePartitionAction) generateFSTab(context *debos.DebosContext) error {

View File

@@ -1,3 +1,28 @@
/*
OstreeCommit Action
Create OSTree commit from rootfs.
Yaml syntax:
- action: ostree-commit
repository: repository name
branch: branch name
subject: commit message
Mandatory properties:
- repository -- path to repository with OSTree structure; the same path is
used by 'ostree' tool with '--repo' argument.
This path is relative to 'artifact' directory.
Please keep in mind -- you will need a root privileges for 'bare' repository
type (https://ostree.readthedocs.io/en/latest/manual/repo/#repository-types-and-locations).
- branch -- OSTree branch name that should be used for the commit.
Optional properties:
- subject -- one line message with commit description.
*/
package actions
import (
@@ -11,10 +36,10 @@ import (
type OstreeCommitAction struct {
debos.BaseAction `yaml:",inline"`
Repository string
Branch string
Subject string
Command string
Repository string
Branch string
Subject string
Command string
}
func emptyDir(dir string) {

View File

@@ -1,3 +1,44 @@
/*
OstreeDeploy Action
Deploy the OSTree branch to the image.
If any preparation has been done for rootfs, it can be overwritten
during this step.
Action 'image-partition' must be called prior to OSTree deploy.
Yaml syntax:
- action: ostree-deploy
repository: repository name
remote_repository: URL
branch: branch name
os: os name
setup-fstab: bool
setup-kernel-cmdline: bool
appendkernelcmdline: arguments
Mandatory properties:
- remote_repository -- URL to remote OSTree repository for pulling stateroot branch.
Currently not implemented, please prepare local repository instead.
- repository -- path to repository with OSTree structure.
This path is relative to 'artifact' directory.
- os -- os deployment name, as explained in:
https://ostree.readthedocs.io/en/latest/manual/deployment/
- branch -- branch of the repository to use for populating the image.
Optional properties:
- setup-fstab -- create '/etc/fstab' file for image
- setup-kernel-cmdline -- add the information from the 'image-partition'
action to the configured commandline.
- appendkernelcmdline -- additional kernel command line arguments passed to kernel.
*/
package actions
import (
@@ -12,13 +53,13 @@ import (
)
type OstreeDeployAction struct {
debos.BaseAction `yaml:",inline"`
debos.BaseAction `yaml:",inline"`
Repository string
RemoteRepository string "remote_repository"
Branch string
Os string
SetupFSTab bool `yaml:"setup-fstab"`
SetupKernelCmdline bool `yaml:"setup-kernel-cmdline"`
SetupFSTab bool `yaml:"setup-fstab"`
SetupKernelCmdline bool `yaml:"setup-kernel-cmdline"`
AppendKernelCmdline string
}

View File

@@ -1,3 +1,27 @@
/*
Overlay Action
Recursive copy of directory or file to target filesystem.
Yaml syntax:
- action: overlay
origin: name
source: directory
destination: directory
Mandatory properties:
- source -- relative path to the directory or file located in path referenced by `origin`.
In case if this property is absent then pure path referenced by 'origin' will be used.
Optional properties:
- origin -- reference to named file or directory.
- destination -- absolute path in the target rootfs where 'source' will be copied.
All existing files will be overwritten.
If destination isn't set '/' of the rootfs will be usedi.
*/
package actions
import (

View File

@@ -1,3 +1,20 @@
/*
Pack Action
Create tarball with filesystem.
Yaml syntax:
- action: pack
file: filename.ext
compression: gz
Mandatory properties:
- file -- name of the output tarball.
- compression -- compression type to use. Only 'gz' is supported at the moment.
*/
package actions
import (
@@ -8,9 +25,9 @@ import (
)
type PackAction struct {
debos.BaseAction `yaml:",inline"`
Compression string
File string
debos.BaseAction `yaml:",inline"`
Compression string
File string
}
func (pf *PackAction) Run(context *debos.DebosContext) error {

View File

@@ -1,3 +1,28 @@
/*
Raw Action
Directly write a file to the output image at a given offset.
This is typically useful for bootloaders.
Yaml syntax:
- action: raw
origin: name
source: filename
offset: bytes
Mandatory properties:
- origin -- reference to named file or directory.
- source -- the name of file located in 'origin' to be written into the output image.
Optional properties:
- offset -- offset in bytes for output image file.
It is possible to use internal templating mechanism of debos to calculate offset
with sectors (512 bytes) instead of bytes, for instance: '{{ sector 256 }}'.
The default value is zero.
*/
package actions
import (

View File

@@ -1,3 +1,35 @@
/*
Run Action
Allows to run any available command or script in the filesystem or
in host environment.
Yaml syntax:
- action: run
chroot: bool
postprocess: bool
script: script name
command: command line
Properties 'command' and 'script' are mutually exclusive.
- command -- command with arguments; the command expected to be accessible in
host's or chrooted environment -- depending on 'chroot' property.
- script -- script with arguments; script must be located in recipe directory.
Optional properties:
- chroot -- run script or command in target filesystem if set to true.
In other case the command or script is executed within the build process, with
access to the filesystem and the image. In both cases it is run with root privileges.
- postprocess -- if set script or command is executed after all other commands and
has access to the image file.
Properties 'chroot' and 'postprocess' are mutually exclusive.
*/
package actions
import (
@@ -10,11 +42,11 @@ import (
)
type RunAction struct {
debos.BaseAction `yaml:",inline"`
Chroot bool
PostProcess bool
Script string
Command string
debos.BaseAction `yaml:",inline"`
Chroot bool
PostProcess bool
Script string
Command string
}
func (run *RunAction) Verify(context *debos.DebosContext) error {

View File

@@ -1,3 +1,35 @@
/*
Unpack Action
Unpack files from archive to the filesystem.
Useful for creating target rootfs from saved tarball with prepared file structure.
Only (compressed) tar archives are supported currently.
Yaml syntax:
- action: unpack
origin: name
file: file.ext
compression: gz
Mandatory properties:
- file -- archive's file name. It is possible to skip this property if 'origin'
referenced to downloaded file.
One of the mandatory properties may be omitted with limitations mentioned above.
It is expected to find archive with name pointed in `file` property inside of `origin` in case if both properties are used.
Optional properties:
- origin -- reference to a named file or directory.
The default value is 'artifacts' directory in case if this property is omitted.
- compression -- optional hint for unpack allowing to use proper compression method.
Currently only 'gz', bzip2' and 'xz' compression types are supported.
If not provided an attempt to autodetect the compression type will be done.
*/
package actions
import (
@@ -18,9 +50,17 @@ func (pf *UnpackAction) Verify(context *debos.DebosContext) error {
return fmt.Errorf("Filename can't be empty. Please add 'file' and/or 'origin' property.")
}
unpackTarOpt := debos.TarOptions(pf.Compression)
if len(pf.Compression) > 0 && len(unpackTarOpt) == 0 {
return fmt.Errorf("Compression '%s' is not supported.\n", pf.Compression)
archive, err := debos.NewArchive(pf.File)
if err != nil {
return err
}
if len(pf.Compression) > 0 {
if archive.Type() != debos.Tar {
return fmt.Errorf("Option 'compression' is supported for Tar archives only.")
}
if err := archive.AddOption("tarcompression", pf.Compression); err != nil {
return fmt.Errorf("'%s': %s", pf.File, err)
}
}
return nil
@@ -46,5 +86,15 @@ func (pf *UnpackAction) Run(context *debos.DebosContext) error {
return err
}
return debos.UnpackTarArchive(infile, context.Rootdir, pf.Compression)
archive, err := debos.NewArchive(infile)
if err != nil {
return err
}
if len(pf.Compression) > 0 {
if err := archive.AddOption("tarcompression", pf.Compression); err != nil {
return err
}
}
return archive.Unpack(context.Rootdir)
}

View File

@@ -1,33 +1,217 @@
package debos
import (
"log"
"fmt"
"os"
"path/filepath"
"strings"
)
func TarOptions(compression string) string {
type ArchiveType int
// Supported types
const (
_ ArchiveType = iota // Guess archive type from file extension
Tar
Zip
Deb
)
type ArchiveBase struct {
file string // Path to archive file
atype ArchiveType
options map[interface{}]interface{} // Archiver-depending map with additional hints
}
type ArchiveTar struct {
ArchiveBase
}
type ArchiveZip struct {
ArchiveBase
}
type ArchiveDeb struct {
ArchiveBase
}
type Unpacker interface {
Unpack(destination string) error
RelaxedUnpack(destination string) error
}
type Archiver interface {
Type() ArchiveType
AddOption(key, value interface{}) error
Unpacker
}
type Archive struct {
Archiver
}
// Unpack archive as is
func (arc *ArchiveBase) Unpack(destination string) error {
return fmt.Errorf("Unpack is not supported for '%s'", arc.file)
}
/*
RelaxedUnpack unpack archive in relaxed mode allowing to ignore or
avoid minor issues with unpacker tool or framework.
*/
func (arc *ArchiveBase) RelaxedUnpack(destination string) error {
return arc.Unpack(destination)
}
func (arc *ArchiveBase) AddOption(key, value interface{}) error {
if arc.options == nil {
arc.options = make(map[interface{}]interface{})
}
arc.options[key] = value
return nil
}
func (arc *ArchiveBase) Type() ArchiveType { return arc.atype }
// Helper function for unpacking with external tool
func unpack(command []string, destination string) error {
if err := os.MkdirAll(destination, 0755); err != nil {
return err
}
return Command{}.Run("unpack", command...)
}
// Helper function for checking allowed compression types
// Returns empty string for unknown
func tarOptions(compression string) string {
unpackTarOpts := map[string]string{
"gz": "-z",
"bzip2": "-j",
"xz": "-J",
} // Trying to guess all other supported formats
} // Trying to guess all other supported compression types
return unpackTarOpts[compression]
}
func UnpackTarArchive(infile, destination, compression string, options ...string) error {
if err := os.MkdirAll(destination, 0755); err != nil {
return err
}
log.Printf("Unpacking %s\n", infile)
func (tar *ArchiveTar) Unpack(destination string) error {
command := []string{"tar"}
command = append(command, options...)
command = append(command, "-x")
if unpackTarOpt := TarOptions(compression); len(unpackTarOpt) > 0 {
command = append(command, unpackTarOpt)
if options, ok := tar.options["taroptions"].([]string); ok {
for _, option := range options {
command = append(command, option)
}
}
command = append(command, "-f", infile, "-C", destination)
command = append(command, "-C", destination)
command = append(command, "-x")
return Command{}.Run("unpack", command...)
if compression, ok := tar.options["tarcompression"]; ok {
if unpackTarOpt := tarOptions(compression.(string)); len(unpackTarOpt) > 0 {
command = append(command, unpackTarOpt)
}
}
command = append(command, "-f", tar.file)
return unpack(command, destination)
}
func (tar *ArchiveTar) RelaxedUnpack(destination string) error {
taroptions := []string{"--no-same-owner", "--no-same-permissions"}
options, ok := tar.options["taroptions"].([]string)
defer func() { tar.options["taroptions"] = options }()
if ok {
for _, option := range options {
taroptions = append(taroptions, option)
}
}
tar.options["taroptions"] = taroptions
return tar.Unpack(destination)
}
func (tar *ArchiveTar) AddOption(key, value interface{}) error {
switch key {
case "taroptions":
// expect a slice
options, ok := value.([]string)
if !ok {
return fmt.Errorf("Wrong type for value")
}
tar.options["taroptions"] = options
case "tarcompression":
compression, ok := value.(string)
if !ok {
return fmt.Errorf("Wrong type for value")
}
option := tarOptions(compression)
if len(option) == 0 {
return fmt.Errorf("Compression '%s' is not supported", compression)
}
tar.options["tarcompression"] = compression
default:
return fmt.Errorf("Option '%v' is not supported for tar archive type", key)
}
return nil
}
func (zip *ArchiveZip) Unpack(destination string) error {
command := []string{"unzip", zip.file, "-d", destination}
return unpack(command, destination)
}
func (zip *ArchiveZip) RelaxedUnpack(destination string) error {
return zip.Unpack(destination)
}
func (deb *ArchiveDeb) Unpack(destination string) error {
command := []string{"dpkg", "-x", deb.file, destination}
return unpack(command, destination)
}
func (deb *ArchiveDeb) RelaxedUnpack(destination string) error {
return deb.Unpack(destination)
}
/*
NewArchive associate correct structure and methods according to
archive type. If ArchiveType is omitted -- trying to guess the type.
Return ArchiveType or nil in case of error.
*/
func NewArchive(file string, arcType ...ArchiveType) (Archive, error) {
var archive Archive
var atype ArchiveType
if len(arcType) == 0 {
ext := filepath.Ext(file)
ext = strings.ToLower(ext)
switch ext {
case ".deb":
atype = Deb
case ".zip":
atype = Zip
default:
//FIXME: guess Tar maybe?
atype = Tar
}
} else {
atype = arcType[0]
}
common := ArchiveBase{}
common.file = file
common.atype = atype
common.options = make(map[interface{}]interface{})
switch atype {
case Tar:
archive = Archive{&ArchiveTar{ArchiveBase: common}}
case Zip:
archive = Archive{&ArchiveZip{ArchiveBase: common}}
case Deb:
archive = Archive{&ArchiveDeb{ArchiveBase: common}}
default:
return archive, fmt.Errorf("Unsupported archive '%s'", file)
}
return archive, nil
}

157
archiver_test.go Normal file
View File

@@ -0,0 +1,157 @@
package debos_test
import (
_ "fmt"
"github.com/go-debos/debos"
"github.com/stretchr/testify/assert"
_ "reflect"
_ "strings"
"testing"
)
func TestBase(t *testing.T) {
// New archive
// Expect Tar by default
_, err := debos.NewArchive("test.base", 0)
assert.EqualError(t, err, "Unsupported archive 'test.base'")
// Test base
archive := debos.ArchiveBase{}
arcType := archive.Type()
assert.Equal(t, 0, int(arcType))
// Add option
err = archive.AddOption("someoption", "somevalue")
assert.Empty(t, err)
err = archive.Unpack("/tmp/test")
assert.EqualError(t, err, "Unpack is not supported for ''")
err = archive.RelaxedUnpack("/tmp/test")
assert.EqualError(t, err, "Unpack is not supported for ''")
}
func TestTar_default(t *testing.T) {
// New archive
// Expect Tar by default
archive, err := debos.NewArchive("test.tar.gz")
assert.NotEmpty(t, archive)
assert.Empty(t, err)
// Type must be Tar by default
arcType := archive.Type()
assert.Equal(t, debos.Tar, arcType)
// Test unpack
err = archive.Unpack("/tmp/test")
// Expect unpack failure
assert.EqualError(t, err, "exit status 2")
// Expect failure for RelaxedUnpack
err = archive.RelaxedUnpack("/tmp/test")
assert.EqualError(t, err, "exit status 2")
// Check options
err = archive.AddOption("taroptions", []string{"--option1"})
assert.Empty(t, err)
err = archive.Unpack("/tmp/test")
assert.EqualError(t, err, "exit status 64")
err = archive.Unpack("/proc/debostest")
assert.EqualError(t, err, "mkdir /proc/debostest: no such file or directory")
err = archive.RelaxedUnpack("/tmp/test")
assert.EqualError(t, err, "exit status 64")
// Add wrong option
err = archive.AddOption("someoption", "somevalue")
assert.EqualError(t, err, "Option 'someoption' is not supported for tar archive type")
}
// Check supported compression types
func TestTar_compression(t *testing.T) {
compressions := map[string]string{
"gz": "tar -C test -x -z -f test.tar.gz",
"bzip2": "tar -C test -x -j -f test.tar.gz",
"xz": "tar -C test -x -J -f test.tar.gz",
}
// Force type
archive, err := debos.NewArchive("test.tar.gz", debos.Tar)
assert.NotEmpty(t, archive)
assert.Empty(t, err)
// Type must be Tar
arcType := archive.Type()
assert.Equal(t, debos.Tar, arcType)
for compression, _ := range compressions {
err = archive.AddOption("tarcompression", compression)
assert.Empty(t, err)
err := archive.Unpack("test")
assert.EqualError(t, err, "exit status 2")
}
// Check of unsupported compression type
err = archive.AddOption("tarcompression", "fake")
assert.EqualError(t, err, "Compression 'fake' is not supported")
// Pass incorrect type
err = archive.AddOption("taroptions", nil)
assert.EqualError(t, err, "Wrong type for value")
err = archive.AddOption("tarcompression", nil)
assert.EqualError(t, err, "Wrong type for value")
}
func TestDeb(t *testing.T) {
// Guess Deb
archive, err := debos.NewArchive("test.deb")
assert.NotEmpty(t, archive)
assert.Empty(t, err)
// Type must be guessed as Deb
arcType := archive.Type()
assert.Equal(t, debos.Deb, arcType)
// Force Deb type
archive, err = debos.NewArchive("test.deb", debos.Deb)
assert.NotEmpty(t, archive)
assert.Empty(t, err)
// Type must be Deb
arcType = archive.Type()
assert.Equal(t, debos.Deb, arcType)
// Expect unpack failure
err = archive.Unpack("/tmp/test")
assert.EqualError(t, err, "exit status 2")
err = archive.Unpack("/proc/debostest")
assert.EqualError(t, err, "mkdir /proc/debostest: no such file or directory")
err = archive.RelaxedUnpack("/tmp/test")
assert.EqualError(t, err, "exit status 2")
}
func TestZip(t *testing.T) {
// Guess zip
archive, err := debos.NewArchive("test.ZiP")
assert.NotEmpty(t, archive)
assert.Empty(t, err)
// Type must be guessed as Zip
arcType := archive.Type()
assert.Equal(t, debos.Zip, arcType)
// Force Zip type
archive, err = debos.NewArchive("test.zip", debos.Zip)
assert.NotEmpty(t, archive)
assert.Empty(t, err)
// Type must be Zip
arcType = archive.Type()
assert.Equal(t, debos.Zip, arcType)
// Expect unpack failure
err = archive.Unpack("/tmp/test")
assert.EqualError(t, err, "exit status 9")
err = archive.Unpack("/proc/debostest")
assert.EqualError(t, err, "mkdir /proc/debostest: no such file or directory")
err = archive.RelaxedUnpack("/tmp/test")
assert.EqualError(t, err, "exit status 9")
}