Welcome to my blog!


Improve programming somewhat, original by Matt Bors
Made with Windows... maybe Written in HTML... maybe Edited with VIM... maybe

Feeding the penguin some RAM.
Performing global updates. Calculating dependencies... done!


My current gitmessage template

:: dev

By: Maciej Barć

It is possible to configure git to use a extra helpful git message when inside the git commit editor.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
#
# When committing follow those rules:
#   1. Use the Conventional Commits style when committing!
#      Follow this template:
#        > <type>[optional scope]: <description>
#        >
#        > [optional body]
#        >
#        > [optional footer(s)]
#      Allowed commit types are:
#        fix, feat, build,
#        chore, ci, docs,
#        style, refactor, perf,
#        test.
#      See also: https://www.conventionalcommits.org/en/v1.0.0/
#   2. Remember to add a "Signed-off-by"!
#      For example:
#        > Signed-off-by: John Smith <js@js.org>
#

Save that as .gitmessage on repo root.

Then wire it to local git config with:

1
git config --local commit.template .gitmessage

See also:

XGQT.Org gallery

:: art, blog, net, sigal

By: Maciej Barć

My image gallery is up on xgqt.org/gallery.

It is a million times better than Instagram and also it has no likes or comments - that’s a feature!

I build it with Sigal which outputs to static HTML pages.

Sigal script

1
2
3
4
5
6
7
out="/var/www/xgqt.org/htdocs/gallery"
mkdir -p "${out}"
sigal build                         \
      --config ./sigal.conf.py      \
      --title Gallery               \
      ./pictures/ "${out}"          \
      "${@}"

See also

Scribble hacks: insert module code

:: dev, lisp

By: Maciej Barć

get-module-content for showing module implementation

Normally Scribble, the Racket’s documentation tool, does not provide a way to see how a function/object/module is actually defined in the code. Just recently I wound a good-enough way to insert the whole content of the module we are documenting with Scribble.

Here’s my implementation:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11

The input is a module name in the form that you would use in absolute require form, except that it is a string, not a bare syntax.

get-module-content will reach out to Your Racket package database and find a module that you gave. It will read it and remove all comments. It returns a Racket string.

The string? returned by get-module-content can later be used to either extract some more info but it can be effectively used to insert the full module implementation block.

get-module-content usage inside Scribble

In Scribble I insert the module source code like so:

1
2
3
The source code of this module:

@codeblock[@get-module-content{mypkg/utils/path}]

See also

Common Project Layout, Version 1… A Rough Draft #1

:: dev

By: Maciej Barć

For CPL version 0 see common-project-layout-version–0. A template project for CPL v1 can be found at gitlab.com/xgqt/xgqt-misc-template-cplv1.

To solve the repository layout problem we propose this hierarchy:

  • separate the code from text/prose by clear distinction on top-level — thus the code dir
  • for code we create this structure:
    • authoring — authoring scripts for developers
    • copyright — copyright documents for the code
    • integration — integration scripts, ie CI/CD scripts or Groovy sources for Jenkins
    • source — versioned application/library sources, each major version is assigned a v<MAJOR> directory; this allows us to keep and maintain multiple versions, it is very reminiscent to having multiple package versions in a Ports (FreeBSD/Gentoo) repository
      • for the v<MAJOR> dirs we separate each bag of sources or scripts into its own directory, for example:
        • 3rd-party
        • admin
        • build-support
        • run
        • <APPNAME>-app
        • <APPNAME>-lib

Tutorial: PowerShell Modules in FSharp

:: dev, dotnet, fsharp, powershell, tutorial

By: Maciej Barć

F# is a amazing functional language bridging C#/.NET ecosystem with OCaml and interactive programming. It has recently became by favorite language to create personal projects in. It both has additional security of strong typing, unlike Python or Ruby while keeping the functional and interactive properties of weak-typed languages. F# is truly a engineering marvel.

PowerShell 7 is the Open-Source implementation of the old Windows PowerShell that is also cross-platform and can be used for scripting and automation. It’s Object-orientation makes an amazing extension capability compared to Bash.

You can use the F# language to create PowerShell modules. Normally PS Modules are written in C# but since the interop between .NET languages is insanely fluent one can just swap C# for F#.

Creating new project

