github.com/pslzym/go-ethereum@v1.8.17-0.20180926104442-4b6824e07b1b/cmd/swarm/manifest.go (about) 1 // Copyright 2017 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 "fmt" 22 "os" 23 "strings" 24 25 "github.com/ethereum/go-ethereum/cmd/utils" 26 "github.com/ethereum/go-ethereum/swarm/api" 27 swarm "github.com/ethereum/go-ethereum/swarm/api/client" 28 "gopkg.in/urfave/cli.v1" 29 ) 30 31 // manifestAdd adds a new entry to the manifest at the given path. 32 // New entry hash, the last argument, must be the hash of a manifest 33 // with only one entry, which meta-data will be added to the original manifest. 34 // On success, this function will print new (updated) manifest's hash. 35 func manifestAdd(ctx *cli.Context) { 36 args := ctx.Args() 37 if len(args) != 3 { 38 utils.Fatalf("Need exactly three arguments <MHASH> <path> <HASH>") 39 } 40 41 var ( 42 mhash = args[0] 43 path = args[1] 44 hash = args[2] 45 ) 46 47 bzzapi := strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/") 48 client := swarm.NewClient(bzzapi) 49 50 m, _, err := client.DownloadManifest(hash) 51 if err != nil { 52 utils.Fatalf("Error downloading manifest to add: %v", err) 53 } 54 l := len(m.Entries) 55 if l == 0 { 56 utils.Fatalf("No entries in manifest %s", hash) 57 } else if l > 1 { 58 utils.Fatalf("Too many entries in manifest %s", hash) 59 } 60 61 newManifest := addEntryToManifest(client, mhash, path, m.Entries[0]) 62 fmt.Println(newManifest) 63 } 64 65 // manifestUpdate replaces an existing entry of the manifest at the given path. 66 // New entry hash, the last argument, must be the hash of a manifest 67 // with only one entry, which meta-data will be added to the original manifest. 68 // On success, this function will print hash of the updated manifest. 69 func manifestUpdate(ctx *cli.Context) { 70 args := ctx.Args() 71 if len(args) != 3 { 72 utils.Fatalf("Need exactly three arguments <MHASH> <path> <HASH>") 73 } 74 75 var ( 76 mhash = args[0] 77 path = args[1] 78 hash = args[2] 79 ) 80 81 bzzapi := strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/") 82 client := swarm.NewClient(bzzapi) 83 84 m, _, err := client.DownloadManifest(hash) 85 if err != nil { 86 utils.Fatalf("Error downloading manifest to update: %v", err) 87 } 88 l := len(m.Entries) 89 if l == 0 { 90 utils.Fatalf("No entries in manifest %s", hash) 91 } else if l > 1 { 92 utils.Fatalf("Too many entries in manifest %s", hash) 93 } 94 95 newManifest, _, defaultEntryUpdated := updateEntryInManifest(client, mhash, path, m.Entries[0], true) 96 if defaultEntryUpdated { 97 // Print informational message to stderr 98 // allowing the user to get the new manifest hash from stdout 99 // without the need to parse the complete output. 100 fmt.Fprintln(os.Stderr, "Manifest default entry is updated, too") 101 } 102 fmt.Println(newManifest) 103 } 104 105 // manifestRemove removes an existing entry of the manifest at the given path. 106 // On success, this function will print hash of the manifest which does not 107 // contain the path. 108 func manifestRemove(ctx *cli.Context) { 109 args := ctx.Args() 110 if len(args) != 2 { 111 utils.Fatalf("Need exactly two arguments <MHASH> <path>") 112 } 113 114 var ( 115 mhash = args[0] 116 path = args[1] 117 ) 118 119 bzzapi := strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/") 120 client := swarm.NewClient(bzzapi) 121 122 newManifest := removeEntryFromManifest(client, mhash, path) 123 fmt.Println(newManifest) 124 } 125 126 func addEntryToManifest(client *swarm.Client, mhash, path string, entry api.ManifestEntry) string { 127 var longestPathEntry = api.ManifestEntry{} 128 129 mroot, isEncrypted, err := client.DownloadManifest(mhash) 130 if err != nil { 131 utils.Fatalf("Manifest download failed: %v", err) 132 } 133 134 // See if we path is in this Manifest or do we have to dig deeper 135 for _, e := range mroot.Entries { 136 if path == e.Path { 137 utils.Fatalf("Path %s already present, not adding anything", path) 138 } else { 139 if e.ContentType == api.ManifestType { 140 prfxlen := strings.HasPrefix(path, e.Path) 141 if prfxlen && len(path) > len(longestPathEntry.Path) { 142 longestPathEntry = e 143 } 144 } 145 } 146 } 147 148 if longestPathEntry.Path != "" { 149 // Load the child Manifest add the entry there 150 newPath := path[len(longestPathEntry.Path):] 151 newHash := addEntryToManifest(client, longestPathEntry.Hash, newPath, entry) 152 153 // Replace the hash for parent Manifests 154 newMRoot := &api.Manifest{} 155 for _, e := range mroot.Entries { 156 if longestPathEntry.Path == e.Path { 157 e.Hash = newHash 158 } 159 newMRoot.Entries = append(newMRoot.Entries, e) 160 } 161 mroot = newMRoot 162 } else { 163 // Add the entry in the leaf Manifest 164 entry.Path = path 165 mroot.Entries = append(mroot.Entries, entry) 166 } 167 168 newManifestHash, err := client.UploadManifest(mroot, isEncrypted) 169 if err != nil { 170 utils.Fatalf("Manifest upload failed: %v", err) 171 } 172 return newManifestHash 173 } 174 175 // updateEntryInManifest updates an existing entry o path with a new one in the manifest with provided mhash 176 // finding the path recursively through all nested manifests. Argument isRoot is used for default 177 // entry update detection. If the updated entry has the same hash as the default entry, then the 178 // default entry in root manifest will be updated too. 179 // Returned values are the new manifest hash, hash of the entry that was replaced by the new entry and 180 // a a bool that is true if default entry is updated. 181 func updateEntryInManifest(client *swarm.Client, mhash, path string, entry api.ManifestEntry, isRoot bool) (newManifestHash, oldHash string, defaultEntryUpdated bool) { 182 var ( 183 newEntry = api.ManifestEntry{} 184 longestPathEntry = api.ManifestEntry{} 185 ) 186 187 mroot, isEncrypted, err := client.DownloadManifest(mhash) 188 if err != nil { 189 utils.Fatalf("Manifest download failed: %v", err) 190 } 191 192 // See if we path is in this Manifest or do we have to dig deeper 193 for _, e := range mroot.Entries { 194 if path == e.Path { 195 newEntry = e 196 // keep the reference of the hash of the entry that should be replaced 197 // for default entry detection 198 oldHash = e.Hash 199 } else { 200 if e.ContentType == api.ManifestType { 201 prfxlen := strings.HasPrefix(path, e.Path) 202 if prfxlen && len(path) > len(longestPathEntry.Path) { 203 longestPathEntry = e 204 } 205 } 206 } 207 } 208 209 if longestPathEntry.Path == "" && newEntry.Path == "" { 210 utils.Fatalf("Path %s not present in the Manifest, not setting anything", path) 211 } 212 213 if longestPathEntry.Path != "" { 214 // Load the child Manifest add the entry there 215 newPath := path[len(longestPathEntry.Path):] 216 var newHash string 217 newHash, oldHash, _ = updateEntryInManifest(client, longestPathEntry.Hash, newPath, entry, false) 218 219 // Replace the hash for parent Manifests 220 newMRoot := &api.Manifest{} 221 for _, e := range mroot.Entries { 222 if longestPathEntry.Path == e.Path { 223 e.Hash = newHash 224 } 225 newMRoot.Entries = append(newMRoot.Entries, e) 226 227 } 228 mroot = newMRoot 229 } 230 231 // update the manifest if the new entry is found and 232 // check if default entry should be updated 233 if newEntry.Path != "" || isRoot { 234 // Replace the hash for leaf Manifest 235 newMRoot := &api.Manifest{} 236 for _, e := range mroot.Entries { 237 if newEntry.Path == e.Path { 238 entry.Path = e.Path 239 newMRoot.Entries = append(newMRoot.Entries, entry) 240 } else if isRoot && e.Path == "" && e.Hash == oldHash { 241 entry.Path = e.Path 242 newMRoot.Entries = append(newMRoot.Entries, entry) 243 defaultEntryUpdated = true 244 } else { 245 newMRoot.Entries = append(newMRoot.Entries, e) 246 } 247 } 248 mroot = newMRoot 249 } 250 251 newManifestHash, err = client.UploadManifest(mroot, isEncrypted) 252 if err != nil { 253 utils.Fatalf("Manifest upload failed: %v", err) 254 } 255 return newManifestHash, oldHash, defaultEntryUpdated 256 } 257 258 func removeEntryFromManifest(client *swarm.Client, mhash, path string) string { 259 var ( 260 entryToRemove = api.ManifestEntry{} 261 longestPathEntry = api.ManifestEntry{} 262 ) 263 264 mroot, isEncrypted, err := client.DownloadManifest(mhash) 265 if err != nil { 266 utils.Fatalf("Manifest download failed: %v", err) 267 } 268 269 // See if we path is in this Manifest or do we have to dig deeper 270 for _, entry := range mroot.Entries { 271 if path == entry.Path { 272 entryToRemove = entry 273 } else { 274 if entry.ContentType == api.ManifestType { 275 prfxlen := strings.HasPrefix(path, entry.Path) 276 if prfxlen && len(path) > len(longestPathEntry.Path) { 277 longestPathEntry = entry 278 } 279 } 280 } 281 } 282 283 if longestPathEntry.Path == "" && entryToRemove.Path == "" { 284 utils.Fatalf("Path %s not present in the Manifest, not removing anything", path) 285 } 286 287 if longestPathEntry.Path != "" { 288 // Load the child Manifest remove the entry there 289 newPath := path[len(longestPathEntry.Path):] 290 newHash := removeEntryFromManifest(client, longestPathEntry.Hash, newPath) 291 292 // Replace the hash for parent Manifests 293 newMRoot := &api.Manifest{} 294 for _, entry := range mroot.Entries { 295 if longestPathEntry.Path == entry.Path { 296 entry.Hash = newHash 297 } 298 newMRoot.Entries = append(newMRoot.Entries, entry) 299 } 300 mroot = newMRoot 301 } 302 303 if entryToRemove.Path != "" { 304 // remove the entry in this Manifest 305 newMRoot := &api.Manifest{} 306 for _, entry := range mroot.Entries { 307 if entryToRemove.Path != entry.Path { 308 newMRoot.Entries = append(newMRoot.Entries, entry) 309 } 310 } 311 mroot = newMRoot 312 } 313 314 newManifestHash, err := client.UploadManifest(mroot, isEncrypted) 315 if err != nil { 316 utils.Fatalf("Manifest upload failed: %v", err) 317 } 318 return newManifestHash 319 }