github.com/devfans/go-ethereum@v1.5.10-0.20170326212234-7419d0c38291/cmd/swarm/manifest.go (about) 1 // Copyright 2016 The go-ethereum Authors 2 // This file is part of go-ethereum. 3 // 4 // go-ethereum is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // go-ethereum is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. 16 17 // Command MANIFEST update 18 package main 19 20 import ( 21 "encoding/json" 22 "fmt" 23 "mime" 24 "path/filepath" 25 "strings" 26 27 "github.com/ethereum/go-ethereum/cmd/utils" 28 "gopkg.in/urfave/cli.v1" 29 ) 30 31 func add(ctx *cli.Context) { 32 args := ctx.Args() 33 if len(args) < 3 { 34 utils.Fatalf("Need atleast three arguments <MHASH> <path> <HASH> [<content-type>]") 35 } 36 37 var ( 38 mhash = args[0] 39 path = args[1] 40 hash = args[2] 41 42 ctype string 43 wantManifest = ctx.GlobalBoolT(SwarmWantManifestFlag.Name) 44 mroot manifest 45 ) 46 47 if len(args) > 3 { 48 ctype = args[3] 49 } else { 50 ctype = mime.TypeByExtension(filepath.Ext(path)) 51 } 52 53 newManifest := addEntryToManifest(ctx, mhash, path, hash, ctype) 54 fmt.Println(newManifest) 55 56 if !wantManifest { 57 // Print the manifest. This is the only output to stdout. 58 mrootJSON, _ := json.MarshalIndent(mroot, "", " ") 59 fmt.Println(string(mrootJSON)) 60 return 61 } 62 } 63 64 func update(ctx *cli.Context) { 65 66 args := ctx.Args() 67 if len(args) < 3 { 68 utils.Fatalf("Need atleast three arguments <MHASH> <path> <HASH>") 69 } 70 71 var ( 72 mhash = args[0] 73 path = args[1] 74 hash = args[2] 75 76 ctype string 77 wantManifest = ctx.GlobalBoolT(SwarmWantManifestFlag.Name) 78 mroot manifest 79 ) 80 if len(args) > 3 { 81 ctype = args[3] 82 } else { 83 ctype = mime.TypeByExtension(filepath.Ext(path)) 84 } 85 86 newManifest := updateEntryInManifest(ctx, mhash, path, hash, ctype) 87 fmt.Println(newManifest) 88 89 if !wantManifest { 90 // Print the manifest. This is the only output to stdout. 91 mrootJSON, _ := json.MarshalIndent(mroot, "", " ") 92 fmt.Println(string(mrootJSON)) 93 return 94 } 95 } 96 97 func remove(ctx *cli.Context) { 98 args := ctx.Args() 99 if len(args) < 2 { 100 utils.Fatalf("Need atleast two arguments <MHASH> <path>") 101 } 102 103 var ( 104 mhash = args[0] 105 path = args[1] 106 107 wantManifest = ctx.GlobalBoolT(SwarmWantManifestFlag.Name) 108 mroot manifest 109 ) 110 111 newManifest := removeEntryFromManifest(ctx, mhash, path) 112 fmt.Println(newManifest) 113 114 if !wantManifest { 115 // Print the manifest. This is the only output to stdout. 116 mrootJSON, _ := json.MarshalIndent(mroot, "", " ") 117 fmt.Println(string(mrootJSON)) 118 return 119 } 120 } 121 122 func addEntryToManifest(ctx *cli.Context, mhash, path, hash, ctype string) string { 123 124 var ( 125 bzzapi = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/") 126 client = &client{api: bzzapi} 127 longestPathEntry = manifestEntry{ 128 Path: "", 129 Hash: "", 130 ContentType: "", 131 } 132 ) 133 134 mroot, err := client.downloadManifest(mhash) 135 if err != nil { 136 utils.Fatalf("Manifest download failed: %v", err) 137 } 138 139 //TODO: check if the "hash" to add is valid and present in swarm 140 _, err = client.downloadManifest(hash) 141 if err != nil { 142 utils.Fatalf("Hash to add is not present: %v", err) 143 } 144 145 // See if we path is in this Manifest or do we have to dig deeper 146 for _, entry := range mroot.Entries { 147 if path == entry.Path { 148 utils.Fatalf("Path %s already present, not adding anything", path) 149 } else { 150 if entry.ContentType == "application/bzz-manifest+json" { 151 prfxlen := strings.HasPrefix(path, entry.Path) 152 if prfxlen && len(path) > len(longestPathEntry.Path) { 153 longestPathEntry = entry 154 } 155 } 156 } 157 } 158 159 if longestPathEntry.Path != "" { 160 // Load the child Manifest add the entry there 161 newPath := path[len(longestPathEntry.Path):] 162 newHash := addEntryToManifest(ctx, longestPathEntry.Hash, newPath, hash, ctype) 163 164 // Replace the hash for parent Manifests 165 newMRoot := manifest{} 166 for _, entry := range mroot.Entries { 167 if longestPathEntry.Path == entry.Path { 168 entry.Hash = newHash 169 } 170 newMRoot.Entries = append(newMRoot.Entries, entry) 171 } 172 mroot = newMRoot 173 } else { 174 // Add the entry in the leaf Manifest 175 newEntry := manifestEntry{ 176 Path: path, 177 Hash: hash, 178 ContentType: ctype, 179 } 180 mroot.Entries = append(mroot.Entries, newEntry) 181 } 182 183 newManifestHash, err := client.uploadManifest(mroot) 184 if err != nil { 185 utils.Fatalf("Manifest upload failed: %v", err) 186 } 187 return newManifestHash 188 189 } 190 191 func updateEntryInManifest(ctx *cli.Context, mhash, path, hash, ctype string) string { 192 193 var ( 194 bzzapi = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/") 195 client = &client{api: bzzapi} 196 newEntry = manifestEntry{ 197 Path: "", 198 Hash: "", 199 ContentType: "", 200 } 201 longestPathEntry = manifestEntry{ 202 Path: "", 203 Hash: "", 204 ContentType: "", 205 } 206 ) 207 208 mroot, err := client.downloadManifest(mhash) 209 if err != nil { 210 utils.Fatalf("Manifest download failed: %v", err) 211 } 212 213 //TODO: check if the "hash" with which to update is valid and present in swarm 214 215 // See if we path is in this Manifest or do we have to dig deeper 216 for _, entry := range mroot.Entries { 217 if path == entry.Path { 218 newEntry = entry 219 } else { 220 if entry.ContentType == "application/bzz-manifest+json" { 221 prfxlen := strings.HasPrefix(path, entry.Path) 222 if prfxlen && len(path) > len(longestPathEntry.Path) { 223 longestPathEntry = entry 224 } 225 } 226 } 227 } 228 229 if longestPathEntry.Path == "" && newEntry.Path == "" { 230 utils.Fatalf("Path %s not present in the Manifest, not setting anything", path) 231 } 232 233 if longestPathEntry.Path != "" { 234 // Load the child Manifest add the entry there 235 newPath := path[len(longestPathEntry.Path):] 236 newHash := updateEntryInManifest(ctx, longestPathEntry.Hash, newPath, hash, ctype) 237 238 // Replace the hash for parent Manifests 239 newMRoot := manifest{} 240 for _, entry := range mroot.Entries { 241 if longestPathEntry.Path == entry.Path { 242 entry.Hash = newHash 243 } 244 newMRoot.Entries = append(newMRoot.Entries, entry) 245 246 } 247 mroot = newMRoot 248 } 249 250 if newEntry.Path != "" { 251 // Replace the hash for leaf Manifest 252 newMRoot := manifest{} 253 for _, entry := range mroot.Entries { 254 if newEntry.Path == entry.Path { 255 myEntry := manifestEntry{ 256 Path: entry.Path, 257 Hash: hash, 258 ContentType: ctype, 259 } 260 newMRoot.Entries = append(newMRoot.Entries, myEntry) 261 } else { 262 newMRoot.Entries = append(newMRoot.Entries, entry) 263 } 264 } 265 mroot = newMRoot 266 } 267 268 newManifestHash, err := client.uploadManifest(mroot) 269 if err != nil { 270 utils.Fatalf("Manifest upload failed: %v", err) 271 } 272 return newManifestHash 273 } 274 275 func removeEntryFromManifest(ctx *cli.Context, mhash, path string) string { 276 277 var ( 278 bzzapi = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/") 279 client = &client{api: bzzapi} 280 entryToRemove = manifestEntry{ 281 Path: "", 282 Hash: "", 283 ContentType: "", 284 } 285 longestPathEntry = manifestEntry{ 286 Path: "", 287 Hash: "", 288 ContentType: "", 289 } 290 ) 291 292 mroot, err := client.downloadManifest(mhash) 293 if err != nil { 294 utils.Fatalf("Manifest download failed: %v", err) 295 } 296 297 // See if we path is in this Manifest or do we have to dig deeper 298 for _, entry := range mroot.Entries { 299 if path == entry.Path { 300 entryToRemove = entry 301 } else { 302 if entry.ContentType == "application/bzz-manifest+json" { 303 prfxlen := strings.HasPrefix(path, entry.Path) 304 if prfxlen && len(path) > len(longestPathEntry.Path) { 305 longestPathEntry = entry 306 } 307 } 308 } 309 } 310 311 if longestPathEntry.Path == "" && entryToRemove.Path == "" { 312 utils.Fatalf("Path %s not present in the Manifest, not removing anything", path) 313 } 314 315 if longestPathEntry.Path != "" { 316 // Load the child Manifest remove the entry there 317 newPath := path[len(longestPathEntry.Path):] 318 newHash := removeEntryFromManifest(ctx, longestPathEntry.Hash, newPath) 319 320 // Replace the hash for parent Manifests 321 newMRoot := manifest{} 322 for _, entry := range mroot.Entries { 323 if longestPathEntry.Path == entry.Path { 324 entry.Hash = newHash 325 } 326 newMRoot.Entries = append(newMRoot.Entries, entry) 327 } 328 mroot = newMRoot 329 } 330 331 if entryToRemove.Path != "" { 332 // remove the entry in this Manifest 333 newMRoot := manifest{} 334 for _, entry := range mroot.Entries { 335 if entryToRemove.Path != entry.Path { 336 newMRoot.Entries = append(newMRoot.Entries, entry) 337 } 338 } 339 mroot = newMRoot 340 } 341 342 newManifestHash, err := client.uploadManifest(mroot) 343 if err != nil { 344 utils.Fatalf("Manifest upload failed: %v", err) 345 } 346 return newManifestHash 347 }