pin.go 4.71 KB
Newer Older
1 2 3
package commands

import (
Jeromy's avatar
Jeromy committed
4
	"bytes"
5
	"fmt"
Jeromy's avatar
Jeromy committed
6
	"io"
7 8

	cmds "github.com/jbenet/go-ipfs/commands"
9
	corerepo "github.com/jbenet/go-ipfs/core/repo"
10
	u "github.com/jbenet/go-ipfs/util"
11 12
)

13
var PinCmd = &cmds.Command{
14
	Helptext: cmds.HelpText{
Brian Tiger Chow's avatar
Brian Tiger Chow committed
15
		Tagline: "Pin (and unpin) objects to local storage",
16
	},
17

Brian Tiger Chow's avatar
Brian Tiger Chow committed
18 19 20
	Subcommands: map[string]*cmds.Command{
		"add": addPinCmd,
		"rm":  rmPinCmd,
21
		"ls":  listPinCmd,
Brian Tiger Chow's avatar
Brian Tiger Chow committed
22 23 24
	},
}

Jeromy's avatar
Jeromy committed
25 26 27 28
type PinOutput struct {
	Pinned []u.Key
}

Brian Tiger Chow's avatar
Brian Tiger Chow committed
29
var addPinCmd = &cmds.Command{
30 31 32 33
	Helptext: cmds.HelpText{
		Tagline: "Pins objects to local storage",
		ShortDescription: `
Retrieves the object named by <ipfs-path> and stores it locally
34
on disk.
Brian Tiger Chow's avatar
Brian Tiger Chow committed
35
`,
36
	},
37

38
	Arguments: []cmds.Argument{
39
		cmds.StringArg("ipfs-path", true, true, "Path to object(s) to be pinned").EnableStdin(),
40 41
	},
	Options: []cmds.Option{
42
		cmds.BoolOption("recursive", "r", "Recursively pin the object linked to by the specified object(s)"),
43
	},
Jeromy's avatar
Jeromy committed
44
	Type: PinOutput{},
45
	Run: func(req cmds.Request) (interface{}, error) {
46 47 48 49
		n, err := req.Context().GetNode()
		if err != nil {
			return nil, err
		}
50 51

		// set recursive flag
52 53 54 55 56 57 58
		recursive, found, err := req.Option("recursive").Bool()
		if err != nil {
			return nil, err
		}
		if !found {
			recursive = false
		}
59

60
		added, err := corerepo.Pin(n, req.Arguments(), recursive)
61
		if err != nil {
62
			return nil, err
63 64
		}

Jeromy's avatar
Jeromy committed
65 66 67 68 69 70 71 72 73
		return &PinOutput{added}, nil
	},
	Marshalers: cmds.MarshalerMap{
		cmds.Text: func(res cmds.Response) (io.Reader, error) {
			added, ok := res.Output().(*PinOutput)
			if !ok {
				return nil, u.ErrCast()
			}

Jeromy's avatar
Jeromy committed
74 75 76 77 78 79 80 81
			var pintype string
			rec, _, _ := res.Request().Option("recursive").Bool()
			if rec {
				pintype = "recursively"
			} else {
				pintype = "directly"
			}

Jeromy's avatar
Jeromy committed
82 83
			buf := new(bytes.Buffer)
			for _, k := range added.Pinned {
Jeromy's avatar
Jeromy committed
84
				fmt.Fprintf(buf, "pinned %s %s\n", k, pintype)
Jeromy's avatar
Jeromy committed
85 86 87
			}
			return buf, nil
		},
88 89 90
	},
}

