Skip to content
This repository has been archived by the owner on Aug 27, 2018. It is now read-only.

Commit

Permalink
Provide missing command suggestions, Ubuntu style
Browse files Browse the repository at this point in the history
If the user tries to run a program that doesn't exist from Bash, the
program name is looked up in a database that maps to Nix package
names.  If it is found, we print out a message like:

  $ pdflatex
  The program ‘pdflatex’ is currently not installed. It is provided by
  several packages. You can install it by typing one of the following:
    nix-env -i tetex
    nix-env -i texlive-core

If the environment variable $NIX_AUTO_INSTALL is set, the command is
installed and executed automatically:

  $ hello --version
  The program ‘hello’ is currently not installed. It is provided by
  the package ‘hello’, which I will now install for you.
  installing `hello-2.8'
  hello (GNU hello) 2.8
  Copyright (C) 2011 Free Software Foundation, Inc. ...

To use this, you must currently manually put the SQLite programs
database in /var/lib/nixos/programs.sqlite.  In the future, this file
should be provided as part of the NixOS channel so it gets updated
automatically.  To get a test version:

  $ curl http://nixos.org/~eelco/programs.sqlite.xz | xz -d > /var/lib/nixos/programs.sqlite
  • Loading branch information
edolstra committed Jan 30, 2013
1 parent 2f97304 commit b89f941
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 1 deletion.
1 change: 1 addition & 0 deletions modules/module-list.nix
Expand Up @@ -36,6 +36,7 @@
./misc/passthru.nix
./misc/version.nix
./programs/bash/bash.nix
./programs/bash/command-not-found.nix
./programs/blcr.nix
./programs/info.nix
./programs/shadow.nix
Expand Down
2 changes: 1 addition & 1 deletion modules/programs/bash/bash.nix
Expand Up @@ -33,7 +33,7 @@ let

options = {

environment.promptInit = mkOption {
environment.promptInit = mkOption {
default = ''
# Provide a nice prompt.
PROMPT_COLOR="1;31m"
Expand Down
48 changes: 48 additions & 0 deletions modules/programs/bash/command-not-found.nix
@@ -0,0 +1,48 @@
# This module provides suggestions of packages to install if the user
# tries to run a missing command in Bash. This is implemented using a
# SQLite database that maps program names to Nix package names (e.g.,
# "pdflatex" is mapped to "tetex").

{ config, pkgs, ... }:

with pkgs.lib;

let

commandNotFound = pkgs.substituteAll {
name = "command-not-found";
dir = "bin";
src = ./command-not-found.pl;
isExecutable = true;
inherit (pkgs) perl;
perlFlags = concatStrings (map (path: "-I ${path}/lib/perl5/site_perl ")
[ pkgs.perlPackages.DBI pkgs.perlPackages.DBDSQLite ]);
};

in

{

environment.interactiveShellInit =
''
# This function is called whenever a command is not found.
command_not_found_handle() {
local p=/run/current-system/sw/bin/command-not-found
if [ -x $p -a -f /var/lib/nixos/programs.sqlite ]; then
# Run the helper program.
$p "$1"
# Retry the command if we just installed it.
if [ $? = 126 ]; then
"$@"
fi
else
echo "$1: command not found" >&2
fi
}
'';

environment.systemPackages = [ commandNotFound ];

# TODO: tab completion for uninstalled commands! :-)

}
48 changes: 48 additions & 0 deletions modules/programs/bash/command-not-found.pl
@@ -0,0 +1,48 @@
#! @perl@/bin/perl -w @perlFlags@

use strict;
use DBI;
use DBD::SQLite;
use Config;

my $program = $ARGV[0];

my $dbPath = "/var/lib/nixos/programs.sqlite";

my $dbh = DBI->connect("dbi:SQLite:dbname=$dbPath", "", "")
or die "cannot open database `$dbPath'";
$dbh->{RaiseError} = 0;
$dbh->{PrintError} = 0;

my $system = $ENV{"NIX_SYSTEM"} // $Config{myarchname};

my $res = $dbh->selectall_arrayref(
"select package from Programs where system = ? and name = ?",
{ Slice => {} }, $system, $program);

if (!defined $res || scalar @$res == 0) {
print STDERR "$program: command not found\n";
} elsif (scalar @$res == 1) {
my $package = @$res[0]->{package};
if ($ENV{"NIX_AUTO_INSTALL"} // "") {
print STDERR <<EOF;
The program ‘$program’ is currently not installed. It is provided by
the package ‘$package’, which I will now install for you.
EOF
;
exit 126 if system("nix-env", "-i", $package) == 0;
} else {
print STDERR <<EOF;
The program ‘$program’ is currently not installed. You can install it by typing:
nix-env -i $package
EOF
}
} else {
print STDERR <<EOF;
The program ‘$program’ is currently not installed. It is provided by
several packages. You can install it by typing one of the following:
EOF
print STDERR " nix-env -i $_->{package}\n" foreach @$res;
}

exit 127;

0 comments on commit b89f941

Please sign in to comment.