Live video on the AT Protocol
at eli/get-segments-rebased 270 lines 6.9 kB view raw
1package main 2 3import ( 4 "encoding/json" 5 "flag" 6 "fmt" 7 "math/rand" 8 "net/http" 9 "os" 10 "sort" 11 "strings" 12 13 "github.com/go-git/go-git/v5" 14 "github.com/go-git/go-git/v5/plumbing" 15 "github.com/go-git/go-git/v5/plumbing/object" 16 "github.com/go-git/go-git/v5/plumbing/storer" 17 "github.com/google/uuid" 18) 19 20func main() { 21 err := makeGit() 22 if err != nil { 23 panic(err) 24 } 25} 26 27var tmpl = `package main 28 29var Version = "%s" 30var BuildTime = "%d" 31var UUID = "%s" 32` 33 34var tmplJS = ` 35export const version = "%s"; 36export const buildTime = "%d"; 37export const uuid = "%s"; 38` 39 40func gitlabURL() string { 41 CI_API_V4_URL := os.Getenv("CI_API_V4_URL") 42 CI_PROJECT_ID := os.Getenv("CI_PROJECT_ID") 43 CI_API_V4_URL = strings.Replace(CI_API_V4_URL, "https://git.stream.place", "https://git-cloudflare.stream.place", 1) 44 return fmt.Sprintf("%s/projects/%s", CI_API_V4_URL, CI_PROJECT_ID) 45} 46 47func gitlab(suffix string, dest any) { 48 u := fmt.Sprintf("%s%s", gitlabURL(), suffix) 49 50 req, err := http.Get(u) 51 if err != nil { 52 panic(err) 53 } 54 if err := json.NewDecoder(req.Body).Decode(dest); err != nil { 55 panic(err) 56 } 57} 58 59func gitlabList(suffix string) []map[string]any { 60 var result []map[string]any 61 gitlab(suffix, &result) 62 return result 63} 64 65func gitlabDict(suffix string) map[string]any { 66 var result map[string]any 67 gitlab(suffix, &result) 68 return result 69} 70 71func makeGit() error { 72 output := flag.String("o", "", "file to output to") 73 version := flag.Bool("v", false, "just print version") 74 env := flag.Bool("env", false, "print a bunch of useful environment variables") 75 doBranch := flag.Bool("branch", false, "print branch") 76 doRelease := flag.Bool("release", false, "print release json file") 77 javascript := flag.Bool("js", false, "print code in javascript format") 78 79 flag.Parse() 80 r, err := git.PlainOpenWithOptions(".", &git.PlainOpenOptions{DetectDotGit: true}) 81 if err != nil { 82 return err 83 } 84 85 // ... retrieving the HEAD reference 86 ref, err := r.Head() 87 if err != nil { 88 return err 89 } 90 c, err := r.CommitObject(ref.Hash()) 91 if err != nil { 92 return err 93 } 94 95 ts := c.Author.When.Unix() 96 rander := rand.New(rand.NewSource(ts)) 97 u, err := uuid.NewV7FromReader(rander) 98 if err != nil { 99 return err 100 } 101 g, err := PlainOpen(".") 102 if err != nil { 103 return err 104 } 105 desc, err := g.Describe(ref) 106 if err != nil { 107 return err 108 } 109 var out string 110 if *version { 111 out = desc 112 } else if *doBranch { 113 out = branch() 114 } else if *env { 115 STREAMPLACE_BRANCH := branch() 116 outMap := map[string]string{} 117 outMap["STREAMPLACE_BRANCH"] = STREAMPLACE_BRANCH 118 outMap["STREAMPLACE_VERSION"] = desc 119 outMap["STREAMPLACE_BRANCH"] = STREAMPLACE_BRANCH 120 for _, arch := range []string{"amd64", "arm64"} { 121 k := fmt.Sprintf("STREAMPLACE_URL_LINUX_%s", strings.ToUpper(arch)) 122 v := fmt.Sprintf("%s/packages/generic/%s/%s/streamplace-%s-linux-%s.tar.gz", gitlabURL(), STREAMPLACE_BRANCH, desc, desc, arch) 123 outMap[k] = v 124 macK := fmt.Sprintf("STREAMPLACE_URL_DARWIN_%s", strings.ToUpper(arch)) 125 macV := fmt.Sprintf("%s/packages/generic/%s/%s/streamplace-%s-darwin-%s.zip", gitlabURL(), STREAMPLACE_BRANCH, desc, desc, arch) 126 outMap[macK] = macV 127 } 128 outMap["STREAMPLACE_DESKTOP_URL_WINDOWS_AMD64"] = fmt.Sprintf("%s/packages/generic/%s/%s/streamplace-desktop-%s-windows-amd64.exe", gitlabURL(), STREAMPLACE_BRANCH, desc, desc) 129 for k, v := range outMap { 130 out = out + fmt.Sprintf("%s=%s\n", k, v) 131 } 132 } else if *doRelease { 133 outMap := map[string]any{} 134 outMap["name"] = desc 135 outMap["tag-name"] = desc 136 pkgs := gitlabList(fmt.Sprintf("/packages?order_by=created_at&sort=desc&package_name=%s", branch())) 137 id := pkgs[0]["id"].(float64) 138 pkgFiles := gitlabList(fmt.Sprintf("/packages/%d/package_files", int(id))) 139 outFiles := []string{} 140 sort.Slice(pkgFiles, func(i, j int) bool { 141 s1 := pkgFiles[i]["file_name"].(string) 142 s2 := pkgFiles[j]["file_name"].(string) 143 return s1 < s2 144 }) 145 for _, file := range pkgFiles { 146 fileJson := map[string]string{ 147 "name": file["file_name"].(string), 148 "url": fmt.Sprintf("%s/packages/generic/%s/%s/%s", gitlabURL(), branch(), desc, file["file_name"].(string)), 149 } 150 bs, err := json.Marshal(fileJson) 151 if err != nil { 152 return err 153 } 154 outFiles = append(outFiles, string(bs)) 155 } 156 outMap["assets-link"] = outFiles 157 changelog := gitlabDict(fmt.Sprintf("/repository/changelog?version=%s", desc)) 158 outMap["description"] = changelog["notes"] 159 bs, err := json.MarshalIndent(outMap, "", " ") 160 if err != nil { 161 return err 162 } 163 out = string(bs) 164 } else if *javascript { 165 out = fmt.Sprintf(tmplJS, desc, ts, u) 166 } else { 167 out = fmt.Sprintf(tmpl, desc, ts, u) 168 } 169 170 if *output != "" { 171 os.WriteFile(*output, []byte(out), 0644) 172 } else { 173 fmt.Print(out) 174 } 175 return nil 176} 177 178func branch() string { 179 CI_COMMIT_TAG := os.Getenv("CI_COMMIT_TAG") 180 CI_COMMIT_BRANCH := os.Getenv("CI_COMMIT_BRANCH") 181 if CI_COMMIT_TAG != "" { 182 return "latest" 183 } else if CI_COMMIT_BRANCH != "" { 184 return strings.Replace(CI_COMMIT_BRANCH, "/", "-", -1) 185 } else { 186 panic("CI_COMMIT_TAG and CI_COMMIT_BRANCH undefined, can't get branch") 187 } 188} 189 190// Git struct wrapps Repository class from go-git to add a tag map used to perform queries when describing. 191type Git struct { 192 TagsMap map[plumbing.Hash]*plumbing.Reference 193 *git.Repository 194} 195 196// PlainOpen opens a git repository from the given path. It detects if the 197// repository is bare or a normal one. If the path doesn't contain a valid 198// repository ErrRepositoryNotExists is returned 199func PlainOpen(path string) (*Git, error) { 200 r, err := git.PlainOpenWithOptions(path, &git.PlainOpenOptions{DetectDotGit: true}) 201 return &Git{ 202 make(map[plumbing.Hash]*plumbing.Reference), 203 r, 204 }, err 205} 206 207func (g *Git) getTagMap() error { 208 tags, err := g.Tags() 209 if err != nil { 210 return err 211 } 212 213 err = tags.ForEach(func(t *plumbing.Reference) error { 214 h, err := g.ResolveRevision(plumbing.Revision(t.Name())) 215 if err != nil { 216 return err 217 } 218 g.TagsMap[*h] = t 219 return nil 220 }) 221 222 return err 223} 224 225// Describe the reference as 'git describe --tags' will do 226func (g *Git) Describe(reference *plumbing.Reference) (string, error) { 227 228 // Fetch the reference log 229 cIter, err := g.Log(&git.LogOptions{ 230 // From: reference.Hash(), 231 Order: git.LogOrderCommitterTime, 232 }) 233 if err != nil { 234 return "", err 235 } 236 237 // Build the tag map 238 err = g.getTagMap() 239 if err != nil { 240 return "", err 241 } 242 243 // Search the tag 244 var tag *plumbing.Reference 245 var count int 246 err = cIter.ForEach(func(c *object.Commit) error { 247 t, ok := g.TagsMap[c.Hash] 248 if ok { 249 tag = t 250 return storer.ErrStop 251 } 252 count++ 253 return nil 254 }) 255 if err != nil { 256 return "", err 257 } 258 head, err := g.Head() 259 if err != nil { 260 return "", err 261 } 262 if count == 0 && os.Getenv("CI_COMMIT_TAG") != "" { 263 return fmt.Sprint(tag.Name().Short()), nil 264 } else { 265 return fmt.Sprintf("%s-%s", 266 tag.Name().Short(), 267 head.Hash().String()[0:8], 268 ), nil 269 } 270}