diff --git a/commands/cli/parse.go b/commands/cli/parse.go index 04aa6ed2a..1e1c8b79c 100644 --- a/commands/cli/parse.go +++ b/commands/cli/parse.go @@ -4,6 +4,7 @@ import ( "bytes" "fmt" "os" + "path" "runtime" "strings" @@ -47,7 +48,7 @@ func Parse(input []string, stdin *os.File, root *cmds.Command) (cmds.Request, *c } req.SetArguments(stringArgs) - file := files.NewSliceFile("", fileArgs) + file := files.NewSliceFile("", "", fileArgs) req.SetFiles(file) err = cmd.CheckArguments(req) @@ -341,9 +342,17 @@ func appendStdinAsString(args []string, stdin *os.File) ([]string, *os.File, err } func appendFile(args []files.File, inputs []string, argDef *cmds.Argument, recursive bool) ([]files.File, []string, error) { - path := inputs[0] + fpath := inputs[0] - file, err := os.Open(path) + if fpath == "." { + cwd, err := os.Getwd() + if err != nil { + return nil, nil, err + } + fpath = cwd + } + + file, err := os.Open(fpath) if err != nil { return nil, nil, err } @@ -356,26 +365,25 @@ func appendFile(args []files.File, inputs []string, argDef *cmds.Argument, recur if stat.IsDir() { if !argDef.Recursive { err = fmt.Errorf("Invalid path '%s', argument '%s' does not support directories", - path, argDef.Name) + fpath, argDef.Name) return nil, nil, err } if !recursive { err = fmt.Errorf("'%s' is a directory, use the '-%s' flag to specify directories", - path, cmds.RecShort) + fpath, cmds.RecShort) return nil, nil, err } } - arg, err := files.NewSerialFile(path, file) + arg, err := files.NewSerialFile(path.Base(fpath), fpath, file) if err != nil { return nil, nil, err } - return append(args, arg), inputs[1:], nil } func appendStdinAsFile(args []files.File, stdin *os.File) ([]files.File, *os.File) { - arg := files.NewReaderFile("", stdin, nil) + arg := files.NewReaderFile("", "", stdin, nil) return append(args, arg), nil } diff --git a/commands/files/file.go b/commands/files/file.go index f1196257d..60ced7a71 100644 --- a/commands/files/file.go +++ b/commands/files/file.go @@ -18,9 +18,12 @@ type File interface { // Files implement ReadCloser, but can only be read from or closed if they are not directories io.ReadCloser - // FileName returns a full filename path associated with this file + // FileName returns a filename path associated with this file FileName() string + // FullPath returns the full path in the os associated with this file + FullPath() string + // IsDirectory returns true if the File is a directory (and therefore supports calling `NextFile`) // and false if the File is a normal file (and therefor supports calling `Read` and `Close`) IsDirectory() bool diff --git a/commands/files/file_test.go b/commands/files/file_test.go index 01b7a9d02..395221d4d 100644 --- a/commands/files/file_test.go +++ b/commands/files/file_test.go @@ -11,13 +11,13 @@ import ( func TestSliceFiles(t *testing.T) { name := "testname" files := []File{ - NewReaderFile("file.txt", ioutil.NopCloser(strings.NewReader("Some text!\n")), nil), - NewReaderFile("beep.txt", ioutil.NopCloser(strings.NewReader("beep")), nil), - NewReaderFile("boop.txt", ioutil.NopCloser(strings.NewReader("boop")), nil), + NewReaderFile("file.txt", "file.txt", ioutil.NopCloser(strings.NewReader("Some text!\n")), nil), + NewReaderFile("beep.txt", "beep.txt", ioutil.NopCloser(strings.NewReader("beep")), nil), + NewReaderFile("boop.txt", "boop.txt", ioutil.NopCloser(strings.NewReader("boop")), nil), } buf := make([]byte, 20) - sf := NewSliceFile(name, files) + sf := NewSliceFile(name, name, files) if !sf.IsDirectory() { t.Error("SliceFile should always be a directory") @@ -55,7 +55,7 @@ func TestSliceFiles(t *testing.T) { func TestReaderFiles(t *testing.T) { message := "beep boop" - rf := NewReaderFile("file.txt", ioutil.NopCloser(strings.NewReader(message)), nil) + rf := NewReaderFile("file.txt", "file.txt", ioutil.NopCloser(strings.NewReader(message)), nil) buf := make([]byte, len(message)) if rf.IsDirectory() { diff --git a/commands/files/multipartfile.go b/commands/files/multipartfile.go index ff2aab56b..b68224cbd 100644 --- a/commands/files/multipartfile.go +++ b/commands/files/multipartfile.go @@ -80,6 +80,10 @@ func (f *MultipartFile) FileName() string { return filename } +func (f *MultipartFile) FullPath() string { + return f.FileName() +} + func (f *MultipartFile) Read(p []byte) (int, error) { if f.IsDirectory() { return 0, ErrNotReader diff --git a/commands/files/readerfile.go b/commands/files/readerfile.go index 741042881..7458e82dd 100644 --- a/commands/files/readerfile.go +++ b/commands/files/readerfile.go @@ -10,12 +10,13 @@ import ( // ReaderFiles are never directories, and can be read from and closed. type ReaderFile struct { filename string + fullpath string reader io.ReadCloser stat os.FileInfo } -func NewReaderFile(filename string, reader io.ReadCloser, stat os.FileInfo) *ReaderFile { - return &ReaderFile{filename, reader, stat} +func NewReaderFile(filename, path string, reader io.ReadCloser, stat os.FileInfo) *ReaderFile { + return &ReaderFile{filename, path, reader, stat} } func (f *ReaderFile) IsDirectory() bool { @@ -30,6 +31,10 @@ func (f *ReaderFile) FileName() string { return f.filename } +func (f *ReaderFile) FullPath() string { + return f.fullpath +} + func (f *ReaderFile) Read(p []byte) (int, error) { return f.reader.Read(p) } diff --git a/commands/files/serialfile.go b/commands/files/serialfile.go index 461bde336..4b15e4434 100644 --- a/commands/files/serialfile.go +++ b/commands/files/serialfile.go @@ -18,25 +18,26 @@ func (es sortFIByName) Less(i, j int) bool { return es[i].Name() < es[j].Name() // No more than one file will be opened at a time (directories will advance // to the next file when NextFile() is called). type serialFile struct { + name string path string files []os.FileInfo stat os.FileInfo current *os.File } -func NewSerialFile(path string, file *os.File) (File, error) { +func NewSerialFile(name, path string, file *os.File) (File, error) { stat, err := file.Stat() if err != nil { return nil, err } - return newSerialFile(path, file, stat) + return newSerialFile(name, path, file, stat) } -func newSerialFile(path string, file *os.File, stat os.FileInfo) (File, error) { +func newSerialFile(name, path string, file *os.File, stat os.FileInfo) (File, error) { // for non-directories, return a ReaderFile if !stat.IsDir() { - return &ReaderFile{path, file, stat}, nil + return &ReaderFile{name, path, file, stat}, nil } // for directories, stat all of the contents first, so we know what files to @@ -56,7 +57,7 @@ func newSerialFile(path string, file *os.File, stat os.FileInfo) (File, error) { // make sure contents are sorted so -- repeatably -- we get the same inputs. sort.Sort(sortFIByName(contents)) - return &serialFile{path, contents, stat, nil}, nil + return &serialFile{name, path, contents, stat, nil}, nil } func (f *serialFile) IsDirectory() bool { @@ -81,6 +82,7 @@ func (f *serialFile) NextFile() (File, error) { f.files = f.files[1:] // open the next file + fileName := fp.Join(f.name, stat.Name()) filePath := fp.Join(f.path, stat.Name()) file, err := os.Open(filePath) if err != nil { @@ -91,10 +93,14 @@ func (f *serialFile) NextFile() (File, error) { // recursively call the constructor on the next file // if it's a regular file, we will open it as a ReaderFile // if it's a directory, files in it will be opened serially - return newSerialFile(filePath, file, stat) + return newSerialFile(fileName, filePath, file, stat) } func (f *serialFile) FileName() string { + return f.name +} + +func (f *serialFile) FullPath() string { return f.path } diff --git a/commands/files/slicefile.go b/commands/files/slicefile.go index f6e204812..b705151f1 100644 --- a/commands/files/slicefile.go +++ b/commands/files/slicefile.go @@ -10,12 +10,13 @@ import ( // SliceFiles are always directories, and can't be read from or closed. type SliceFile struct { filename string + path string files []File n int } -func NewSliceFile(filename string, files []File) *SliceFile { - return &SliceFile{filename, files, 0} +func NewSliceFile(filename, path string, files []File) *SliceFile { + return &SliceFile{filename, path, files, 0} } func (f *SliceFile) IsDirectory() bool { @@ -35,6 +36,10 @@ func (f *SliceFile) FileName() string { return f.filename } +func (f *SliceFile) FullPath() string { + return f.path +} + func (f *SliceFile) Read(p []byte) (int, error) { return 0, ErrNotReader } diff --git a/commands/http/multifilereader_test.go b/commands/http/multifilereader_test.go index f1c7aa94d..edd3d6bf2 100644 --- a/commands/http/multifilereader_test.go +++ b/commands/http/multifilereader_test.go @@ -13,14 +13,14 @@ import ( func TestOutput(t *testing.T) { text := "Some text! :)" fileset := []files.File{ - files.NewReaderFile("file.txt", ioutil.NopCloser(strings.NewReader(text)), nil), - files.NewSliceFile("boop", []files.File{ - files.NewReaderFile("boop/a.txt", ioutil.NopCloser(strings.NewReader("bleep")), nil), - files.NewReaderFile("boop/b.txt", ioutil.NopCloser(strings.NewReader("bloop")), nil), + files.NewReaderFile("file.txt", "file.txt", ioutil.NopCloser(strings.NewReader(text)), nil), + files.NewSliceFile("boop", "boop", []files.File{ + files.NewReaderFile("boop/a.txt", "boop/a.txt", ioutil.NopCloser(strings.NewReader("bleep")), nil), + files.NewReaderFile("boop/b.txt", "boop/b.txt", ioutil.NopCloser(strings.NewReader("bloop")), nil), }), - files.NewReaderFile("beep.txt", ioutil.NopCloser(strings.NewReader("beep")), nil), + files.NewReaderFile("beep.txt", "beep.txt", ioutil.NopCloser(strings.NewReader("beep")), nil), } - sf := files.NewSliceFile("", fileset) + sf := files.NewSliceFile("", "", fileset) buf := make([]byte, 20) // testing output by reading it with the go stdlib "mime/multipart" Reader diff --git a/core/commands/add.go b/core/commands/add.go index 614305126..4f87054b6 100644 --- a/core/commands/add.go +++ b/core/commands/add.go @@ -6,6 +6,7 @@ import ( "path" "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/cheggaaa/pb" + cxt "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" cmds "github.com/ipfs/go-ipfs/commands" files "github.com/ipfs/go-ipfs/commands/files" @@ -13,6 +14,7 @@ import ( importer "github.com/ipfs/go-ipfs/importer" "github.com/ipfs/go-ipfs/importer/chunk" dag "github.com/ipfs/go-ipfs/merkledag" + dagutils "github.com/ipfs/go-ipfs/merkledag/utils" pin "github.com/ipfs/go-ipfs/pin" ft "github.com/ipfs/go-ipfs/unixfs" u "github.com/ipfs/go-ipfs/util" @@ -102,7 +104,7 @@ remains to be implemented. chunker, _, _ := req.Option(chunkerOptionName).String() if hash { - nilnode, err := core.NewNodeBuilder().NilRepo().Build(n.Context()) + nilnode, err := core.NewNodeBuilder().Build(n.Context()) if err != nil { res.SetError(err, cmds.ErrNormal) return @@ -113,22 +115,37 @@ remains to be implemented. outChan := make(chan interface{}, 8) res.SetOutput((<-chan interface{})(outChan)) - // addSingleFile is a function that adds a file given as a param. - addSingleFile := func(file files.File) error { - addParams := adder{ - node: n, - out: outChan, - progress: progress, - hidden: hidden, - trickle: trickle, - chunker: chunker, - } + fileAdder := adder{ + ctx: req.Context(), + node: n, + editor: dagutils.NewDagEditor(n.DAG, newDirNode()), + out: outChan, + chunker: chunker, + progress: progress, + hidden: hidden, + trickle: trickle, + wrap: wrap, + } - rootnd, err := addParams.addFile(file) - if err != nil { - return err - } + // addAllFiles loops over a convenience slice file to + // add each file individually. e.g. 'ipfs add a b c' + addAllFiles := func(sliceFile files.File) error { + for { + file, err := sliceFile.NextFile() + if err != nil && err != io.EOF { + return err + } + if file == nil { + return nil // done + } + if _, err := fileAdder.addFile(file); err != nil { + return err + } + } + } + + pinRoot := func(rootnd *dag.Node) error { rnk, err := rootnd.Key() if err != nil { return err @@ -140,37 +157,22 @@ remains to be implemented. return n.Pinning.Flush() } - // addFilesSeparately loops over a convenience slice file to - // add each file individually. e.g. 'ipfs add a b c' - addFilesSeparately := func(sliceFile files.File) error { - for { - file, err := sliceFile.NextFile() - if err != nil && err != io.EOF { - return err - } - if file == nil { - return nil // done - } - - if err := addSingleFile(file); err != nil { - return err - } + addAllAndPin := func(f files.File) error { + if err := addAllFiles(f); err != nil { + return err } + + rootnd, err := fileAdder.RootNode() + if err != nil { + return err + } + + return pinRoot(rootnd) } go func() { defer close(outChan) - - // really, we're unrapping, if !wrap, because - // req.Files() is already a SliceFile() with all of them, - // so can just use that slice as the wrapper. - var err error - if wrap { - err = addSingleFile(req.Files()) - } else { - err = addFilesSeparately(req.Files()) - } - if err != nil { + if err := addAllAndPin(req.Files()); err != nil { res.SetError(err, cmds.ErrNormal) return } @@ -264,12 +266,17 @@ remains to be implemented. // Internal structure for holding the switches passed to the `add` call type adder struct { + ctx cxt.Context node *core.IpfsNode + editor *dagutils.Editor out chan interface{} progress bool hidden bool trickle bool + wrap bool chunker string + + nextUntitled int } // Perform the actual add & pin locally, outputting results to reader @@ -301,6 +308,40 @@ func add(n *core.IpfsNode, reader io.Reader, useTrickle bool, chunker string) (* return node, nil } +func (params *adder) RootNode() (*dag.Node, error) { + r := params.editor.GetNode() + + // if not wrapping, AND one root file, use that hash as root. + if !params.wrap && len(r.Links) == 1 { + var err error + r, err = r.Links[0].GetNode(params.ctx, params.node.DAG) + // no need to output, as we've already done so. + return r, err + } + + // otherwise need to output, as we have not. + err := outputDagnode(params.out, "", r) + return r, err +} + +func (params *adder) addNode(node *dag.Node, path string) error { + // patch it into the root + key, err := node.Key() + if err != nil { + return err + } + + if path == "" { + path = key.Pretty() + } + + if err := params.editor.InsertNodeAtPath(params.ctx, path, key, newDirNode); err != nil { + return err + } + + return outputDagnode(params.out, path, node) +} + // Add the given file while respecting the params. func (params *adder) addFile(file files.File) (*dag.Node, error) { // Check if file is hidden @@ -326,11 +367,10 @@ func (params *adder) addFile(file files.File) (*dag.Node, error) { return nil, err } + // patch it into the root log.Infof("adding file: %s", file.FileName()) - if err := outputDagnode(params.out, file.FileName(), dagnode); err != nil { - return nil, err - } - return dagnode, nil + err = params.addNode(dagnode, file.FileName()) + return dagnode, err } func (params *adder) addDir(file files.File) (*dag.Node, error) { @@ -364,8 +404,7 @@ func (params *adder) addDir(file files.File) (*dag.Node, error) { } } - err := outputDagnode(params.out, file.FileName(), tree) - if err != nil { + if err := params.addNode(tree, file.FileName()); err != nil { return nil, err } @@ -431,3 +470,8 @@ func (i *progressReader) Read(p []byte) (int, error) { return n, err } + +// TODO: generalize this to more than unix-fs nodes. +func newDirNode() *dag.Node { + return &dag.Node{Data: ft.FolderPBData()} +} diff --git a/core/coreunix/add.go b/core/coreunix/add.go index 17864c9f7..1d3f6cf6b 100644 --- a/core/coreunix/add.go +++ b/core/coreunix/add.go @@ -50,7 +50,7 @@ func AddR(n *core.IpfsNode, root string) (key string, err error) { } defer f.Close() - ff, err := files.NewSerialFile(root, f) + ff, err := files.NewSerialFile(root, root, f) if err != nil { return "", err } @@ -79,8 +79,8 @@ func AddR(n *core.IpfsNode, root string) (key string, err error) { // Returns the path of the added file ("/filename"), the DAG node of // the directory, and and error if any. func AddWrapped(n *core.IpfsNode, r io.Reader, filename string) (string, *merkledag.Node, error) { - file := files.NewReaderFile(filename, ioutil.NopCloser(r), nil) - dir := files.NewSliceFile("", []files.File{file}) + file := files.NewReaderFile(filename, filename, ioutil.NopCloser(r), nil) + dir := files.NewSliceFile("", "", []files.File{file}) dagnode, err := addDir(n, dir) if err != nil { return "", nil, err diff --git a/test/sharness/t0040-add-and-cat.sh b/test/sharness/t0040-add-and-cat.sh index ef74be1c4..28da0225c 100755 --- a/test/sharness/t0040-add-and-cat.sh +++ b/test/sharness/t0040-add-and-cat.sh @@ -35,7 +35,7 @@ test_expect_success "ipfs add succeeds" ' test_expect_success "ipfs add output looks good" ' HASH="QmVr26fY1tKyspEJBniVhqxQeEjhF78XerGiqWAwraVLQH" && - echo "added $HASH mountdir/hello.txt" >expected && + echo "added $HASH hello.txt" >expected && test_cmp expected actual ' @@ -116,7 +116,7 @@ test_expect_success "'ipfs add' with stdin input succeeds" ' test_expect_success "'ipfs add' output looks good" ' HASH="QmZDhWpi8NvKrekaYYhxKCdNVGWsFFe1CREnAjP1QbPaB3" && - echo "added $HASH " >expected && + echo "added $HASH $HASH" >expected && test_cmp expected actual ' @@ -140,9 +140,9 @@ test_expect_success "'ipfs add -r' output looks good" ' PLANETS="QmWSgS32xQEcXMeqd3YPJLrNBLSdsfYCep2U7CFkyrjXwY" && MARS="QmPrrHqJzto9m7SyiRzarwkqPcCSsKR2EB1AyqJfe8L8tN" && VENUS="QmU5kp3BH3B8tnWUU2Pikdb2maksBNkb92FHRr56hyghh4" && - echo "added $MARS mountdir/planets/mars.txt" >expected && - echo "added $VENUS mountdir/planets/venus.txt" >>expected && - echo "added $PLANETS mountdir/planets" >>expected && + echo "added $MARS planets/mars.txt" >expected && + echo "added $VENUS planets/venus.txt" >>expected && + echo "added $PLANETS planets" >>expected && test_cmp expected actual ' @@ -201,7 +201,7 @@ test_expect_success "'ipfs add bigfile' succeeds" ' test_expect_success "'ipfs add bigfile' output looks good" ' HASH="QmSr7FqYkxYWGoSfy8ZiaMWQ5vosb18DQGCzjwEQnVHkTb" && - echo "added $HASH mountdir/bigfile" >expected && + echo "added $HASH bigfile" >expected && test_cmp expected actual ' test_expect_success "'ipfs cat' succeeds" ' @@ -236,7 +236,7 @@ test_expect_success EXPENSIVE "ipfs add bigfile succeeds" ' test_expect_success EXPENSIVE "ipfs add bigfile output looks good" ' HASH="QmU9SWAPPmNEKZB8umYMmjYvN7VyHqABNvdA6GUi4MMEz3" && - echo "added $HASH mountdir/bigfile" >expected && + echo "added $HASH bigfile" >expected && test_cmp expected actual ' diff --git a/test/sharness/t0042-add-skip.sh b/test/sharness/t0042-add-skip.sh index d1b9f4f3c..afa80f3dc 100755 --- a/test/sharness/t0042-add-skip.sh +++ b/test/sharness/t0042-add-skip.sh @@ -22,9 +22,9 @@ test_add_skip() { ' test_expect_success "'ipfs add -r' did not include . files" ' - echo "added QmZy3khu7qf696i5HtkgL2NotsCZ8wzvNZJ1eUdA5n8KaV mountdir/planets/mars.txt -added QmQnv4m3Q5512zgVtpbJ9z85osQrzZzGRn934AGh6iVEXz mountdir/planets/venus.txt -added QmR8nD1Vzk5twWVC6oShTHvv7mMYkVh6dApCByBJyV2oj3 mountdir/planets" >expected + echo "added QmZy3khu7qf696i5HtkgL2NotsCZ8wzvNZJ1eUdA5n8KaV planets/mars.txt +added QmQnv4m3Q5512zgVtpbJ9z85osQrzZzGRn934AGh6iVEXz planets/venus.txt +added QmR8nD1Vzk5twWVC6oShTHvv7mMYkVh6dApCByBJyV2oj3 planets" >expected test_cmp expected actual ' @@ -33,14 +33,14 @@ added QmR8nD1Vzk5twWVC6oShTHvv7mMYkVh6dApCByBJyV2oj3 mountdir/planets" >expected ' test_expect_success "'ipfs add -r --hidden' did include . files" ' - echo "added QmcAREBcjgnUpKfyFmUGnfajA1NQS5ydqRp7WfqZ6JF8Dx mountdir/planets/.asteroids/ceres.txt -added QmZ5eaLybJ5GUZBNwy24AA9EEDTDpA4B8qXnuN3cGxu2uF mountdir/planets/.asteroids/pallas.txt -added Qmf6rbs5GF85anDuoxpSAdtuZPM9D2Yt3HngzjUVSQ7kDV mountdir/planets/.asteroids -added QmaowqjedBkUrMUXgzt9c2ZnAJncM9jpJtkFfgdFstGr5a mountdir/planets/.charon.txt -added QmU4zFD5eJtRBsWC63AvpozM9Atiadg9kPVTuTrnCYJiNF mountdir/planets/.pluto.txt -added QmZy3khu7qf696i5HtkgL2NotsCZ8wzvNZJ1eUdA5n8KaV mountdir/planets/mars.txt -added QmQnv4m3Q5512zgVtpbJ9z85osQrzZzGRn934AGh6iVEXz mountdir/planets/venus.txt -added QmetajtFdmzhWYodAsZoVZSiqpeJDAiaw2NwbM3xcWcpDj mountdir/planets" >expected && + echo "added QmcAREBcjgnUpKfyFmUGnfajA1NQS5ydqRp7WfqZ6JF8Dx planets/.asteroids/ceres.txt +added QmZ5eaLybJ5GUZBNwy24AA9EEDTDpA4B8qXnuN3cGxu2uF planets/.asteroids/pallas.txt +added Qmf6rbs5GF85anDuoxpSAdtuZPM9D2Yt3HngzjUVSQ7kDV planets/.asteroids +added QmaowqjedBkUrMUXgzt9c2ZnAJncM9jpJtkFfgdFstGr5a planets/.charon.txt +added QmU4zFD5eJtRBsWC63AvpozM9Atiadg9kPVTuTrnCYJiNF planets/.pluto.txt +added QmZy3khu7qf696i5HtkgL2NotsCZ8wzvNZJ1eUdA5n8KaV planets/mars.txt +added QmQnv4m3Q5512zgVtpbJ9z85osQrzZzGRn934AGh6iVEXz planets/venus.txt +added QmetajtFdmzhWYodAsZoVZSiqpeJDAiaw2NwbM3xcWcpDj planets" >expected && test_cmp expected actual ' diff --git a/test/sharness/t0043-add-w.sh b/test/sharness/t0043-add-w.sh index 5719aecb9..d4f7decaa 100755 --- a/test/sharness/t0043-add-w.sh +++ b/test/sharness/t0043-add-w.sh @@ -8,42 +8,42 @@ test_description="Test add -w" add_w_m='QmazHkwx6mPmmCEi1jR5YzjjQd1g5XzKfYQLzRAg7x5uUk' -add_w_1='added Qme987pqNBhZZXy4ckeXiR7zaRQwBabB7fTgHurW2yJfNu m/4r93 +add_w_1='added Qme987pqNBhZZXy4ckeXiR7zaRQwBabB7fTgHurW2yJfNu 4r93 added Qmf82PSsMpUHcrqxa69KG6Qp5yeK7K9BTizXgG3nvzWcNG ' -add_w_12='added Qme987pqNBhZZXy4ckeXiR7zaRQwBabB7fTgHurW2yJfNu m/4r93 -added QmVb4ntSZZnT2J2zvCmXKMJc52cmZYH6AB37MzeYewnkjs m/4u6ead +add_w_12='added Qme987pqNBhZZXy4ckeXiR7zaRQwBabB7fTgHurW2yJfNu 4r93 +added QmVb4ntSZZnT2J2zvCmXKMJc52cmZYH6AB37MzeYewnkjs 4u6ead added QmZPASVB6EsADrLN8S2sak34zEHL8mx4TAVsPJU9cNnQQJ ' -add_w_21='added QmVb4ntSZZnT2J2zvCmXKMJc52cmZYH6AB37MzeYewnkjs m/4u6ead -added Qme987pqNBhZZXy4ckeXiR7zaRQwBabB7fTgHurW2yJfNu m/4r93 +add_w_21='added QmVb4ntSZZnT2J2zvCmXKMJc52cmZYH6AB37MzeYewnkjs 4u6ead +added Qme987pqNBhZZXy4ckeXiR7zaRQwBabB7fTgHurW2yJfNu 4r93 added QmZPASVB6EsADrLN8S2sak34zEHL8mx4TAVsPJU9cNnQQJ ' -add_w_d1='added QmPcaX84tDiTfzdTn8GQxexodgeWH6mHjSss5Zfr5ojssb m/t_1wp-8a2/_jo7/-s782qgs -added QmaVBqquUuXKjkyWHXaXfsaQUxAnsCKS95VRDHU8PzGA4K m/t_1wp-8a2/_jo7/15totauzkak- -added QmaAHFG8cmhW3WLjofx5siSp44VV25ETN6ThzrU8iAqpkR m/t_1wp-8a2/_jo7/galecuirrj4r -added QmeuSfhJNKwBESp1W9H8cfoMdBfW3AeHQDWXbNXQJYWp53 m/t_1wp-8a2/_jo7/mzo50r-1xidf5zx -added QmYC3u5jGWuyFwvTxtvLYm2K3SpWZ31tg3NjpVVvh9cJaJ m/t_1wp-8a2/_jo7/wzvsihy -added QmQkib3f9XNX5sj6WEahLUPFpheTcwSRJwUCSvjcv8b9by m/t_1wp-8a2/_jo7 +add_w_d1='added QmPcaX84tDiTfzdTn8GQxexodgeWH6mHjSss5Zfr5ojssb _jo7/-s782qgs +added QmaVBqquUuXKjkyWHXaXfsaQUxAnsCKS95VRDHU8PzGA4K _jo7/15totauzkak- +added QmaAHFG8cmhW3WLjofx5siSp44VV25ETN6ThzrU8iAqpkR _jo7/galecuirrj4r +added QmeuSfhJNKwBESp1W9H8cfoMdBfW3AeHQDWXbNXQJYWp53 _jo7/mzo50r-1xidf5zx +added QmYC3u5jGWuyFwvTxtvLYm2K3SpWZ31tg3NjpVVvh9cJaJ _jo7/wzvsihy +added QmQkib3f9XNX5sj6WEahLUPFpheTcwSRJwUCSvjcv8b9by _jo7 added QmNQoesMj1qp8ApE51NbtTjFYksyzkezPD4cat7V2kzbKN ' -add_w_d2='added QmVaKAt2eVftNKFfKhiBV7Mu5HjCugffuLqWqobSSFgiA7 m/t_1wp-8a2/h3qpecj0 -added QmU9Jqks8TPu4vFr6t7EKkAKQrSJuEujNj1AkzoCeTEDFJ m/ha6f0x7su6/gnz66h/1k0xpx34 -added QmSLYZycXAufRw3ePMVH2brbtYWCcWsmksGLbHcT8ia9Ke m/ha6f0x7su6/gnz66h/9cwudvacx -added QmfYmpCCAMU9nLe7xbrYsHf5z2R2GxeQnsm4zavUhX9vq2 m/ha6f0x7su6/gnz66h/9ximv51cbo8 -added QmWgEE4e2kfx3b8HZcBk5cLrfhoi8kTMQP2MipgPhykuV3 m/ha6f0x7su6/gnz66h/b54ygh6gs -added QmcLbqEqhREGednc6mrVtanee4WHKp5JnUfiwTTHCJwuDf m/ha6f0x7su6/gnz66h/lbl5 -added QmVPwNy8pZegpsNmsjjZvdTQn4uCeuZgtzhgWhRSQWjK9x m/ha6f0x7su6/gnz66h -added QmPcaX84tDiTfzdTn8GQxexodgeWH6mHjSss5Zfr5ojssb m/t_1wp-8a2/_jo7/-s782qgs -added QmaVBqquUuXKjkyWHXaXfsaQUxAnsCKS95VRDHU8PzGA4K m/t_1wp-8a2/_jo7/15totauzkak- -added QmaAHFG8cmhW3WLjofx5siSp44VV25ETN6ThzrU8iAqpkR m/t_1wp-8a2/_jo7/galecuirrj4r -added QmeuSfhJNKwBESp1W9H8cfoMdBfW3AeHQDWXbNXQJYWp53 m/t_1wp-8a2/_jo7/mzo50r-1xidf5zx -added QmYC3u5jGWuyFwvTxtvLYm2K3SpWZ31tg3NjpVVvh9cJaJ m/t_1wp-8a2/_jo7/wzvsihy -added QmQkib3f9XNX5sj6WEahLUPFpheTcwSRJwUCSvjcv8b9by m/t_1wp-8a2/_jo7 -added Qme987pqNBhZZXy4ckeXiR7zaRQwBabB7fTgHurW2yJfNu m/4r93 +add_w_d2='added QmVaKAt2eVftNKFfKhiBV7Mu5HjCugffuLqWqobSSFgiA7 h3qpecj0 +added QmU9Jqks8TPu4vFr6t7EKkAKQrSJuEujNj1AkzoCeTEDFJ gnz66h/1k0xpx34 +added QmSLYZycXAufRw3ePMVH2brbtYWCcWsmksGLbHcT8ia9Ke gnz66h/9cwudvacx +added QmfYmpCCAMU9nLe7xbrYsHf5z2R2GxeQnsm4zavUhX9vq2 gnz66h/9ximv51cbo8 +added QmWgEE4e2kfx3b8HZcBk5cLrfhoi8kTMQP2MipgPhykuV3 gnz66h/b54ygh6gs +added QmcLbqEqhREGednc6mrVtanee4WHKp5JnUfiwTTHCJwuDf gnz66h/lbl5 +added QmVPwNy8pZegpsNmsjjZvdTQn4uCeuZgtzhgWhRSQWjK9x gnz66h +added QmPcaX84tDiTfzdTn8GQxexodgeWH6mHjSss5Zfr5ojssb _jo7/-s782qgs +added QmaVBqquUuXKjkyWHXaXfsaQUxAnsCKS95VRDHU8PzGA4K _jo7/15totauzkak- +added QmaAHFG8cmhW3WLjofx5siSp44VV25ETN6ThzrU8iAqpkR _jo7/galecuirrj4r +added QmeuSfhJNKwBESp1W9H8cfoMdBfW3AeHQDWXbNXQJYWp53 _jo7/mzo50r-1xidf5zx +added QmYC3u5jGWuyFwvTxtvLYm2K3SpWZ31tg3NjpVVvh9cJaJ _jo7/wzvsihy +added QmQkib3f9XNX5sj6WEahLUPFpheTcwSRJwUCSvjcv8b9by _jo7 +added Qme987pqNBhZZXy4ckeXiR7zaRQwBabB7fTgHurW2yJfNu 4r93 added QmTmc46fhKC8Liuh5soy1VotdnHcqLu3r6HpPGwDZCnqL1 ' -add_w_r='QmWpSjVaMts6cXr4g4uQ9AVadunLKxW7Fhyxk3TXo36hEf' +add_w_r='QmcCksBMDuuyuyfAMMNzEAx6Z7jTrdRy9a23WpufAhG9ji' . lib/test-lib.sh diff --git a/test/sharness/t0080-repo.sh b/test/sharness/t0080-repo.sh index 6e7b9203c..0066b0086 100755 --- a/test/sharness/t0080-repo.sh +++ b/test/sharness/t0080-repo.sh @@ -11,6 +11,15 @@ test_description="Test ipfs repo operations" test_init_ipfs test_launch_ipfs_daemon +test_expect_success "'ipfs repo gc' succeeds" ' + ipfs repo gc >gc_out_actual +' + +test_expect_success "'ipfs repo gc' looks good (empty)" ' + true >empty && + test_cmp empty gc_out_actual +' + test_expect_success "'ipfs add afile' succeeds" ' echo "some text" >afile && HASH=`ipfs add -q afile` @@ -25,9 +34,10 @@ test_expect_success "'ipfs repo gc' succeeds" ' ipfs repo gc >gc_out_actual ' -test_expect_success "'ipfs repo gc' looks good (empty)" ' - true >empty && - test_cmp empty gc_out_actual +test_expect_success "'ipfs repo gc' looks good (patch root)" ' + PATCH_ROOT=QmQXirSbubiySKnqaFyfs5YzziXRB5JEVQVjU6xsd7innr && + echo "removed $PATCH_ROOT" >patch_root && + test_cmp patch_root gc_out_actual ' test_expect_success "'ipfs repo gc' doesnt remove file" ' @@ -60,7 +70,8 @@ test_expect_success "file no longer pinned" ' ipfs refs -r "$HASH_WELCOME_DOCS" >>expected2 && echo "$HASH_GATEWAY_ASSETS" >>expected2 && ipfs refs -r "$HASH_GATEWAY_ASSETS" >>expected2 && - echo QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn >> expected2 && + EMPTY_DIR=QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn && + echo "$EMPTY_DIR" >>expected2 && ipfs pin ls --type=recursive --quiet >actual2 && test_sort_cmp expected2 actual2 ' @@ -96,14 +107,16 @@ test_expect_success "remove direct pin" ' ' test_expect_success "'ipfs repo gc' removes file" ' - echo "removed $HASH" >expected7 && + echo "removed $PATCH_ROOT" >expected7 && + echo "removed $HASH" >>expected7 && ipfs repo gc >actual7 && - test_cmp expected7 actual7 + test_sort_cmp expected7 actual7 ' # TODO: there seems to be a serious bug with leveldb not returning a key. test_expect_failure "'ipfs refs local' no longer shows file" ' - echo QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn >expected8 && + EMPTY_DIR=QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn && + echo "$EMPTY_DIR" >expected8 && echo "$HASH_WELCOME_DOCS" >>expected8 && ipfs refs -r "$HASH_WELCOME_DOCS" >>expected8 && ipfs refs local >actual8 && @@ -146,7 +159,7 @@ test_expect_success "'ipfs pin ls --type=recursive' is correct" ' echo "$MBLOCKHASH" >rp_expected && echo "$HASH_WELCOME_DOCS" >>rp_expected && echo "$HASH_GATEWAY_ASSETS" >>rp_expected && - echo QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn >>rp_expected && + echo "$EMPTY_DIR" >>rp_expected && ipfs refs -r "$HASH_WELCOME_DOCS" >>rp_expected && ipfs refs -r "$HASH_GATEWAY_ASSETS" >>rp_expected && sed -i="" "s/\(.*\)/\1 recursive/g" rp_expected && diff --git a/test/sharness/t0081-repo-pinning.sh b/test/sharness/t0081-repo-pinning.sh index 1d3b02ac7..33a1a59f9 100755 --- a/test/sharness/t0081-repo-pinning.sh +++ b/test/sharness/t0081-repo-pinning.sh @@ -100,6 +100,7 @@ test_expect_success "'ipfs add dir' succeeds" ' echo "some text 5" >dir1/dir3/file5 && ipfs add -q -r dir1 | tail -n1 >actual1 && echo "$HASH_DIR1" >expected1 && + ipfs repo gc && # remove the patch chaff test_cmp actual1 expected1 '