libeopkg

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 18, 2020 License: Apache-2.0 Imports: 12 Imported by: 0

README

libeopkg

Go library for manipulating eopkg archives.

License

Copyright 2017-2020 Solus Project copyright@getsol.us

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

Documentation

Overview

Package libeopkg provides Go-native access to `.eopkg` files, allowing ferryd to read and manipulate them without having a host-side eopkg tool.

It should also be noted that `eopkg` is implemented in Python, so calling out to the host-side tool just isn't acceptable for the performance we require. In time, `sol` will replace eopkg and it is very likely that we'll base the new `libsol` component on the C library using cgo.

Package libeopkg provides Go-native access to `.eopkg` files, allowing ferryd to read and manipulate them without having a host-side eopkg tool.

It should also be noted that `eopkg` is implemented in Python, so calling out to the host-side tool just isn't acceptable for the performance we require. In time, `sol` will replace eopkg and it is very likely that we'll base the new `libsol` component on the C library using cgo.

Package libeopkg provides Go-native access to `.eopkg` files, allowing ferryd to read and manipulate them without having a host-side eopkg tool.

It should also be noted that `eopkg` is implemented in Python, so calling out to the host-side tool just isn't acceptable for the performance we require. In time, `sol` will replace eopkg and it is very likely that we'll base the new `libsol` component on the C library using cgo.

Index

Constants

View Source
const (
	// DefaultMaintainerName is the catch-all name for Solus maintainers
	DefaultMaintainerName = "Solus Team"
	// DefaultMaintainerEmail is the catch-all email for Solus maintainers
	DefaultMaintainerEmail = "root@solus-project.com"
)

Variables

View Source
var (
	// ErrMismatchedDelta is returned when the input packages should never be delta'd,
	// i.e. they're unrelated
	ErrMismatchedDelta = errors.New("Delta is not possible between the input packages")

	// ErrDeltaPointless is returned when it is quite literally pointless to bother making
	// a delta package, due to the packages having exactly the same content.
	ErrDeltaPointless = errors.New("File set is the same, no point in creating delta")
)
View Source
var (
	// ErrNotYetImplemented is a placeholder during development
	ErrNotYetImplemented = errors.New("Not yet implemented")

	// ErrEopkgCorrupted is provided when a file does not conform to eopkg spec
	ErrEopkgCorrupted = errors.New(".eopkg file is corrupted or invalid")
)

Functions

func ComputeDeltaName

func ComputeDeltaName(oldPackage, newPackage *MetaPackage) string

ComputeDeltaName will determine the target name for the delta eopkg

func FixMissingLocalLanguage

func FixMissingLocalLanguage(fields *[]LocalisedField)

FixMissingLocalLanguage should be used on a set of LocalisedField to restore the missing "en" that is required in the very first field set.

func IsDeltaPossible

func IsDeltaPossible(oldPackage, newPackage *MetaPackage) bool

IsDeltaPossible will compare the two input packages and determine if it is possible for a delta to be considered. Note that we do not compare the distribution _name_ because Solus already had to do a rename once, and that broke delta updates. Let's not do that again. eopkg should in reality determine delta applicability based on repo origin + upgrade path, not names

func UnxzFile

func UnxzFile(inputPath string, keepOriginal bool) error

UnxzFile will decompress the input XZ file and leave a new file in place without the .xz suffix

func XzFile

func XzFile(inputPath string, keepOriginal bool) error

XzFile is a simple wrapper around the xz utility to compress the input file. This will be performed in place and leave a ".xz" suffixed file in place Keep original determines whether we'll keep the original file

Types

type Action

type Action struct {
	Value   string `xml:",chardata"`
	Package string `xml:"package,attr,omitempty"`
}

Action represents an action to take upon applying an update, such as restarting the system.

type COMAR

type COMAR struct {
	Value  string `xml:",chardata"`
	Script string `xml:"script,attr,omitempty"`
}

A COMAR script

type Component

