Crates.io | peckish |
lib.rs | peckish |
version | 0.0.8 |
source | src |
created_at | 2023-04-09 23:41:42.018558 |
updated_at | 2023-09-15 18:43:54.462594 |
description | Create, manipulate, and transform Linux package formats! |
homepage | https://github.com/queer/peckish |
repository | https://github.com/queer/peckish |
max_upload_size | |
id | 834595 |
size | 327,874 |
peckish (case-sensitive) is a tool for repackaging Linux software artifacts.
For example, suppose you're an application developer. You just made something
cool and want to distribute it. However, packaging is hard. Different package
formats do things differently -- ex. Arch has x86_64
and any
as
architectures, but Debian has over a dozen and calls "x86_64
" "amd64
" --
and it's hard to remember all the specifics. This is compounded by having to
figure out the appropriate CLI flags for each package format. How many people
can write a valid tar
command on the first try? :P
This problem is fairly common:
It seems more and more common, at least in the self-hosted community, to provide two methods of installations: Docker or a shell script installer. It seems that many new projects don’t even bother with a native package manager, such as dpkg or rpm, which makes me reluctant to use them.
https://yotam.net/posts/the-audacity-of-piping-curl-to-bash/
It's easier to compile the linux kernel from scratch than it is to build a debian package from scratch.
It's mind-blowing how complicated it is; at the end of the day it's just an archive. I hate having to do it.
The impact of having frictionless package building cannot be understated. I'm publishing Arch Linux packages for all my applications because it takes just a few minutes to write up a PKGBUILD. Then one time, I tried providing a Debian package as well, but I gave up after several hours of trying to get through all the bureaucracy of the tooling.
[...] I've created my own RPM and DEB packages in the past as well; but, at least when I did it years ago, it wasn't as effective as a PKGBUILD on arch.
Official documentation is a problem. It is aimed at Debian maintainers building a fully policy compliant package that could be accepted to the official repository. You don't need any of that crap for making a .deb package. It puts off people from creating Debian packages for their own programs or private use.
If my package manager had an Oh My Zsh package
This is the author missing the point. The reason
curl | bash
is common is because devs don't like packaging for every distro under the sun, and MacOS, and FreeBSD, and... If you really thinkcurl | bash
is the problem, then you should be lining up to package the stuff you use for your distro. Instead, it is always someone else's problem.Package managers are great... for the user. For everyone else, a polyglot system, with arcane technical policies, and even more arcane human policies is... not ideal.
peckish aims to solve this. Instead of mangling your files with various arcane tools, spinning up Docker containers or VMs to try to build packages and make sure they install or are even valid, and all the other pains, you can just write a basic YAML file, and you're done! peckish does the rest, without shelling out to distro-specific tools!
Additionally, peckish makes repackaging software easier. You can take a DEB and convert it into an RPM, or a Docker image to flat files on the filesystem, or turn a tarball into an installable package for DEB-based, RPM-based, or Arch-based distros.
peckish lets you convert back and forth between all of these formats:
peckish is based around the concept of "artifacts" and "producers." An artifact is some metadata about a package that exists on your system, and a producer is something that takes in an artifact and produces a new artifact. For example, taking a tarball and producing a DEB or RPM package.
.deb
packages.rpm
packages0.x.y
! Treat it accordingly. Maybe don't run it in prod.peckish is a part of the amyware discord server.
If you like what I make, consider supporting me on Patreon:
Create a peckish.yaml
file in the root of your project.
# whether to chain outputs, ie each artifact output is the input to the next
# producer. defaults to `false` if not specified.
chain: false
# metadata about the package. required, even if you're only producing a file or
# a tarball. this is because it's just easier than trying to play the "is there
# enough metadata to build the package" game.
metadata:
name: "my-cool-pkg"
# many distros want versions that end in -#, which is a revision number for
# the package. this is required if you are producing an Arch/Deb/RPM/similar
# package.
version: "0.1.0-1"
description: "a package"
# suggested format: "me <me@example.com>"
author: "me"
# the architecture of the system the package is built for. this is usually
# the same as the architecture of the system you're building on. will be
# automatically set to the correct value for the target package format, ex.
# x86_64 -> amd64 for debian.
arch: "amd64"
license: "Apache-2.0"
# the artifact being used as input to the pipeline.
input:
name: "some file"
type: "file"
paths:
- "./path/to/file"
# the producers being used as outputs. see `docs/` for more info about each
# producer.
output:
- name: "tarball"
type: "tarball"
path: "./whatever.tar"
- name: "debian package"
type: "deb"
path: "./whatever.deb"
# a list of changes to inject into the filesystem. this lets you move,
# copy, symlink, etc. files and directories within the artifact before it's
# written to disk. see `docs/injections.md` for more info.
injections:
- "move-file"
- "cleanup"
# the actual injections that are applied to output artifacts. these are
# specified in their own group to allow for reuse between multiple producers.
injections:
move-file:
type: "move"
src: "/path/to/file"
dest: "/new/path/to/file"
cleanup:
type: "delete"
path: "/path"
Dockerfile
crates.io: https://crates.io/crates/peckish
MSRV 1.71.
// artifacts
use peckish::prelude::builder::*;
use peckish::prelude::*;
let file_artifact = FileArtifactBuilder::new("example file artifact".into())
.add_path("./examples/a".into())
.build()?;
let tarball_producer = TarballProducerBuilder::new("example tarball producer".into())
.path("test.tar.gz".into())
.build()?;
let tarball_artifact = tarball_producer.produce(&file_artifact).await?;
// pipelines
use peckish::prelude::pipeline::*;
use peckish::prelude::*;
let file_artifact = ...;
let tarball_producer = ...;
let debian_producer = ...;
let config = PeckishConfig {
input: ConfiguredArtifact::File(file_artifact),
output: vec![
ConfiguredProducer::Tarball(tarball_producer),
ConfiguredProducer::Deb(debian_producer),
],
chain: false,
};
let pipeline = Pipeline::new();
let out = pipeline.run(config).await?;
println!("produced {} artifacts", out.len());
GitHub Actions for peckish can be found at queer/actions.
- name: "install peckish!"
uses: "queer/actions/peckish_install@mistress"
with:
token: "${{ secrets.GITHUB_TOKEN }}"
- name: "run peckish!"
uses: "queer/actions/peckish_run@mistress"
peckish tries to respect SOURCE_DATE_EPOCH
.
Please open issues or PRs if you find places where it doesn't!
The goal/hope is to be able to support all of these. Formats not listed may end up on the list in the future. Formats that are not currently supported may never be supported.
"file"
"arch"
"tarball"
"deb"
"docker"
"rpm"
"ext4"
"oci"
"appimage"
SOURCE_DATE_EPOCH
support for reproducible buildspeckish is built around the concepts of artifacts and producers.
Artifacts are some sort of data that exists on your system that can be
packaged; artifacts themselves do not contain any of that data, just metadata.
For example, a FileArtifact
is a list of paths to files on your system. A
TarballArtifact
is a path to a tarball. A DebArtifact
is a path to a
.deb
file. So on and so forth.
Producers are a bit more interesting. Producers are the things that actually
do the packaging: they take an artifact as input and produce a new artifact
as output. For example, a TarballProducer
may take a FileArtifact
as input
and produce a TarballArtifact
as output, a DebProducer
may take a
TarballArtifact
as input and produce a DebArtifact
as output, and so on.
peckish artifacts and producers are centred around the idea of an in-memory filesystem. Rather than having to mangle things on the disk, peckish moves everything into memory, manipulates it, then flushes it back to disk. This allows for trivial manipulation of software artifacts, as changing them is simply injecting some changes into the in-memory filesystem and repackaging with the metadata in the producer. No knowledge of the previous artifact is needed beyond its in-memory filesystem representation.
If you pretend really hard, "peckish" sounds kinda sorta a bit like "package."
floppy-disk
: async filesystem facadedisk-drive
: multi-floppy-disk
utilsflop
: floppy-disk
archive facadesmoosh
: automagic async (re)compressionnyoom
: filesystem walker for floppy-disk
flail
: floppy-disk
facade for ext4Copyright 2023-present amy null
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.