{"id":22145021,"url":"https://github.com/pbrisbin/indirect","last_synced_at":"2026-02-19T00:35:10.197Z","repository":{"id":262720390,"uuid":"888141793","full_name":"pbrisbin/indirect","owner":"pbrisbin","description":"Executable used to indirectly call other executables","archived":false,"fork":false,"pushed_at":"2025-01-10T20:26:37.000Z","size":76,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-08-19T20:31:55.532Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Haskell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pbrisbin.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"COPYING","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2024-11-13T22:15:37.000Z","updated_at":"2025-01-10T20:26:39.000Z","dependencies_parsed_at":"2025-06-16T01:31:56.731Z","dependency_job_id":null,"html_url":"https://github.com/pbrisbin/indirect","commit_stats":null,"previous_names":["pbrisbin/indirect"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/pbrisbin/indirect","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pbrisbin%2Findirect","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pbrisbin%2Findirect/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pbrisbin%2Findirect/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pbrisbin%2Findirect/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pbrisbin","download_url":"https://codeload.github.com/pbrisbin/indirect/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pbrisbin%2Findirect/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29599396,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-18T22:25:43.180Z","status":"ssl_error","status_checked_at":"2026-02-18T22:25:42.766Z","response_time":162,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-12-01T22:37:39.773Z","updated_at":"2026-02-19T00:35:10.153Z","avatar_url":"https://github.com/pbrisbin.png","language":"Haskell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Indirect\n\nIndirect is an executable that can be used to indirectly call other executables.\nIt can be useful when you can't (or don't want to) change how something is\ninvoked, but want finer control over what is actually invoked.\n\n## Motivating Example\n\nWe use [Fourmolu][] to format Haskell code in a large team across a number of\nprojects. How that code is formatted differs slightly from version to version,\nso we all have to agree on the version we use. Otherwise, two folks working on\nthe same code over time might repeatedly reformat each others work back and\nforth, causing confusion and frustration each time.\n\n[fourmolu]: https://fourmolu.github.io/\n\nKeeping these versions correct is not trivial. Some editor tooling makes it\ndifficult to ensure its \"format on save\" feature calls a given executable, and\nalmost none make it easy to have that executable differ project to project.\n\nThere are solutions for this. Nix is the hammer that works for all nails, but\nthis project explores a lighter, more surgical solution.\n\nWith `indirect` installed and symlinked as the `fourmolu` on `$PATH`, invoking\nit naively (as editor tooling will most often do) will consult a configuration\nfile to determine which _actual_ executable to invoke.\n\nAdditionally, `indirect` can install the executable if necessary, using the\ninstructions given in the same configuration file.\n\n## Installation\n\n```console\ncurl --proto '=https' --tlsv1.2 -sSf \\\n  https://raw.githubusercontent.com/pbrisbin/indirect/main/install |\n  sh -s -- -p ~/.local\n```\n\nOr download the appropriate binary from the [latest release][releases], make it\nexecutable, and add it to `$PATH`.\n\n[releases]: https://github.com/pbrisbin/indirect/releases\n\n## User Configuration\n\nIndirect follows [XDG][], meaning user-configuration most likely occurs in\n`~/.config/indirect/indirect.toml`.\n\n[xdg]: https://specifications.freedesktop.org/basedir-spec/latest/\n\nThis file should be a list of [TOML tables][toml-table]. The table's name\ndenotes an executable you want `indirect` to manage.\n\n\u003e [!IMPORTANT]\n\u003e The special table name `defaults`, if present, will be used as a base for all\n\u003e other defined tables.\n\n[toml-table]: https://toml.io/en/v1.0.0#table\n\nValid keys in any table are:\n\n- `vars.x`: any arbitrary `x`, which can then be accessed as `${x}` in the\n  values of other fields\n\n  `vars` can reference other `vars`, even those yet to be defined. All\n  environment variables, `name`, and `binary` are also made available for\n  interpolation.\n\n- `binary`: required, relative path to name the versioned executable. Typically,\n  this would be `${name}-${version}` using a `vars.version` you define.\n\n- `install`: required, if `binary` is not present, this will be executed with\n  `sh -c` to install it.\n\n  The desired destination of the binary will be given as `$1`; if running this\n  script does not produce an executable at that location, `indirect` will error.\n\n### Example\n\n```toml\n[defaults]\nvars.artifact = \"${name}-${version}-linux-x86_64\"\n\nbinary = \"${name}-${version}\"\n\ninstall = \"\"\"\n  curl -sSf -L -O https://github.com/${name}/${name}/releases/download/v${version}/${artifact}\n  install ${artifact} \"$1\"\n\"\"\"\n\n[fourmolu]\nvars.version = \"0.16.2.0\"\n```\n\nThis configuration alone establishes a managed `fourmolu-0.16.2.0` on your\nsystem. To use this installation, you only need to execute `indirect` as a\nsymlink named `fourmolu`.\n\nSetting up that symlink (or copy, or hardlink) can be done manually, or you can\nuse our own `setup` sub-command:\n\n```console\n% indirect setup --no-install\n[indirect] Linking fourmolu to /home/patrick/.local/bin/indirect\n```\n\n\u003e [!NOTE]\n\u003e `--no-install` is used here so we can witness on-demand installation later.\n\u003e Run `indirect setup --help` for more details.\n\n```console\n% ls -l ~/.local/bin/fourmolu\nlrwxrwxrwx 1 patrick patrick 160 Nov 13 22:20 /home/patrick/.local/bin/fourmolu -\u003e indirect\n```\n\nRunning `fourmolu` installs the configured version:\n\n```console\n% fourmolu --version\n[indirect] Installing /home/patrick/.local/share/indirect/targets/fourmolu-0.16.2.0\nfourmolu 0.16.2.0 e8aa5a666f94eca63e2d8bb1db80b419484ed61a\nusing ghc-lib-parser 9.10.1.20240511\n```\n\n```console\n% ls -l ~/.local/share/indirect/targets/fourmolu-*\n-rwxr-xr-x 1 patrick patrick 64309880 Nov 13 22:20 /home/patrick/.local/share/indirect/targets/fourmolu-0.16.2.0\n```\n\nRunning `fourmolu` again uses what's already there:\n\n```console\n% fourmolu --version\nfourmolu 0.16.2.0 e8aa5a666f94eca63e2d8bb1db80b419484ed61a\nusing ghc-lib-parser 9.10.1.20240511\n```\n\n## Project Configuration\n\nThis is already quite valuable, but how do we deal with a project that expects a\ndifferent version? Well, Indirect configurations can be merged, and\n`.indirect.toml`, if present, will take precedence over the user configuration\ndescribed above.\n\nThis means you can check a `.indirect.toml` file into any project and use it to\noverride some `vars`:\n\n```toml\n[fourmolu]\nvars.version = \"0.13.1.0\"\n```\n\nRunning `fourmolu` in this directory installs the configured version:\n\n```console\n% fourmolu --version\n[indirect] Installing /home/patrick/.local/bin/fourmolu-0.13.1.0\nfourmolu 0.13.1.0 9181f7e5daf4fe816adf69cdaf5c0c76dcd0a089\nusing ghc-lib-parser 9.6.2.20230523\n```\n\n```console\n% ls -l ~/.local/share/indirect/fourmolu-*\n-rwxr-xr-x 1 patrick patrick 59604696 Nov 13 22:34 /home/patrick/.local/share/indirect/targets/fourmolu-0.13.1.0\n-rwxr-xr-x 1 patrick patrick 64309880 Nov 13 22:20 /home/patrick/.local/share/indirect/targets/fourmolu-0.16.2.0\n```\n\nAnd again, running it again uses what's already there:\n\n```console\n% fourmolu --version\nfourmolu 0.13.1.0 9181f7e5daf4fe816adf69cdaf5c0c76dcd0a089\nusing ghc-lib-parser 9.6.2.20230523\n```\n\n## Development\n\nWhen developing, be sure to use `--copy-bins` and test by running the installed\n`indirect` and never `stack exec indirect`. The latter will infer a directory\nwithin `.stack-work` as the place to look for or install links, which you most\nlikely do not want.\n\n---\n\nIndirect is licensed AGPLv3. See [COPYING](./COPYING).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpbrisbin%2Findirect","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpbrisbin%2Findirect","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpbrisbin%2Findirect/lists"}