⛩️ Powerful yet Minimal Nix Dependency Manager
flake flakes home-manager nixos go nix dependency dependencies
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat(yae): git sources and remote git source updater

Fuwn 0433ac6a ca12e53a

+133 -44
+7 -3
sources.go
··· 9 9 type Sources map[string]Source 10 10 11 11 type Source struct { 12 - URI string `json:"url"` 13 - SHA256 string `json:"sha256"` 14 - Unpack bool `json:"unpack"` 12 + URI string `json:"url"` 13 + SHA256 string `json:"sha256"` 14 + Unpack bool `json:"unpack"` 15 + Type string `json:"type"` 16 + Version string `json:"version,omitempty"` 17 + URITemplate string `json:"uri_template,omitempty"` 18 + TagPredicate string `json:"tag_predicate,omitempty"` 15 19 } 16 20 17 21 func (s *Sources) EnsureLoaded() error {
+126 -41
yae.go
··· 13 13 func main() { 14 14 sources := Sources{} 15 15 16 - (&cli.App{ 16 + if err := (&cli.App{ 17 17 Name: "yae", 18 18 Usage: "Nix Dependency Manager", 19 19 Description: "Nix Dependency Manager", ··· 42 42 ExitErrHandler: func(c *cli.Context, err error) { 43 43 if err != nil { 44 44 fmt.Println(err) 45 + os.Exit(1) 45 46 } 46 47 }, 47 48 Suggest: true, ··· 68 69 Usage: "Unpack the source into the Nix Store", 69 70 Value: true, 70 71 }, 72 + &cli.StringFlag{ 73 + Name: "type", 74 + Usage: "Source type", 75 + Required: true, 76 + Action: func(c *cli.Context, value string) error { 77 + if value != "binary" && value != "git" { 78 + return fmt.Errorf("invalid source type: must be 'binary' or 'git'") 79 + } 80 + 81 + return nil 82 + }, 83 + }, 84 + &cli.StringFlag{ 85 + Name: "version", 86 + Usage: "Source version used in identifying latest git source", 87 + }, 88 + &cli.StringFlag{ 89 + Name: "tag-predicate", 90 + Usage: "Git tag predicate used in identifying latest git source", 91 + }, 71 92 }, 72 93 Action: func(c *cli.Context) error { 73 94 if c.Args().Len() != 2 { ··· 78 99 return fmt.Errorf("source already exists") 79 100 } 80 101 81 - sha256, err := fetchSHA256(c.Args().Get(1), c.Bool("unpack")) 102 + source := Source{ 103 + Unpack: c.Bool("unpack"), 104 + Type: c.String("type"), 105 + } 106 + version := c.String("version") 107 + 108 + if version != "" { 109 + source.URITemplate = c.Args().Get(1) 110 + source.Version = c.String("version") 82 111 83 - if err != nil { 112 + if strings.Contains(source.URITemplate, "{version}") { 113 + source.URI = strings.Replace(source.URITemplate, "{version}", source.Version, 1) 114 + } 115 + } else { 116 + source.URI = c.Args().Get(1) 117 + } 118 + 119 + if source.Type == "git" && c.String("tag-predicate") != "" { 120 + source.TagPredicate = c.String("tag-predicate") 121 + } 122 + 123 + if sha256, err := fetchSHA256(source.URI, c.Bool("unpack")); err != nil { 84 124 return err 125 + } else { 126 + source.SHA256 = sha256 85 127 } 86 128 87 - if err = sources.Add(c.Args().Get(0), Source{ 88 - URI: c.Args().Get(1), 89 - SHA256: sha256, 90 - Unpack: c.Bool("unpack"), 91 - }); err != nil { 129 + if err := sources.Add(c.Args().Get(0), source); err != nil { 92 130 return err 93 131 } 94 132 ··· 127 165 Action: func(c *cli.Context) error { 128 166 if c.Args().Len() == 0 { 129 167 for key, value := range sources { 130 - sha256, err := fetchSHA256(value.URI, value.Unpack) 131 - 132 - if err != nil { 133 - return err 134 - } 135 - 136 - if sha256 != value.SHA256 { 137 - sources[key] = Source{ 138 - URI: value.URI, 139 - SHA256: sha256, 140 - Unpack: value.Unpack, 141 - } 142 - 143 - fmt.Println("updated hash for", key) 144 - } 145 - 146 - if err = sources.Save(c.String("sources")); err != nil { 168 + if err := updateSource(&sources, key, value); err != nil { 147 169 return err 148 170 } 149 171 } 150 172 } else { 151 - if !sources.Exists(c.Args().Get(0)) { 152 - return fmt.Errorf("source does not exist") 153 - } 173 + name := c.Args().Get(0) 154 174 155 - sha256, err := fetchSHA256(sources[c.Args().Get(0)].URI, c.Bool("unpack")) 156 - 157 - if err != nil { 175 + if err := updateSource(&sources, name, sources[name]); err != nil { 158 176 return err 159 177 } 178 + } 160 179 161 - sources[c.Args().Get(0)] = Source{ 162 - URI: sources[c.Args().Get(0)].URI, 163 - SHA256: sha256, 164 - Unpack: c.Bool("unpack"), 165 - } 166 - 167 - if err = sources.Save(c.String("sources")); err != nil { 168 - return err 169 - } 180 + if err := sources.Save(c.String("sources")); err != nil { 181 + return err 170 182 } 171 183 172 184 return nil 173 185 }, 174 186 }, 175 187 }, 176 - }).Run(os.Args) 188 + }).Run(os.Args); err != nil { 189 + fmt.Println(err) 190 + os.Exit(1) 191 + } 177 192 } 178 193 179 194 func fetchSHA256(uri string, unpack bool) (string, error) { ··· 204 219 205 220 return string(out), err 206 221 } 222 + 223 + func fetchLatestGitTag(source Source) (string, error) { 224 + if source.Type == "git" { 225 + repository := "https://github.com/" + strings.Split(source.URI, "/")[3] + "/" + strings.Split(source.URI, "/")[4] 226 + remotes, err := commandOutput("git", "ls-remote", "--tags", repository) 227 + 228 + if err != nil { 229 + return "", err 230 + } 231 + 232 + refs := strings.Split(remotes, "\n") 233 + var latest string 234 + 235 + if source.TagPredicate == "" { 236 + latest = refs[len(refs)-2] 237 + } else { 238 + for i := len(refs) - 2; i >= 0; i-- { 239 + if strings.Contains(refs[i], source.TagPredicate) { 240 + latest = strings.Split(refs[i], "/")[2] 241 + 242 + break 243 + } 244 + } 245 + } 246 + 247 + return latest, nil 248 + } 249 + 250 + return "", fmt.Errorf("source is not a git repository") 251 + } 252 + 253 + func updateSource(sources *Sources, name string, source Source) error { 254 + if !sources.Exists(name) { 255 + return fmt.Errorf("source does not exist") 256 + } 257 + 258 + if source.Type == "git" { 259 + tag, err := fetchLatestGitTag(source) 260 + 261 + if err != nil { 262 + return err 263 + } 264 + 265 + if tag != source.Version { 266 + fmt.Println("updated version for", name, "from", source.Version, "to", tag) 267 + 268 + source.Version = tag 269 + 270 + if strings.Contains(source.URITemplate, "{version}") { 271 + source.URI = strings.Replace(source.URITemplate, "{version}", source.Version, 1) 272 + } 273 + } 274 + } 275 + 276 + sha256, err := fetchSHA256(source.URI, source.Unpack) 277 + 278 + if err != nil { 279 + return err 280 + } 281 + 282 + if sha256 != source.SHA256 { 283 + fmt.Println("updated hash for", name, "from", source.SHA256, "to", sha256) 284 + 285 + source.SHA256 = sha256 286 + } 287 + 288 + (*sources)[name] = source 289 + 290 + return nil 291 + }