github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/cmd/swarm/manifest.go (about) 1 2 //<developer> 3 // <name>linapex 曹一峰</name> 4 // <email>linapex@163.com</email> 5 // <wx>superexc</wx> 6 // <qqgroup>128148617</qqgroup> 7 // <url>https://jsq.ink</url> 8 // <role>pku engineer</role> 9 // <date>2019-03-16 19:16:33</date> 10 //</624450071156494336> 11 12 13 //命令清单更新 14 package main 15 16 import ( 17 "fmt" 18 "os" 19 "strings" 20 21 "github.com/ethereum/go-ethereum/cmd/utils" 22 "github.com/ethereum/go-ethereum/swarm/api" 23 swarm "github.com/ethereum/go-ethereum/swarm/api/client" 24 "gopkg.in/urfave/cli.v1" 25 ) 26 27 var manifestCommand = cli.Command{ 28 Name: "manifest", 29 CustomHelpTemplate: helpTemplate, 30 Usage: "perform operations on swarm manifests", 31 ArgsUsage: "COMMAND", 32 Description: "Updates a MANIFEST by adding/removing/updating the hash of a path.\nCOMMAND could be: add, update, remove", 33 Subcommands: []cli.Command{ 34 { 35 Action: manifestAdd, 36 CustomHelpTemplate: helpTemplate, 37 Name: "add", 38 Usage: "add a new path to the manifest", 39 ArgsUsage: "<MANIFEST> <path> <hash>", 40 Description: "Adds a new path to the manifest", 41 }, 42 { 43 Action: manifestUpdate, 44 CustomHelpTemplate: helpTemplate, 45 Name: "update", 46 Usage: "update the hash for an already existing path in the manifest", 47 ArgsUsage: "<MANIFEST> <path> <newhash>", 48 Description: "Update the hash for an already existing path in the manifest", 49 }, 50 { 51 Action: manifestRemove, 52 CustomHelpTemplate: helpTemplate, 53 Name: "remove", 54 Usage: "removes a path from the manifest", 55 ArgsUsage: "<MANIFEST> <path>", 56 Description: "Removes a path from the manifest", 57 }, 58 }, 59 } 60 61 //manifestAdd在给定路径向清单添加新条目。 62 //最后一个参数new entry hash必须是清单的hash 63 //只有一个条目,这些元数据将添加到原始清单中。 64 // 65 func manifestAdd(ctx *cli.Context) { 66 args := ctx.Args() 67 if len(args) != 3 { 68 utils.Fatalf("Need exactly three arguments <MHASH> <path> <HASH>") 69 } 70 71 var ( 72 mhash = args[0] 73 path = args[1] 74 hash = args[2] 75 ) 76 77 bzzapi := strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/") 78 client := swarm.NewClient(bzzapi) 79 80 m, _, err := client.DownloadManifest(hash) 81 if err != nil { 82 utils.Fatalf("Error downloading manifest to add: %v", err) 83 } 84 l := len(m.Entries) 85 if l == 0 { 86 utils.Fatalf("No entries in manifest %s", hash) 87 } else if l > 1 { 88 utils.Fatalf("Too many entries in manifest %s", hash) 89 } 90 91 newManifest := addEntryToManifest(client, mhash, path, m.Entries[0]) 92 fmt.Println(newManifest) 93 } 94 95 //清单更新将替换给定路径上清单的现有条目。 96 //最后一个参数new entry hash必须是清单的hash 97 //只有一个条目,这些元数据将添加到原始清单中。 98 //成功后,此函数将打印更新清单的哈希。 99 func manifestUpdate(ctx *cli.Context) { 100 args := ctx.Args() 101 if len(args) != 3 { 102 utils.Fatalf("Need exactly three arguments <MHASH> <path> <HASH>") 103 } 104 105 var ( 106 mhash = args[0] 107 path = args[1] 108 hash = args[2] 109 ) 110 111 bzzapi := strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/") 112 client := swarm.NewClient(bzzapi) 113 114 m, _, err := client.DownloadManifest(hash) 115 if err != nil { 116 utils.Fatalf("Error downloading manifest to update: %v", err) 117 } 118 l := len(m.Entries) 119 if l == 0 { 120 utils.Fatalf("No entries in manifest %s", hash) 121 } else if l > 1 { 122 utils.Fatalf("Too many entries in manifest %s", hash) 123 } 124 125 newManifest, _, defaultEntryUpdated := updateEntryInManifest(client, mhash, path, m.Entries[0], true) 126 if defaultEntryUpdated { 127 //将信息消息打印到stderr 128 //允许用户从stdout获取新清单哈希 129 //不需要解析完整的输出。 130 fmt.Fprintln(os.Stderr, "Manifest default entry is updated, too") 131 } 132 fmt.Println(newManifest) 133 } 134 135 //manifestremove删除给定路径上清单的现有条目。 136 //成功后,此函数将打印清单的哈希,但该哈希没有 137 //包含路径。 138 func manifestRemove(ctx *cli.Context) { 139 args := ctx.Args() 140 if len(args) != 2 { 141 utils.Fatalf("Need exactly two arguments <MHASH> <path>") 142 } 143 144 var ( 145 mhash = args[0] 146 path = args[1] 147 ) 148 149 bzzapi := strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/") 150 client := swarm.NewClient(bzzapi) 151 152 newManifest := removeEntryFromManifest(client, mhash, path) 153 fmt.Println(newManifest) 154 } 155 156 func addEntryToManifest(client *swarm.Client, mhash, path string, entry api.ManifestEntry) string { 157 var longestPathEntry = api.ManifestEntry{} 158 159 mroot, isEncrypted, err := client.DownloadManifest(mhash) 160 if err != nil { 161 utils.Fatalf("Manifest download failed: %v", err) 162 } 163 164 //看看我们的道路是否在这张清单中,或者我们需要更深入地挖掘 165 for _, e := range mroot.Entries { 166 if path == e.Path { 167 utils.Fatalf("Path %s already present, not adding anything", path) 168 } else { 169 if e.ContentType == api.ManifestType { 170 prfxlen := strings.HasPrefix(path, e.Path) 171 if prfxlen && len(path) > len(longestPathEntry.Path) { 172 longestPathEntry = e 173 } 174 } 175 } 176 } 177 178 if longestPathEntry.Path != "" { 179 //加载子清单在其中添加条目 180 newPath := path[len(longestPathEntry.Path):] 181 newHash := addEntryToManifest(client, longestPathEntry.Hash, newPath, entry) 182 183 //替换父清单的哈希 184 newMRoot := &api.Manifest{} 185 for _, e := range mroot.Entries { 186 if longestPathEntry.Path == e.Path { 187 e.Hash = newHash 188 } 189 newMRoot.Entries = append(newMRoot.Entries, e) 190 } 191 mroot = newMRoot 192 } else { 193 //在叶清单中添加条目 194 entry.Path = path 195 mroot.Entries = append(mroot.Entries, entry) 196 } 197 198 newManifestHash, err := client.UploadManifest(mroot, isEncrypted) 199 if err != nil { 200 utils.Fatalf("Manifest upload failed: %v", err) 201 } 202 return newManifestHash 203 } 204 205 // 206 //通过所有嵌套清单递归查找路径。参数isroot用于默认值 207 //条目更新检测。如果更新的条目与默认条目具有相同的哈希,则 208 // 209 // 210 //一个布尔值,如果更新默认条目,则为真。 211 func updateEntryInManifest(client *swarm.Client, mhash, path string, entry api.ManifestEntry, isRoot bool) (newManifestHash, oldHash string, defaultEntryUpdated bool) { 212 var ( 213 newEntry = api.ManifestEntry{} 214 longestPathEntry = api.ManifestEntry{} 215 ) 216 217 mroot, isEncrypted, err := client.DownloadManifest(mhash) 218 if err != nil { 219 utils.Fatalf("Manifest download failed: %v", err) 220 } 221 222 //看看我们的道路是否在这张清单中,或者我们需要更深入地挖掘 223 for _, e := range mroot.Entries { 224 if path == e.Path { 225 newEntry = e 226 // 227 // 228 oldHash = e.Hash 229 } else { 230 if e.ContentType == api.ManifestType { 231 prfxlen := strings.HasPrefix(path, e.Path) 232 if prfxlen && len(path) > len(longestPathEntry.Path) { 233 longestPathEntry = e 234 } 235 } 236 } 237 } 238 239 if longestPathEntry.Path == "" && newEntry.Path == "" { 240 utils.Fatalf("Path %s not present in the Manifest, not setting anything", path) 241 } 242 243 if longestPathEntry.Path != "" { 244 //加载子清单在其中添加条目 245 newPath := path[len(longestPathEntry.Path):] 246 var newHash string 247 newHash, oldHash, _ = updateEntryInManifest(client, longestPathEntry.Hash, newPath, entry, false) 248 249 //替换父清单的哈希 250 newMRoot := &api.Manifest{} 251 for _, e := range mroot.Entries { 252 if longestPathEntry.Path == e.Path { 253 e.Hash = newHash 254 } 255 newMRoot.Entries = append(newMRoot.Entries, e) 256 257 } 258 mroot = newMRoot 259 } 260 261 // 262 //检查是否应更新默认条目 263 if newEntry.Path != "" || isRoot { 264 //替换叶清单的哈希 265 newMRoot := &api.Manifest{} 266 for _, e := range mroot.Entries { 267 if newEntry.Path == e.Path { 268 entry.Path = e.Path 269 newMRoot.Entries = append(newMRoot.Entries, entry) 270 } else if isRoot && e.Path == "" && e.Hash == oldHash { 271 entry.Path = e.Path 272 newMRoot.Entries = append(newMRoot.Entries, entry) 273 defaultEntryUpdated = true 274 } else { 275 newMRoot.Entries = append(newMRoot.Entries, e) 276 } 277 } 278 mroot = newMRoot 279 } 280 281 newManifestHash, err = client.UploadManifest(mroot, isEncrypted) 282 if err != nil { 283 utils.Fatalf("Manifest upload failed: %v", err) 284 } 285 return newManifestHash, oldHash, defaultEntryUpdated 286 } 287 288 func removeEntryFromManifest(client *swarm.Client, mhash, path string) string { 289 var ( 290 entryToRemove = api.ManifestEntry{} 291 longestPathEntry = api.ManifestEntry{} 292 ) 293 294 mroot, isEncrypted, err := client.DownloadManifest(mhash) 295 if err != nil { 296 utils.Fatalf("Manifest download failed: %v", err) 297 } 298 299 //看看我们的道路是否在这张清单中,或者我们需要更深入地挖掘 300 for _, entry := range mroot.Entries { 301 if path == entry.Path { 302 entryToRemove = entry 303 } else { 304 if entry.ContentType == api.ManifestType { 305 prfxlen := strings.HasPrefix(path, entry.Path) 306 if prfxlen && len(path) > len(longestPathEntry.Path) { 307 longestPathEntry = entry 308 } 309 } 310 } 311 } 312 313 if longestPathEntry.Path == "" && entryToRemove.Path == "" { 314 utils.Fatalf("Path %s not present in the Manifest, not removing anything", path) 315 } 316 317 if longestPathEntry.Path != "" { 318 //加载子清单删除其中的项 319 newPath := path[len(longestPathEntry.Path):] 320 newHash := removeEntryFromManifest(client, longestPathEntry.Hash, newPath) 321 322 //替换父清单的哈希 323 newMRoot := &api.Manifest{} 324 for _, entry := range mroot.Entries { 325 if longestPathEntry.Path == entry.Path { 326 entry.Hash = newHash 327 } 328 newMRoot.Entries = append(newMRoot.Entries, entry) 329 } 330 mroot = newMRoot 331 } 332 333 if entryToRemove.Path != "" { 334 //删除此清单中的条目 335 newMRoot := &api.Manifest{} 336 for _, entry := range mroot.Entries { 337 if entryToRemove.Path != entry.Path { 338 newMRoot.Entries = append(newMRoot.Entries, entry) 339 } 340 } 341 mroot = newMRoot 342 } 343 344 newManifestHash, err := client.UploadManifest(mroot, isEncrypted) 345 if err != nil { 346 utils.Fatalf("Manifest upload failed: %v", err) 347 } 348 return newManifestHash 349 } 350