From cbef421081f1e65b1dcd81c9a6434e69cbc50f8e Mon Sep 17 00:00:00 2001 From: sternenseemann <0rpkxez4ksa01gb3typccl0i@systemli.org> Date: Fri, 12 Feb 2021 14:05:56 +0100 Subject: pkgs/profpatsch/nman: initial rewrite in rust This is a complete and user interface compatible rewrite of nman.go in Rust which aleviates a few flaws of the previous implementation: * Garbage collector roots for both the derivation and the build outputs are created in a temporary directory which is cleaned afterwards. This prevents a race condition between nman and nix-store --gc and doesn't pollute the user's working directory. * Instead of building just one build output, nman now checks every output for the requested man page which fixes nman for derivations which have their man pages split between multiple outputs, e. g. man and devman. Future work: * Improve error messages reported to the user * Man page * Implement man page search heuristics if no section is specified: Instead of falling back to section 1, all sections should be checked for the desired page (in an ascending order?) --- pkgs/profpatsch/nman/nman.go | 137 ------------------------------------------- 1 file changed, 137 deletions(-) delete mode 100644 pkgs/profpatsch/nman/nman.go (limited to 'pkgs/profpatsch/nman/nman.go') diff --git a/pkgs/profpatsch/nman/nman.go b/pkgs/profpatsch/nman/nman.go deleted file mode 100644 index b62479a0..00000000 --- a/pkgs/profpatsch/nman/nman.go +++ /dev/null @@ -1,137 +0,0 @@ -package main - -import ( - "fmt" - "os" - "strconv" - "log" - "bytes" - "os/exec" - "io/ioutil" - "syscall" -) - -var usage = `nman drvAttr [section|page] [page] - -Open man pages in a temporary nix-shell. -1 If one argument is given, the drvAttr & page have the same name. -2 If two arguments are given and the second arg is - a ) like 1, but in the man section - a ) like 1, but open the page -3 If three arguments are given, the order is -` - -func lookupManPage(manpath string, manSection int64, manPage string) (int, error) { - if manSection < -1 { - panic("manSection must not be < -1") - } - // holy debug printf - // fmt.Printf("attr: %s, sect: %d, page: %s\n", drvAttr, manSection, manPage) - - manBin, err := exec.LookPath("man"); - if err != nil { - return 0, fmt.Errorf("man executable not in PATH") - } - - var manArgs []string - if (manSection == -1) { - manArgs = []string{manPage} - } else { - manArgs = []string{strconv.FormatInt(manSection, 10), manPage} - } - - man := exec.Command(manBin, manArgs...) - - man.Env = append( - os.Environ(), - fmt.Sprintf("MANPATH=%s", manpath)) - man.Stderr = os.Stderr - man.Stdout = os.Stdout - err = man.Run() - if exiterr, ok := err.(*exec.ExitError); ok { - ws := exiterr.Sys().(syscall.WaitStatus) - return ws.ExitStatus(), nil - } else { - return 0, err - } - -} - -func buildManOutput(drvAttr string) (string, error) { - nixExpr := fmt.Sprintf( - `with import {}; %s.man or %s.doc or %s.out or %s`, - drvAttr, drvAttr, drvAttr, drvAttr) - - nixBuild := exec.Command("nix-build", "--no-out-link", "-E", nixExpr) - nixBuild.Stderr = os.Stderr - pipe, err := nixBuild.StdoutPipe() - if err != nil { return "", fmt.Errorf("could not access stdout of nix-build: %s", err) } - - err = nixBuild.Start() - if err != nil { return "", fmt.Errorf("could not start nix-build: %s", err) } - - out, err := ioutil.ReadAll(pipe) - if err != nil { return "", fmt.Errorf("could not read from nix-build: %s", err) } - - lines := bytes.Split(bytes.TrimSpace(out), []byte("\n")) - err = nixBuild.Wait() - if err != nil { return "", fmt.Errorf("nix-build process died: %s", err) } - - // last line ouf output looks like: /nix/store/abc…-foobar.drv!output - drvPath := bytes.Split(lines[len(lines)-1], []byte("!"))[0] - if _, err := os.Stat(string(drvPath)); err != nil { - return "", fmt.Errorf("%s doesn’t look like an output path: %s", drvPath, err) - } - - return string(drvPath), nil -} - -func main() { - var manPage string - var drvAttr string - - args := os.Args - - // man section or -1 if no man section - var manSection int64 = -1 - if (len(args) >= 3) { - i, err := strconv.ParseUint(args[2], 10, 64) - if err == nil && i >= 0 { - manSection = int64(i) - } - } - - // the first argument is always a derivation attribute - switch len(args) { - case 2: - // arg is package and drv attr - manPage = args[1] - case 3: - if (manSection == -1) { - // like 2, but arg 2 is package - manPage = args[2] - } else { - // man section given, page is arg 1 - manPage = args[1] - } - case 4: - // arg 2 is manSection, arg 3 is package - manPage = args[3] - default: - fmt.Print(usage) - os.Exit(-1) - } - - drvAttr = args[1] - drvPath, err := buildManOutput(drvAttr) - if err != nil { - log.Fatal(err) - } - exitStatus, err := lookupManPage(drvPath + "/share/man", manSection, manPage) - if err != nil { - log.Fatal(err) - } - - os.Exit(exitStatus) - -} -- cgit 1.4.1