Skip to content

Commit

Permalink
fix: export Task type, improve docs
Browse files Browse the repository at this point in the history
  • Loading branch information
cdaringe committed Apr 27, 2020
1 parent f27c5d5 commit 9e95680
Show file tree
Hide file tree
Showing 8 changed files with 162 additions and 89 deletions.
49 changes: 34 additions & 15 deletions assets/rad.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,37 @@
export const tasks = {
yarn: {
input: "package.json",
output: "node_modules",
cmd: "yarn",
import { Task } from "https://raw.githubusercontent.com/cdaringe/rad/master/src/mod.ts";

const meet: Task = `echo "hi friend."`;

/**
* example rad tasks
*/
export const tasks: Tasks = {
/**
* make-style tasks!
*/
install: {
target: "node_modules",
prereqs: ["package.json"],
onMake: ({ sh }) => sh(`npm install && touch node_modules`),
},
build: {
input: "node_modules",
output: "bundle.zip",
dependsOn: ["yarn"],
cmd: (opts) =>
`
zip ${opts.task.output} \\
src \\
${opts.upstream.yarn.task.output}
`,
/**
* command style tasks
*/
build: `tsc`,
format: `deno fmt`,
meet,
/**
* function style tasks
*/
greet: {
dependsOn: [meet],
fn: async (toolkit) => {
const { fs, path, logger, Deno, sh, task } = toolkit;
fs.mkdirp && fs.readFile && await fs.writeFile("/tmp/hello", "world!");
path.resolve && path.relative && path.isAbsolute; // etc
logger.error("crikey!");
Deno.cwd() && Deno.pid;
await sh(`caw, caw!, ${task.name}`);
},
},
};
13 changes: 13 additions & 0 deletions assets/site/0005-manual.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
## manual

your guide to `rad`!

### understanding rad

- `rad` is written in typescript and runs on [deno](https://deno.land/)
- you write tasks, then ask `rad` to run them
- `rad` reads your radfile (i.e. `rad.ts`), compiles & type checks it, then runs it through its task graph executor

🤯

### setting up a radfile, rad.ts
4 changes: 4 additions & 0 deletions assets/site/0008-toolkit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
## toolkit

https://github.com/cdaringe/rad/blob/
f27c5d5f7cd8c40b1cb94b1f659c1b3768c7dc00/src/Task.ts#L33-L42
16 changes: 14 additions & 2 deletions assets/site/0009-why-not.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,21 @@ the intent here it not to dump on anyone or any tool, but articulate feature gap
| tool | DSL-less | static types | standalone | polyglot | incremental | debuggable | beautiful | dependency manager |
| ---------- | -------- | ------------ | ---------- | -------- | ----------- | ---------- | --------- | ------------------ |
| bazel | | | ||| | | |
| gradle | | ✓ (kinda) | | || |||
| gradle | | | | || |||
| gulp/grunt || | | | ||| |
| make | | |||| | | |
| rad |||||||| |
| npm-scripts|| | | | | | ||
| rad ||| ||||| |

ant, scons, ninja, etc were omitted. haven't used 'em!

here are some genuine, not-trying-be-rude-opinions.

bazel is complex. maybe you need that complexity. 🤷🏻‍♀️
gradle is full of magic and is often hard to reason about _where_ behavior comes from and is applied.
gulp/grunt have no make-style tasks, are generally node only, comparatively slow, & stringly typed in various places.
make is great, but a lame DSL and is coupled to a bad scripting language
npm-scripts are simple, but suffer releated drawbacks to gulp/grunt.

loose typing, unneeded/obsolete DSLs, lack of great static analysis, and _other_ gaps
leave room for improvement in this space.
13 changes: 12 additions & 1 deletion assets/site/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,21 @@
.token.operator {
background-color: transparent !important;
}

/* page */
@import url(https://fonts.googleapis.com/css?family=Open+Sans:800);
html, body {
height: 100%;
margin: 0;
width: 100vw;
}
@import url(https://fonts.googleapis.com/css?family=Open+Sans:800);
a, a:visited {color:#2196f3;} /* Visited link */
table {
display: block;
overflow-x: scroll;
}

/* hero */
.baby-rad {
transition: all 5s;
}
Expand All @@ -26,6 +36,7 @@
stroke: beige;
}

/* content */
body {
font-family: sans-serif;
background-color: #303030;
Expand Down
69 changes: 41 additions & 28 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,26 @@

a general purpose build tool.

statically typed, programmable, transparent, batteries included. shell, function based, and make-style task support.
statically typed, batteries included. command tasks, function tasks, and make-style tasks support.

![master](https://github.com/cdaringe/rad/workflows/master/badge.svg)

jump to:

1. [documentation site](https://cdaringe.github.io/rad/)
1. [usage](#usage)
1. [install](#install)
1. [what](#what-is-it)
1. [why](#what-is-it)
1. [why not `<my-favorite-build-tool>`?](#why-not-my-favorite-build-tool)
1. [manual](https://cdaringe.github.io/rad/#manual)

## usage

`$ rad <task-name> [--help]`

```ts
// rad.ts - your buildfile
// rad.ts
import { Tasks } from "https://raw.githubusercontent.com/cdaringe/rad/master/src/mod.ts";

// command tasks
Expand All @@ -26,13 +38,10 @@ const compile = {
const transpile = {
target: "phony",
prereqs: ["p1", "p2"],
async onMake({ logger }, { prereqs, getChangedPrereqFilenames }) {
const babel = await import("https://my.cdn/babel/7.js")
for await (const req of prereqs) {
async onMake({ logger }, { changedPrereqs /*, prereqs */}) {
for await (const req of changedPrereqs) {
logger.info(`req: ${req.filename} ${JSON.stringify(req.info)}`);
}
const changed = await getChangedPrereqFilenames();
logger.info(`changed: ${changed} (${changed.length})`);
},
}

Expand All @@ -45,7 +54,9 @@ export const tasks: Tasks = {

## install

there are a few formal ways to use `rad`:
there are a few formal ways to use `rad`. regardless of the route you choose,
know that all strategies support using pinned versions, adherent to semver.
see the [releases page](https://github.com/cdaringe/rad/releases).

| usage | install-method | install-steps |
| -- | -- | -- |
Expand All @@ -66,30 +77,32 @@ function rad() {

## what is it

a build tool! it competes with make, npm-scripts, bazel, gradle, ant, gulp, or any of the
other many tools out there!

`rad` offers:

- simple, programmable task interfaces
- easy to understand, declarative build steps
- type-checked tasks
- productive toolkit API for nuanced tasks that benefit from progamming. see [toolkit](#toolkit)<!-- @todo write toolkit docs-->
- bottom-up, `make`-style build targets
- fast builds, skip redundant tasks when inputs haven't changed!
- pipeline style builds
- easy to understand, declarative build steps
- highly portable. build automation for _any_ language or project, in many environments
- generic package management
- great UX is priority 1 (after priorities 0.33 works, 0.66 correct, & 0.99 fast-enough :))
- fast builds, skip redundant work when inputs haven't changed
- cli mode, or library mode
- portable. build automation for _any_ language or project, in many environments (*limited to _Deno_ target architectures, for the time being. long term, we may package this in `Rust`)
- great UX
- no quirky DSLs (`make`, `gradle`, and friends 😢). **your build is code**--tasks are typescript & are indeed type-checked!
- debuggable. 🐛 inspect your data, tasks, or even _rad_ itself
- simplicity of `make`, without the DSL, coupling to `sh`, and C/C++ biases
- use a real scripting language--**not** `bash/sh`! shell languages are great for running other programs, not for plumbing data

## why

no build tools in ~2018~ ~2019~ 2020 have a complete feature set that the average polyglot programmer needs without coercing it or piling on extraneous complexity.
🙄, _another build tool?_.

see [why not just use <my-favorite-build-tool>](./why-not.md)
definitely. no other build tools in ~2018~ ~2019~ 2020 have a sufficiently
balanced enough feature set that the average polyglot programmer needs without
coercing it or piling on extraneous complexity.

## features
see [why not just use <my-favorite-build-tool>](#why-not-my-favorite-build-tool)

- stop using `make` and `bash`. use a modern syntax and a real scripting language
- `<ref to why bash is not fit for general purpose scripting>`
- no DSL. your **build is code**--tasks are POJOs with a verified interface
- debuggable. :bug: halt the runtime, inspect your data, tasks, or even _rad_ itself
- beautiful.
- take it anywhere.
- osx, linux, windows!
- help us support other architectures
- no dependencies.
- e.g. you don't need bash, or java, this lib, that lib, etc. we bundle everything we need,
courtesy of `deno bundle`!
86 changes: 43 additions & 43 deletions src/Task.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,51 +106,51 @@ export type Makearooni = Dependarooni & {
* dependsOn?: [otherThing]
*/

export const makearooniToFuncarooni: (task: Makearooni) => Funcarooni = (
task,
) => {
const { target, onMake, prereqs = [], cwd = ".", ...rest } = task;
const funcer: Funcarooni = {
fn: async function makeTaskFn(toolkit) {
const targetWalkEntry: WalkEntry = await glob(cwd, target).next().then(
(res) => res.value,
);
const targetModified = targetWalkEntry?.info?.modified || -1;
const getPrereqs = async function* getMakePrereqs(
filter: (predicate: WalkEntry) => boolean,
): AsyncIterable<WalkEntry> {
for (const prereq of prereqs) {
for await (const walkEntry of glob(cwd, prereq)) {
if (filter(walkEntry)) yield walkEntry;
export const makearooniToFuncarooni: (task: Makearooni) => Funcarooni =
(task) => {
const { target, onMake, prereqs = [], cwd = ".", ...rest } = task;
const funcer: Funcarooni = {
fn: async function makeTaskFn(toolkit) {
const targetWalkEntry: WalkEntry = await glob(cwd, target).next().then(
(res) => res.value,
);
const targetModified = targetWalkEntry?.info?.modified || -1;
const getPrereqs = async function* getMakePrereqs(
filter: (predicate: WalkEntry) => boolean,
): AsyncIterable<WalkEntry> {
for (const prereq of prereqs) {
for await (const walkEntry of glob(cwd, prereq)) {
if (filter(walkEntry)) yield walkEntry;
}
}
}
};
const changedPrereqs = () =>
getPrereqs((walkEntry) => {
const { created, modified } = walkEntry.info;
const isPrereqChanged = (modified || created || 0) >= targetModified;
return isPrereqChanged;
});
return onMake(
toolkit,
{
prereqs: getPrereqs((i) => !!i),
changedPrereqs: changedPrereqs(),
getPrereqFilenames: () =>
iter.toArray(getPrereqs((i) => !!i)).then((reqs) =>
reqs.map((req) => req.filename)
),
getChangedPrereqFilenames: () =>
iter.toArray(changedPrereqs()).then((reqs) =>
reqs.map((req) => req.filename)
),
},
);
},
...rest,
};
const changedPrereqs = () =>
getPrereqs((walkEntry) => {
const { created, modified } = walkEntry.info;
const isPrereqChanged =
(modified || created || 0) >= targetModified;
return isPrereqChanged;
});
return onMake(
toolkit,
{
prereqs: getPrereqs((i) => !!i),
changedPrereqs: changedPrereqs(),
getPrereqFilenames: () =>
iter.toArray(getPrereqs((i) => !!i)).then((reqs) =>
reqs.map((req) => req.filename)
),
getChangedPrereqFilenames: () =>
iter.toArray(changedPrereqs()).then((reqs) =>
reqs.map((req) => req.filename)
),
},
);
},
...rest,
};
return funcer;
};
return funcer;
};

export const asFuncarooni = (
task: Task,
Expand Down
1 change: 1 addition & 0 deletions src/mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,4 @@ export function createTaskGraph(radness: Radness, { logger }: WithLogger) {

export { Radness } from "./Radness.ts";
export type Tasks = Radness["tasks"];
export { Task } from "./Task.ts";

0 comments on commit 9e95680

Please sign in to comment.