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"
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"
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
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 {
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
}
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
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
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) {
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
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
+}