1
0
Fork
You've already forked xp
0
A tiny task runner written in Rust
  • Rust 100%
2025年06月08日 19:55:49 +03:00
src A much needed makeover 2025年06月08日 19:55:49 +03:00
.gitignore Initial commit! Add shell support and basic tasks and env management 2025年02月21日 23:03:51 +03:00
Cargo.lock Add dir support 2025年02月25日 09:53:33 +03:00
Cargo.toml A much needed makeover 2025年06月08日 19:55:49 +03:00
LICENSE A much needed makeover 2025年06月08日 19:55:49 +03:00
README.md A much needed makeover 2025年06月08日 19:55:49 +03:00
rustfmt.toml Initial commit! Add shell support and basic tasks and env management 2025年02月21日 23:03:51 +03:00
xp.toml A much needed makeover 2025年06月08日 19:55:49 +03:00

xP - a tiny task runner written in Rust

Please don't upload to GitHub

I hate Gradle with a passion and I don't want to write a full blown build system.

So tiny task runner it is!

Installation

Until I put this on crates.io or wherever else, you can build and install from source:

git clone https://codeberg.org/noth/xp.git
cd xp
cargo install --path .

Ironically, you can use xp to build or install xp:

# clone, cd...
xp build # or: xp install

Usage

In any project you want to use it in, create a xp.toml in its root directory:

[tasks.build]
run = "cargo build"
alias = "b"
[tasks.lint]
run = "cargo clippy"
alias = "l"

Given this config, you can run xp build or xp b to build the project and xp lint or xp l to lint it with Clippy.

If you want to see more options, you can either continue reading or read the config.rs file, which defines all of the structures used in configuration.

Defining tasks

Tasks are defined in the [tasks] section:

[tasks.build]
run = "cargo build"
alias = "b"
[tasks.publish]
run = "cargo publish"
dotenv = ".env" # take tokens from here
[tasks.sitedev]
run = "bun run dev"
env = { PORT = "8080" }

The run field declares a command (or an array of commands) to be run. If multiple commands are provided, they will be run in order and execution halts if any of them fail. (see: Multiple commands)

The alias field is optional and it can be used to declare an alias for the task. If you want more than one, put them in the aliases array. Any given alias will run the same task.

The env and envfiles/dotenv fields control the environment variables for the task. See: Environment variables

The shell field controls the shell that will be used to run the given commands. See: Shells

Features

Environment variables

You can set environment variables in the xp.toml file. They will apply for all ran tasks.

[env]
RUST_LOG = "info"

Usage of .env files is encouraged - just add them to the envfiles array.

envfiles = [".env", ".env.local"]

Usually, you only have one - so just set it as the dotenv.

dotenv = ".env"

For tasks, it's almost the same:

[tasks.dev] # `xp dev`
run = "cargo run"
env = { RUST_LOG = "info" }
dotenv = ".env.dev" # it stacks with the global one, so if you set dotenv = ".env" on the top, it'll apply both .env and .env.dev but ONLY for this task
# or you can use a table:
[tasks.dev.env]
RUST_LOG = "info"
DB_HOST = "localhost:9199"
DB_USER = "root" # and your boss can yell at you for using root as a db user!

Shells

You can set a shell that will be used to run commands. A shell can be set globally or per task.

shell = "sh -c" # Use sh by default
[tasks.shtask]
run = "echo $SHELL" # shows 'sh'
[tasks.bashtask] # We need to use Bash here, so set it
shell = "bash -c"
run = "echo $SHELL" # shows 'bash'
[tasks.rawonlytask]
shell = "" # overrides global shell and disables it
run = "echo $SHELL" # shows the literal '$SHELL' because there's no shell to substitute the variable

We can express our hatred for Gradle even more by using the gradle.properties file as an environment file:

envfiles = ["gradle.properties", ".env"]
[tasks.showdeps]
run = "echo Valkyrien Skies 2: $vs2_version" # Shows the version of Valkyrien Skies 2 defined in gradle.properties

Multiple commands

You can run multiple commands in a task.

[tasks.ci]
run = ["cargo build --release", "cargo test --release", "bash ./scripts/upload-to-forgejo.sh"]

These commands will be run in order, and if any of them fail, execution is terminated and the task is marked as failed.

Setting the current directory for commands

The current directory for commands can be set using the dir field on a task object.

[tasks.themes]
run = "whiskers nite.tera"
dir = "themes/catppuccin" # <- relative to workspace root i.e. folder where xp.toml is

You can also set the command to run explicitly in the workspace root with dir = "{workspace}":

[tasks.clean-themes]
run = "rm -rf themes/**/*.kdl"
dir = "{workspace}"

Additional commands

xp has a few additional commands:

  • @help or --help - shows help for the command
  • @tasks or just xp without args - shows all tasks
  • @exec or @x - executes a command in the xp environment
  • @shell or @sh - runs a shell in the xp environment

The xp environment means that the commands are run with the env vars that were dumped from the global envfiles/dotenv and env fields from the config. For further details, see: Environment variables

Motivation

First, my hatred for Gradle, stated in the first paragraph of this README.

Second, I have a ton of tiny scripts in my projects and I'm just tired of having to write a lot of different files and usually just boilerplate for them (i.e. chmod-ing them).

Oh, also, with this I can invoke stupidly slow gradle tasks faster! Hooray!

Credits

  • mise - which is the inspiration for this project (I wanted a mise that was just tinier and shorter to invoke)