pin.go 4.54 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 74 75 76 77 78 79
		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()
			}

			buf := new(bytes.Buffer)
			for _, k := range added.Pinned {
				fmt.Fprintf(buf, "Pinned %s\n", k)
			}
			return buf, nil
		},
80 81 82
	},
}

Brian Tiger Chow's avatar
Brian Tiger Chow committed
83
var rmPinCmd = &cmds.Command{
84 85 86 87
	Helptext: cmds.HelpText{
		Tagline: "Unpin an object from local storage",
		ShortDescription: `
Removes the pin from the given object allowing it to be garbage
88
collected if needed.
Brian Tiger Chow's avatar
Brian Tiger Chow committed
89
`,
90
	},
91

92
	Arguments: []cmds.Argument{
93
		cmds.StringArg("ipfs-path", true, true, "Path to object(s) to be unpinned").EnableStdin(),
94 95
	},
	Options: []cmds.Option{
96
		cmds.BoolOption("recursive", "r", "Recursively unpin the object linked to by the specified object(s)"),
97
	},
Jeromy's avatar
Jeromy committed
98
	Type: PinOutput{},
99
	Run: func(req cmds.Request) (interface{}, error) {
100 101 102 103
		n, err := req.Context().GetNode()
		if err != nil {
			return nil, err
		}
104 105

		// set recursive flag
106 107 108 109 110 111 112
		recursive, found, err := req.Option("recursive").Bool()
		if err != nil {
			return nil, err
		}
		if !found {
			recursive = false // default
		}
113

114
		removed, err := corerepo.Unpin(n, req.Arguments(), recursive)
115
		if err != nil {
116
			return nil, err
117 118
		}

Jeromy's avatar
Jeromy committed
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
		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 {
				fmt.Fprintf(buf, "Unpinned %s\n", k)
			}
			return buf, nil
		},
134 135
	},
}
Brian Tiger Chow's avatar
Brian Tiger Chow committed
136

137 138 139 140 141 142
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.
143 144 145 146 147 148 149 150 151 152 153
`,
		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")
154 155 156
`,
	},

157
	Options: []cmds.Option{
158
		cmds.StringOption("type", "t", "The type of pinned keys to list. Can be \"direct\", \"indirect\", \"recursive\", or \"all\". Defaults to \"direct\""),
159
	},
160 161 162 163 164 165
	Run: func(req cmds.Request) (interface{}, error) {
		n, err := req.Context().GetNode()
		if err != nil {
			return nil, err
		}

166 167 168 169 170
		typeStr, found, err := req.Option("type").String()
		if err != nil {
			return nil, err
		}
		if !found {
171
			typeStr = "direct"
172 173
		}

174 175 176 177
		switch typeStr {
		case "all", "direct", "indirect", "recursive":
		default:
			return nil, cmds.ClientError("Invalid type '" + typeStr + "', must be one of {direct, indirect, recursive, all}")
178 179 180 181 182 183 184 185 186 187 188 189 190 191
		}

		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
192
	},
193
	Type: KeyList{},
194 195
	Marshalers: cmds.MarshalerMap{
		cmds.Text: KeyListTextMarshaler,
196 197
	},
}