Code Monkey home page Code Monkey logo

go-billy's Introduction

go-git logo GoDoc Build Status Go Report Card

go-git is a highly extensible git implementation library written in pure Go.

It can be used to manipulate git repositories at low level (plumbing) or high level (porcelain), through an idiomatic Go API. It also supports several types of storage, such as in-memory filesystems, or custom implementations, thanks to the Storer interface.

It's being actively developed since 2015 and is being used extensively by Keybase, Gitea or Pulumi, and by many other libraries and tools.

Project Status

After the legal issues with the src-d organization, the lack of update for four months and the requirement to make a hard fork, the project is now back to normality.

The project is currently actively maintained by individual contributors, including several of the original authors, but also backed by a new company, gitsight, where go-git is a critical component used at scale.

Comparison with git

go-git aims to be fully compatible with git, all the porcelain operations are implemented to work exactly as git does.

git is a humongous project with years of development by thousands of contributors, making it challenging for go-git to implement all the features. You can find a comparison of go-git vs git in the compatibility documentation.

Installation

The recommended way to install go-git is:

import "github.com/go-git/go-git/v5" // with go modules enabled (GO111MODULE=on or outside GOPATH)
import "github.com/go-git/go-git" // with go modules disabled

Examples

Please note that the CheckIfError and Info functions used in the examples are from the examples package just to be used in the examples.

Basic example

A basic example that mimics the standard git clone command

// Clone the given repository to the given directory
Info("git clone https://github.com/go-git/go-git")

_, err := git.PlainClone("/tmp/foo", false, &git.CloneOptions{
    URL:      "https://github.com/go-git/go-git",
    Progress: os.Stdout,
})

CheckIfError(err)

Outputs:

Counting objects: 4924, done.
Compressing objects: 100% (1333/1333), done.
Total 4924 (delta 530), reused 6 (delta 6), pack-reused 3533

In-memory example

Cloning a repository into memory and printing the history of HEAD, just like git log does

// Clones the given repository in memory, creating the remote, the local
// branches and fetching the objects, exactly as:
Info("git clone https://github.com/go-git/go-billy")

r, err := git.Clone(memory.NewStorage(), nil, &git.CloneOptions{
    URL: "https://github.com/go-git/go-billy",
})

CheckIfError(err)

// Gets the HEAD history from HEAD, just like this command:
Info("git log")

// ... retrieves the branch pointed by HEAD
ref, err := r.Head()
CheckIfError(err)


// ... retrieves the commit history
cIter, err := r.Log(&git.LogOptions{From: ref.Hash()})
CheckIfError(err)

// ... just iterates over the commits, printing it
err = cIter.ForEach(func(c *object.Commit) error {
	fmt.Println(c)
	return nil
})
CheckIfError(err)

Outputs:

