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
|
package main
import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"os"
"os/exec"
"strings"
)
// managedBy names the tool that installs skills instead of this one, such as
// home-manager. skills then only maintains the lock and the Nix store.
func managedBy() string { return os.Getenv("SKILLS_MANAGED_BY") }
// nixFetch copies a locked source into the Nix store as the current user and
// returns its narHash. A later evaluation, even by root without this user's
// SSH keys, then finds it there instead of fetching it.
func nixFetch(ctx context.Context, url, rev string) (string, error) {
ref := "git+" + url + "?rev=" + rev + "&allRefs=1"
cmd := exec.CommandContext(ctx, "nix", "--extra-experimental-features", "nix-command flakes",
"flake", "prefetch", "--json", ref)
var stderr bytes.Buffer
cmd.Stderr = &stderr
out, err := cmd.Output()
if errors.Is(err, exec.ErrNotFound) {
return "", fmt.Errorf("SKILLS_MANAGED_BY=%s needs nix, which is not installed", managedBy())
}
if err != nil {
return "", fmt.Errorf("nix could not fetch %s: %s", url, strings.TrimSpace(stderr.String()))
}
var p struct {
Hash string `json:"hash"`
}
if err := json.Unmarshal(out, &p); err != nil || p.Hash == "" {
return "", fmt.Errorf("unexpected output from nix flake prefetch: %s", out)
}
return p.Hash, nil
}
|