Brian Tiger Chow's avatar
Brian Tiger Chow committed
91
var rmPinCmd = &cmds.Command{
92 93 94 95
	Helptext: cmds.HelpText{
		Tagline: "Unpin an object from local storage",
		ShortDescription: `
Removes the pin from the given object allowing it to be garbage
96
collected if needed.
Brian Tiger Chow's avatar
Brian Tiger Chow committed
97
`,
98
	},
99

100
	Arguments: []cmds.Argument{
101
		cmds.StringArg("ipfs-path", true, true, "Path to object(s) to be unpinned").EnableStdin(),
102 103
	},
	Options: []cmds.Option{
104
		cmds.BoolOption("recursive", "r", "Recursively unpin the object linked to by the specified object(s)"),
105
	},
Jeromy's avatar
Jeromy committed
106
	Type: PinOutput{},
107
	Run: func(req cmds.Request) (interface{}, error) {
108 109 110 111
		n, err := req.Context().GetNode()
		if err != nil {
			return nil, err
		}
112 113

		// set recursive flag
114 115 116 117 118 119 120
		recursive, found, err := req.Option("recursive").Bool()
		if err != nil {
			return nil, err
		}
		if !found {
			recursive = false // default
		}
121

122
		removed, err := corerepo.Unpin(n, req.Arguments(), recursive)
123
		if err != nil {
124
			return nil, err
125 126
		}

Jeromy's avatar
Jeromy committed
127 128 129 130 131 132 133 134 135 136 137
		return &PinOutput{removed}, nil
	},
	Marshalers: cmds.MarshalerMap{
		cmds.Text: func(res cmds.Response) (io.Reader, error) {
			added, ok := res.Output().(*PinOutput)
			if !ok {
				return nil, u.ErrCast()
			}

			buf := new(bytes.Buffer)
			for _, k := range added.Pinned {
Jeromy's avatar
Jeromy committed
138
				fmt.Fprintf(buf, "unpinned %s\n", k)
Jeromy's avatar
Jeromy committed
139 140 141
			}
			return buf, nil
		},
142 143
	},
}
Brian Tiger Chow's avatar
Brian Tiger Chow committed
144

145 146 147 148 149 150
var listPinCmd = &cmds.Command{
	Helptext: cmds.HelpText{
		Tagline: "List objects pinned to local storage",
		ShortDescription: `
Returns a list of hashes of objects being pinned. Objects that are indirectly
or recursively pinned are not included in the list.
151 152 153 154 155 156 157 158 159 160 161
`,
		LongDescription: `
Returns a list of hashes of objects being pinned. Objects that are indirectly
or recursively pinned are not included in the list.

Use --type=<type> to specify the type of pinned keys to list. Valid values are:
    * "direct"
    * "indirect"
    * "recursive"
    * "all"
(Defaults to "direct")
162 163 164
`,
	},

165
	Options: []cmds.Option{
166
		cmds.StringOption("type", "t", "The type of pinned keys to list. Can be \"direct\", \"indirect\", \"recursive\", or \"all\". Defaults to \"direct\""),
167
	},
168 169 170 171 172 173
	Run: func(req cmds.Request) (interface{}, error) {
		n, err := req.Context().GetNode()
		if err != nil {
			return nil, err
		}

174 175 176 177 178
		typeStr, found, err := req.Option("type").String()
		if err != nil {
			return nil, err
		}
		if !found {
179
			typeStr = "direct"
180 181
		}

182 183 184 185
		switch typeStr {
		case "all", "direct", "indirect", "recursive":
		default:
			return nil, cmds.ClientError("Invalid type '" + typeStr + "', must be one of {direct, indirect, recursive, all}")
186 187 188 189 190 191 192 193 194 195 196 197 198 199
		}

		keys := make([]u.Key, 0)
		if typeStr == "direct" || typeStr == "all" {
			keys = append(keys, n.Pinning.DirectKeys()...)
		}
		if typeStr == "indirect" || typeStr == "all" {
			keys = append(keys, n.Pinning.IndirectKeys()...)
		}
		if typeStr == "recursive" || typeStr == "all" {
			keys = append(keys, n.Pinning.RecursiveKeys()...)
		}

		return &KeyList{Keys: keys}, nil
200
	},
201
	Type: KeyList{},
202 203
	Marshalers: cmds.MarshalerMap{
		cmds.Text: KeyListTextMarshaler,
204 205
	},
}