An open API service indexing awesome lists of open source software.

https://github.com/gapotchenko/gnu-tk

A mutli-platform command-line utility that provides seamless access to GNU toolkits on non-GNU operating systems.
https://github.com/gapotchenko/gnu-tk

Last synced: 5 months ago
JSON representation

A mutli-platform command-line utility that provides seamless access to GNU toolkits on non-GNU operating systems.

Awesome Lists containing this project

README

          

# GNU-TK

GNU-TK is a tiny project that provides seamless scriptable access to GNU tools
on non-Unix operating systems.

## Overview

[GNU](https://www.gnu.org/software/) is a software system that has been
developed by many people working together for the sake of freedom of all
software users to control their computing.

The GNU system offers a wide range of tools, including essential command-line
utilities such as `bash`, `cp`, `sed`, and many others. For instance, GNU
[core utilities](https://www.gnu.org/software/coreutils/) are crucial for
automating cross-platform projects by enabling the creation of reproducible
scripts. Beyond that, GNU tools support a wide variety of other use cases.

A **recurring issue with GNU tools**, however, is their limited accessibility on
non-Unix operating systems. For example, on Windows, you can use toolkits such
as [MSYS2](https://www.msys2.org/), [Cygwin](https://cygwin.com/) or
[WSL](https://learn.microsoft.com/windows/wsl/ "Windows Subsystem for Linux").
Yet, they introduce their own challenges: correctly identifying the toolkit
installation path, modifying environment variables, configuring shells with
toolkit-specific parameters, and, finally, managing the handoff of control to
and from the toolkit. All of this makes using GNU tools far from easy and
reproducible.

GNU-TK project addresses these problems by providing a small `gnu-tk`
command-line utility that acts as an automatic gateway to a GNU toolkit
installed on the system. `gnu-tk` has a concise and stable command-line
interface making it suitable for effortless cross-platform scripting. In
addition, it smoothes out the inconsistencies and shortcomings that typically
come with individual GNU toolkit distributions.

## Usage

The basic usage example:

```sh
gnu-tk -l cp --help
```

The command above invokes `cp` GNU utility with `--help` command-line option.

You can also pass a command to execute as a single command-line argument:

```sh
gnu-tk -c "cp --help"
```

Or as a script file:

```sh
gnu-tk -f
```

## Installation

You can install GNU-TK using one of the supported methods below.

### Setup Packages

Setup packages are standalone installers that let you install GNU-TK directly on
your system — no additional tools required.

#### Windows

- [GNU-TK Setup for Windows (x64)](https://download.gapotchenko.com/gnu-tk/latest/gnu-tk-setup-windows-x64.msi)
- [GNU-TK Setup for Windows (ARM64)](https://download.gapotchenko.com/gnu-tk/latest/gnu-tk-setup-windows-arm64.msi)

### Package Managers

#### NPM

NPM is a part of [Node.js](https://nodejs.org/). Use the following command to
install GNU-TK globally:

```sh
npm install -g @gapotchenko/gnu-tk
```

Alternatively, you can install GNU-TK locally within the Node.js project that
uses it: `npm install --save-dev @gapotchenko/gnu-tk`.

#### NuGet

NuGet is a part of [.NET](https://dotnet.microsoft.com/). Use the following
command to install GNU-TK as a global .NET tool:

```sh
dotnet tool install -g Gapotchenko.GnuTK
```

### Supported Platforms

GNU-TK can be readily used on the following platforms:

- Operating systems: Windows, macOS, Linux
- CPU architectures: x64, ARM64

### GNU Toolkits

Aside from GNU-TK utility itself, you may also need an actual GNU toolkit
installed on your system:

- **Windows:**
- [BusyBox](https://frippery.org/busybox/)
- [Cygwin](https://cygwin.com/)
- [Git](https://git-scm.com/downloads/win) (isn't a GNU toolkit by itself, but it conveniently includes a stripped-down immutable version of MSYS2)
- [MSYS2](https://www.msys2.org/) (recommended)
- [WSL](https://learn.microsoft.com/windows/wsl/ "Windows Subsystem for Linux")
- **macOS:**
- [Homebrew](https://brew.sh/) package manager with installed GNU packages;
[`bash`](https://formulae.brew.sh/formula/bash) and
[`coreutils`](https://formulae.brew.sh/formula/coreutils) is a recommended
bare minimum
- OS includes a pre-installed GNU-like toolkit
- **Linux:**
- [BusyBox](http://www.busybox.net/)
- OS includes a pre-installed GNU toolkit

#### Built-in Toolkits

The following built-in toolkits are bundled with GNU-TK packages to guarantee
that GNU tools minimally work even when no specialized GNU toolkit is available:

- **Windows:** [BusyBox](https://frippery.org/busybox/)

## How it Works

Internally, `gnu-tk` automatically finds and selects an appropriate GNU toolkit
installed in the system, and then executes a specified command using it.

To list all available toolkits, you can use `gnu-tk list` command:

```
Available GNU Toolkits

Name Description Location
------------------------------------------------------------------------------
busybox BusyBox 1.38.0 (built-in)
cygwin Cygwin 3.6.2 C:\cygwin64
git Git 2.50.1 C:\Program Files\Git
msys2-clang64 MSYS2 2025-02-21 C:\msys64
msys2-clangarm64 MSYS2 2025-02-21 C:\msys64
msys2-mingw32 MSYS2 2025-02-21 C:\msys64
msys2-mingw64 MSYS2 2025-02-21 C:\msys64
msys2-msys MSYS2 2025-02-21 C:\msys64
msys2-ucrt64 MSYS2 2025-02-21 C:\msys64
wsl WSL 2.5.9.0 C:\Program Files\WSL

Tips:
- You can install a GNU toolkit to add it to the list:
https://gapt.ch/help/gnu-tk/install-toolkits
- You can use 'GNU_TK_TOOLKIT_PATH' environment variable to specify the
directory paths of portable GNU toolkits
- GNU toolkits supported on Windows: BusyBox, Cygwin, Git, MSYS2, WSL
```

To simplify usage, GNU-TK automatically selects the most suitable GNU toolkit
based on common-sense factors. You can verify the GNU toolkit selection and
availability using `gnu-tk check` command:

```
GNU Toolkit Check

Name: msys2-ucrt64
Description: MSYS2 2025-02-21
Location: C:\msys64
Semantics: GNU
Isolation: none

Check status: PASS

Tips:
- To change the selected toolkit, specify '--toolkit' command-line option or
its shorthand '-t'
- Alternatively, you can set 'GNU_TK_TOOLKIT' environment variable to the
name of a GNU toolkit to use by default
```

You can affect GNU toolkit selection during command invocation. For example, you
can pass `-s` (or `--strict`) command-line option to `gnu-tk`, indicating that a
toolkit with strict GNU semantics is required:

```
gnu-tk -s -l sed --help
```

This can be vital on Unix operating systems like macOS that have built-in
versions of Unix utilities. By specifying the `-s` command-line option, you
explicitly assert that only a GNU version of `sed` utility should be ever used.
Without that option, `gnu-tk` works in relaxed mode allowing built-in Unix OS
commands to work as close-enough substitutes when no corresponding GNU utilities
are found.

## Examples

GNU-TK is an adaptable tool that can work with a variety of technologies. In
this section, we'll explore a few integration examples.

### Node.js

Node.js projects use a `package.json` file to define project configuration. One
key feature of this file is the ability to specify custom scripts, which can be
executed using the `npm run ` command.

By default, custom scripts defined in `package.json` are executed using the
command shell of the host operating system. This is sufficient for basic tasks,
but more complex scenarios may require commands like `cp`, `mv`, `sed`, and
others. While some of these commands have OS-specific equivalents, relying on
them can reduce the portability of your project across different environments.

In that case, you can use `gnu-tk` to make your scripts provably portable across
different platforms. Let's examine a sample `package.json` file:

```json
{
"scripts": {
"rebuild": "npm run clear && npm run build",
"build": "docusaurus build && gnu-tk -l rm -rf public && gnu-tk -l mkdir public && gnu-tk -l cp -r build public/content && gnu-tk -l mv public/content/_* public && gnu-tk -l mv public/content/*.txt public && gnu-tk -s -l sed -i public/content/sitemap.xml -f src/patches/sitemap.xml.sed",
"clear": "docusaurus clear && gnu-tk -l rm -rf public"
}
}
```

Note how the `gnu-tk` tool is used in the script definitions. In this mode, you
can seamlessly switch between native shell commands and GNU tools as needed.

For this to work, `gnu-tk` must be installed either [globally](#installation),
or locally within the Node.js project that uses `gnu-tk`:

```sh
npm install --save-dev @gapotchenko/gnu-tk
```

### Just

[`just`](https://github.com/casey/just) is a cross-platform script runner.

By default, `just` executes scripts using the command shell of the host
operating system. This approach works well for trivial cases but falls apart on
more complex scenarios. Let's examine a sample `justfile`:

```just
run:
echo Just hello
cp --help
```

If you try to run this script with `just run` command on a Unix system, you will
get the expected correct result. On Windows, you'll encounter an error because
the `cp` command is not available on this OS.

One way to solve that problem is to use `gnu-tk` in place:

```just
set windows-shell := ["cmd", "/c"]

run:
echo Just hello
gnu-tk -l cp --help
```

This gives us the desired result.

While the above approach works, repeatedly invoking `gnu-tk` can become tedious.
To simplify things, we can configure `gnu-tk` as the default command shell for
`justfile`:

```just
set windows-shell := ["gnu-tk", "-i", "-c"]

run:
echo Just hello
cp --help
```

Now, `just run` command will produce the correct results on all supported
platforms.

Setting `windows-shell` to `gnu-tk` for an entire `justfile` can sometimes be
too aggressive. In such cases, a more gradual approach using the `[script]`
attribute may be preferable
([docs](https://just.systems/man/en/script-recipes.html)):

```just
set windows-shell := ["cmd", "/c"]
set script-interpreter := ["gnu-tk", "-i", "-l", "/bin/sh", "-eu"]

[script]
run:
echo Just hello
cp --help
```

And if you would like to write your cross-platform `just` recipes in another
language – say, Python:

```just
[script("gnu-tk", "-i", "-l", "/usr/bin/env", "python3")]
run:
print("Hello from Python script")
```