type Component struct {
	// ID of this component, i.e. "system.base"
	Name string
	// Translated short name
	LocalName []LocalisedField
	// Translated summary
	Summary []LocalisedField
	// Translated description
	Description []LocalisedField
	// Which group this component belongs to
	Group string
	// Maintainer for this component
	Maintainer struct {
		// Name of the component maintainer
		Name string
		// Contact e-mail address of component maintainer
		Email string // Contact e-mail address of component maintainer
	}
}

A Component as seen through the eyes of XML

type ComponentList

type ComponentList []Component

ComponentList allows us to quickly sort our components by name

func (ComponentList) Len

func (l ComponentList) Len() int

Len returns the length of a ComponentList

func (ComponentList) Less

func (l ComponentList) Less(a, b int) bool

Less returns true if the name of the first component is a lower value

func (ComponentList) Swap

func (l ComponentList) Swap(a, b int)

Swap exchanges two components for sorting

type Components

type Components struct {
	// Components is a list of Components
	Components ComponentList `xml:"Components>Component"`
}

Components is a simple helper wrapper for loading from components.xml files

func NewComponents

func NewComponents(xmlfile string) (cs *Components, err error)

NewComponents will load the Components data from the XML file

type Delta

type Delta struct {
	ReleaseFrom int `xml:"releaseFrom,attr,omitempty"`
	PackageURI  string
	PackageSize int64
	PackageHash string
}

Delta describes a delta package that may be used for an update to save on bandwidth for the users.

Delta upgrades are determined by placing the <DeltaPackages> section into the index, with each Delta listed with a releaseFrom. If the user is currently using one of the listed releaseFrom IDs in their installation, that delta package will be selected instead of the full package.

type DeltaProducer

type DeltaProducer struct {
	// contains filtered or unexported fields
}

DeltaProducer is responsible for taking two eopkg packages and spitting out a delta package for them, containing only the new files.

func NewDeltaProducer

func NewDeltaProducer(baseDir string, left string, right string) (dp *DeltaProducer, err error)

NewDeltaProducer will return a new delta producer for the given input packages It is very important that the old and new packages are in the correct order!

func (*DeltaProducer) Close

func (d *DeltaProducer) Close() error

Close the DeltaProducer

func (*DeltaProducer) Create

func (d *DeltaProducer) Create() (filename string, err error)

Create will attempt to produce a delta between the 2 eopkg files This will be performed in temporary storage so must then be copied into the final resting location, and unlinked, before it can be used.

type Dependency

type Dependency struct {
	Name string `xml:",chardata"`

	// Release based dependencies
	ReleaseFrom int `xml:"releaseFrom,attr,omitempty"`
	ReleaseTo   int `xml:"releaseTo,attr,omitempty"`
	Release     int `xml:"release,attr,omitempty"`

	// Version based dependencies
	VersionFrom string `xml:"versionFrom,attr,omitempty"`
	VersionTo   string `xml:"versionTo,attr,omitempty"`
	Version     string `xml:"version,attr,omitempty"`
}

A Dependency has various attributes which help determine what needs to be installed when updating or installing the package.

type Distribution

type Distribution struct {
	// Name of source to match source repos
	SourceName string
	// Translated description
	Description []LocalisedField
	// Published version number for compatibility
	Version string
	// Type of repository (should always be main, really. Just descriptive)
	Type string
	// Name of the binary repository
	BinaryName string
	// Package names that are no longer supported
	Obsoletes []string `xml:"Obsoletes>Package"`
	// contains filtered or unexported fields
}

A Distribution as seen through the eyes of XML

func NewDistribution

func NewDistribution(xmlfile string) (dist *Distribution, err error)

NewDistribution will load the Distribution data from the XML file

func (*Distribution) IsObsolete

func (d *Distribution) IsObsolete(id string) bool

IsObsolete will allow quickly determination of whether the package name was marked obsolete and should be hidden from the index

type File

type File struct {
	Path      string
	Type      string
	Size      int64  `xml:",omitempty"`
	UID       int    `xml:"UID,omitempty"`
	GID       int    `xml:"GID,omitempty"`
	Mode      string `xml:",omitempty"`
	Hash      string `xml:",omitempty"`
	Permanent string `xml:",omitempty"`
	// contains filtered or unexported fields
}

