apko
relies on parsing apk packages and installing them in the appropriate directories.
The implementation is in apk_implementation.go. Interface is:
type apkImplementation interface {
// InitDB initializes the APK database and all directories.
InitDB() error
// InitKeyring initializes the keyring with the given keyfiles. The first argument, keyfiles, is a list of
// keyfile locations. If present, they override the default keyfiles. The second argument, extraKeyfiles, is a list
// of files to append to the existing ones.
// Can provide file locations or URLs.
InitKeyring(keyfiles, extraKeyfiles []string) error
// SetWorld set the list of packages in the world file. Replaces any existing ones.
SetWorld(packages []string) error
// GetWorld get the list of packages in the world file.
GetWorld() ([]string, error)
// FixateWorld use the world file to set the state of the system, including any dependencies.
FixateWorld(cache, updateCache, executeScripts bool, sourceDateEpoch *time.Time) error
// SetRepositories sets the repositories to use. Replaces any existing ones.
SetRepositories(repos []string) error
// GetRepositories gets the list of repositories in use.
GetRepositories() ([]string, error)
// GetInstalled gets the list of installed packages.
GetInstalled() ([]*apkimpl.InstalledPackage, error)
// ListInitFiles lists the directories and files that are installed via InitDB
ListInitFiles() []tar.Header
}
Note that all of these are plain-vanilla apk functions; there is nothing "apko-specific" about them.
The actual implementation of that interface is in pkg/apk/impl/. The intent is either to upstream those to maintenance by the apk team, e.g. at https://gitlab.alpinelinux.org/alpine/go, or, if the above is not an appropriate place, to separate it into a standalone apk-go library.
The entire structure of pkg/apk/impl/ is built to be completely standalone, and should be replaceable
without affecting any other parts of apko
.
Certain functions within installation of packages or the database installation work differently, depending on whether the
one executing the commands is root or not, or is on a filesystem that supports certain features. For example, Windows does not have symlinks,
some memfs implementations do not support any kinds of links, and running as non-root will cause chown
to fail.
For all of the above, apko
does the following. Much of this is possible because the result is a tar file, and the tar file
has support for all of these features.
- Ignore
chown
/chmod
errors, while adding overrides to the tar file headers. - Ignore symlink/hardlink creation errors, while adding entries for them to the tar file headers.
- Ignore
mknod
errors, while adding entries for them to the tar file headers. - Ensure that the correct character devices exist in the tar stream, even if the apk
InitDB()
could not create them.
In general, when running apk --initdb
, it tries to create character devices. If it cannot, for example, if the user
does not have sufficient permissions, it bypasses creating them. apko
does the same, and accounts for it by adding
them to the final layer tar file.
This implementation relies heavily on tar.Header
to pass information around. If it needs overrides or additional
file information, tar.Header
conveniently has all of the fields we need. We very well could use another structure
or interface; this was chosen for its universality and convenience.
The implementation uses a virtual filesystem throughout, in order to unify and simplify access. It is inspired by
fs.FS, but does not use it since fs.FS
is read-only.
In order to support read-write, the implementation includes rwfs, which is a read-write filesystem interface, extending:
as well as requirements for Mkdir
/MkdirAll
, OpenFile
, WriteFile
, Symlink
and Mknod
.
For testing, the implementation uses memfs, which is an extension of
the memory-based filesystem implementation memfs, including features to implement the full rwfs
.
This turned out to be very similar in structure to pkg/vfs, with a bit of additional functionality,
It is inside of pkg/apk/impl/
.
A potential alternate implementation of VFS is https://github.com/spf13/afero.