github.com/nevalang/neva@v0.23.1-0.20240507185603-7696a9bb8dda/internal/builder/git.go (about) 1 package builder 2 3 import ( 4 "fmt" 5 "os" 6 "strings" 7 8 git "github.com/go-git/go-git/v5" 9 "github.com/go-git/go-git/v5/plumbing" 10 11 "github.com/nevalang/neva/internal/compiler/sourcecode" 12 ) 13 14 // downloadDep returns path where it downloaded dependency 15 // and its downloaded version in case version wasn't specified. 16 func (p Builder) downloadDep(depModRef sourcecode.ModuleRef) (string, string, error) { 17 fsPath := fmt.Sprintf( 18 "%s/%s_%s", 19 p.thirdPartyPath, 20 depModRef.Path, 21 depModRef.Version, 22 ) 23 24 _, err := os.Stat(fsPath) 25 if err == nil { 26 return fsPath, depModRef.Version, nil 27 } 28 29 if !os.IsNotExist(err) { 30 return "", "", fmt.Errorf("os stat: %w", err) 31 } 32 33 var ref plumbing.ReferenceName 34 if depModRef.Version != "" { 35 ref = plumbing.NewTagReferenceName(depModRef.Version) 36 } 37 38 repo, err := git.PlainClone(fsPath, false, &git.CloneOptions{ 39 URL: "https://" + depModRef.Path, 40 ReferenceName: ref, 41 }) 42 if err != nil { 43 return "", "", err 44 } 45 46 if ref != "" { 47 return fsPath, "", nil 48 } 49 50 latestTagHash, tagName, err := getLatestTagHash(repo) 51 if err != nil { 52 return "", "", err 53 } 54 55 tree, err := repo.Worktree() 56 if err != nil { 57 return "", "", err 58 } 59 60 if err := tree.Checkout(&git.CheckoutOptions{ 61 Hash: latestTagHash, 62 }); err != nil { 63 return "", "", err 64 } 65 66 // Append the latest tag to the directory name 67 newFsPath := fmt.Sprintf("%s%s", fsPath, tagName) 68 69 // Remove the directory if it already exists 70 if _, err := os.Stat(newFsPath); err == nil { 71 if err := os.RemoveAll(newFsPath); err != nil { 72 return "", "", fmt.Errorf("os.RemoveAll: %w", err) 73 } 74 } 75 76 // Finally rename new directory 77 if err := os.Rename(fsPath, newFsPath); err != nil { 78 return "", "", fmt.Errorf("os rename: %w", err) 79 } 80 81 return newFsPath, tagName, nil 82 } 83 84 func getLatestTagHash(repository *git.Repository) (plumbing.Hash, string, error) { 85 tagRefs, err := repository.Tags() 86 if err != nil { 87 return plumbing.Hash{}, "", err 88 } 89 90 var ( 91 hash plumbing.Hash 92 name string 93 ) 94 err = tagRefs.ForEach(func(tagRef *plumbing.Reference) error { 95 hash = tagRef.Hash() 96 name = tagRef.Name().String() 97 return nil 98 }) 99 if err != nil { 100 return plumbing.Hash{}, "", err 101 } 102 103 return hash, strings.Split(name, "/")[2], nil 104 }