commit ded8054fd0c3994453e9c8aacaf48d118d42991e
Author: Santiago M. Mola <[email protected]>
Date:   Sat Nov 12 21:18:41 2016 +0100

    index: ReadFrom/WriteTo returns IndexReadError/IndexWriteError. (#9)

commit df707095626f384ce2dc1a83b30f9a21d69b9dfc
Author: Santiago M. Mola <[email protected]>
Date:   Fri Nov 11 13:23:22 2016 +0100

    readwriter: fix bug when writing index. (#10)

    When using ReadWriter on an existing siva file, absolute offset for
    index entries was not being calculated correctly.
...

You can find this example and many others in the examples folder.

Contribute

Contributions are more than welcome, if you are interested please take a look to our Contributing Guidelines.

License

Apache License Version 2.0, see LICENSE

go-billy's People

Contributors

ajnavarro avatar akavel avatar alcortesm avatar cuishuang avatar dependabot[bot] avatar fhs avatar fkorotkov avatar jawr avatar jfontan avatar jinroh avatar jmalloc avatar mcuadros avatar nikandfor avatar onee-only avatar paralin avatar pjbgf avatar rminnich avatar serabe avatar sfc-gh-thardie avatar smola avatar spennymac avatar taruti avatar tjamet avatar toasterson avatar tryggvil avatar weberc2-tempus avatar whickman avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

go-billy's Issues

question: chroot does not process path target ​​from symlink?

Chroot does not process path target ​​from symlink? It is normal behavior?

Follow concept code

baseDir := "/foo/bar"
fs := chroot.New(&billyFilesystemSomeImpl{}, baseDir)
// lrwxr-xr-x /foo/bar/lint-to-tmp -> /tmp
fs.Open("/foo/bar/link-to-tmp")
// opened without errors

Need a new release

github.com/u-root/cpu depends on go-billy, and it would be nice to have a new release with the BoundsOS fix in.

memfs: fresh memfs does not have a root directory

This works:

package main

import (
	"fmt"

	"github.com/go-git/go-billy/v5/memfs"
)

func main() {
	mfs := memfs.New()
	if err := mfs.MkdirAll("test", 0755); err != nil {
		panic(err)
	}

	st, err := mfs.Stat(".")
	if err != nil {
		panic(err)
	}
	fmt.Printf("%#v\n", st)
}

If you comment out the MkdirAll line, it returns error not found.

This means that the root directory is created in the MkdirAll command.

The fresh memfs.New() should have a root / directory just after new() is called, right?

thoughts on chown/acl support

Just wondering if there are any thoughts about adding an abstraction for os.Chown (which for windows does work pretty badly as you need string SSIDs and the semantics differ from Linux in the regard that you don't change user (uid) and group (gid) at the same time like os.Chown does.

Seemingly ACLs are common on those platforms or changing file owner and file owner group independently of each other might be an approach.

Also getting the current owner and owner group or a list of all ACLs of a file might be another interesting feature which would be necessary for like copying files and applying the same ownership permissions as the source file had.

Support for limits on `memfs`?

We're using memfs alongside go-git to perform a shallow clone of Git repositories. We'd like to be able to limit the data written to the memfs (other than heap memory / crashing).

Would additions to the memfs interface to support limiting the filesystem contents be of interest / accepted?

Add support for Readdir in File interface

I'm trying to use go-git for a tool but I'm getting stuck with the lack of interoperability of go-billy. Particularly, I need to cast billy.File to another custom File interface we have that implements Readdir but billy.File does not. How reasonable is to get this added to go-billy?

Thanks!

go-billy afero wrapper

As a bit of a test as one of my projects uses spf13/afero for all other disk operations I implemented the go-billy interface as a wrapper for afero for use in go-git.

https://github.com/Maldris/go-billy-afero

This was done as a quick and dirty implementation to test the concept, but as part of it, I have gotten optional support for Symlink and ReadLink merged into afero.

To revisit the idea and look at potentially cleaning it up for actual use, I would appreciate some feedback to see what needs to be done, and if this could be imported as a new filesystem option.

My main concern for support is the file Lock and Unlock methods, which do not have equivalents in afero. To control the behaviour within memory I've provided a mutex, however if multiple instances are created in different processes, or multiple applications try to access the same file, this is an inadequate solution, requiring additional application level logic.

Example code on How to get an instance of an object/struct that implements billy.Filesystem?

Hello folks,

I know it sounds like a rookie question and that surely is the case ...

not being such a golang guru, and trying to use https://github.com/go-git, I happened to come along the billy filesystem abstraction.

Well, I like abstraction and billy looks very fine so far, so I tried to get some instances but not achieving somehow. Then tried to get some example code and the only thing I find is the projects' homepage; but to no avail, because there is no source code where I could find out how to get an instance of type billy.Filesystem, only what to do with it if one has gotten one from somewhere. What I tried to code was something like:

myFileSystem := Filesystem (pathToFileSystem) and
myFileSystem := billy.Filesystem (pathToFileSystem)

and following the projects' statement on the homepage, stating that

each Filesystem implementation gives you a New method

i tried

myFileSystem := Filesystem.New (pathToFileSystem)
and myFileSystem := Basic.New (pathToFileSystem)
and myFileSystem := Dir.New (pathToFileSystem)

and even, prefixing the above with billy, like so:

myFileSystem := billy.Filesystem.New (pathToFileSystem)

I also tried a little bit around with ioutil ... but whatever I do, I dont find a constructor that takes a string path and gives back an instance of billy.Filesystem.

As mentioned, yes it might be a golang rookies' question and I might be as dumb as hell, but... please relieve me,...

Best Regards,

Michael

Edit: wayyy too much typos

memfs ReadDir() doesn't return an error when the directory doesn't exist

Version

v5.4.1

Description

memfs.New().ReadDir("asdf") returns nil, nil instead of nil, <directory-not-found-err>.

Minimal example

func TestMemoryReadDir(t *testing.T) {
	if _, err := osfs.New("/tmp").ReadDir("asdf"); err == nil {
		t.Fatal("osfs: expected error; found <nil>")
	} else {
		t.Logf("osfs: error was correctly returned!")
	}

	if _, err := memfs.New().ReadDir("asdf"); err == nil {
		t.Fatal("memfs: expected error; found <nil>")
	} else {
		t.Logf("memfs: error was correctly returned!")
	}
}

// Output
//   osfs: error was correctly returned!
//   memfs: expected error; found <nil>

Proposed changes

func (fs *Memory) ReadDir(path string) ([]os.FileInfo, error) {
	if f, has := fs.s.Get(path); has {
		if target, isLink := fs.resolveLink(path, f); isLink {
			return fs.ReadDir(target)
		}
+	} else {
+		return nil, &fs.PathError{Op: "open", Path: path, Err: unix.ENOENT}
}

	var entries []os.FileInfo
	for _, f := range fs.s.Children(path) {
		fi, _ := f.Stat()
		entries = append(entries, fi)
	}

	sort.Sort(ByName(entries))

	return entries, nil
}

Creating new files is not multi-goroutine safe

If you call New() on the storage objects from multiple goroutines at the same time, go runtime may error with fatal error: concurrent map writes. This happens because the files map inside the storage struct has no concurrency protection around multiple access.

Other concurrency issues probably exist for accessing the children map inside the storage object.

Support for os.Link functionality

Would it be appropriate to add support a billy.Filesystem method equivalent to os.Link? I gave it a try and it doesn't seem too hard to implement. The os.Link method is useful for implementing certain types of safe file moves, for example.

Minor release containing `util.Walk`

Would it be possible to have a minor version released which contains util.Walk? We are currently pinning to v5.0.0-20210804024030-7ab80d7c013d but it would be great if we could just have v5.3.2 instead.

If there is any outstanding work left for an official version to be cut, please let us know and we can try to contribute towards it.

Non-module import violates import path restriction

import "github.com/go-git/go-billy/v5" // with go modules enabled (GO111MODULE=on or outside GOPATH)
import "github.com/go-git/go-billy" // with go modules disabled

The second line does not work: the code expects import "github.com/go-git/go-billy/v5".

source contains fork of Apache-2.0 license file

This project includes in source an Apache-2.0 license text, with appendix changed to list the actual copyright holders of this project.

Please don't do that.

Instead, please do as instructed right above that copyright line:

To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives.

I.e. copy the boilerplate text and paste it at the top of each code source file, commented as appropriate for the coding language.

There is no legal need to state copyright since 1989.
The reason we do it anyway is as a curtesy for our users: We want to promote the code as Free Software, which requires it to be licensed as such, which can be done only by copyright holders - we therefore want our users to most easily locate not only licensing statement but also who made those statements for which code pieces.

When you list copyright notices in a project-wide file instead of inside each code file, you make it more difficult for your users to reuse code and still keep track of owers and licensing of the mixed parts.

When you edit general public licenses (concretely, the Apache-2.0 license text) you make it more difficult for users to rely on such files being general.

MemFS ReadDir doesn't list entries sorted by filename

By the interface definition of ReadDir

// ReadDir reads the directory named by dirname and returns a list of
// directory entries sorted by filename.
ReadDir(path string) ([]os.FileInfo, error)

The current implementation returns the files in random order because it is retrieved from a map in a for loop. This can be fixed by sorting the result. I will submit a PR.

Thank you for this awesome project!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.