-
Notifications
You must be signed in to change notification settings - Fork 352
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement lakectl local list #6302
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
package cmd | ||
|
||
import ( | ||
"path/filepath" | ||
|
||
"github.com/cockroachdb/errors" | ||
"github.com/jedib0t/go-pretty/v6/table" | ||
"github.com/spf13/cobra" | ||
"github.com/treeverse/lakefs/pkg/git" | ||
"github.com/treeverse/lakefs/pkg/local" | ||
) | ||
|
||
const ( | ||
localListMinArgs = 0 | ||
localListMaxArgs = 1 | ||
|
||
indicesListTemplate = `{{.IndicesListTable | table -}}` | ||
) | ||
|
||
var localListCmd = &cobra.Command{ | ||
Use: "list [directory]", | ||
Short: "find and list directories that are synced with lakeFS", | ||
Args: cobra.RangeArgs(localListMinArgs, localListMaxArgs), | ||
Run: func(cmd *cobra.Command, args []string) { | ||
dir := "." | ||
if len(args) > 0 { | ||
dir = args[0] | ||
} | ||
abs, err := filepath.Abs(dir) | ||
if err != nil { | ||
DieErr(err) | ||
} | ||
gitRoot, err := git.GetRepositoryPath(abs) | ||
if err == nil { | ||
abs = gitRoot | ||
} else if !(errors.Is(err, git.ErrNotARepository) || errors.Is(err, git.ErrNoGit)) { // allow support in environments with no git | ||
DieErr(err) | ||
} | ||
|
||
dirs, err := local.FindIndices(abs) | ||
if err != nil { | ||
DieErr(err) | ||
} | ||
|
||
var rows [][]interface{} | ||
for _, d := range dirs { | ||
idx, err := local.ReadIndex(d) | ||
if err != nil { | ||
DieErr(err) | ||
} | ||
remote, err := idx.GetCurrentURI() | ||
if err != nil { | ||
DieErr(err) | ||
} | ||
rows = append(rows, table.Row{d, remote, idx.AtHead}) | ||
} | ||
data := struct { | ||
IndicesListTable *Table | ||
}{ | ||
IndicesListTable: &Table{ | ||
Headers: []interface{}{ | ||
"Directory", | ||
"Remote URI", | ||
"Last synced HEAD", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. suggestion: "Synced Ref" There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the ref is too general. Should be either head or commit. WDYT? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Commit sounds better |
||
}, | ||
Rows: rows, | ||
}, | ||
} | ||
Write(indicesListTemplate, data) | ||
}, | ||
} | ||
|
||
//nolint:gochecknoinits | ||
func init() { | ||
localCmd.AddCommand(localListCmd) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
package fileutil_test | ||
|
||
import ( | ||
"os" | ||
"path/filepath" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/require" | ||
"github.com/treeverse/lakefs/pkg/fileutil" | ||
) | ||
|
||
func TestFindInParents(t *testing.T) { | ||
root := t.TempDir() | ||
dirTree := filepath.Join(root, "foo", "bar", "baz", "taz") | ||
require.NoError(t, os.MkdirAll(dirTree, fileutil.DefaultDirectoryMask)) | ||
t.Run("does not exist", func(t *testing.T) { | ||
found, err := fileutil.FindInParents(root, ".doesnotexist21348329043289") | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
if found != "" { | ||
t.Errorf("expected found to be empty, got %v", found) | ||
} | ||
}) | ||
|
||
tests := []struct { | ||
name string | ||
deep string | ||
filename string | ||
filepath string | ||
find bool | ||
}{ | ||
{ | ||
name: "find_at_leaf", | ||
deep: filepath.Join(root, "foo", "bar", "baz"), | ||
filename: "some_file0", | ||
filepath: filepath.Join(root, "foo", "bar", "baz", "some_file0"), | ||
find: true, | ||
}, | ||
{ | ||
name: "find_at_root", | ||
deep: filepath.Join(root, "foo", "bar", "baz"), | ||
filename: "some_file1", | ||
filepath: filepath.Join(root, "some_file1"), | ||
find: true, | ||
}, | ||
{ | ||
name: "find_at_subpath", | ||
deep: filepath.Join(root, "foo", "bar", "baz", "taz"), | ||
filename: "some_file2", | ||
filepath: filepath.Join(root, "foo", "some_file2"), | ||
find: true, | ||
}, | ||
{ | ||
name: "not_found_above", | ||
deep: filepath.Join(root, "foo", "bar", "baz"), | ||
filename: "some_file3", | ||
filepath: filepath.Join(root, "foo", "bar", "baz", "taz", "some_file3"), | ||
find: false, | ||
}, | ||
{ | ||
name: "doesnt_exist", | ||
deep: filepath.Join(root, "foo", "bar", "baz"), | ||
filename: ".doesnotexist21348329043289", | ||
filepath: filepath.Join(root, "foo", "bar", "some_file4"), | ||
find: false, | ||
}, | ||
} | ||
|
||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
f, err := os.Create(tt.filepath) | ||
require.NoError(t, err) | ||
require.NoError(t, f.Close()) | ||
|
||
found, err := fileutil.FindInParents(tt.deep, tt.filename) | ||
require.NoError(t, err) | ||
if tt.find { | ||
require.Equal(t, tt.filepath, found) | ||
} else { | ||
require.Equal(t, "", found) | ||
} | ||
}) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,6 +21,10 @@ const ( | |
) | ||
|
||
func git(dir string, args ...string) (string, error) { | ||
_, err := exec.LookPath("git") // assume git is in path, otherwise consider as not having git support | ||
if err != nil { | ||
return "", ErrNoGit | ||
} | ||
Comment on lines
+24
to
+27
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm worried that there will be a long list of errors we would like to capture - why can we have one success and fail with all the rest? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There are 2 types of errors we would like to specifically distinguish from which are the environment doesn't support git, and the current working directory is not a git repository. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You added lookup for git - so in the case we found git - we left only with the fact that that we have git tool and it didn't recognize a git repository. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove the generic GitError |
||
cmd := exec.Command("git", args...) | ||
cmd.Dir = dir | ||
out, err := cmd.CombinedOutput() | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"errors" from the std lib