github.com/keltia/go-ipfs@v0.3.8-0.20150909044612-210793031c63/core/commands/pin.go (about) 1 package commands 2 3 import ( 4 "bytes" 5 "fmt" 6 "io" 7 8 key "github.com/ipfs/go-ipfs/blocks/key" 9 cmds "github.com/ipfs/go-ipfs/commands" 10 corerepo "github.com/ipfs/go-ipfs/core/corerepo" 11 u "github.com/ipfs/go-ipfs/util" 12 ) 13 14 var PinCmd = &cmds.Command{ 15 Helptext: cmds.HelpText{ 16 Tagline: "Pin (and unpin) objects to local storage", 17 }, 18 19 Subcommands: map[string]*cmds.Command{ 20 "add": addPinCmd, 21 "rm": rmPinCmd, 22 "ls": listPinCmd, 23 }, 24 } 25 26 type PinOutput struct { 27 Pinned []key.Key 28 } 29 30 var addPinCmd = &cmds.Command{ 31 Helptext: cmds.HelpText{ 32 Tagline: "Pins objects to local storage", 33 ShortDescription: ` 34 Retrieves the object named by <ipfs-path> and stores it locally 35 on disk. 36 `, 37 }, 38 39 Arguments: []cmds.Argument{ 40 cmds.StringArg("ipfs-path", true, true, "Path to object(s) to be pinned").EnableStdin(), 41 }, 42 Options: []cmds.Option{ 43 cmds.BoolOption("recursive", "r", "Recursively pin the object linked to by the specified object(s)"), 44 }, 45 Type: PinOutput{}, 46 Run: func(req cmds.Request, res cmds.Response) { 47 n, err := req.InvocContext().GetNode() 48 if err != nil { 49 res.SetError(err, cmds.ErrNormal) 50 return 51 } 52 53 // set recursive flag 54 recursive, found, err := req.Option("recursive").Bool() 55 if err != nil { 56 res.SetError(err, cmds.ErrNormal) 57 return 58 } 59 if !found { 60 recursive = false 61 } 62 63 added, err := corerepo.Pin(n, req.Context(), req.Arguments(), recursive) 64 if err != nil { 65 res.SetError(err, cmds.ErrNormal) 66 return 67 } 68 69 res.SetOutput(&PinOutput{added}) 70 }, 71 Marshalers: cmds.MarshalerMap{ 72 cmds.Text: func(res cmds.Response) (io.Reader, error) { 73 added, ok := res.Output().(*PinOutput) 74 if !ok { 75 return nil, u.ErrCast() 76 } 77 78 var pintype string 79 rec, _, _ := res.Request().Option("recursive").Bool() 80 if rec { 81 pintype = "recursively" 82 } else { 83 pintype = "directly" 84 } 85 86 buf := new(bytes.Buffer) 87 for _, k := range added.Pinned { 88 fmt.Fprintf(buf, "pinned %s %s\n", k, pintype) 89 } 90 return buf, nil 91 }, 92 }, 93 } 94 95 var rmPinCmd = &cmds.Command{ 96 Helptext: cmds.HelpText{ 97 Tagline: "Unpin an object from local storage", 98 ShortDescription: ` 99 Removes the pin from the given object allowing it to be garbage 100 collected if needed. 101 `, 102 }, 103 104 Arguments: []cmds.Argument{ 105 cmds.StringArg("ipfs-path", true, true, "Path to object(s) to be unpinned").EnableStdin(), 106 }, 107 Options: []cmds.Option{ 108 cmds.BoolOption("recursive", "r", "Recursively unpin the object linked to by the specified object(s)"), 109 }, 110 Type: PinOutput{}, 111 Run: func(req cmds.Request, res cmds.Response) { 112 n, err := req.InvocContext().GetNode() 113 if err != nil { 114 res.SetError(err, cmds.ErrNormal) 115 return 116 } 117 118 // set recursive flag 119 recursive, found, err := req.Option("recursive").Bool() 120 if err != nil { 121 res.SetError(err, cmds.ErrNormal) 122 return 123 } 124 if !found { 125 recursive = false // default 126 } 127 128 removed, err := corerepo.Unpin(n, req.Context(), req.Arguments(), recursive) 129 if err != nil { 130 res.SetError(err, cmds.ErrNormal) 131 return 132 } 133 134 res.SetOutput(&PinOutput{removed}) 135 }, 136 Marshalers: cmds.MarshalerMap{ 137 cmds.Text: func(res cmds.Response) (io.Reader, error) { 138 added, ok := res.Output().(*PinOutput) 139 if !ok { 140 return nil, u.ErrCast() 141 } 142 143 buf := new(bytes.Buffer) 144 for _, k := range added.Pinned { 145 fmt.Fprintf(buf, "unpinned %s\n", k) 146 } 147 return buf, nil 148 }, 149 }, 150 } 151 152 var listPinCmd = &cmds.Command{ 153 Helptext: cmds.HelpText{ 154 Tagline: "List objects pinned to local storage", 155 ShortDescription: ` 156 Returns a list of hashes of objects being pinned. Objects that are indirectly 157 or recursively pinned are not included in the list. 158 `, 159 LongDescription: ` 160 Returns a list of hashes of objects being pinned. Objects that are indirectly 161 or recursively pinned are not included in the list. 162 163 Use --type=<type> to specify the type of pinned keys to list. Valid values are: 164 * "direct": pin that specific object. 165 * "recursive": pin that specific object, and indirectly pin all its decendants 166 * "indirect": pinned indirectly by an ancestor (like a refcount) 167 * "all" 168 169 To see the ref count on indirect pins, pass the -count option flag. 170 Defaults to "direct". 171 `, 172 }, 173 174 Options: []cmds.Option{ 175 cmds.StringOption("type", "t", "The type of pinned keys to list. Can be \"direct\", \"indirect\", \"recursive\", or \"all\". Defaults to \"direct\""), 176 cmds.BoolOption("count", "n", "Show refcount when listing indirect pins"), 177 cmds.BoolOption("quiet", "q", "Write just hashes of objects"), 178 }, 179 Run: func(req cmds.Request, res cmds.Response) { 180 n, err := req.InvocContext().GetNode() 181 if err != nil { 182 res.SetError(err, cmds.ErrNormal) 183 return 184 } 185 186 typeStr, found, err := req.Option("type").String() 187 if err != nil { 188 res.SetError(err, cmds.ErrNormal) 189 return 190 } 191 if !found { 192 typeStr = "direct" 193 } 194 195 switch typeStr { 196 case "all", "direct", "indirect", "recursive": 197 default: 198 err = fmt.Errorf("Invalid type '%s', must be one of {direct, indirect, recursive, all}", typeStr) 199 res.SetError(err, cmds.ErrClient) 200 } 201 202 keys := make(map[string]RefKeyObject) 203 if typeStr == "direct" || typeStr == "all" { 204 for _, k := range n.Pinning.DirectKeys() { 205 keys[k.B58String()] = RefKeyObject{ 206 Type: "direct", 207 Count: 1, 208 } 209 } 210 } 211 if typeStr == "indirect" || typeStr == "all" { 212 for k, v := range n.Pinning.IndirectKeys() { 213 keys[k.B58String()] = RefKeyObject{ 214 Type: "indirect", 215 Count: v, 216 } 217 } 218 } 219 if typeStr == "recursive" || typeStr == "all" { 220 for _, k := range n.Pinning.RecursiveKeys() { 221 keys[k.B58String()] = RefKeyObject{ 222 Type: "recursive", 223 Count: 1, 224 } 225 } 226 } 227 228 res.SetOutput(&RefKeyList{Keys: keys}) 229 }, 230 Type: RefKeyList{}, 231 Marshalers: cmds.MarshalerMap{ 232 cmds.Text: func(res cmds.Response) (io.Reader, error) { 233 typeStr, _, err := res.Request().Option("type").String() 234 if err != nil { 235 return nil, err 236 } 237 238 count, _, err := res.Request().Option("count").Bool() 239 if err != nil { 240 return nil, err 241 } 242 243 quiet, _, err := res.Request().Option("quiet").Bool() 244 if err != nil { 245 return nil, err 246 } 247 248 keys, ok := res.Output().(*RefKeyList) 249 if !ok { 250 return nil, u.ErrCast() 251 } 252 out := new(bytes.Buffer) 253 if typeStr == "indirect" && count { 254 for k, v := range keys.Keys { 255 if quiet { 256 fmt.Fprintf(out, "%s %d\n", k, v.Count) 257 } else { 258 fmt.Fprintf(out, "%s %s %d\n", k, v.Type, v.Count) 259 } 260 } 261 } else { 262 for k, v := range keys.Keys { 263 if quiet { 264 fmt.Fprintf(out, "%s\n", k) 265 } else { 266 fmt.Fprintf(out, "%s %s\n", k, v.Type) 267 } 268 } 269 } 270 return out, nil 271 }, 272 }, 273 } 274 275 type RefKeyObject struct { 276 Type string 277 Count int 278 } 279 280 type RefKeyList struct { 281 Keys map[string]RefKeyObject 282 }