garnix-io / garn

garn is a build tool and environment manager that replaces justfiles/makefiles, docker, and the annoying parts of READMEs. The builders lingua franca.
https://garn.io
Apache License 2.0
251 stars 6 forks source link

The Builders' Lingua Franca

[![built with garnix](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Fgarnix.io%2Fapi%2Fbadges%2Fgarnix-io%2Fgarn)](https://garnix.io) [![](https://dcbadge.vercel.app/api/server/q2Fptb7My4?style=flat)](https://discord.gg/q2Fptb7My4) [![](https://img.shields.io/badge/library-v0.0.20-black)](https://doc.deno.land/https://garn.io/ts/v0.0.20/mod.ts) [![License](https://img.shields.io/github/license/garnix-io/garn)](LICENSE)

garn is a build tool and development environment manager. You configure your project with a garn.ts file that declaratively describes your project and its dependencies.

You can think of it as coding up your README. Users, collaborators, and coworkers no longer need to manually follow install steps, or figure out what commands they can run, but instead can just use garn directly. And if it works for you, it works for everyone.[^1]

For example, with this garn.ts file:

import * as garn from "https://garn.io/ts/v0.0.20/mod.ts";

export const frontend = garn.javascript.mkNpmProject({
  description: "My project frontend",
  src: "frontend",
  nodeVersion: "18",
})
  .addExecutable("run", "cd frontend && npm install && npm start");

export const backend = garn.go.mkGoProject({
  description: "My project backend",
  src: "backend",
  goVersion: "1.21",
})
  .addExecutable("run", "cd backend && go run ./main.go");

export const startAll = garn.processCompose({
  frontend: frontend.run,
  backend: backend.run,
});

Anyone can run your frontend with garn run frontend, backend with garn run backend, or both with garn run startAll. All without needing to worry about having the correct version of go, nodejs, or anything else installed.

You may have noticed the use of import URLs in the file above. This is supported by Deno, which we use under the hood. But you don't need to install that either. In fact, garn might just be one of the last things you have to manually install.[^2]

garn is powered by Nix, so you get portable and reproducible builds and development environments.


Table of contents

Getting started

1) Install garn:

   sh <(curl --proto '=https' --tlsv1.2 -sSf https://garn.io/install.sh)

garn needs nix to be installed, so if you don't have nix already the above installer will install nix first, after asking for confirmation.

Manual install (Optional) If you prefer to know exactly what garn is doing, or if you have a special setup not covered by our installation script, you can see this page for manual installation steps.
Installing shell completion (Optional) You can also install shell completion scripts for the most popular shells. See this page for more information.
Deno LSP for garn files (Optional) garn is much nicer with an IDE-like experience. You can use garn edit for that or, if you prefer, you can set up your own editor. See this page for more information

2) Create your first garn.ts file:

You can use garn init to template out an initial configuration. You can use garn edit to start a text editor.

Check out the getting started guide for more information on how to write and modify your garn.ts file.

3) Run some things: Use the garn commands to run some tests, build packages, or run executables.

Commands

garn init

Running garn init in a directory without a garn.ts file will try to automatically detect what kind of project you have and generate a garn.ts file for you.

garn enter

garn enter [project or environment] will put you in a development shell with all needed dependencies available in your $PATH.

garn build

garn build [project] will build the specified project and create a symlink named result which links to the resulting build artifacts.

garn run

garn run [project] will run the default executable for the specified project.

garn check

garn check [check] will run all checks for the specified project. These checks run in a sandbox. The downside of sandboxing is that these checks won't have access to the internet. The upside is that they'll be (almost) perfectly reproducible.

garn edit

garn edit will start (and, if necessary, download) VSCodium, with Deno LSP configured for you. It will open garn.ts in the current directory. This won't clobber any of your existing VSCode/VSCodium configuration and data.

Core concepts

Languages and Stacks



We currently have support for the Npm, Yarn, Go, and Haskell projects, with more languages coming soon. If you really want to see something, make your voice heard in our issue tracker!

Note also our examples directory, which contains tested examples of using garn in various ways.

All examples below require the two following imports:

import * as garn from "https://garn.io/ts/v0.0.20/mod.ts";
import * as pkgs from "https://garn.io/ts/v0.0.20/nixpkgs.ts";

All garn.ts files require the first import, and often you also need the second. Besides that, you rarely need other imports.

Npm

The basic workhorse of Npm projects is mkNpmProject. An example:

export const frontend = garn.javascript.mkNpmProject({
  description: "My project frontend",
  src: ".",
  nodeVersion: "18",
})
  .withDevTools([pkgs.jq])
  .addExecutable("run", "npm install && npm start")
  .addCheck("test", "npm install && npm run test");

This creates a Project containing:

The right version of node, npm, jq, etc. will be used for all these. You can see a full project here.

Go

Go projects are usually built with mkGoProject:

export const server = garn.go.mkGoProject({
    description: "example backend server in go",
    src: ".",
    goVersion: "1.21",
  })
  .addExecutable("migrate", "go run ./scripts/migrate.go")
  .addExecutable("dev", "go run ./main.go");

Haskell

For creating Haskell projects, there's mkHaskellProject. An example:

export const project = garn.haskell.mkHaskellProject({
  description: "My project",
  src: ".",
  executables: ["server", "openapi-generation"]
  ghcVersion: "ghc94"
})

Assuming you have a cabal file in ., this creates a Project containing:

The right version of node, npm, jq, etc. will be used for all these. You can see a full project here.

How it works

The essential idea is to generate Nix code corresponding to your projects, and then run Nix behind the scenes. In here, you can see the simple but low-level Nix AST we use. Objects such as Checks have a nixExpression field that contains their corresponding Nix expression.

garn then generates a flake.nix that, for every exported variable of the garn.ts file, has a corresponding package, check, devshell or app.

This means that garn integrates with Nix (and the Nix ecosystem) both ways: you can write pure Nix expressions and embed them in garn.ts files, or import Nix projects, but you can also from Nix call things generated by garn.

Typescript API

You can find documentation for the garn Deno library here.

Comparison to other tools

[^1]: This might not always be true between different architectures and platforms (e.g. Linux vs. MacOS). [^2]: That said, the installation of garn itself isn't always smooth on MacOS. If you encounter a problem, please let us know.