The Basics
Installing a package
- If you know the name
paxy install {name}
installs a given package or packages by name. - If you don't know the name
paxy search {query}
searches for a package by name or description.
Note:
add
works as an alias forinstall
.
Updating a package
paxy update {name}
updates a given package or packages by name Alternatively, paxy
by itself updates the entire system.
Note:
upgrade
works as an alias forupdate
.
Removing a package
paxy remove {name}
removes a given package or packages by name.
Note:
uninstall
works as an alias forremove
.
Listing packages
paxy list
lists all installed packages.
Automatic correction
For all commands, paxy
will automatically correct typos and abbreviations. For example, imagine a scenario where bash
isn't installed, but sh
is. paxy remove bash
will provide you with a prompt: "Did you mean 'sh'? [Y/n]". If you answer "Y", paxy
will remove sh
instead.
Warning: please don't remove sh. That is a horrible idea.
The Basics
Installing a package
- If you know the name
paxy install {name}
installs a given package or packages by name. - If you don't know the name
paxy search {query}
searches for a package by name or description.
Note:
add
works as an alias forinstall
.
Updating a package
paxy update {name}
updates a given package or packages by name Alternatively, paxy
by itself updates the entire system.
Note:
upgrade
works as an alias forupdate
.
Removing a package
paxy remove {name}
removes a given package or packages by name.
Note:
uninstall
works as an alias forremove
.
Listing packages
paxy list
lists all installed packages.
Automatic correction
For all commands, paxy
will automatically correct typos and abbreviations. For example, imagine a scenario where bash
isn't installed, but sh
is. paxy remove bash
will provide you with a prompt: "Did you mean 'sh'? [Y/n]". If you answer "Y", paxy
will remove sh
instead.
Warning: please don't remove sh. That is a horrible idea.
Environments
What is an environment?
A Paxy environment is like a docker container. It allows you to use a specific version of a package without installing it globally. This is useful for testing, or if you want to use a different version of a package than the one installed globally. It's also useful if the package is temporary. For example, if you need a specific version of python, but you don't usually use python, you can create an environment for that version of python, and when you're done it is automatically removed.
How do I create an environment?
Environments are created with paxy env {package(s)}
. For example, to create an environment with python 3.6, you would run paxy env python@3.6
. You will be provided with an instance of your system shell, or the shell specified in your configuration. You can then use the package as you would normally. For example, to install a python package, you would run pip install {package}
. You can specify more than one package to the command.
How are environment packages stored?
They are stored on the system as regular packages, with the env flag set. A paxy clean
command will remove them permanently.
Creating a Package
Before You Begin
Consider the following items:
- Does this package already exist?
- If so, are you uploading a specific version? Add a version to the original package instead.
- Does this package contain everything necessary for it to work?
What should a package have?
A package should contain the following:
- The package itself
- Any pieces of the package that are necessary for use.
For example, consider the rust
package. It downloads rustup
, then uses rustup
to install rustc
and cargo
. This provides a complete rust environment.
Package Versions
Package versions should correspond to versions of the actual software. For example, version 3.6 of python
should install python 3.6. Package maintainers should make an effort to provide all versions of a package (automatic deployment of non-breaking versions is recommended).
Package Flavors
Package flavors are often provided in the form of a specific architecture. For example, rust
uses flavors for the target triple. A package should provide flavors for anything that seems relevant. In other cases, package flavors specify the origin of the package. For example, jdk
provides flavors openjdk
and oracle
.
Package Names
A package name should reflect what's inside the package. If the package provides a single executable, it should be named for that executable. Otherwise, if a package provides a collection of software, like gcc
, it should be named after the cannonical name for that software. In addition, if there are multiple sources for said software, like Java JDKs, they should be specified in the package flavors.
Begin
Now that you have considered all of these, you may continue on to the next section to begin your package.
Creating a Package
Before You Begin
Consider the following items:
- Does this package already exist?
- If so, are you uploading a specific version? Add a version to the original package instead.
- Does this package contain everything necessary for it to work?
What should a package have?
A package should contain the following:
- The package itself
- Any pieces of the package that are necessary for use.
For example, consider the rust
package. It downloads rustup
, then uses rustup
to install rustc
and cargo
. This provides a complete rust environment.
Package Versions
Package versions should correspond to versions of the actual software. For example, version 3.6 of python
should install python 3.6. Package maintainers should make an effort to provide all versions of a package (automatic deployment of non-breaking versions is recommended).
Package Flavors
Package flavors are often provided in the form of a specific architecture. For example, rust
uses flavors for the target triple. A package should provide flavors for anything that seems relevant. In other cases, package flavors specify the origin of the package. For example, jdk
provides flavors openjdk
and oracle
.
Package Names
A package name should reflect what's inside the package. If the package provides a single executable, it should be named for that executable. Otherwise, if a package provides a collection of software, like gcc
, it should be named after the cannonical name for that software. In addition, if there are multiple sources for said software, like Java JDKs, they should be specified in the package flavors.
Begin
Now that you have considered all of these, you may continue on to the next section to begin your package.
Package Manifest
The package manifest is split into three parts. First, we have the base package. A package contains multiple flavors, each flavor contains multiple versions.
Package metadata is specified in essentially any file format, however, examples in this file will be in toml
. Many other formats are supported, and translations to those file formats can be found in Manifest Formats. Structure goes as follows:
[package]
name = "package-name"
description = "A package description"
authors = ["Author Name <Author Email>"]
license = "License"
homepage = "https://example.com"
repository = "https://example.com"
documentation = "https://example.com"
readme = "README.md"
keywords = ["keyword1", "keyword2"]
[dependencies]
dependency1 = "1.0.0"
dependency2 = {
version = "1.0.0",
flavor = "flavor"
}
[flavors]
flavor = "path/to/flavor.toml"
package
The package
table contains metadata about the package itself. The following fields are supported (* = required):
name
*: The name of the package. This is the name that will be used to refer to the package in other packages' manifests, as well as by users during installation.description
*: A description of the package. This should be a short description of what the package does.authors
: A list of authors of the package. This should be a list of git identifiers (Name (Domain) <Email>
).license
: The license of the package. This should be a valid SPDX license identifier.homepage
: The homepage of the package. This should be a URL to the package's homepage.repository
: The repository of the package. This should be a URL to the package's repository.documentation
: The documentation of the package. This should be a URL to the package's documentation.readme
: The readme of the package. This should be a path to the package's readme from the directory the manifest is in.keywords
: A list of keywords for the package. These keywords should describe the package.
dependencies
The dependencies
table lists all dependencies that are required for all flavors of the package. Each entry should point to either a version or a table with version
and flavor
fields.
flavors
The flavors
table lists all flavors of the package. Each entry contain a path to a flavor manifest.
Flavor Manifests
Each flavor specifies its own metadata, dependencies, and all versions of itself.
[flavor]
description = "A flavor description"
authors = ["Author Name <Author Email>"]
license = "License"
homepage = "https://example.com"
repository = "https://example.com"
documentation = "https://example.com"
readme = "README.md"
[versions]
"0.1.0" = "path/to/0.1.0.toml"
flavor
The flavor
table contains metadata about the flavor itself. The following fields are supported (* = required):
description
*: A description of the flavor. This should explain the differences between this flavor and other flavors of the same package.license
,homepage
,repository
,documentation
,readme
: The same as in thepackage
table. Only include if they're different from the package's.
versions
The versions
table lists all versions of the flavor. Each entry should point to a version manifest.
Version Manifests
You're almost at the end. You've created a package, and you've created a flavor. Now you need to create a version. This is the last step in creating a package. A version manifest contains all the information necessary to install a specific version of a package.
[version]
authors = ["Author Name <Author Email>"]
license = "License"
homepage = "https://example.com"
repository = "https://example.com"
documentation = "https://example.com"
readme = "README.md"
[step1]
type = "clone"
url = "https://example.com"
branch = "master"
commit = "1234567890abcdef"
[step2]
type = "copy"
source = "path/to/source"
destination = "path/to/destination"
[step3]
type = "run"
command = "command"
[install]
steps = ["step1", "step2", "step3"]
artifacts = ["path/to/artifact1", "path/to/artifact2"]
[dependencies]
dependency1 = "1.0.0"
dependency2 = {
version = "1.0.0",
flavor = "flavor"
}
version
All of the fields under version
need only be specified if they different from the prior manifests.
dependencies
The dependencies
table lists all dependencies that are required for this version of the flavor. Each entry should point to either a version or a table with version
and flavor
fields.
install
steps
Takes a list of steps. Each step is a key in the manifest. The steps are executed in the order they are listed. The following step types are supported (* = required):
clone
: Clones a repository. The following fields are supported:url
*: The URL of the repository to clone.branch
: The branch to clone. Defaults tomaster
.commit
: The commit to clone. Defaults to the latest commit on the branch.
copy
: Copies a file or directory. The following fields are supported:source
*: The source of the file or directory to copy.destination
*: The destination of the file or directory to copy.
run
: Runs a shell command. The following fields are supported:command
*: The command to run.
All install steps are run in an isolated environment without root access, and artifacts should be installed to the local directory.
artifacts
Artifacts is a list of paths to files or directories that should be installed. These paths are relative to the local directory. All listed artifacts will be symbolically linked to the target directory.
Manifest Formats
Package manifests can be written in nearly any language. The following are all directly supported, but more could be implemented with little difficulty. The only requirement is a rust serde
implementation.
toml
The default format for manifests is toml. This is the format used in the examples in this book.
json
Package Manifest
{
"package": {
"name": "package-name",
"description": "A package description",
"authors": ["Author Name <Author Email>"],
"license": "License",
"homepage": "https://example.com",
"repository": "https://example.com",
"documentation": "https://example.com",
"readme": "README.md",
"keywords": ["keyword1", "keyword2"]
},
"dependencies": {
"dependency1": "1.0.0",
"dependency2": {
"version": "1.0.0",
"flavor": "flavor"
}
},
"flavors": {
"flavor": "path/to/flavor.json"
}
}
Flavor Manifest
{
"flavor": {
"description": "A flavor description",
"authors": ["Author Name <Author Email>"],
"license": "License",
"homepage": "https://example.com",
"repository": "https://example.com",
"documentation": "https://example.com",
"readme": "README.md"
},
"versions": {
"0.1.0": "path/to/0.1.0.json"
}
}
Version Manifest
{
"version": {
"authors": ["Author Name <Author Email>"],
"license": "License",
"homepage": "https://example.com",
"repository": "https://example.com",
"documentation": "https://example.com",
"readme": "README.md"
},
"step1": {
"type": "clone",
"url": "https://example.com",
"branch": "master",
"commit": "1234567890abcdef"
},
"step2": {
"type": "copy",
"source": "path/to/source",
"destination": "path/to/destination"
},
"step3": {
"type": "run",
"command": "command"
},
"install": {
"steps": ["step1", "step2", "step3"],
"artifacts": ["path/to/artifact1", "path/to/artifact2"]
}
"dependencies": {
"dependency1": "1.0.0",
"dependency2": {
"version": "1.0.0",
"flavor": "flavor"
}
}
}
yaml
Package Manifest
package:
name: package-name
description: A package description
authors:
- Author Name <Author Email>
license: License
homepage: https://example.com
repository: https://example.com
documentation: https://example.com
readme: README.md
keywords:
- keyword1
- keyword2
dependencies:
dependency1: 1.0.0
dependency2:
version: 1.0.0
flavor: flavor
flavors:
flavor: path/to/flavor.yaml
Flavor Manifest
flavor:
description: A flavor description
authors:
- Author Name <Author Email>
license: License
homepage: https://example.com
repository: https://example.com
documentation: https://example.com
readme: README.md
versions:
"0.1.0": path/to/0.1.0.yaml
Version Manifest
version:
authors:
- Author Name <Author Email>
license: License
homepage: https://example.com
repository: https://example.com
documentation: https://example.com
readme: README.md
step1:
type: clone
url: https://example.com
branch: master
commit: 1234567890abcdef
step2:
type: copy
source: path/to/source
destination: path/to/destination
step3:
type: run
command: command
install:
steps:
- step1
- step2
- step3
artifacts:
- path/to/artifact1
- path/to/artifact2
dependencies:
dependency1: 1.0.0
dependency2:
version: 1.0.0
flavor: flavor