cargo_task/
lib.rs

1#![allow(clippy::upper_case_acronyms)]
2#![deny(unsafe_code)]
3#![deny(missing_docs)]
4#![deny(warnings)]
5//! Ultra-Lightweight Zero-Dependency Rust Cargo Task Runner.
6//!
7//! - Platform Agnostic - runs on any platform that cargo runs on.
8//! - Zero-Dependency - the task manager itself installs almost instantly.
9//! - Rust Task Logic - stop writing separate bash and powershell scripts.
10//! - Take a look at the ['.cargo-task' directory](./.cargo-task) in this repo for examples.
11//!
12//! ```shell
13//! cargo install -f cargo-task
14//! cargo help task
15//! ```
16//!
17//! ## Creating `cargo-task` automation tasks.
18//!
19//! ```shell
20//! cargo task ct-init
21//! cd .cargo-task
22//! cargo new --bin my-task
23//! cd ..
24//! cargo task my-task
25//! ```
26//!
27//! - `cargo task ct-init` - creates the `.cargo-task` directory and `.gitignore`.
28//! - `cargo task my-task` - runs the crate named `my-task` defined in the `.cargo-task` directory.
29//!
30//! It's that simple!
31//!
32//! ## Script-like single file tasks.
33//!
34//! If you don't want to commit a whole directory / Cargo.toml etc... you can
35//! specify cargo-task tasks as single files.
36//!
37//! Just create a file in your `.cargo-task` directory named something like
38//! `my-task.ct.rs` and write it as you would a `main.rs`.
39//!
40//! This will also create a `my-task` cargo task. You can even specify cargo
41//! crate dependencies via AtAt directive `@ct-cargo-deps@` (see below).
42//!
43//! ## Customizing how tasks are executed.
44//!
45//! `cargo-task` uses a metadata format called AtAt - because it uses `@` signs:
46//!
47//! ```ignore
48//! /*
49//! @ct-default@ true @@
50//! @ct-task-deps@
51//! one
52//! two
53//! @@
54//! */
55//! ```
56//!
57//! Some things to know about AtAt:
58//! - protocol: `@key@ value @@`.
59//! - the first `@` for the key must be the first character on a line.
60//! - the value is terminated by a two ats, "`@@`".
61//! - the value can contain newlines or be on a single line.
62//! - you probably want it in a rust comment block : )
63//!
64//! These directives will be read from your `main.rs` file when parsing the
65//! `.cargo-task` crates.
66//!
67//! ### Default tasks.
68//!
69//! ```ignore
70//! /*
71//! @ct-default@ true @@
72//! */
73//! ```
74//!
75//! Default tasks will be executed if the task list is empty on `cargo task`
76//! invocations.
77//!
78//! ### Bootstrap tasks.
79//!
80//! ```ignore
81//! /*
82//! @ct-bootstrap@ true @@
83//! */
84//! ```
85//!
86//! Bootstrap tasks will *always* be executed before any task-list tasks.
87//! Also, the cargo-task metadata will be reloaded after bootstrap tasks
88//! are executed. You can use this to download / install / configure
89//! additional tasks.
90//!
91//! ### Cargo dependencies.
92//!
93//! ```ignore
94//! /*
95//! @ct-cargo-deps@
96//! num_cpus = "1"
97//! serde = { version = "1", features = [ "derive" ] }
98//! @@
99//! */
100//! ```
101//!
102//! Write them just as you would in your Cargo.toml.
103//!
104//! ### Task dependencies.
105//!
106//! ```ignore
107//! /*
108//! @ct-task-deps@
109//! my-first-dependency
110//! my-second-dependency
111//! @@
112//! */
113//! ```
114//!
115//! A whitespace delimited list of tasks that must be run prior to the current
116//! task. Can be on a single line or multiple lines.
117//!
118//! ### Minimum cargo-task version.
119//!
120//! ```ignore
121//! /*
122//! @ct-min-version@ 0.0.7 @@
123//! */
124//! ```
125//!
126//! Require at least a minimum version of cargo-task to prompt users
127//! to upgrade if you are depending on features.
128//! Note, this directive works well when combined with `@ct-bootstrap@`
129//!
130//! ## The magic `cargo_task_util` dependency.
131//!
132//! - [cargo_task_util on docs.rs](https://docs.rs/cargo-task/latest/cargo_task/_cargo_task_util/index.html)
133//!
134//! This module will be available at the root of your crate during build time.
135//! To include it, simply add a `mod` directive in your `main.rs` file.
136//! A crate dependency with the same pub contents of this module will be
137//! available to your crate a run-time. The dependency is automatically added
138//! to script-type tasks.
139//!
140//! To add it to crate-type tasks simply include the dependency in your
141//! Cargo.toml:
142//!
143//! ```ignore
144//! [dependencies]
145//! cargo_task_util = "*"
146//! ```
147//!
148//! ```ignore
149//! /*
150//! @ct-default@ true @@
151//! */
152//!
153//! use cargo_task_util::*;
154//!
155//! fn main() {
156//!     // cargo task metadata env helper
157//!     let env = ct_env();
158//!
159//!     // print out some cool cargo-task metadata
160//!     // (this does the same thing as `cargo task ct-meta`)
161//!     println!("{:#?}", env);
162//!
163//!     // also includes cargo-task special log helpers
164//!     ct_warn!("ahh, a warning! {:?}", std::time::SystemTime::now());
165//! }
166//! ```
167//!
168//! ### Configuring tasks and the `cargo_task_util` crate for direct execution.
169//!
170//! So, you want to run your cargo tasks directly? The `cargo_task_util` crate
171//! is generated into your .cargo-task directory, but is ignored from git
172//! by a `.cargo-task/.gitignore` file. You can delete the .gitignore lines
173//! to check the crate into version control.
174//!
175//! Due to a windows pathing quirk, we need to use a workspace-level `[patch]`
176//! directive to make this dependency work.
177//!
178//! If you want a root workspace `Cargo.toml`, you can create one at the root
179//! of your project, and include all your crates, and your task crates.
180//!
181//! If, instead, you want to keep the task crates in a separate workspace,
182//! you can put a workspace `Cargo.toml` file in your `.cargo-task` directory.
183//! (You will also need to remove that line from your `.cargo-task/.gitignore`)
184//!
185//! This example is for a `.cargo-task/Cargo.toml` workspace. If your workspace
186//! root is a different directory, you'll have to adjust the paths.
187//!
188//! ```ignore
189//! [workspace]
190//! members = [
191//!     "cargo_task_util",
192//!     "my_task_crate",
193//! ]
194//!
195//! [patch.crates-io]
196//! cargo_task_util = { path = "cargo_task_util" }
197//! ```
198//!
199//! ## Exporting environment variables to configure other tasks.
200//!
201//! `cargo_task_util::CTEnv` also includes a utility for exporting environment
202//! variables.
203//!
204//! If you just use the rust `std::env::set_var` function, the variable will
205//! be set for the current task execution, but no other tasks will see it.
206//!
207//! Instead you can use `cargo_task_util::CTEnv::set_env` function.
208//!
209//! You probably want to do this in a "bootstrap" task so it is available
210//! to other tasks that are run later.
211//!
212//! ```ignore
213//! /*
214//! @ct-bootstrap@ true @@
215//! */
216//!
217//! mod cargo_task_util;
218//! use cargo_task_util::*;
219//!
220//! fn main() {
221//!     // cargo task metadata env helper
222//!     let env = ct_env();
223//!
224//!     // set a variable that will be available in other tasks.
225//!     env.set_env("MY_VARIABLE", "MY_VALUE");
226//! }
227//! ```
228
229pub mod _cargo_task_util;
230pub mod at_at;
231mod env_loader;
232mod task;
233
234#[cfg(windows)]
235include!(concat!(env!("OUT_DIR"), "\\ver.rs"));
236#[cfg(not(windows))]
237include!(concat!(env!("OUT_DIR"), "/ver.rs"));
238
239/// The .cargo-task directory name
240const CARGO_TASK_DIR: &str = ".cargo-task";
241
242/// The .cargo-task/.gitignore file
243#[cfg(windows)]
244const CT_DIR_GIT_IGNORE: &str = ".cargo-task\\.gitignore";
245#[cfg(not(windows))]
246const CT_DIR_GIT_IGNORE: &str = ".cargo-task/.gitignore";
247
248/// Source content of .cargo-task/.gitignore for 'ct-init'
249#[cfg(windows)]
250const CT_DIR_GIT_IGNORE_SRC: &[u8] = include_bytes!(concat!(
251    env!("CARGO_MANIFEST_DIR"),
252    "\\.cargo-task\\.gitignore"
253));
254#[cfg(not(windows))]
255const CT_DIR_GIT_IGNORE_SRC: &[u8] = include_bytes!(concat!(
256    env!("CARGO_MANIFEST_DIR"),
257    "/.cargo-task/.gitignore"
258));
259
260/// Source-code content of cargo_task_util.rs
261const CARGO_TASK_UTIL_SRC: &[u8] = include_bytes!("_cargo_task_util.rs");
262
263mod exec;
264pub use exec::*;