mirror of
https://github.com/outbackdingo/debos.git
synced 2026-01-27 10:18:47 +00:00
Enabled additional linters from fakemachine configuration: - errorlint: Error wrapping with %w - misspell: Spelling checks - revive: Code quality checks - whitespace: Formatting checks Fixed all issues including: - Error handling: Added proper error checks for all function returns - Error wrapping: Changed %v to %w for proper error wrapping - Type assertions: Used errors.As instead of direct type assertions - Unused parameters: Renamed to underscore where appropriate - Variable naming: Fixed ALL_CAPS constants and underscored names - Whitespace: Removed unnecessary leading/trailing newlines - Code flow: Removed unnecessary else blocks Renamed types (breaking internal API changes): - DebosState → State - DebosContext → Context - DownloadHttpUrl → DownloadHTTPURL Fixed struct field naming with proper YAML tags: - Url → URL (with yaml:"url" tag) - TlsClientCertPath → TLSClientCertPath (kept yaml:"tls-client-cert-path") - TlsClientKeyPath → TLSClientKeyPath (kept yaml:"tls-client-key-path") - validateUrl → validateURL method Co-authored-by: sjoerdsimons <22603932+sjoerdsimons@users.noreply.github.com>
229 lines
5.3 KiB
Go
229 lines
5.3 KiB
Go
package debos
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"strings"
|
|
)
|
|
|
|
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(_ 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{
|
|
"bzip2": "--bzip2",
|
|
"gz": "--gzip",
|
|
"lzip": "--lzip",
|
|
"lzma": "--lzma",
|
|
"lzop": "--lzop",
|
|
"xz": "--xz",
|
|
"zstd": "--zstd",
|
|
} // Trying to guess all other supported compression types
|
|
|
|
return unpackTarOpts[compression]
|
|
}
|
|
|
|
func (tar *ArchiveTar) Unpack(destination string) error {
|
|
command := []string{"tar"}
|
|
usePigz := false
|
|
if compression, ok := tar.options["tarcompression"]; ok && compression == "gz" {
|
|
if _, err := exec.LookPath("pigz"); err == nil {
|
|
usePigz = true
|
|
}
|
|
}
|
|
if options, ok := tar.options["taroptions"].([]string); ok {
|
|
command = append(command, options...)
|
|
}
|
|
command = append(command, "-C", destination)
|
|
command = append(command, "-x")
|
|
command = append(command, "--xattrs")
|
|
command = append(command, "--xattrs-include=*.*")
|
|
|
|
if compression, ok := tar.options["tarcompression"]; ok {
|
|
if unpackTarOpt := tarOptions(compression.(string)); len(unpackTarOpt) > 0 {
|
|
if usePigz {
|
|
command = append(command, "--use-compress-program=pigz")
|
|
} else {
|
|
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 {
|
|
taroptions = append(taroptions, options...)
|
|
}
|
|
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
|
|
}
|