File is the idoimatic representation of the XML <File> node

Note that directories are indicated by a missing hash. Unfortunately however eopkg doesn't record the actual _type_ of a file in an intelligent sense, thus we'll have to deal with symlinks separately.

In an ideal world the package archive would be hash indexed with no file names or special permissions inside the archive, and we'd record all relevant metadata. This would allow a single copy, many hardlink approach to blit the files out, as well as allowing us to more accurately represent symbolic links instead of pretending they're real files.

Long story short: Wait for eopkg's successor to worry about this stuff.

func (*File) FileMode

func (f *File) FileMode() os.FileMode

FileMode will return an os.FileMode version of our string encoded "Mode" member

func (*File) ParseFileMode

func (f *File) ParseFileMode() error

ParseFileMode converts a string filemode to a binary one

type Files

type Files struct {
	File []*File
}

Files is the idiomatic representation of the XML <Files> node with one or more <File> children

type Group

type Group struct {
	// ID of this group, i.e. "multimedia"
	Name string
	// Translated short name
	LocalName []LocalisedField
	// Display icon for this Group
	Icon string
}

A Group as seen through the eyes of XML

type GroupList

type GroupList []Group

GroupList allows us to quickly sort our groups by name

func (GroupList) Len

func (l GroupList) Len() int

Len returns the size of the list for sorting

func (GroupList) Less

func (l GroupList) Less(a, b int) bool

Less returns true if the name of Group A is less than Group B's

func (GroupList) Swap

func (l GroupList) Swap(a, b int)

Swap exchanges groups while sorting

type Groups

type Groups struct {
	Groups GroupList `xml:"Groups>Group"`
}

Groups is a simple helper wrapper for loading from components.xml files

func NewGroups

func NewGroups(xmlfile string) (*Groups, error)

NewGroups will load the Groups data from the XML file

type LocalisedField

type LocalisedField struct {
	Value string `xml:",cdata"`
	Lang  string `xml:"http://www.w3.org/XML/1998/namespace lang,attr,omitempty"`
}

LocalisedField is used in various parts of the eopkg metadata to provide a field value with an xml:lang attribute describing the language

type MetaPackage

type MetaPackage struct {
	Name string
	// Brief description, one line, of the package functionality
	Summary []LocalisedField
	// A full fleshed description of the package
	Description         []LocalisedField
	IsA                 string `xml:"IsA,omitempty"`    // Legacy
	PartOf              string `xml:"PartOf,omitempty"` // component
	License             []string
	RuntimeDependencies *[]Dependency `xml:"RuntimeDependencies>Dependency,omitempty"`
	Conflicts           *[]string     `xml:"Conflicts>Package,omitempty"`
	Replaces            *[]string     `xml:"Replaces>Package,omitempty"`
	Provides            *Provides     `xml:"Provides,omitempty"`
	History             []Update      `xml:"History>Update"`
	// Binary details
	BuildHost           string
	Distribution        string
	DistributionRelease string
	Architecture        string
	InstalledSize       int64
	PackageSize         int64
	PackageHash         string
	PackageURI          string
	DeltaPackages       *[]Delta `xml:"DeltaPackages>Delta,omitempty"`
	PackageFormat       string   // Version
	// Index needs this, so do we for source==release matching
	Source Source
}

A MetaPackage is the Package section of the metadata file. It contains the main details that are important to users.

func (*MetaPackage) GetID

func (m *MetaPackage) GetID() string

GetID will return the package ID for ferryd

func (*MetaPackage) GetPathComponent

func (m *MetaPackage) GetPathComponent() string

GetPathComponent will get the source part of the string which is used in all subdirectories of the repository.

For all packages with a source name of 4 or more characters, the path component will be split on this, i.e.:

libr/libreoffice

For all other packages, the first letter of the source name is used, i.e.:

n/nano

func (*MetaPackage) GetRelease

func (m *MetaPackage) GetRelease() int

GetRelease is a helpful wrapper to return the package's current release

func (*MetaPackage) GetVersion