1
2
mkdir -p ~/source/temporary/powershell-modules/fs-example
cd ~/source/temporary/powershell-modules/fs-example

Dotnet ClassLib

Init new F# Class project:

1
dotnet new classlib --language "F#"

Dependencies

Add dependency on Powershell interaction library:

1
dotnet add package PowerShellStandard.Library --version 5.1.1

F# interaction with PowerShell

Let’s rewrite Library.fs to contain:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
namespace FsExample.PowerShell

open System.Management.Automation

[<Cmdlet(VerbsCommon.Format, "FsExample")>]
type FsExample() =
    inherit PSCmdlet()

    [<Parameter>]
    [<ValidateNotNullOrEmpty>]
    member val Name: string = "Me" with get, set

    override this.BeginProcessing() =
        printfn "Hello %s" this.Name

Then, change RootNamespace to the main module name, that is FsExample.PowerShell.

We need to copy all assemblies to output. Add <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>net9.0</TargetFramework>
    <RootNamespace>FsExample.PowerShell</RootNamespace>
    <GenerateDocumentationFile>true</GenerateDocumentationFile>

    <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
  </PropertyGroup>

  <!-- Snip ... -->

</Project>

PowerShell library

Create PSModuleAssets directory:

1
2
mkdir -p PSModuleAssets
cd PSModuleAssets

The main module file will in turn load the DLL compiled form above F# code.

Create main module file - fs-example.psm1:

1
2
3
#!/usr/bin/env -S pwsh -NoLogo -NoProfile -NonInteractive

Import-Module "$PSScriptRoot/fs-example.dll"

We then need to create the main manifest file fs-example.psd1.

  • Path - relative path to output the manifest,
  • RootModule - relative module path to load on module import,
  • ModuleVersion, Description, Author and Copyright are some of standard metadata fields,
  • AliasesToExport, CmdletsToExport, DscResourcesToExport, FunctionsToExport and VariablesToExport are either globs or lists that tell what functions will be available on module load, for simplicity we will just specify a glob expression '*'.
