github.com/lmorg/murex@v0.0.0-20240217211045-e081c89cd4ef/builtins/core/modules/cmd-list.go (about) 1 package modules 2 3 import ( 4 "fmt" 5 "os" 6 "path/filepath" 7 "strings" 8 9 "github.com/lmorg/murex/config/profile" 10 "github.com/lmorg/murex/debug" 11 "github.com/lmorg/murex/lang" 12 "github.com/lmorg/murex/lang/types" 13 ) 14 15 const expecting = `Expecting enabled | disabled | loaded | not-loaded | packages` 16 17 func listModules(p *lang.Process) error { 18 p.Stdout.SetDataType(types.Json) 19 20 flag, _ := p.Parameters.String(1) 21 22 switch flag { 23 case "enabled": 24 return listAndPrint(listModulesEnDis, p, true) 25 26 case "disabled": 27 return listAndPrint(listModulesEnDis, p, false) 28 29 case "loaded": 30 return listAndPrint(listModulesLoadNotLoad, p, true) 31 32 case "not-loaded": 33 return listAndPrint(listModulesLoadNotLoad, p, false) 34 35 case "packages": 36 return listPackages(p) 37 38 case "": 39 return fmt.Errorf("missing parameter. %s", expecting) 40 41 default: 42 return fmt.Errorf("invalid parameter `%s`. %s", flag, expecting) 43 } 44 } 45 46 // listAndPrint is a wrapper function around the listModules...() functions. The 47 // rational behind this weird design is so that the code is concise and readable 48 // for normal execution but easily testable (ie the p.Stdout.Write code) is 49 // removed from the logic 50 func listAndPrint(fn func(*lang.Process, bool) (map[string]string, error), p *lang.Process, enabled bool) error { 51 list, err := fn(p, enabled) 52 if err != nil { 53 return err 54 } 55 56 b, err := lang.MarshalData(p, types.Json, &list) 57 if err != nil { 58 return err 59 } 60 61 _, err = p.Stdout.Write(b) 62 return err 63 } 64 65 // listModulesEnDis reads from disk rather than the package cache (like `runtime`) 66 // because the typical use for `murex-package list enabled|disabled` is to view 67 // which packages and modules will be loaded with murex. To get a view of what is 68 // currently loaded in a given session then use `loaded` / `not-loaded` instead of 69 // `enabled` / `disabled` 70 func listModulesEnDis(p *lang.Process, enabled bool) (map[string]string, error) { 71 var disabled []string 72 modulePath := profile.ModulePath() 73 74 err := profile.ReadJson(modulePath+profile.DisabledFile, &disabled) 75 if err != nil { 76 return nil, err 77 } 78 79 isDisabled := func(name string) bool { 80 for i := range disabled { 81 if disabled[i] == name { 82 return true 83 } 84 } 85 86 return false 87 } 88 89 paths, err := filepath.Glob(modulePath + "*") 90 if err != nil { 91 return nil, err 92 } 93 94 list := make(map[string]string) 95 96 for _, pack := range paths { 97 f, err := os.Stat(pack) 98 if err != nil { 99 return nil, err 100 } 101 102 // only read directories 103 if !f.IsDir() { 104 debug.Log("File not directory:", pack) 105 continue 106 } 107 108 // no hidden files nor empty strings 109 if len(f.Name()) == 0 || f.Name()[0] == '.' { 110 continue 111 } 112 113 mods, err := profile.LoadPackage(pack, false) 114 if err != nil { 115 write(p, "{RED}%s{RESET}", err.Error()) 116 } 117 118 // these should NOT equate ;) 119 if strings.HasSuffix(f.Name(), profile.IgnoredExt) != enabled { 120 name := cropIgnoreExt(f.Name()) 121 list[name] = name 122 } 123 124 for i := range mods { 125 if isDisabled(mods[i].Package+"/"+mods[i].Name) == enabled { 126 continue 127 } 128 list[mods[i].Package+"/"+mods[i].Name] = mods[i].Summary 129 } 130 } 131 132 return list, nil 133 } 134 135 func listModulesLoadNotLoad(p *lang.Process, loaded bool) (map[string]string, error) { 136 list := make(map[string]string) 137 138 for _, mods := range profile.Packages { 139 for i := range mods { 140 if mods[i].Loaded == loaded { 141 list[mods[i].Package+"/"+mods[i].Name] = mods[i].Summary 142 } 143 } 144 } 145 146 return list, nil 147 } 148 149 func listPackages(p *lang.Process) error { 150 paths, err := filepath.Glob(profile.ModulePath() + "*") 151 if err != nil { 152 return err 153 } 154 155 var list []string 156 157 for _, pack := range paths { 158 f, err := os.Stat(pack) 159 if err != nil { 160 return err 161 } 162 if !f.IsDir() { 163 debug.Log("File not directory:", pack) 164 continue 165 } 166 167 list = append(list, cropIgnoreExt(f.Name())) 168 } 169 170 b, err := lang.MarshalData(p, types.Json, &list) 171 if err != nil { 172 return err 173 } 174 _, err = p.Stdout.Write(b) 175 return err 176 } 177 178 func cropIgnoreExt(name string) string { 179 return strings.Replace(name, profile.IgnoredExt, "", 1) 180 }