func (m *MetaPackage) GetVersion() string

GetVersion is a helpful wrapper to return the package's current version

type Metadata

type Metadata struct {
	Source  Source
	Package MetaPackage `xml:"Package"`
}

Metadata contains all of the information a package can provide to a user prior to installation. This includes the name, version, release, and so forth.

Every Package contains Metadata, and during eopkg indexing, a reduced version of the Metadata is emitted.

type Package

type Package struct {
	// Path to this .eopkg file
	Path string
	// Basename of the package, unique.
	ID string
	// Metadata for this package
	Meta *Metadata
	// Files for this package
	Files *Files
	// contains filtered or unexported fields
}

A Package is used for accessing a `.eopkg` archive, the current format used within Solus for software packages.

An .eopkg archive is actually a ZIP archive. Internally it has the following structure:

metadata.xml    -> Package information
files.xml       -> Record of the files and hash/uid/gid/etc
comar/          -> Postinstall scripts
install.tar.xz  -> Filesystem contents

Due to this toplevel simplicity, we can use golang's native `archive/zip` library to achieve eopkg access, and parse the contents accordingly. This is much faster than having to call out to the host side tool, which is presently written in Python.

func Open

func Open(path string) (*Package, error)

Open will attempt to open the given .eopkg file. This must be a valid .eopkg file and this stage will assert that it is indeed a real archive.

func (*Package) Close

func (p *Package) Close() error

Close a previously opened .eopkg file

func (*Package) ExtractTarball

func (p *Package) ExtractTarball(directory string) error

ExtractTarball will fully extract install.tar.xz to the destination direction + install.tar suffix

func (*Package) FindFile

func (p *Package) FindFile(path string) *zip.File

FindFile will search for the given name in the .zip's file headers. We do not need to worry about the issue with the Name member being the basename, as the filenames are always unique.

In the event of the file requested not being found, we return nil. The caller should then bail and indicate that the eopkg is corrupted.

func (*Package) ReadAll

func (p *Package) ReadAll() error

ReadAll will read both the metadata + files xml files

func (*Package) ReadFiles

func (p *Package) ReadFiles() error

ReadFiles will read the `files.xml` file within the archive and deserialize it into something accessible within the .eopkg container.

func (*Package) ReadMetadata

func (p *Package) ReadMetadata() error

ReadMetadata will read the `metadata.xml` file within the archive and deserialize it into something accessible within the .eopkg container.

type PackageSet

type PackageSet []*MetaPackage

PackageSet provides sorting capabilities for a slice of packages

func (PackageSet) Len

func (p PackageSet) Len() int

Len returns the size of the PackageSet for sorting

func (PackageSet) Less

func (p PackageSet) Less(a, b int) bool

Less returns true if Release A is less than Release B

func (PackageSet) Swap

func (p PackageSet) Swap(a, b int)

Swap exchanges packages when sorting

type Packager

type Packager struct {
	Name  string
	Email string
}

A Packager identifies the person responsible for maintaining the source package. In terms of ypkg builds, it will indicate the last person who made a change to the package, allowing a natural "blame" system to work much like git.

type Provides

type Provides struct {
	COMAR       []COMAR  `xml:"COMAR,omitempty"`
	PkgConfig   []string `xml:"PkgConfig,omitempty"`
	PkgConfig32 []string `xml:"PkgConfig32,omitempty"`
}

Provides defines special items that might be exported by a package

type Source

type Source struct {
	Name     string
	Homepage string `xml:"Homepage,omitempty"`
	Packager Packager
}

Source provides the information relating to the source package within each binary package. This source identifies one or more packages coming from the same origin, i.e they have the same *source name*.

type Update

type Update struct {
	Release int    `xml:"release,attr"`
	Type    string `xml:"type,attr,omitempty"`
	Date    string
	Version string
	Comment struct {
		Value string `xml:",cdata"`
	}
	Name struct {
		Value string `xml:",cdata"`
	}
	Email    string
	Requires *[]Action `xml:"Requires>Action,omitempty"`
}

An Update forms part of a package's history, describing the version, release, etc, for each release of the package.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL