github.com/replit/upm@v0.0.0-20240423230255-9ce4fc3ea24c/internal/nix/nix.go (about) 1 package nix 2 3 import ( 4 "context" 5 _ "embed" 6 "encoding/json" 7 "errors" 8 "io" 9 "log" 10 "os" 11 "os/exec" 12 "path" 13 14 "github.com/replit/upm/internal/api" 15 "github.com/replit/upm/internal/util" 16 ) 17 18 type NixEditorDepType string 19 20 const ( 21 Regular NixEditorDepType = "regular" 22 ) 23 24 type NixEditorOp struct { 25 Op string `json:"op"` 26 DepType NixEditorDepType `json:"dep_type"` 27 Dep string `json:"dep"` 28 } 29 30 type ReplitNixAdd struct { 31 Deps []string `json:"deps,omitempty"` 32 } 33 34 var ( 35 python_map_var map[string]ReplitNixAdd 36 37 python_map_var_loaded bool 38 39 //go:embed python_map.json 40 python_map_json []byte 41 ) 42 43 func DefaultInstallReplitNixSystemDependencies(context.Context, []api.PkgName) { 44 // do nothing by default, if the language doesn't implement a system 45 // dependency mapping, there is no work to be done. 46 } 47 48 func python_map() map[string]ReplitNixAdd { 49 if python_map_var_loaded { 50 return python_map_var 51 } 52 err := json.Unmarshal(python_map_json, &python_map_var) 53 if err != nil { 54 log.Fatal("Error during Unmarshal(): ", err) 55 } 56 python_map_var_loaded = true 57 return python_map_var 58 } 59 60 func PythonNixDeps(pack string) ReplitNixAdd { 61 val, ok := python_map()[pack] 62 if !ok { 63 return ReplitNixAdd{} 64 } 65 return val 66 } 67 68 func ReplitNixAddToNixEditorOps(replitNixAdd ReplitNixAdd) []NixEditorOp { 69 result := []NixEditorOp{} 70 for _, dep := range replitNixAdd.Deps { 71 result = append(result, NixEditorOp{Op: "add", Dep: dep, DepType: Regular}) 72 } 73 return result 74 } 75 76 func RunNixEditorOps(ops []NixEditorOp) { 77 repl_home := os.Getenv("REPL_HOME") 78 if repl_home == "" { 79 util.DieInitializationError("REPL_HOME was not set") 80 } 81 path := path.Join(repl_home, "replit.nix") 82 83 cmd := exec.Command("nix-editor", "--path", path) 84 stdin, err := cmd.StdinPipe() 85 if err != nil { 86 util.DieSubprocess("couldn't make stdin pipe to nix-editor") 87 } 88 stdout, err := cmd.StdoutPipe() 89 if err != nil { 90 util.DieSubprocess("couldn't make stdout pipe to nix-editor") 91 } 92 93 err = cmd.Start() 94 if err != nil { 95 util.DieSubprocess("nix-editor error: %s", err) 96 } 97 98 encoder := json.NewEncoder(stdin) 99 for _, op := range ops { 100 err := encoder.Encode(op) 101 if err != nil { 102 util.DieProtocol("unable to turn op into json: %v error: %s", op, err) 103 } 104 } 105 err = stdin.Close() 106 if err != nil { 107 util.DieSubprocess("unable to write to nix-editor") 108 } 109 110 decoder := json.NewDecoder(stdout) 111 for { 112 var nixEditorStatus struct { 113 Status string 114 Data string 115 } 116 err := decoder.Decode(&nixEditorStatus) 117 if err != nil { 118 if errors.Is(err, io.EOF) { 119 break 120 } 121 util.DieSubprocess("unexpected nix-editor output: %s", err) 122 } 123 if nixEditorStatus.Status != "success" { 124 util.DieSubprocess("nix-editor error: %s", nixEditorStatus.Data) 125 } 126 } 127 stdout.Close() 128 129 err = cmd.Wait() 130 if err != nil { 131 util.DieSubprocess("nix-editor error: %s", err) 132 } 133 }