1
2
3
4
5
6
New-ModuleManifest -Path ./fs-example.psd1 -RootModule ./fs-example.psm1 `
    -ModuleVersion "1.0.0" `
    -Description "FSharp example module" `
    -Author "Me" -Copyright "Copyright (c) 2025, Me" `
    -AliasesToExport '*' -CmdletsToExport '*' `
    -DscResourcesToExport '*' -FunctionsToExport '*' -VariablesToExport '*'

Copying PowerShell assets

Following ItemGroup will copy all files from PSModuleAssets to the output directory:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<Project Sdk="Microsoft.NET.Sdk">

  <!-- Snip ... -->

  <ItemGroup>
    <None Include="PSModuleAssets/*.*">
      <Link>%(Filename)%(Extension)</Link>
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </None>
  </ItemGroup>

  <!-- Snip ... -->

</Project>

Building the F# module

Clean up the old builds:

1
2
rm -fr ./psrepository
rm -fr ./out-module/fs-example

Dotnet-Build

And then build the module:

1
2
dotnet restore
dotnet build --configuration Release --output ./out-module/fs-example

Language locality bug

You have to use the en-US locale when publishing PowerShell modules.

1
2
3
$env:LANG = "en_US.UTF-8"
$env:LANGUAGE = "en_US.UTF-8"
$env:LC_MESSAGES = "en_US.utf8"

Installation

Remove old registered PowerShell repository:

1
try { Unregister-PSRepository -Name fs-example } catch { }

Register-PSRepository and Publish-Module

This quite complicated script will:

  • set up a PowerShell repository in current location,
  • register the PowerShell repository,
  • publish the module into the PowerShell repository,
  • install that published module from the PowerShell repository.
1
2
3
4
5
6
7
8
$repo = "fs-example"
$repoPath = "$pwd/psrepository/fs-example"

New-Item -ItemType Directory -Path $repoPath | Out-Null
Register-PSRepository -InstallationPolicy Trusted -Name $repo -SourceLocation $repoPath

Publish-Module -Verbose -Path $pwd/out-module/fs-example -Repository $repo
Install-Module -Scope CurrentUser -Force -Verbose -Name fs-example -Repository $repo

Removal

Uninstall-Module

Just call Uninstall-Module to remove any PowerShell module.

1
Uninstall-Module -Name fs-example

Usage in the REPL

Import-Module

Import it with Import-Module.

1
Import-Module -Verbose fs-example -Force

Finally - use Format-FsExample

Remember the above F# function that was defined in the class?

1
2
[<Cmdlet(VerbsCommon.Format, "FsExample")>]
type FsExample()

It will be now available under the name composed of the “common verb” and a secondary part, so Format-FsExample.

Try it:

1
Format-FsExample -Name Maciej

Interacting with OneDrive in Nextcloud by using RClone

:: linux, microsoft, nextcloud, onedrive, tutorial

By: Maciej Barć

How it works

  • There will be a FUSE OneDrive filesystem mounted on the machine Nextcloud runs on,
  • You configure filesystem-local “External storage” and point to the mountpoint of a cloud drive (in this case OneDrive),
  • users connected via Nextcloud Client will have a option to sync any chosen files from the External storage as if they were Nextcloud-owned files.

Benefits

There are some benefits from connecting OneDrive to Nextcloud:

  • faster cached sync than by normal straight-to OneDrive connection - files will be pushed to Nextcloud and then uploaded to Nextcloud, this will take less time than uploading straight to OneDrive because of Microsoft OneDrive rate-limiting the uploads (especially in case of larger files),
  • clients of Nextcloud do not have to configure any OneDrive connection,
  • you will be able to have two-way sync of your OneDrive files (currently two-way sync on the RClone side is experimental, this will use Nextcloud’s two-way sync mechanism).

Set up RClone

First You will have to set up RClone. Connect to your cloud of choice and then copy the config to a location that will be readable by a service that mounts a given cloud drive.

For OneDrive I use /usr/local/share/rclone/config/rclone.conf that is accessible only to the apache user.

The config will look something like this:

1
2
3
4
5
6
[OneDrive]
type = onedrive
region = global
token = *REDACTED*
drive_id = *REDACTED*
drive_type = personal

Mounting OneDrive

I created this helper script (in /usr/local/bin/rclone-mount.sh):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#!/bin/sh

set -e
set -u
trap "exit 130" INT

conf_path="${1}"

local_user="${2}"
local_path="${3}"

cloud_name="${4}"
cloud_path="${5}"

log_dir="/var/log/rclone"
log_file="${log_dir}/rclone-mount-${local_user}-${cloud_name}.log"

mkdir -p "${log_dir}"
touch "${log_file}"

chmod a+r "${log_file}"
chown "${local_user}" "${log_file}"

exec rclone                                         \
     --default-permissions                          \
     --allow-other                                  \
     --verbose                                      \
     --vfs-cache-mode full                          \
     --config "${conf_path}"                        \
     mount                                          \
     "${cloud_name}:${cloud_path}" "${local_path}"  \
     >> "${log_file}" 2>&1

Then, I use it in a OpenRC service like this (/etc/init.d/mount-OneDrive):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#!/sbin/openrc-run

conf_path="/usr/local/share/rclone/config/rclone.conf"

cloud_name="OneDrive"
cloud_path="/"

local_user="apache"
local_path="/mnt/${cloud_name}"

command="/usr/local/bin/rclone-mount.sh"
command_args="${conf_path} ${local_user} ${local_path} ${cloud_name} ${cloud_path}"

command_background="false"
command_user="${local_user}:$(id -g -n ${local_user})"
supervisor="supervise-daemon"

depend() {
    need net
}

start_pre() {
    ebegin "Unmounting leftovers from ${local_path} before service start"
    umount "${local_path}"
    eend 0
}

stop_post() {
    ebegin "Unmounting leftovers from ${local_path} after service stop"
    umount "${local_path}"
    eend 0
}

Enabling the RClone service

Set up directories and correct permissions:

1
2
3
4
5
mkdir -p /usr/local/share/rclone/config
chown -R apache:apache /usr/local/share/rclone/config

mkdir -p /var/log/rclone
chown -R apache:apache /var/log/rclone

Do not forget to make the mount service script executable:

1
chmod +x /etc/init.d/mount-OneDrive

Enable and start this service on OpenRC:

1
2
rc-update add mount-OneDrive default
rc-service mount-OneDrive start

Drive permissions

RClone mounts cloud drives by using FUSE. To have the RClone option --allow-other available in order to allow root to access the drive you will have to modify the FUSE config file (/etc/fuse.conf) - add user_allow_other.

Nextcloud configuration

Download and enable the “External storage” app. Then, in “Administration” settings add a external storage:

  • name: ExternalStorage_OneDrive
  • type: Local
  • authentication: None
  • configuration: /mnt/OneDrive
  • available for: YOUR USER

nextcloud admin external storage onedrive

GHC 9.8 and Cabal 3.10.3 on Gentoo Linux

:: dev, gentoo, haskell, tutorial

By: Maciej Barć

The official ::gentoo repository currently contains only GHC on version 9.2.8. To install newer GHC one has to either download/build themselves or use the ::haskell overlay (https://github.com/gentoo-haskell/gentoo-haskell).

Enable the ::haskell overlay

Enable:

1
eselect repository enable haskell

Sync:

1
2
3
emerge --sync haskell
egencache --update --repo haskell --jobs 12 --load 6
eix-update

Unmask needed packages

Add to /etc/portage/package.unmask/0000_hs.conf

1
2
3
4
5
6
7
8
<dev-lang/ghc-9.9

<dev-haskell/cabal-3.11
<dev-haskell/cabal-install-3.11
<dev-haskell/cabal-install-solver-3.11
<dev-haskell/cabal-syntax-3.11
<dev-haskell/text-2.2
<dev-haskell/parsec-3.1.18

Add to /etc/portage/package.accept_keywords/0000_hs.conf

1
2
3
app-admin/haskell-updater
dev-haskell/*
dev-lang/ghc

Install

1
emerge --ask --verbose ">=dev-lang/ghc-9.8" ">=dev-haskell/cabal-install-3.10"

Build of GHC 9.8 takes around ~2 hours on a 8-core laptop-grade CPU.

Bonus: masking packages from ::haskell

If you want to exclude a given version from the ::haskell overly from being installed/updated, then you can add a similar line(s) to /etc/portage/package.mask/0000_hs.conf:

1
app-emacs/haskell-mode::haskell

Forgotten SysStat

:: linux

By: Maciej Barć

SysStat is a amazing tool. In the age where telegraf and grafana are all the rage everybody forgot about the good old sysstat.

Selected command examples

  • iostat -d -p nvme0n1 3 - disk I/O for a NVME drive (nvme0n1),
  • sar -n DEV 3 - network throughput,
  • sar -h -r 3 - memory usage,
  • sar -P ALL 3 - CPU utilization
  • sar -q 3 - system load levels,
  • sar -A 3 - all the metrics.

Gathered info

qlist app-admin/sysstat | grep /usr/bin/

The app-admin/sysstat contains the following binaries and their respective statistic fields:

  • sar - general utilization statistics,
  • cifsiostat - CIFS,
  • iostat - device input/output,
  • mpstat - processors,
  • pidstat - Linux tasks,
  • tapestat - tape (yes, the real tape disks).

Installation

Gentoo

1
2
3
emerge --noreplace --verbose sys-process/cronie app-admin/sysstat
rc-service cronie start
rc-update add cronie default

Files

By default (on Gentoo): * sa (the collector) saves statistics to /var/log/sa, * /etc/sysstat is the configuration file * cron jobs are run via the *system* cronjob table.

Tag the releases

:: dev

By: Maciej Barć

Tag your releases!

There were so many times when I wanted to use some package, it has a version on repology, but when I open the project’s repo there are no tags.

Nowadays it is extremely easy to bump software versions according to semantic versioning and also to tag them, that it should go without saying that most OSS and proprietary projects could also follow that workflow.

There are many projects both language-specific and agnostic to manage the release (and tagging) process. My favorite agnostic one is tbump and I highly recommend it.

Install Bazel ZSH completion

:: bazel, dev

By: Maciej Barć

1
2
3
4
5
6
7
8
(
    repo="bazelbuild/bazel";
    raw="https://raw.githubusercontent.com/${repo}";
    url="${raw}/master/scripts/zsh_completion/_bazel";
    site_functions="/usr/share/zsh/site-functions";

    wget "${url}" -O ${site_functions}/_bazel
)

Afterwards, restart your ZSH shell session.

This also works if you have bazelisk installed but bazel has to be symlinked to the bazelisk executable path.

Do not split make.conf

:: gentoo, linux

By: Maciej Barć

I made a mistake when splitting my Portage make.conf file, having it as one file instead of a directly with many small files is a lot easier to maintain.

Portage allows users to split all of files inside /etc/portage such as make.conf, package.use, package.mask and other into groups of files contained in directories of the same name. This is very helpful when using automation to add some wanted configuration. But in case of make.conf it becomes a “form over function” issue.

I would also recommend to keep make.conf as simple as possible, without useless overrides and variable reassignment.

See also:

Bonus: config

And of course, this is my current /etc/portage/make.conf of my main dev machine:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
BINPKG_FORMAT="gpkg"
CCACHE_DIR="/var/cache/ccache"
EMERGE_WARNING_DELAY="0"
LC_MESSAGES="C"

PORTAGE_NICENESS="10"
PORTAGE_WORKDIR_MODE="0775"

PORTAGE_LOGDIR="${EPREFIX}/var/log/portage"
PORTAGE_ELOG_CLASSES="warn error log"
PORTAGE_ELOG_SYSTEM="save"

QUICKPKG_DEFAULT_OPTS="--include-config=y --umask=0003"
MAKEOPTS="--jobs=7 --load-average=6"

COMMON_FLAGS="
  -march=znver1 -O2 -falign-functions=32
  -fstack-clash-protection -fstack-protector-strong
  -fdiagnostics-color=always -frecord-gcc-switches -pipe"

ADAFLAGS="${COMMON_FLAGS}"
CFLAGS="${COMMON_FLAGS}"
CXXFLAGS="${COMMON_FLAGS}"
FCFLAGS="${COMMON_FLAGS}"
FFLAGS="${COMMON_FLAGS}"

CARGO_TERM_VERBOSE="false"
RUSTFLAGS="-C opt-level=3 -C debuginfo=0"

LDFLAGS="${LDFLAGS} -Wl,--defsym=__gentoo_check_ldflags__=0"

L10N="en de pl"
VIDEO_CARDS="amdgpu radeon radeonsi"

CPU_FLAGS_X86="
  aes avx avx2 f16c fma3 mmx mmxext pclmul popcnt
  sha sse sse2 sse3 sse4_1 sse4_2 sse4a ssse3"

EMERGE_DEFAULT_OPTS="
  --binpkg-changed-deps=y --binpkg-respect-use=y
  --nospinner --keep-going=y
  --jobs=3 --load-average=8"

GENTOO_MIRRORS="
  https://mirror.leaseweb.com/gentoo/
  https://gentoo.osuosl.org/
  https://distfiles.gentoo.org/"

FEATURES="
  userpriv usersandbox usersync
  downgrade-backup unmerge-backup binpkg-multi-instance buildsyspkg
  parallel-fetch parallel-install
  ccache
  -binpkg-logs -ebuild-locks"

USE="
  custom-cflags custom-optimization firmware initramfs vaapi vulkan
  -bindist -zeroconf"

The dilemma between Gentoo and Nixos

:: fediverse

By: Maciej Barć

The dilemma between #Gentoo and #NixOS is this:

The most important value of #Gentoo is configuration/customization and reproducibility comes 2nd.

In case of NixOS those value are reversed. The most important to NixOS is ability to reproduce given setup.

Both of those systems will suit users that value control over their systems very highly (unlike, say, Ubuntu - where the most important value is convenience), but the tie-breaking is between what value out of those two should come 1st.

Imported via Fedimpost from emacs.ch/@xgqt/112581104037953790

Installing unstable GIMP with Flatpak

:: linux, packaging

By: Maciej Barć

Add Flathub-Beta

Add the Flathub-Beta remote repository:

1
flatpak remote-add --user flathub-beta https://flathub.org/beta-repo/flathub-beta.flatpakrepo

Install GIMP beta

Install org.gimp.GIMP form flathub-beta:

1
flatpak install --assumeyes --user flathub-beta org.gimp.GIMP

Run GIMP

If you have other GIMP versions installed you will have to specify the “beta” version with //beta.

1
flatpak run org.gimp.GIMP//beta

Otherwise you can just run:

1
flatpak run org.gimp.GIMP

Also, in the desktop menus (like KRunner) this version of GIMP will have (beta) in its name so there is no chance to miss it.

Change location of intermediate objects in .NET

:: dev, dotnet

By: Maciej Barć

.NET creates the so-called intermediate objects while building .NET projects, those are located in the “bin” and “obj” directories. The default is not very satisfying, primarily because if a program from a different machine or a container modifies those, then any cached file system paths that are encoded in the objects will be broken. But also it is probably mostly a legacy behavior to have them split between “bin” and “obj” directories.

I prefer for them to say in one - ".cache", because that’s that they are - cache. With the following configuration objects will be stored inside the ".cache" directory. Furthermore, the objects produced by the native machine in the “native” subdirectory and the ones produced by container software in “container” subdirectory.

1
2
3
4
5
6
7
<PropertyGroup>
  <CachePath>.\.cache\native</CachePath>
  <CachePath Condition="'$(DOTNET_RUNNING_IN_CONTAINER)' == 'true'">.\.cache\container</CachePath>
  <MSBUildProjectExtensionsPath>$(CachePath)\obj\</MSBUildProjectExtensionsPath>
  <BaseIntermediateOutputPath>$(CachePath)\obj\</BaseIntermediateOutputPath>
  <BaseOutputPath>$(CachePath)\bin\</BaseOutputPath>
</PropertyGroup>

If anybody want to go hardcore and cache the intermediate objects based on the RID or architecture triplet, then this can also be done, for example, by adding environment variables to the path.

Safer Nix installation

:: linux, nix, packaging, sandbox, shell, test, tutorial

By: Maciej Barć

Nix is useful for quickly testing out software and providing a strict environment that can be shared between people.

Today I’m trying out Nix again, this time I want to do it my way.

Installation process

Nix store

I know Nix needs “Nix store” installation on / (the system root).

Create it manually to prevent the installation script from calling sudo. 1st I switch to the root account, and then I run:

1
2
mkdir -p -m 0755 /nix
chown -R xy:xy /nix

Running the install script

Download the Nix install script and examine the contents.

1
curl -L https://nixos.org/nix/install > nix_install.sh

Then, run it with --no-daemon to prevent it running as system service.

1
sh ./nix_install.sh --no-daemon
performing a single-user installation of Nix...
copying Nix to /nix/store...
installing 'nix-2.20.1'
building '/nix/store/1ahlg3bviy174d6ig1gn393c23sqlki6-user-environment.drv'...
unpacking channels...
modifying /home/xy/.bash_profile...
modifying /home/xy/.zshenv...
placing /home/xy/.config/fish/conf.d/nix.fish...

Installation finished!  To ensure that the necessary environment
variables are set, either log in again, or type

. /home/xy/.nix-profile/etc/profile.d/nix.fish

in your shell.

Wait!

modifying /home/xy/.bash_profile...
modifying /home/xy/.zshenv...
placing /home/xy/.config/fish/conf.d/nix.fish...

That’s very rude!

Stopping Nix from making a mess

I need to prevent Nix from mess up with my environment when I do not want it to. Nix puts some code into the Bash, ZSH and Fish initialization files during installation to ease it’s use. I do not want that since I do not want Nix to meddle with my environment without me knowing it.

I keep my .bash_profile and .zshenv in a stow-managed git repo so I can just cd into my repo and do git reset --hard, but for you will have to revert those files to their old forms manually.

Playing with Nix

We do not have nix in PATH but we still can launch it. Nix executables are located inside ~/.nix-profile/bin/.

By invoking nix-shell one can create a ephemeral environment containing only packages specified after the -p flag. I always add -p nix to have the Nix tools available also inside the spawned environment.

I will test out chibi (small Scheme interpreter) + rlwrap (REPL support for software lacking it) inside a Nix ephemeral environment:

1
~/.nix-profile/bin/nix-shell -p nix chibi rlwrap

Inside the spawned shell:

1
rlwrap chibi-scheme

In the chibi REPL, let’s see the contents of the PATH environment variable:

1
(get-environment-variable "PATH")

And exit the Scheme REPL:

1
(exit)

After the playtime, run garbage collection:

1
~/.nix-profile/bin/nix-collect-garbage