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  }