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