@cryptotaxi247 / kubo / commits / 978c9fa16

cmds/add: use dagutils.Editor, like patch

This changes the pin behavior. It uses the filenames given through the api, and allows files to be streamed faltly (not a hierarchy), which is easier for other things (like vinyl in node-ipfs-api land). Files can also be entirely out of order, and the garbage intermediate directories will not be pinned (gc-ed later). The changes also mean the output of add has changed slightly-- it no longer shows the local path added, but rather the dag path relative to the added roots. This is a small difference, but changes tests. The dagutils.Editor creates a lot of chaff (intermediate objects) along the way. Wonder how we might minimize the writes to the datastore... This commit also removes the "NilRepo()" part of the --only-hash mode. We need to store at least in an in-mem repo/datastore because otherwise the dagutils.Editor breaks. License: MIT Signed-off-by: Juan Batiz-Benet <juan@benet.ai>

Juan Batiz-Benet committed Aug 11, 2015 at 20:38 UTC 978c9fa16fe47ee3c5d524241202e74edec82147
15 files changed +219 -130
commands/cli/parse.go
+16 -8
@@ -4,6 +4,7 @@ import (
4 "bytes"
5 "fmt"
6 "os"
7 + "path"
8 "runtime"
9 "strings"
10
@@ -47,7 +48,7 @@ func Parse(input []string, stdin *os.File, root *cmds.Command) (cmds.Request, *c
48 }
49 req.SetArguments(stringArgs)
50
50 - file := files.NewSliceFile("", fileArgs)
51 + file := files.NewSliceFile("", "", fileArgs)
52 req.SetFiles(file)
53
54 err = cmd.CheckArguments(req)
@@ -341,9 +342,17 @@ func appendStdinAsString(args []string, stdin *os.File) ([]string, *os.File, err
342 }
343
344 func appendFile(args []files.File, inputs []string, argDef *cmds.Argument, recursive bool) ([]files.File, []string, error) {
344 - path := inputs[0]
345 + fpath := inputs[0]
346
346 - file, err := os.Open(path)
347 + if fpath == "." {
348 + cwd, err := os.Getwd()
349 + if err != nil {
350 + return nil, nil, err
351 + }
352 + fpath = cwd
353 + }
354 +
355 + file, err := os.Open(fpath)
356 if err != nil {
357 return nil, nil, err
358 }
@@ -356,26 +365,25 @@ func appendFile(args []files.File, inputs []string, argDef *cmds.Argument, recur
365 if stat.IsDir() {
366 if !argDef.Recursive {
367 err = fmt.Errorf("Invalid path '%s', argument '%s' does not support directories",
359 - path, argDef.Name)
368 + fpath, argDef.Name)
369 return nil, nil, err
370 }
371 if !recursive {
372 err = fmt.Errorf("'%s' is a directory, use the '-%s' flag to specify directories",
364 - path, cmds.RecShort)
373 + fpath, cmds.RecShort)
374 return nil, nil, err
375 }
376 }
377
369 - arg, err := files.NewSerialFile(path, file)
378 + arg, err := files.NewSerialFile(path.Base(fpath), fpath, file)
379 if err != nil {
380 return nil, nil, err
381 }
373 -
382 return append(args, arg), inputs[1:], nil
383 }
384
385 func appendStdinAsFile(args []files.File, stdin *os.File) ([]files.File, *os.File) {
378 - arg := files.NewReaderFile("", stdin, nil)
386 + arg := files.NewReaderFile("", "", stdin, nil)
387 return append(args, arg), nil
388 }
389
commands/files/file.go
+4 -1
@@ -18,9 +18,12 @@ type File interface {
18 // Files implement ReadCloser, but can only be read from or closed if they are not directories
19 io.ReadCloser
20
21 - // FileName returns a full filename path associated with this file
21 + // FileName returns a filename path associated with this file
22 FileName() string
23
24 + // FullPath returns the full path in the os associated with this file
25 + FullPath() string
26 +
27 // IsDirectory returns true if the File is a directory (and therefore supports calling `NextFile`)
28 // and false if the File is a normal file (and therefor supports calling `Read` and `Close`)
29 IsDirectory() bool
commands/files/file_test.go
+5 -5
@@ -11,13 +11,13 @@ import (
11 func TestSliceFiles(t *testing.T) {
12 name := "testname"
13 files := []File{
14 - NewReaderFile("file.txt", ioutil.NopCloser(strings.NewReader("Some text!\n")), nil),
15 - NewReaderFile("beep.txt", ioutil.NopCloser(strings.NewReader("beep")), nil),
16 - NewReaderFile("boop.txt", ioutil.NopCloser(strings.NewReader("boop")), nil),
14 + NewReaderFile("file.txt", "file.txt", ioutil.NopCloser(strings.NewReader("Some text!\n")), nil),
15 + NewReaderFile("beep.txt", "beep.txt", ioutil.NopCloser(strings.NewReader("beep")), nil),
16 + NewReaderFile("boop.txt", "boop.txt", ioutil.NopCloser(strings.NewReader("boop")), nil),
17 }
18 buf := make([]byte, 20)
19
20 - sf := NewSliceFile(name, files)
20 + sf := NewSliceFile(name, name, files)
21
22 if !sf.IsDirectory() {
23 t.Error("SliceFile should always be a directory")
@@ -55,7 +55,7 @@ func TestSliceFiles(t *testing.T) {
55
56 func TestReaderFiles(t *testing.T) {
57 message := "beep boop"
58 - rf := NewReaderFile("file.txt", ioutil.NopCloser(strings.NewReader(message)), nil)
58 + rf := NewReaderFile("file.txt", "file.txt", ioutil.NopCloser(strings.NewReader(message)), nil)
59 buf := make([]byte, len(message))
60
61 if rf.IsDirectory() {
commands/files/multipartfile.go
+4
@@ -80,6 +80,10 @@ func (f *MultipartFile) FileName() string {
80 return filename
81 }
82
83 +func (f *MultipartFile) FullPath() string {
84 + return f.FileName()
85 +}
86 +
87 func (f *MultipartFile) Read(p []byte) (int, error) {
88 if f.IsDirectory() {
89 return 0, ErrNotReader
commands/files/readerfile.go
+7 -2
@@ -10,12 +10,13 @@ import (
10 // ReaderFiles are never directories, and can be read from and closed.
11 type ReaderFile struct {
12 filename string
13 + fullpath string
14 reader io.ReadCloser
15 stat os.FileInfo
16 }
17
17 -func NewReaderFile(filename string, reader io.ReadCloser, stat os.FileInfo) *ReaderFile {
18 - return &ReaderFile{filename, reader, stat}
18 +func NewReaderFile(filename, path string, reader io.ReadCloser, stat os.FileInfo) *ReaderFile {
19 + return &ReaderFile{filename, path, reader, stat}
20 }
21
22 func (f *ReaderFile) IsDirectory() bool {
@@ -30,6 +31,10 @@ func (f *ReaderFile) FileName() string {
31 return f.filename
32 }
33
34 +func (f *ReaderFile) FullPath() string {
35 + return f.fullpath
36 +}
37 +
38 func (f *ReaderFile) Read(p []byte) (int, error) {
39 return f.reader.Read(p)
40 }
commands/files/serialfile.go
+12 -6
@@ -18,25 +18,26 @@ func (es sortFIByName) Less(i, j int) bool { return es[i].Name() < es[j].Name()
18 // No more than one file will be opened at a time (directories will advance
19 // to the next file when NextFile() is called).
20 type serialFile struct {
21 + name string
22 path string
23 files []os.FileInfo
24 stat os.FileInfo
25 current *os.File
26 }
27
27 -func NewSerialFile(path string, file *os.File) (File, error) {
28 +func NewSerialFile(name, path string, file *os.File) (File, error) {
29 stat, err := file.Stat()
30 if err != nil {
31 return nil, err
32 }
33
33 - return newSerialFile(path, file, stat)
34 + return newSerialFile(name, path, file, stat)
35 }
36
36 -func newSerialFile(path string, file *os.File, stat os.FileInfo) (File, error) {
37 +func newSerialFile(name, path string, file *os.File, stat os.FileInfo) (File, error) {
38 // for non-directories, return a ReaderFile
39 if !stat.IsDir() {
39 - return &ReaderFile{path, file, stat}, nil
40 + return &ReaderFile{name, path, file, stat}, nil
41 }
42
43 // 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) {
57 // make sure contents are sorted so -- repeatably -- we get the same inputs.
58 sort.Sort(sortFIByName(contents))
59
59 - return &serialFile{path, contents, stat, nil}, nil
60 + return &serialFile{name, path, contents, stat, nil}, nil
61 }
62
63 func (f *serialFile) IsDirectory() bool {
@@ -81,6 +82,7 @@ func (f *serialFile) NextFile() (File, error) {
82 f.files = f.files[1:]
83
84 // open the next file
85 + fileName := fp.Join(f.name, stat.Name())
86 filePath := fp.Join(f.path, stat.Name())
87 file, err := os.Open(filePath)
88 if err != nil {
@@ -91,10 +93,14 @@ func (f *serialFile) NextFile() (File, error) {
93 // recursively call the constructor on the next file
94 // if it's a regular file, we will open it as a ReaderFile
95 // if it's a directory, files in it will be opened serially
94 - return newSerialFile(filePath, file, stat)
96 + return newSerialFile(fileName, filePath, file, stat)
97 }
98
99 func (f *serialFile) FileName() string {
100 + return f.name
101 +}
102 +
103 +func (f *serialFile) FullPath() string {
104 return f.path
105 }
106
commands/files/slicefile.go
+7 -2
@@ -10,12 +10,13 @@ import (
10 // SliceFiles are always directories, and can't be read from or closed.
11 type SliceFile struct {
12 filename string
13 + path string
14 files []File
15 n int
16 }
17
17 -func NewSliceFile(filename string, files []File) *SliceFile {
18 - return &SliceFile{filename, files, 0}
18 +func NewSliceFile(filename, path string, files []File) *SliceFile {
19 + return &SliceFile{filename, path, files, 0}
20 }
21
22 func (f *SliceFile) IsDirectory() bool {
@@ -35,6 +36,10 @@ func (f *SliceFile) FileName() string {
36 return f.filename
37 }
38
39 +func (f *SliceFile) FullPath() string {
40 + return f.path
41 +}
42 +
43 func (f *SliceFile) Read(p []byte) (int, error) {
44 return 0, ErrNotReader
45 }
commands/http/multifilereader_test.go
+6 -6
@@ -13,14 +13,14 @@ import (
13 func TestOutput(t *testing.T) {
14 text := "Some text! :)"
15 fileset := []files.File{
16 - files.NewReaderFile("file.txt", ioutil.NopCloser(strings.NewReader(text)), nil),
17 - files.NewSliceFile("boop", []files.File{
18 - files.NewReaderFile("boop/a.txt", ioutil.NopCloser(strings.NewReader("bleep")), nil),
19 - files.NewReaderFile("boop/b.txt", ioutil.NopCloser(strings.NewReader("bloop")), nil),
16 + files.NewReaderFile("file.txt", "file.txt", ioutil.NopCloser(strings.NewReader(text)), nil),
17 + files.NewSliceFile("boop", "boop", []files.File{
18 + files.NewReaderFile("boop/a.txt", "boop/a.txt", ioutil.NopCloser(strings.NewReader("bleep")), nil),
19 + files.NewReaderFile("boop/b.txt", "boop/b.txt", ioutil.NopCloser(strings.NewReader("bloop")), nil),
20 }),
21 - files.NewReaderFile("beep.txt", ioutil.NopCloser(strings.NewReader("beep")), nil),
21 + files.NewReaderFile("beep.txt", "beep.txt", ioutil.NopCloser(strings.NewReader("beep")), nil),
22 }
23 - sf := files.NewSliceFile("", fileset)
23 + sf := files.NewSliceFile("", "", fileset)
24 buf := make([]byte, 20)
25
26 // testing output by reading it with the go stdlib "mime/multipart" Reader
core/commands/add.go
+89 -45
@@ -6,6 +6,7 @@ import (
6 "path"
7
8 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/cheggaaa/pb"
9 + cxt "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
10
11 cmds "github.com/ipfs/go-ipfs/commands"
12 files "github.com/ipfs/go-ipfs/commands/files"
@@ -13,6 +14,7 @@ import (
14 importer "github.com/ipfs/go-ipfs/importer"
15 "github.com/ipfs/go-ipfs/importer/chunk"
16 dag "github.com/ipfs/go-ipfs/merkledag"
17 + dagutils "github.com/ipfs/go-ipfs/merkledag/utils"
18 pin "github.com/ipfs/go-ipfs/pin"
19 ft "github.com/ipfs/go-ipfs/unixfs"
20 u "github.com/ipfs/go-ipfs/util"
@@ -102,7 +104,7 @@ remains to be implemented.
104 chunker, _, _ := req.Option(chunkerOptionName).String()
105
106 if hash {
105 - nilnode, err := core.NewNodeBuilder().NilRepo().Build(n.Context())
107 + nilnode, err := core.NewNodeBuilder().Build(n.Context())
108 if err != nil {
109 res.SetError(err, cmds.ErrNormal)
110 return
@@ -113,36 +115,21 @@ remains to be implemented.
115 outChan := make(chan interface{}, 8)
116 res.SetOutput((<-chan interface{})(outChan))
117
116 - // addSingleFile is a function that adds a file given as a param.
117 - addSingleFile := func(file files.File) error {
118 - addParams := adder{
119 - node: n,
120 - out: outChan,
121 - progress: progress,
122 - hidden: hidden,
123 - trickle: trickle,
124 - chunker: chunker,
125 - }
126 -
127 - rootnd, err := addParams.addFile(file)
128 - if err != nil {
129 - return err
130 - }
131 -
132 - rnk, err := rootnd.Key()
133 - if err != nil {
134 - return err
135 - }
136 -
137 - mp := n.Pinning.GetManual()
138 - mp.RemovePinWithMode(rnk, pin.Indirect)
139 - mp.PinWithMode(rnk, pin.Recursive)
140 - return n.Pinning.Flush()
118 + fileAdder := adder{
119 + ctx: req.Context(),
120 + node: n,
121 + editor: dagutils.NewDagEditor(n.DAG, newDirNode()),
122 + out: outChan,
123 + chunker: chunker,
124 + progress: progress,
125 + hidden: hidden,
126 + trickle: trickle,
127 + wrap: wrap,
128 }
129
143 - // addFilesSeparately loops over a convenience slice file to
130 + // addAllFiles loops over a convenience slice file to
131 // add each file individually. e.g. 'ipfs add a b c'
145 - addFilesSeparately := func(sliceFile files.File) error {
132 + addAllFiles := func(sliceFile files.File) error {
133 for {
134 file, err := sliceFile.NextFile()
135 if err != nil && err != io.EOF {
@@ -152,25 +139,40 @@ remains to be implemented.
139 return nil // done
140 }
141
155 - if err := addSingleFile(file); err != nil {
142 + if _, err := fileAdder.addFile(file); err != nil {
143 return err
144 }
145 }
146 }
147
161 - go func() {
162 - defer close(outChan)
148 + pinRoot := func(rootnd *dag.Node) error {
149 + rnk, err := rootnd.Key()
150 + if err != nil {
151 + return err
152 + }
153
164 - // really, we're unrapping, if !wrap, because
165 - // req.Files() is already a SliceFile() with all of them,
166 - // so can just use that slice as the wrapper.
167 - var err error
168 - if wrap {
169 - err = addSingleFile(req.Files())
170 - } else {
171 - err = addFilesSeparately(req.Files())
154 + mp := n.Pinning.GetManual()
155 + mp.RemovePinWithMode(rnk, pin.Indirect)
156 + mp.PinWithMode(rnk, pin.Recursive)
157 + return n.Pinning.Flush()
158 + }
159 +
160 + addAllAndPin := func(f files.File) error {
161 + if err := addAllFiles(f); err != nil {
162 + return err
163 }
164 +
165 + rootnd, err := fileAdder.RootNode()
166 if err != nil {
167 + return err
168 + }
169 +
170 + return pinRoot(rootnd)
171 + }
172 +
173 + go func() {
174 + defer close(outChan)
175 + if err := addAllAndPin(req.Files()); err != nil {
176 res.SetError(err, cmds.ErrNormal)
177 return
178 }
@@ -264,12 +266,17 @@ remains to be implemented.
266
267 // Internal structure for holding the switches passed to the `add` call
268 type adder struct {
269 + ctx cxt.Context
270 node *core.IpfsNode
271 + editor *dagutils.Editor
272 out chan interface{}
273 progress bool
274 hidden bool
275 trickle bool
276 + wrap bool
277 chunker string
278 +
279 + nextUntitled int
280 }
281
282 // 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) (*
308 return node, nil
309 }
310
311 +func (params *adder) RootNode() (*dag.Node, error) {
312 + r := params.editor.GetNode()
313 +
314 + // if not wrapping, AND one root file, use that hash as root.
315 + if !params.wrap && len(r.Links) == 1 {
316 + var err error
317 + r, err = r.Links[0].GetNode(params.ctx, params.node.DAG)
318 + // no need to output, as we've already done so.
319 + return r, err
320 + }
321 +
322 + // otherwise need to output, as we have not.
323 + err := outputDagnode(params.out, "", r)
324 + return r, err
325 +}
326 +
327 +func (params *adder) addNode(node *dag.Node, path string) error {
328 + // patch it into the root
329 + key, err := node.Key()
330 + if err != nil {
331 + return err
332 + }
333 +
334 + if path == "" {
335 + path = key.Pretty()
336 + }
337 +
338 + if err := params.editor.InsertNodeAtPath(params.ctx, path, key, newDirNode); err != nil {
339 + return err
340 + }
341 +
342 + return outputDagnode(params.out, path, node)
343 +}
344 +
345 // Add the given file while respecting the params.
346 func (params *adder) addFile(file files.File) (*dag.Node, error) {
347 // Check if file is hidden
@@ -326,11 +367,10 @@ func (params *adder) addFile(file files.File) (*dag.Node, error) {
367 return nil, err
368 }
369
370 + // patch it into the root
371 log.Infof("adding file: %s", file.FileName())
330 - if err := outputDagnode(params.out, file.FileName(), dagnode); err != nil {
331 - return nil, err
332 - }
333 - return dagnode, nil
372 + err = params.addNode(dagnode, file.FileName())
373 + return dagnode, err
374 }
375
376 func (params *adder) addDir(file files.File) (*dag.Node, error) {
@@ -364,8 +404,7 @@ func (params *adder) addDir(file files.File) (*dag.Node, error) {
404 }
405 }
406
367 - err := outputDagnode(params.out, file.FileName(), tree)
368 - if err != nil {
407 + if err := params.addNode(tree, file.FileName()); err != nil {
408 return nil, err
409 }
410
@@ -431,3 +470,8 @@ func (i *progressReader) Read(p []byte) (int, error) {
470
471 return n, err
472 }
473 +
474 +// TODO: generalize this to more than unix-fs nodes.
475 +func newDirNode() *dag.Node {
476 + return &dag.Node{Data: ft.FolderPBData()}
477 +}
core/coreunix/add.go
+3 -3
@@ -50,7 +50,7 @@ func AddR(n *core.IpfsNode, root string) (key string, err error) {
50 }
51 defer f.Close()
52
53 - ff, err := files.NewSerialFile(root, f)
53 + ff, err := files.NewSerialFile(root, root, f)
54 if err != nil {
55 return "", err
56 }
@@ -79,8 +79,8 @@ func AddR(n *core.IpfsNode, root string) (key string, err error) {
79 // Returns the path of the added file ("<dir hash>/filename"), the DAG node of
80 // the directory, and and error if any.
81 func AddWrapped(n *core.IpfsNode, r io.Reader, filename string) (string, *merkledag.Node, error) {
82 - file := files.NewReaderFile(filename, ioutil.NopCloser(r), nil)
83 - dir := files.NewSliceFile("", []files.File{file})
82 + file := files.NewReaderFile(filename, filename, ioutil.NopCloser(r), nil)
83 + dir := files.NewSliceFile("", "", []files.File{file})
84 dagnode, err := addDir(n, dir)
85 if err != nil {
86 return "", nil, err
test/sharness/t0040-add-and-cat.sh
+7 -7
@@ -35,7 +35,7 @@ test_expect_success "ipfs add succeeds" '
35
36 test_expect_success "ipfs add output looks good" '
37 HASH="QmVr26fY1tKyspEJBniVhqxQeEjhF78XerGiqWAwraVLQH" &&
38 - echo "added $HASH mountdir/hello.txt" >expected &&
38 + echo "added $HASH hello.txt" >expected &&
39 test_cmp expected actual
40 '
41
@@ -116,7 +116,7 @@ test_expect_success "'ipfs add' with stdin input succeeds" '
116
117 test_expect_success "'ipfs add' output looks good" '
118 HASH="QmZDhWpi8NvKrekaYYhxKCdNVGWsFFe1CREnAjP1QbPaB3" &&
119 - echo "added $HASH " >expected &&
119 + echo "added $HASH $HASH" >expected &&
120 test_cmp expected actual
121 '
122
@@ -140,9 +140,9 @@ test_expect_success "'ipfs add -r' output looks good" '
140 PLANETS="QmWSgS32xQEcXMeqd3YPJLrNBLSdsfYCep2U7CFkyrjXwY" &&
141 MARS="QmPrrHqJzto9m7SyiRzarwkqPcCSsKR2EB1AyqJfe8L8tN" &&
142 VENUS="QmU5kp3BH3B8tnWUU2Pikdb2maksBNkb92FHRr56hyghh4" &&
143 - echo "added $MARS mountdir/planets/mars.txt" >expected &&
144 - echo "added $VENUS mountdir/planets/venus.txt" >>expected &&
145 - echo "added $PLANETS mountdir/planets" >>expected &&
143 + echo "added $MARS planets/mars.txt" >expected &&
144 + echo "added $VENUS planets/venus.txt" >>expected &&
145 + echo "added $PLANETS planets" >>expected &&
146 test_cmp expected actual
147 '
148
@@ -201,7 +201,7 @@ test_expect_success "'ipfs add bigfile' succeeds" '
201
202 test_expect_success "'ipfs add bigfile' output looks good" '
203 HASH="QmSr7FqYkxYWGoSfy8ZiaMWQ5vosb18DQGCzjwEQnVHkTb" &&
204 - echo "added $HASH mountdir/bigfile" >expected &&
204 + echo "added $HASH bigfile" >expected &&
205 test_cmp expected actual
206 '
207 test_expect_success "'ipfs cat' succeeds" '
@@ -236,7 +236,7 @@ test_expect_success EXPENSIVE "ipfs add bigfile succeeds" '
236
237 test_expect_success EXPENSIVE "ipfs add bigfile output looks good" '
238 HASH="QmU9SWAPPmNEKZB8umYMmjYvN7VyHqABNvdA6GUi4MMEz3" &&
239 - echo "added $HASH mountdir/bigfile" >expected &&
239 + echo "added $HASH bigfile" >expected &&
240 test_cmp expected actual
241 '
242
test/sharness/t0042-add-skip.sh
+11 -11
@@ -22,9 +22,9 @@ test_add_skip() {
22 '
23
24 test_expect_success "'ipfs add -r' did not include . files" '
25 - echo "added QmZy3khu7qf696i5HtkgL2NotsCZ8wzvNZJ1eUdA5n8KaV mountdir/planets/mars.txt
26 -added QmQnv4m3Q5512zgVtpbJ9z85osQrzZzGRn934AGh6iVEXz mountdir/planets/venus.txt
27 -added QmR8nD1Vzk5twWVC6oShTHvv7mMYkVh6dApCByBJyV2oj3 mountdir/planets" >expected
25 + echo "added QmZy3khu7qf696i5HtkgL2NotsCZ8wzvNZJ1eUdA5n8KaV planets/mars.txt
26 +added QmQnv4m3Q5512zgVtpbJ9z85osQrzZzGRn934AGh6iVEXz planets/venus.txt
27 +added QmR8nD1Vzk5twWVC6oShTHvv7mMYkVh6dApCByBJyV2oj3 planets" >expected
28 test_cmp expected actual
29 '
30
@@ -33,14 +33,14 @@ added QmR8nD1Vzk5twWVC6oShTHvv7mMYkVh6dApCByBJyV2oj3 mountdir/planets" >expected
33 '
34
35 test_expect_success "'ipfs add -r --hidden' did include . files" '
36 - echo "added QmcAREBcjgnUpKfyFmUGnfajA1NQS5ydqRp7WfqZ6JF8Dx mountdir/planets/.asteroids/ceres.txt
37 -added QmZ5eaLybJ5GUZBNwy24AA9EEDTDpA4B8qXnuN3cGxu2uF mountdir/planets/.asteroids/pallas.txt
38 -added Qmf6rbs5GF85anDuoxpSAdtuZPM9D2Yt3HngzjUVSQ7kDV mountdir/planets/.asteroids
39 -added QmaowqjedBkUrMUXgzt9c2ZnAJncM9jpJtkFfgdFstGr5a mountdir/planets/.charon.txt
40 -added QmU4zFD5eJtRBsWC63AvpozM9Atiadg9kPVTuTrnCYJiNF mountdir/planets/.pluto.txt
41 -added QmZy3khu7qf696i5HtkgL2NotsCZ8wzvNZJ1eUdA5n8KaV mountdir/planets/mars.txt
42 -added QmQnv4m3Q5512zgVtpbJ9z85osQrzZzGRn934AGh6iVEXz mountdir/planets/venus.txt
43 -added QmetajtFdmzhWYodAsZoVZSiqpeJDAiaw2NwbM3xcWcpDj mountdir/planets" >expected &&
36 + echo "added QmcAREBcjgnUpKfyFmUGnfajA1NQS5ydqRp7WfqZ6JF8Dx planets/.asteroids/ceres.txt
37 +added QmZ5eaLybJ5GUZBNwy24AA9EEDTDpA4B8qXnuN3cGxu2uF planets/.asteroids/pallas.txt
38 +added Qmf6rbs5GF85anDuoxpSAdtuZPM9D2Yt3HngzjUVSQ7kDV planets/.asteroids
39 +added QmaowqjedBkUrMUXgzt9c2ZnAJncM9jpJtkFfgdFstGr5a planets/.charon.txt
40 +added QmU4zFD5eJtRBsWC63AvpozM9Atiadg9kPVTuTrnCYJiNF planets/.pluto.txt
41 +added QmZy3khu7qf696i5HtkgL2NotsCZ8wzvNZJ1eUdA5n8KaV planets/mars.txt
42 +added QmQnv4m3Q5512zgVtpbJ9z85osQrzZzGRn934AGh6iVEXz planets/venus.txt
43 +added QmetajtFdmzhWYodAsZoVZSiqpeJDAiaw2NwbM3xcWcpDj planets" >expected &&
44 test_cmp expected actual
45 '
46
test/sharness/t0043-add-w.sh
+26 -26
@@ -8,42 +8,42 @@ test_description="Test add -w"
8
9 add_w_m='QmazHkwx6mPmmCEi1jR5YzjjQd1g5XzKfYQLzRAg7x5uUk'
10
11 -add_w_1='added Qme987pqNBhZZXy4ckeXiR7zaRQwBabB7fTgHurW2yJfNu m/4r93
11 +add_w_1='added Qme987pqNBhZZXy4ckeXiR7zaRQwBabB7fTgHurW2yJfNu 4r93
12 added Qmf82PSsMpUHcrqxa69KG6Qp5yeK7K9BTizXgG3nvzWcNG '
13
14 -add_w_12='added Qme987pqNBhZZXy4ckeXiR7zaRQwBabB7fTgHurW2yJfNu m/4r93
15 -added QmVb4ntSZZnT2J2zvCmXKMJc52cmZYH6AB37MzeYewnkjs m/4u6ead
14 +add_w_12='added Qme987pqNBhZZXy4ckeXiR7zaRQwBabB7fTgHurW2yJfNu 4r93
15 +added QmVb4ntSZZnT2J2zvCmXKMJc52cmZYH6AB37MzeYewnkjs 4u6ead
16 added QmZPASVB6EsADrLN8S2sak34zEHL8mx4TAVsPJU9cNnQQJ '
17
18 -add_w_21='added QmVb4ntSZZnT2J2zvCmXKMJc52cmZYH6AB37MzeYewnkjs m/4u6ead
19 -added Qme987pqNBhZZXy4ckeXiR7zaRQwBabB7fTgHurW2yJfNu m/4r93
18 +add_w_21='added QmVb4ntSZZnT2J2zvCmXKMJc52cmZYH6AB37MzeYewnkjs 4u6ead
19 +added Qme987pqNBhZZXy4ckeXiR7zaRQwBabB7fTgHurW2yJfNu 4r93
20 added QmZPASVB6EsADrLN8S2sak34zEHL8mx4TAVsPJU9cNnQQJ '
21
22 -add_w_d1='added QmPcaX84tDiTfzdTn8GQxexodgeWH6mHjSss5Zfr5ojssb m/t_1wp-8a2/_jo7/-s782qgs
23 -added QmaVBqquUuXKjkyWHXaXfsaQUxAnsCKS95VRDHU8PzGA4K m/t_1wp-8a2/_jo7/15totauzkak-
24 -added QmaAHFG8cmhW3WLjofx5siSp44VV25ETN6ThzrU8iAqpkR m/t_1wp-8a2/_jo7/galecuirrj4r
25 -added QmeuSfhJNKwBESp1W9H8cfoMdBfW3AeHQDWXbNXQJYWp53 m/t_1wp-8a2/_jo7/mzo50r-1xidf5zx
26 -added QmYC3u5jGWuyFwvTxtvLYm2K3SpWZ31tg3NjpVVvh9cJaJ m/t_1wp-8a2/_jo7/wzvsihy
27 -added QmQkib3f9XNX5sj6WEahLUPFpheTcwSRJwUCSvjcv8b9by m/t_1wp-8a2/_jo7
22 +add_w_d1='added QmPcaX84tDiTfzdTn8GQxexodgeWH6mHjSss5Zfr5ojssb _jo7/-s782qgs
23 +added QmaVBqquUuXKjkyWHXaXfsaQUxAnsCKS95VRDHU8PzGA4K _jo7/15totauzkak-
24 +added QmaAHFG8cmhW3WLjofx5siSp44VV25ETN6ThzrU8iAqpkR _jo7/galecuirrj4r
25 +added QmeuSfhJNKwBESp1W9H8cfoMdBfW3AeHQDWXbNXQJYWp53 _jo7/mzo50r-1xidf5zx
26 +added QmYC3u5jGWuyFwvTxtvLYm2K3SpWZ31tg3NjpVVvh9cJaJ _jo7/wzvsihy
27 +added QmQkib3f9XNX5sj6WEahLUPFpheTcwSRJwUCSvjcv8b9by _jo7
28 added QmNQoesMj1qp8ApE51NbtTjFYksyzkezPD4cat7V2kzbKN '
29
30 -add_w_d2='added QmVaKAt2eVftNKFfKhiBV7Mu5HjCugffuLqWqobSSFgiA7 m/t_1wp-8a2/h3qpecj0
31 -added QmU9Jqks8TPu4vFr6t7EKkAKQrSJuEujNj1AkzoCeTEDFJ m/ha6f0x7su6/gnz66h/1k0xpx34
32 -added QmSLYZycXAufRw3ePMVH2brbtYWCcWsmksGLbHcT8ia9Ke m/ha6f0x7su6/gnz66h/9cwudvacx
33 -added QmfYmpCCAMU9nLe7xbrYsHf5z2R2GxeQnsm4zavUhX9vq2 m/ha6f0x7su6/gnz66h/9ximv51cbo8
34 -added QmWgEE4e2kfx3b8HZcBk5cLrfhoi8kTMQP2MipgPhykuV3 m/ha6f0x7su6/gnz66h/b54ygh6gs
35 -added QmcLbqEqhREGednc6mrVtanee4WHKp5JnUfiwTTHCJwuDf m/ha6f0x7su6/gnz66h/lbl5
36 -added QmVPwNy8pZegpsNmsjjZvdTQn4uCeuZgtzhgWhRSQWjK9x m/ha6f0x7su6/gnz66h
37 -added QmPcaX84tDiTfzdTn8GQxexodgeWH6mHjSss5Zfr5ojssb m/t_1wp-8a2/_jo7/-s782qgs
38 -added QmaVBqquUuXKjkyWHXaXfsaQUxAnsCKS95VRDHU8PzGA4K m/t_1wp-8a2/_jo7/15totauzkak-
39 -added QmaAHFG8cmhW3WLjofx5siSp44VV25ETN6ThzrU8iAqpkR m/t_1wp-8a2/_jo7/galecuirrj4r
40 -added QmeuSfhJNKwBESp1W9H8cfoMdBfW3AeHQDWXbNXQJYWp53 m/t_1wp-8a2/_jo7/mzo50r-1xidf5zx
41 -added QmYC3u5jGWuyFwvTxtvLYm2K3SpWZ31tg3NjpVVvh9cJaJ m/t_1wp-8a2/_jo7/wzvsihy
42 -added QmQkib3f9XNX5sj6WEahLUPFpheTcwSRJwUCSvjcv8b9by m/t_1wp-8a2/_jo7
43 -added Qme987pqNBhZZXy4ckeXiR7zaRQwBabB7fTgHurW2yJfNu m/4r93
30 +add_w_d2='added QmVaKAt2eVftNKFfKhiBV7Mu5HjCugffuLqWqobSSFgiA7 h3qpecj0
31 +added QmU9Jqks8TPu4vFr6t7EKkAKQrSJuEujNj1AkzoCeTEDFJ gnz66h/1k0xpx34
32 +added QmSLYZycXAufRw3ePMVH2brbtYWCcWsmksGLbHcT8ia9Ke gnz66h/9cwudvacx
33 +added QmfYmpCCAMU9nLe7xbrYsHf5z2R2GxeQnsm4zavUhX9vq2 gnz66h/9ximv51cbo8
34 +added QmWgEE4e2kfx3b8HZcBk5cLrfhoi8kTMQP2MipgPhykuV3 gnz66h/b54ygh6gs
35 +added QmcLbqEqhREGednc6mrVtanee4WHKp5JnUfiwTTHCJwuDf gnz66h/lbl5
36 +added QmVPwNy8pZegpsNmsjjZvdTQn4uCeuZgtzhgWhRSQWjK9x gnz66h
37 +added QmPcaX84tDiTfzdTn8GQxexodgeWH6mHjSss5Zfr5ojssb _jo7/-s782qgs
38 +added QmaVBqquUuXKjkyWHXaXfsaQUxAnsCKS95VRDHU8PzGA4K _jo7/15totauzkak-
39 +added QmaAHFG8cmhW3WLjofx5siSp44VV25ETN6ThzrU8iAqpkR _jo7/galecuirrj4r
40 +added QmeuSfhJNKwBESp1W9H8cfoMdBfW3AeHQDWXbNXQJYWp53 _jo7/mzo50r-1xidf5zx
41 +added QmYC3u5jGWuyFwvTxtvLYm2K3SpWZ31tg3NjpVVvh9cJaJ _jo7/wzvsihy
42 +added QmQkib3f9XNX5sj6WEahLUPFpheTcwSRJwUCSvjcv8b9by _jo7
43 +added Qme987pqNBhZZXy4ckeXiR7zaRQwBabB7fTgHurW2yJfNu 4r93
44 added QmTmc46fhKC8Liuh5soy1VotdnHcqLu3r6HpPGwDZCnqL1 '
45
46 -add_w_r='QmWpSjVaMts6cXr4g4uQ9AVadunLKxW7Fhyxk3TXo36hEf'
46 +add_w_r='QmcCksBMDuuyuyfAMMNzEAx6Z7jTrdRy9a23WpufAhG9ji'
47
48 . lib/test-lib.sh
49
test/sharness/t0080-repo.sh
+21 -8
@@ -11,6 +11,15 @@ test_description="Test ipfs repo operations"
11 test_init_ipfs
12 test_launch_ipfs_daemon
13
14 +test_expect_success "'ipfs repo gc' succeeds" '
15 + ipfs repo gc >gc_out_actual
16 +'
17 +
18 +test_expect_success "'ipfs repo gc' looks good (empty)" '
19 + true >empty &&
20 + test_cmp empty gc_out_actual
21 +'
22 +
23 test_expect_success "'ipfs add afile' succeeds" '
24 echo "some text" >afile &&
25 HASH=`ipfs add -q afile`
@@ -25,9 +34,10 @@ test_expect_success "'ipfs repo gc' succeeds" '
34 ipfs repo gc >gc_out_actual
35 '
36
28 -test_expect_success "'ipfs repo gc' looks good (empty)" '
29 - true >empty &&
30 - test_cmp empty gc_out_actual
37 +test_expect_success "'ipfs repo gc' looks good (patch root)" '
38 + PATCH_ROOT=QmQXirSbubiySKnqaFyfs5YzziXRB5JEVQVjU6xsd7innr &&
39 + echo "removed $PATCH_ROOT" >patch_root &&
40 + test_cmp patch_root gc_out_actual
41 '
42
43 test_expect_success "'ipfs repo gc' doesnt remove file" '
@@ -60,7 +70,8 @@ test_expect_success "file no longer pinned" '
70 ipfs refs -r "$HASH_WELCOME_DOCS" >>expected2 &&
71 echo "$HASH_GATEWAY_ASSETS" >>expected2 &&
72 ipfs refs -r "$HASH_GATEWAY_ASSETS" >>expected2 &&
63 - echo QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn >> expected2 &&
73 + EMPTY_DIR=QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn &&
74 + echo "$EMPTY_DIR" >>expected2 &&
75 ipfs pin ls --type=recursive --quiet >actual2 &&
76 test_sort_cmp expected2 actual2
77 '
@@ -96,14 +107,16 @@ test_expect_success "remove direct pin" '
107 '
108
109 test_expect_success "'ipfs repo gc' removes file" '
99 - echo "removed $HASH" >expected7 &&
110 + echo "removed $PATCH_ROOT" >expected7 &&
111 + echo "removed $HASH" >>expected7 &&
112 ipfs repo gc >actual7 &&
101 - test_cmp expected7 actual7
113 + test_sort_cmp expected7 actual7
114 '
115
116 # TODO: there seems to be a serious bug with leveldb not returning a key.
117 test_expect_failure "'ipfs refs local' no longer shows file" '
106 - echo QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn >expected8 &&
118 + EMPTY_DIR=QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn &&
119 + echo "$EMPTY_DIR" >expected8 &&
120 echo "$HASH_WELCOME_DOCS" >>expected8 &&
121 ipfs refs -r "$HASH_WELCOME_DOCS" >>expected8 &&
122 ipfs refs local >actual8 &&
@@ -146,7 +159,7 @@ test_expect_success "'ipfs pin ls --type=recursive' is correct" '
159 echo "$MBLOCKHASH" >rp_expected &&
160 echo "$HASH_WELCOME_DOCS" >>rp_expected &&
161 echo "$HASH_GATEWAY_ASSETS" >>rp_expected &&
149 - echo QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn >>rp_expected &&
162 + echo "$EMPTY_DIR" >>rp_expected &&
163 ipfs refs -r "$HASH_WELCOME_DOCS" >>rp_expected &&
164 ipfs refs -r "$HASH_GATEWAY_ASSETS" >>rp_expected &&
165 sed -i="" "s/\(.*\)/\1 recursive/g" rp_expected &&
test/sharness/t0081-repo-pinning.sh
+1
@@ -100,6 +100,7 @@ test_expect_success "'ipfs add dir' succeeds" '
100 echo "some text 5" >dir1/dir3/file5 &&
101 ipfs add -q -r dir1 | tail -n1 >actual1 &&
102 echo "$HASH_DIR1" >expected1 &&
103 + ipfs repo gc && # remove the patch chaff
104 test_cmp actual1 expected1
105 '
106