Quality of Life Scripts

#1

I imagine most of us each have a little treasure trove of little scripts and shell aliases that make our lives with Nix just a little bit sweeter.
I invite you to share!

I have my larger fuzzy finder script that has it’s own topic (a bit big to repost so I’ll just link it). This also has a Deoplete (vim) source for completing Options and Packages, pulled from Nix’s env so it will complete all of your overlayed modules and packages.

on the simpler side are these small shell functions to hop into the store path of a program/derivation that I use to sniff around sources.

# `nat fzf` or `nat nixpkgs.fzf` => prints store path of fzf's derivation
function nat () { nix path-info nixpkgs.${1#nixpkgs.} }
function ngo () { cd `nixat ${1}`}

I know I have some others floating around that I will add later, and I am sure collectively we have a ton of convenient little helpers. :heart:

0 Likes

#2

I have a xonsh alias I named ‘w’ that is a convenience wrapper for nix-shell. I’d call it ‘with’, but ‘with’ is a reserved keyword in xonsh. It’s kinda messy at the moment, but I love it

# add a powerful 'w' ('with') command.
# Examples:
# w ncdu /
# w extra_file.nix ncdu /
# w ncdu -- ncdu /
# w - ncdu /
# w ncdu --- /
# w - sudo ncdu /
# w py:numpy,notebook -- python -m notebook
def _w(args):
    def expand_arg(arg):  # what to turn a dependency word into?
        if arg.endswith('.nix'):  # a file
            return [arg]
        elif arg.startswith('py:'):  # ex: py:numpy,notebook
            return ['-p',
                    'python3.withPackages (ps: with ps; [ ' +
                    ' '.join(arg.split(':', 1)[1].split(',')) +
                    '])']
        elif arg.startswith('xsh:'):  # ex: xsh:numpy,notebook
            return ['-p',
                    'xonsh.overridePythonAttrs(old: ' +
                    '{propagatedBuildInputs = old.propagatedBuildInputs ' +
                    '++ (with python3Packages; [ ' +
                    ' '.join(arg.split(':', 1)[1].split(',')) +
                    ']);})']
        else:  # probably a package name
            return ['-p', arg]

    cmd = []
    if '--' in args:  # run cmd, ex: with ncdu -- ncdu /
        i = args.index('--')
        args, cmd = args[:i], args[i + 1:]
    elif '-' in args:  # pull in following argument, ex: with - ncdu /
        i = args.index('-')
        if args[i + 1] != 'sudo':
            args, cmd = args[:i] + [args[i + 1]], args[i + 1:]
        else:  # 'forgot sudo' scenario: with file - sudo file -s /dev/sdc*
            args, cmd = args[:i] + [args[i + 2]], ['sudo'] + args[i + 2:]
    elif '---' in args:  # run last dependency, ex: with ncdu --- /
        i = args.index('---')
        args, cmd = args[:i], [args[i - 1]] + args[i + 1:]
    dir_tail = $(pwd).strip().split('/')[-1]
    features = ['+' + a for a in args] if args else ['@' + dir_tail]
    with_features = ' '.join(features + ${...}.get('WITH_FEATURES', '').split())
    flatten = lambda l: [item for sublist in l for item in sublist]
    args = flatten([expand_arg(a) for a in args])
    with ${...}.swap(WITH_FEATURES=with_features):
        with ${...}.swap(WITH_FEATURES_IMMEDIATE=' '.join(features)):
             nix-shell @(args) --run @(' '.join(cmd) if cmd else '.xonsh-wrapped')
aliases['w'] = _w
def _with_completer(prefix, line, begidx, endidx, ctx):
    if not line.startswith('w '):
        return set()
    if '-' in line or '--' in line or '---' in line:
        return set()
    import xonsh.completers.bash_completion
    # TODO: completers for py: and xsh:
    l = line.replace('w ', 'nix-shell -p ', 1)
    r = xonsh.completers.bash_completion.bash_complete_line(l)
    r = {x.replace('nix-shell -p ', 'w ', 1).split()[-1] for x in r}
    return r
completer add with _with_completer
del _w

What is not mentioned above is that my right prompt has a list of stuff (WITH_FEATURES) that I have summoned in my shell, divided into two sublists of different colors, for the innermost shell and for all the others. This way I always see what extra tools I have and I have a good estimate of what I will lose by pressing ^D. I have no idea how to live without that now.

0 Likes

#3

While we are at it, some other aliases of mine:

  • nxg syncs my configuration changes with git (stashing uncommitted changes and restoring them)
  • nxu updates channels
  • nxo builds my configuration on a beefy buildhost
  • nxl builds my configuration locally with a nice progressbar
  • nxt is sudo nixos-rebuild test that doesn’t create a link
  • nxf is same with --fast
  • nxs is sudo nixos-rebuild switch

and all of them have --cores 4.

Moreover, I have autogenerated aliases for a metric ton of their sensible combinations, like nxguos: sync git, update channels, build offloaded and switch:

$ ', '.join([a for a in aliases if a.startswith('nx') and len(a) > 3])
'nxlt, nxlf, nxls, nxot, nxof, nxos, nxut, nxuf, nxus, nxult, nxulf, nxuls, nxul, nxuot, nxuof, nxuos, nxuo, nxup, nxgt, nxgf, nxgs, nxglt, nxglf, nxgls, nxgl, nxgot, nxgof, nxgos, nxgo, nxgp, nxgut, nxguf, nxgus, nxgu, nxgult, nxgulf, nxguls, nxgul, nxguot, nxguof, nxguos, nxguo, nxgup'

Gist: https://gist.github.com/t184256/0ca8d6941b45ee7abdf932b03e51cacf

1 Like

#4

Any particular reason not to just set this globally with nix.buildCores?

0 Likes

#5

Not really. Fixed. Thanks!

0 Likes

#6

Whoa I had never heard of this shell before. Reminds me a bit of Turtle in Haskell; this seems rad.

0 Likes

#7

I had never thought of auto-generating aliases like this. I have seen this kind of laundry list for classics like Oh-my-Zsh’s git aliases; but generating a collection this way is so clean. Thanks for post. I’m going to try and expand my nixos-rebuild aliases beyond my little nrs='nixos-rebuild switch' haha.

0 Likes

#9

I wouldn’t call that these particular scripts of mine ‘clean’, but yeah, xonsh is rad. I’d recommend it to any pythonista without hesitation. It totally kicks ass if you’re doing data analysis, it is usable as one’s daily shell, and it makes shell scripting so trivial it feels like cheating.

0 Likes