cirruslabs / cirrus-ci-agent

Agent to execute Cirrus CI tasks
Mozilla Public License 2.0
13 stars 6 forks source link

Investigate if it's possible to add GitLFS support to go-git #262

Open fkorotkov opened 1 year ago

fkorotkov commented 1 year ago

It will be nice to have Git LFS support as part of the built-in Git client that the agent has. Unfortunately, there is no such support out of the box and Git LFS itself encourages not to source depend on it.

But it seems worth investigating if the integration is that hard and if APIs that the integration need are changing that often as Git LFS claims in limitations.

edigaryev commented 1 year ago

It seems that github.com/git-lfs/git-lfs heavily depends on the git binary being present, for example this code, which mimicks the inner-workings of the git-lfs pull command, works:

package main

import (
    "fmt"
    "github.com/git-lfs/git-lfs/v3/config"
    "github.com/git-lfs/git-lfs/v3/lfs"
    "github.com/go-git/go-git/v5"
    "os"
)

func main() {
    if err := lfsScan(); err != nil {
        panic(err)
    }
}

func lfsScan() error {
    dir, err := os.MkdirTemp("", "")
    if err != nil {
        return err
    }

    if err := os.Chdir(dir); err != nil {
        return err
    }

    repo, err := git.PlainClone(dir, false, &git.CloneOptions{
        URL: "https://github.com/devopswise/git-lfs-sample.git",
    })
    if err != nil {
        return err
    }

    head, err := repo.Head()
    if err != nil {
        return err
    }

    cfg := config.NewIn(dir, dir)

    scanner := lfs.NewGitScanner(cfg, func(p *lfs.WrappedPointer, err error) {
        fmt.Println(p, err)
    })
    defer scanner.Close()

    if err := scanner.ScanTree(head.Hash().String(), nil); err != nil {
        return err
    }

    return nil
}

But if we comment the:

    if err := os.Chdir(dir); err != nil {
        return err
    }

We will get the following error:

<nil> error in `git ls-tree`: exit status 128 fatal: not a tree object

This comes from git.LsTree() function, and if you look into that file — there are lots of functions that call the git binary.

Perhaps we could implement a lightweight library based on the spec + API spec.

fkorotkov commented 1 year ago

Thank you for the investigation! In that case I started thinking of making the CLONE command smarter and use git executable if available (presumably with Git LFS already configured). If git is not installed, than fallback to the builtin one. 🤔

edigaryev commented 1 year ago

In that case I started thinking of making the CLONE command smarter and use git executable if available (presumably with Git LFS already configured). If git is not installed, than fallback to the builtin one.

You mean we should use built-in git (instead of github.com/go-git/go-git) if git-lfs binary is present on the system?