original commands to original dir
Brian Tiger Chow committed
Oct 29, 2014 at 00:05 UTC
a5db13f3ae75da38b3145258f77696f22572fe01
13 files changed
+734
core/commands/add.go
new
+122
@@ -0,0 +1,122 @@
1
+package commands
2
+
3
+import (
4
+ "errors"
5
+ "fmt"
6
+ "io"
7
+ "io/ioutil"
8
+ "os"
9
+ "path/filepath"
10
+
11
+ "github.com/jbenet/go-ipfs/core"
12
+ "github.com/jbenet/go-ipfs/importer"
13
+ dag "github.com/jbenet/go-ipfs/merkledag"
14
+ ft "github.com/jbenet/go-ipfs/unixfs"
15
+)
16
+
17
+// Error indicating the max depth has been exceded.
18
+var ErrDepthLimitExceeded = fmt.Errorf("depth limit exceeded")
19
+
20
+// Add is a command that imports files and directories -- given as arguments -- into ipfs.
21
+func Add(n *core.IpfsNode, args []string, opts map[string]interface{}, out io.Writer) error {
22
+ depth := 1
23
+
24
+ // if recursive, set depth to reflect so
25
+ if r, ok := opts["r"].(bool); r && ok {
26
+ depth = -1
27
+ }
28
+
29
+ // add every path in args
30
+ for _, path := range args {
31
+
32
+ // Add the file
33
+ _, err := AddPath(n, path, depth, out)
34
+ if err != nil {
35
+ if err == ErrDepthLimitExceeded && depth == 1 {
36
+ err = errors.New("use -r to recursively add directories")
37
+ }
38
+ return fmt.Errorf("addFile error: %v", err)
39
+ }
40
+
41
+ }
42
+ return nil
43
+}
44
+
45
+// AddPath adds a particular path to ipfs.
46
+func AddPath(n *core.IpfsNode, fpath string, depth int, out io.Writer) (*dag.Node, error) {
47
+ if depth == 0 {
48
+ return nil, ErrDepthLimitExceeded
49
+ }
50
+
51
+ fi, err := os.Stat(fpath)
52
+ if err != nil {
53
+ return nil, err
54
+ }
55
+
56
+ if fi.IsDir() {
57
+ return addDir(n, fpath, depth, out)
58
+ }
59
+
60
+ return addFile(n, fpath, depth, out)
61
+}
62
+
63
+func addDir(n *core.IpfsNode, fpath string, depth int, out io.Writer) (*dag.Node, error) {
64
+ tree := &dag.Node{Data: ft.FolderPBData()}
65
+
66
+ files, err := ioutil.ReadDir(fpath)
67
+ if err != nil {
68
+ return nil, err
69
+ }
70
+
71
+ // construct nodes for containing files.
72
+ for _, f := range files {
73
+ fp := filepath.Join(fpath, f.Name())
74
+ nd, err := AddPath(n, fp, depth-1, out)
75
+ if err != nil {
76
+ return nil, err
77
+ }
78
+
79
+ if err = tree.AddNodeLink(f.Name(), nd); err != nil {
80
+ return nil, err
81
+ }
82
+ }
83
+
84
+ log.Info("adding dir: %s", fpath)
85
+
86
+ return tree, addNode(n, tree, fpath, out)
87
+}
88
+
89
+func addFile(n *core.IpfsNode, fpath string, depth int, out io.Writer) (*dag.Node, error) {
90
+ root, err := importer.NewDagFromFile(fpath)
91
+ if err != nil {
92
+ return nil, err
93
+ }
94
+
95
+ log.Info("adding file: %s", fpath)
96
+
97
+ for _, l := range root.Links {
98
+ log.Info("adding subblock: %s %s", l.Name, l.Hash.B58String())
99
+ }
100
+
101
+ return root, addNode(n, root, fpath, out)
102
+}
103
+
104
+// addNode adds the node to the graph + local storage
105
+func addNode(n *core.IpfsNode, nd *dag.Node, fpath string, out io.Writer) error {
106
+ // add the file to the graph + local storage
107
+ err := n.DAG.AddRecursive(nd)
108
+ if err != nil {
109
+ return err
110
+ }
111
+
112
+ k, err := nd.Key()
113
+ if err != nil {
114
+ return err
115
+ }
116
+
117
+ // output that we've added this node
118
+ fmt.Fprintf(out, "added %s %s\n", k, fpath)
119
+
120
+ // ensure we keep it
121
+ return n.Pinning.Pin(nd, true)
122
+}
core/commands/block.go
new
+60
@@ -0,0 +1,60 @@
1
+package commands
2
+
3
+import (
4
+ "fmt"
5
+ "io"
6
+ "io/ioutil"
7
+ "os"
8
+ "time"
9
+
10
+ "code.google.com/p/go.net/context"
11
+
12
+ mh "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash"
13
+ "github.com/jbenet/go-ipfs/blocks"
14
+ "github.com/jbenet/go-ipfs/core"
15
+ u "github.com/jbenet/go-ipfs/util"
16
+)
17
+
18
+// BlockGet retrives a raw ipfs block from the node's BlockService
19
+func BlockGet(n *core.IpfsNode, args []string, opts map[string]interface{}, out io.Writer) error {
20
+
21
+ if !u.IsValidHash(args[0]) {
22
+ return fmt.Errorf("block get: not a valid hash")
23
+ }
24
+
25
+ h, err := mh.FromB58String(args[0])
26
+ if err != nil {
27
+ return fmt.Errorf("block get: %v", err)
28
+ }
29
+
30
+ k := u.Key(h)
31
+ log.Debug("BlockGet key: '%q'", k)
32
+ ctx, _ := context.WithTimeout(context.TODO(), time.Second*5)
33
+ b, err := n.Blocks.GetBlock(ctx, k)
34
+ if err != nil {
35
+ return fmt.Errorf("block get: %v", err)
36
+ }
37
+
38
+ _, err = out.Write(b.Data)
39
+ return err
40
+}
41
+
42
+// BlockPut reads everything from conn and saves the data to the nodes BlockService
43
+func BlockPut(n *core.IpfsNode, args []string, opts map[string]interface{}, out io.Writer) error {
44
+ // TODO: this should read from an io.Reader arg
45
+ data, err := ioutil.ReadAll(os.Stdin)
46
+ if err != nil {
47
+ return err
48
+ }
49
+
50
+ b := blocks.NewBlock(data)
51
+ log.Debug("BlockPut key: '%q'", b.Key())
52
+
53
+ k, err := n.Blocks.AddBlock(b)
54
+ if err != nil {
55
+ return err
56
+ }
57
+ fmt.Fprintf(out, "added as '%s'\n", k)
58
+
59
+ return nil
60
+}
core/commands/cat.go
new
+29
@@ -0,0 +1,29 @@
1
+package commands
2
+
3
+import (
4
+ "fmt"
5
+ "io"
6
+
7
+ "github.com/jbenet/go-ipfs/core"
8
+ uio "github.com/jbenet/go-ipfs/unixfs/io"
9
+)
10
+
11
+func Cat(n *core.IpfsNode, args []string, opts map[string]interface{}, out io.Writer) error {
12
+ for _, fn := range args {
13
+ dagnode, err := n.Resolver.ResolvePath(fn)
14
+ if err != nil {
15
+ return fmt.Errorf("catFile error: %v", err)
16
+ }
17
+
18
+ read, err := uio.NewDagReader(dagnode, n.DAG)
19
+ if err != nil {
20
+ return fmt.Errorf("cat error: %v", err)
21
+ }
22
+
23
+ _, err = io.Copy(out, read)
24
+ if err != nil {
25
+ return fmt.Errorf("cat error: %v", err)
26
+ }
27
+ }
28
+ return nil
29
+}
core/commands/commands.go
new
+12
@@ -0,0 +1,12 @@
1
+package commands
2
+
3
+import (
4
+ "io"
5
+
6
+ "github.com/jbenet/go-ipfs/core"
7
+ u "github.com/jbenet/go-ipfs/util"
8
+)
9
+
10
+var log = u.Logger("commands")
11
+
12
+type CmdFunc func(*core.IpfsNode, []string, map[string]interface{}, io.Writer) error
core/commands/diag.go
new
+49
@@ -0,0 +1,49 @@
1
+package commands
2
+
3
+import (
4
+ "encoding/json"
5
+ "errors"
6
+ "fmt"
7
+ "io"
8
+ "time"
9
+
10
+ "github.com/jbenet/go-ipfs/core"
11
+ diagn "github.com/jbenet/go-ipfs/diagnostics"
12
+)
13
+
14
+func PrintDiagnostics(info []*diagn.DiagInfo, out io.Writer) {
15
+ for _, i := range info {
16
+ fmt.Fprintf(out, "Peer: %s\n", i.ID)
17
+ fmt.Fprintf(out, "\tUp for: %s\n", i.LifeSpan.String())
18
+ fmt.Fprintf(out, "\tConnected To:\n")
19
+ for _, c := range i.Connections {
20
+ fmt.Fprintf(out, "\t%s\n\t\tLatency = %s\n", c.ID, c.Latency.String())
21
+ }
22
+ fmt.Fprintln(out)
23
+ }
24
+
25
+}
26
+
27
+func Diag(n *core.IpfsNode, args []string, opts map[string]interface{}, out io.Writer) error {
28
+ if n.Diagnostics == nil {
29
+ return errors.New("Cannot run diagnostic in offline mode!")
30
+ }
31
+ info, err := n.Diagnostics.GetDiagnostic(time.Second * 20)
32
+ if err != nil {
33
+ return err
34
+ }
35
+ raw, ok := opts["raw"].(bool)
36
+ if !ok {
37
+ return errors.New("incorrect value to parameter 'raw'")
38
+ }
39
+ if raw {
40
+ enc := json.NewEncoder(out)
41
+ err = enc.Encode(info)
42
+ if err != nil {
43
+ return err
44
+ }
45
+ } else {
46
+ PrintDiagnostics(info, out)
47
+ }
48
+ return nil
49
+}
core/commands/log.go
new
+18
@@ -0,0 +1,18 @@
1
+package commands
2
+
3
+import (
4
+ "io"
5
+
6
+ "github.com/jbenet/go-ipfs/core"
7
+ u "github.com/jbenet/go-ipfs/util"
8
+)
9
+
10
+// Log changes the log level of a subsystem
11
+func Log(n *core.IpfsNode, args []string, opts map[string]interface{}, out io.Writer) error {
12
+ if err := u.SetLogLevel(args[0], args[1]); err != nil {
13
+ return err
14
+ }
15
+
16
+ log.Info("Changed LogLevel of %q to %q", args[0], args[1])
17
+ return nil
18
+}
core/commands/ls.go
new
+22
@@ -0,0 +1,22 @@
1
+package commands
2
+
3
+import (
4
+ "fmt"
5
+ "io"
6
+
7
+ "github.com/jbenet/go-ipfs/core"
8
+)
9
+
10
+func Ls(n *core.IpfsNode, args []string, opts map[string]interface{}, out io.Writer) error {
11
+ for _, fn := range args {
12
+ dagnode, err := n.Resolver.ResolvePath(fn)
13
+ if err != nil {
14
+ return fmt.Errorf("ls error: %v", err)
15
+ }
16
+
17
+ for _, link := range dagnode.Links {
18
+ fmt.Fprintf(out, "%s %d %s\n", link.Hash.B58String(), link.Size, link.Name)
19
+ }
20
+ }
21
+ return nil
22
+}
core/commands/object.go
new
+135
@@ -0,0 +1,135 @@
1
+package commands
2
+
3
+import (
4
+ "bytes"
5
+ "encoding/json"
6
+ "errors"
7
+ "fmt"
8
+ "io"
9
+ "io/ioutil"
10
+ "os"
11
+
12
+ "github.com/jbenet/go-ipfs/core"
13
+ dag "github.com/jbenet/go-ipfs/merkledag"
14
+)
15
+
16
+// ObjectData takes a key string from args and writes out the raw bytes of that node (if there is one)
17
+func ObjectData(n *core.IpfsNode, args []string, opts map[string]interface{}, out io.Writer) error {
18
+ dagnode, err := n.Resolver.ResolvePath(args[0])
19
+ if err != nil {
20
+ return fmt.Errorf("objectData error: %v", err)
21
+ }
22
+ log.Debug("objectData: found dagnode %q (# of bytes: %d - # links: %d)", args[0], len(dagnode.Data), len(dagnode.Links))
23
+
24
+ _, err = io.Copy(out, bytes.NewReader(dagnode.Data))
25
+ return err
26
+}
27
+
28
+// ObjectLinks takes a key string from args and lists the links it points to
29
+func ObjectLinks(n *core.IpfsNode, args []string, opts map[string]interface{}, out io.Writer) error {
30
+ dagnode, err := n.Resolver.ResolvePath(args[0])
31
+ if err != nil {
32
+ return fmt.Errorf("objectLinks error: %v", err)
33
+ }
34
+ log.Debug("ObjectLinks: found dagnode %q (# of bytes: %d - # links: %d)", args[0], len(dagnode.Data), len(dagnode.Links))
35
+
36
+ for _, link := range dagnode.Links {
37
+ _, err = fmt.Fprintf(out, "%s %d %q\n", link.Hash.B58String(), link.Size, link.Name)
38
+ if err != nil {
39
+ break
40
+ }
41
+ }
42
+
43
+ return err
44
+}
45
+
46
+// ErrUnknownObjectEnc is returned if a invalid encoding is supplied
47
+var ErrUnknownObjectEnc = errors.New("unknown object encoding")
48
+
49
+type objectEncoding string
50
+
51
+const (
52
+ objectEncodingJSON objectEncoding = "json"
53
+ objectEncodingProtobuf = "protobuf"
54
+)
55
+
56
+func getObjectEnc(o interface{}) objectEncoding {
57
+ v, ok := o.(string)
58
+ if !ok {
59
+ // chosen as default because it's human readable
60
+ log.Warning("option is not a string - falling back to json")
61
+ return objectEncodingJSON
62
+ }
63
+
64
+ return objectEncoding(v)
65
+}
66
+
67
+// ObjectGet takes a key string from args and a format option and serializes the dagnode to that format
68
+func ObjectGet(n *core.IpfsNode, args []string, opts map[string]interface{}, out io.Writer) error {
69
+ dagnode, err := n.Resolver.ResolvePath(args[0])
70
+ if err != nil {
71
+ return fmt.Errorf("ObjectGet error: %v", err)
72
+ }
73
+ log.Debug("objectGet: found dagnode %q (# of bytes: %d - # links: %d)", args[0], len(dagnode.Data), len(dagnode.Links))
74
+
75
+ // sadly all encodings dont implement a common interface
76
+ var data []byte
77
+ switch getObjectEnc(opts["encoding"]) {
78
+ case objectEncodingJSON:
79
+ data, err = json.MarshalIndent(dagnode, "", " ")
80
+
81
+ case objectEncodingProtobuf:
82
+ data, err = dagnode.Marshal()
83
+
84
+ default:
85
+ return ErrUnknownObjectEnc
86
+ }
87
+
88
+ if err != nil {
89
+ return fmt.Errorf("ObjectGet error: %v", err)
90
+ }
91
+
92
+ _, err = io.Copy(out, bytes.NewReader(data))
93
+ return err
94
+}
95
+
96
+// ErrObjectTooLarge is returned when too much data was read from stdin. current limit 512k
97
+var ErrObjectTooLarge = errors.New("input object was too large. limit is 512kbytes")
98
+
99
+const inputLimit = 512 * 1024
100
+
101
+// ObjectPut takes a format option, serilizes bytes from stdin and updates the dag with that data
102
+func ObjectPut(n *core.IpfsNode, args []string, opts map[string]interface{}, out io.Writer) error {
103
+ var (
104
+ dagnode *dag.Node
105
+ data []byte
106
+ err error
107
+ )
108
+
109
+ data, err = ioutil.ReadAll(io.LimitReader(os.Stdin, inputLimit+10))
110
+ if err != nil {
111
+ return fmt.Errorf("ObjectPut error: %v", err)
112
+ }
113
+
114
+ if len(data) >= inputLimit {
115
+ return ErrObjectTooLarge
116
+ }
117
+
118
+ switch getObjectEnc(opts["encoding"]) {
119
+ case objectEncodingJSON:
120
+ dagnode = new(dag.Node)
121
+ err = json.Unmarshal(data, dagnode)
122
+
123
+ case objectEncodingProtobuf:
124
+ dagnode, err = dag.Decoded(data)
125
+
126
+ default:
127
+ return ErrUnknownObjectEnc
128
+ }
129
+
130
+ if err != nil {
131
+ return fmt.Errorf("ObjectPut error: %v", err)
132
+ }
133
+
134
+ return addNode(n, dagnode, "stdin", out)
135
+}
core/commands/pin.go
new
+58
@@ -0,0 +1,58 @@
1
+package commands
2
+
3
+import (
4
+ "fmt"
5
+ "io"
6
+
7
+ "github.com/jbenet/go-ipfs/core"
8
+)
9
+
10
+func Pin(n *core.IpfsNode, args []string, opts map[string]interface{}, out io.Writer) error {
11
+
12
+ // set recursive flag
13
+ recursive, _ := opts["r"].(bool) // false if cast fails.
14
+
15
+ // if recursive, set depth flag
16
+ depth := 1 // default (non recursive)
17
+ if d, ok := opts["d"].(int); recursive && ok {
18
+ depth = d
19
+ }
20
+ if depth < -1 {
21
+ return fmt.Errorf("ipfs pin: called with invalid depth: %v", depth)
22
+ }
23
+
24
+ fmt.Printf("recursive, depth: %v, %v\n", recursive, depth)
25
+
26
+ for _, fn := range args {
27
+ dagnode, err := n.Resolver.ResolvePath(fn)
28
+ if err != nil {
29
+ return fmt.Errorf("pin error: %v", err)
30
+ }
31
+
32
+ err = n.Pinning.Pin(dagnode, recursive)
33
+ if err != nil {
34
+ return fmt.Errorf("pin: %v", err)
35
+ }
36
+ }
37
+ return n.Pinning.Flush()
38
+}
39
+
40
+func Unpin(n *core.IpfsNode, args []string, opts map[string]interface{}, out io.Writer) error {
41
+
42
+ // set recursive flag
43
+ recursive, _ := opts["r"].(bool) // false if cast fails.
44
+
45
+ for _, fn := range args {
46
+ dagnode, err := n.Resolver.ResolvePath(fn)
47
+ if err != nil {
48
+ return fmt.Errorf("pin error: %v", err)
49
+ }
50
+
51
+ k, _ := dagnode.Key()
52
+ err = n.Pinning.Unpin(k, recursive)
53
+ if err != nil {
54
+ return fmt.Errorf("pin: %v", err)
55
+ }
56
+ }
57
+ return n.Pinning.Flush()
58
+}
core/commands/publish.go
new
+53
@@ -0,0 +1,53 @@
1
+package commands
2
+
3
+import (
4
+ "errors"
5
+ "fmt"
6
+ "io"
7
+
8
+ "github.com/jbenet/go-ipfs/core"
9
+ u "github.com/jbenet/go-ipfs/util"
10
+
11
+ nsys "github.com/jbenet/go-ipfs/namesys"
12
+)
13
+
14
+func Publish(n *core.IpfsNode, args []string, opts map[string]interface{}, out io.Writer) error {
15
+ log.Debug("Begin Publish")
16
+
17
+ if n.Identity == nil {
18
+ return errors.New("Identity not loaded!")
19
+ }
20
+
21
+ // name := ""
22
+ ref := ""
23
+
24
+ switch len(args) {
25
+ case 2:
26
+ // name = args[0]
27
+ ref = args[1]
28
+ return errors.New("keychains not yet implemented")
29
+ case 1:
30
+ // name = n.Identity.ID.String()
31
+ ref = args[0]
32
+
33
+ default:
34
+ return fmt.Errorf("Publish expects 1 or 2 args; got %d.", len(args))
35
+ }
36
+
37
+ // later, n.Keychain.Get(name).PrivKey
38
+ k := n.Identity.PrivKey()
39
+
40
+ pub := nsys.NewRoutingPublisher(n.Routing)
41
+ err := pub.Publish(k, ref)
42
+ if err != nil {
43
+ return err
44
+ }
45
+
46
+ hash, err := k.GetPublic().Hash()
47
+ if err != nil {
48
+ return err
49
+ }
50
+ fmt.Fprintf(out, "published name %s to %s\n", u.Key(hash), ref)
51
+
52
+ return nil
53
+}
core/commands/refs.go
new
+65
@@ -0,0 +1,65 @@
1
+package commands
2
+
3
+import (
4
+ "io"
5
+
6
+ mh "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash"
7
+ "github.com/jbenet/go-ipfs/core"
8
+ mdag "github.com/jbenet/go-ipfs/merkledag"
9
+ u "github.com/jbenet/go-ipfs/util"
10
+)
11
+
12
+func Refs(n *core.IpfsNode, args []string, opts map[string]interface{}, out io.Writer) error {
13
+ unique, ok := opts["u"].(bool)
14
+ if !ok {
15
+ unique = false
16
+ }
17
+
18
+ recursive, ok := opts["r"].(bool)
19
+ if !ok {
20
+ recursive = false
21
+ }
22
+
23
+ var refsSeen map[u.Key]bool
24
+ if unique {
25
+ refsSeen = make(map[u.Key]bool)
26
+ }
27
+
28
+ for _, fn := range args {
29
+ nd, err := n.Resolver.ResolvePath(fn)
30
+ if err != nil {
31
+ return err
32
+ }
33
+
34
+ printRefs(n, nd, refsSeen, recursive)
35
+ }
36
+ return nil
37
+}
38
+
39
+func printRefs(n *core.IpfsNode, nd *mdag.Node, refSeen map[u.Key]bool, recursive bool) {
40
+ for _, link := range nd.Links {
41
+ printRef(link.Hash, refSeen)
42
+
43
+ if recursive {
44
+ nd, err := n.DAG.Get(u.Key(link.Hash))
45
+ if err != nil {
46
+ log.Errorf("error: cannot retrieve %s (%s)", link.Hash.B58String(), err)
47
+ return
48
+ }
49
+
50
+ printRefs(n, nd, refSeen, recursive)
51
+ }
52
+ }
53
+}
54
+
55
+func printRef(h mh.Multihash, refsSeen map[u.Key]bool) {
56
+ if refsSeen != nil {
57
+ _, found := refsSeen[u.Key(h)]
58
+ if found {
59
+ return
60
+ }
61
+ refsSeen[u.Key(h)] = true
62
+ }
63
+
64
+ u.POut("%s\n", h.B58String())
65
+}
core/commands/resolve.go
new
+35
@@ -0,0 +1,35 @@
1
+package commands
2
+
3
+import (
4
+ "errors"
5
+ "fmt"
6
+ "io"
7
+
8
+ "github.com/jbenet/go-ipfs/core"
9
+)
10
+
11
+func Resolve(n *core.IpfsNode, args []string, opts map[string]interface{}, out io.Writer) error {
12
+
13
+ name := ""
14
+
15
+ switch len(args) {
16
+ case 1:
17
+ name = args[0]
18
+ case 0:
19
+ if n.Identity == nil {
20
+ return errors.New("Identity not loaded!")
21
+ }
22
+ name = n.Identity.ID().String()
23
+
24
+ default:
25
+ return fmt.Errorf("Publish expects 1 or 2 args; got %d.", len(args))
26
+ }
27
+
28
+ res, err := n.Namesys.Resolve(name)
29
+ if err != nil {
30
+ return err
31
+ }
32
+
33
+ fmt.Fprintf(out, "%s\n", res)
34
+ return nil
35
+}
core/commands/update.go
new
+76
@@ -0,0 +1,76 @@
1
+package commands
2
+
3
+import (
4
+ "errors"
5
+ "fmt"
6
+ "io"
7
+ "os"
8
+
9
+ "github.com/jbenet/go-ipfs/core"
10
+ "github.com/jbenet/go-ipfs/updates"
11
+)
12
+
13
+// UpdateApply applys an update of the ipfs binary and shuts down the node if successful
14
+func UpdateApply(n *core.IpfsNode, args []string, opts map[string]interface{}, out io.Writer) error {
15
+ fmt.Fprintln(out, "Current Version:", updates.Version)
16
+ u, err := updates.CheckForUpdate()
17
+ if err != nil {
18
+ return err
19
+ }
20
+
21
+ if u == nil {
22
+ fmt.Fprintln(out, "No update available")
23
+ return nil
24
+ }
25
+ fmt.Fprintln(out, "New Version:", u.Version)
26
+
27
+ _, onDaemon := opts["onDaemon"]
28
+ force := opts["force"].(bool)
29
+ if onDaemon && !force {
30
+ return fmt.Errorf(`Error: update must stop running ipfs service.
31
+You may want to abort the update, or shut the service down manually.
32
+To shut it down automatically, run:
33
+
34
+ ipfs update --force
35
+`)
36
+ }
37
+
38
+ if err = updates.Apply(u); err != nil {
39
+ fmt.Fprint(out, err.Error())
40
+ return fmt.Errorf("Couldn't apply update: %v", err)
41
+ }
42
+
43
+ fmt.Fprintln(out, "Updated applied!")
44
+ if onDaemon {
45
+ if force {
46
+ fmt.Fprintln(out, "Shutting down ipfs service.")
47
+ os.Exit(1) // is there a cleaner shutdown routine?
48
+ } else {
49
+ fmt.Fprintln(out, "You can now restart the ipfs service.")
50
+ }
51
+ }
52
+
53
+ return nil
54
+}
55
+
56
+// UpdateCheck checks wether there is an update available
57
+func UpdateCheck(n *core.IpfsNode, args []string, opts map[string]interface{}, out io.Writer) error {
58
+ fmt.Fprintln(out, "Current Version:", updates.Version)
59
+ u, err := updates.CheckForUpdate()
60
+ if err != nil {
61
+ return err
62
+ }
63
+
64
+ if u == nil {
65
+ fmt.Fprintln(out, "No update available")
66
+ return nil
67
+ }
68
+
69
+ fmt.Fprintln(out, "New Version:", u.Version)
70
+ return nil
71
+}
72
+
73
+// UpdateLog lists the version available online
74
+func UpdateLog(n *core.IpfsNode, args []string, opts map[string]interface{}, out io.Writer) error {
75
+ return errors.New("Not yet implemented")
76
+}