manifest.go 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  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. // Command MANIFEST update
  17. package main
  18. import (
  19. "encoding/json"
  20. "fmt"
  21. "mime"
  22. "path/filepath"
  23. "strings"
  24. "github.com/ethereum/go-ethereum/cmd/utils"
  25. "github.com/ethereum/go-ethereum/swarm/api"
  26. swarm "github.com/ethereum/go-ethereum/swarm/api/client"
  27. "gopkg.in/urfave/cli.v1"
  28. )
  29. func add(ctx *cli.Context) {
  30. args := ctx.Args()
  31. if len(args) < 3 {
  32. utils.Fatalf("Need atleast three arguments <MHASH> <path> <HASH> [<content-type>]")
  33. }
  34. var (
  35. mhash = args[0]
  36. path = args[1]
  37. hash = args[2]
  38. ctype string
  39. wantManifest = ctx.GlobalBoolT(SwarmWantManifestFlag.Name)
  40. mroot api.Manifest
  41. )
  42. if len(args) > 3 {
  43. ctype = args[3]
  44. } else {
  45. ctype = mime.TypeByExtension(filepath.Ext(path))
  46. }
  47. newManifest := addEntryToManifest(ctx, mhash, path, hash, ctype)
  48. fmt.Println(newManifest)
  49. if !wantManifest {
  50. // Print the manifest. This is the only output to stdout.
  51. mrootJSON, _ := json.MarshalIndent(mroot, "", " ")
  52. fmt.Println(string(mrootJSON))
  53. return
  54. }
  55. }
  56. func update(ctx *cli.Context) {
  57. args := ctx.Args()
  58. if len(args) < 3 {
  59. utils.Fatalf("Need atleast three arguments <MHASH> <path> <HASH>")
  60. }
  61. var (
  62. mhash = args[0]
  63. path = args[1]
  64. hash = args[2]
  65. ctype string
  66. wantManifest = ctx.GlobalBoolT(SwarmWantManifestFlag.Name)
  67. mroot api.Manifest
  68. )
  69. if len(args) > 3 {
  70. ctype = args[3]
  71. } else {
  72. ctype = mime.TypeByExtension(filepath.Ext(path))
  73. }
  74. newManifest := updateEntryInManifest(ctx, mhash, path, hash, ctype)
  75. fmt.Println(newManifest)
  76. if !wantManifest {
  77. // Print the manifest. This is the only output to stdout.
  78. mrootJSON, _ := json.MarshalIndent(mroot, "", " ")
  79. fmt.Println(string(mrootJSON))
  80. return
  81. }
  82. }
  83. func remove(ctx *cli.Context) {
  84. args := ctx.Args()
  85. if len(args) < 2 {
  86. utils.Fatalf("Need atleast two arguments <MHASH> <path>")
  87. }
  88. var (
  89. mhash = args[0]
  90. path = args[1]
  91. wantManifest = ctx.GlobalBoolT(SwarmWantManifestFlag.Name)
  92. mroot api.Manifest
  93. )
  94. newManifest := removeEntryFromManifest(ctx, mhash, path)
  95. fmt.Println(newManifest)
  96. if !wantManifest {
  97. // Print the manifest. This is the only output to stdout.
  98. mrootJSON, _ := json.MarshalIndent(mroot, "", " ")
  99. fmt.Println(string(mrootJSON))
  100. return
  101. }
  102. }
  103. func addEntryToManifest(ctx *cli.Context, mhash, path, hash, ctype string) string {
  104. var (
  105. bzzapi = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
  106. client = swarm.NewClient(bzzapi)
  107. longestPathEntry = api.ManifestEntry{}
  108. )
  109. mroot, err := client.DownloadManifest(mhash)
  110. if err != nil {
  111. utils.Fatalf("Manifest download failed: %v", err)
  112. }
  113. //TODO: check if the "hash" to add is valid and present in swarm
  114. _, err = client.DownloadManifest(hash)
  115. if err != nil {
  116. utils.Fatalf("Hash to add is not present: %v", err)
  117. }
  118. // See if we path is in this Manifest or do we have to dig deeper
  119. for _, entry := range mroot.Entries {
  120. if path == entry.Path {
  121. utils.Fatalf("Path %s already present, not adding anything", path)
  122. } else {
  123. if entry.ContentType == "application/bzz-manifest+json" {
  124. prfxlen := strings.HasPrefix(path, entry.Path)
  125. if prfxlen && len(path) > len(longestPathEntry.Path) {
  126. longestPathEntry = entry
  127. }
  128. }
  129. }
  130. }
  131. if longestPathEntry.Path != "" {
  132. // Load the child Manifest add the entry there
  133. newPath := path[len(longestPathEntry.Path):]
  134. newHash := addEntryToManifest(ctx, longestPathEntry.Hash, newPath, hash, ctype)
  135. // Replace the hash for parent Manifests
  136. newMRoot := &api.Manifest{}
  137. for _, entry := range mroot.Entries {
  138. if longestPathEntry.Path == entry.Path {
  139. entry.Hash = newHash
  140. }
  141. newMRoot.Entries = append(newMRoot.Entries, entry)
  142. }
  143. mroot = newMRoot
  144. } else {
  145. // Add the entry in the leaf Manifest
  146. newEntry := api.ManifestEntry{
  147. Hash: hash,
  148. Path: path,
  149. ContentType: ctype,
  150. }
  151. mroot.Entries = append(mroot.Entries, newEntry)
  152. }
  153. newManifestHash, err := client.UploadManifest(mroot)
  154. if err != nil {
  155. utils.Fatalf("Manifest upload failed: %v", err)
  156. }
  157. return newManifestHash
  158. }
  159. func updateEntryInManifest(ctx *cli.Context, mhash, path, hash, ctype string) string {
  160. var (
  161. bzzapi = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
  162. client = swarm.NewClient(bzzapi)
  163. newEntry = api.ManifestEntry{}
  164. longestPathEntry = api.ManifestEntry{}
  165. )
  166. mroot, err := client.DownloadManifest(mhash)
  167. if err != nil {
  168. utils.Fatalf("Manifest download failed: %v", err)
  169. }
  170. //TODO: check if the "hash" with which to update is valid and present in swarm
  171. // See if we path is in this Manifest or do we have to dig deeper
  172. for _, entry := range mroot.Entries {
  173. if path == entry.Path {
  174. newEntry = entry
  175. } else {
  176. if entry.ContentType == "application/bzz-manifest+json" {
  177. prfxlen := strings.HasPrefix(path, entry.Path)
  178. if prfxlen && len(path) > len(longestPathEntry.Path) {
  179. longestPathEntry = entry
  180. }
  181. }
  182. }
  183. }
  184. if longestPathEntry.Path == "" && newEntry.Path == "" {
  185. utils.Fatalf("Path %s not present in the Manifest, not setting anything", path)
  186. }
  187. if longestPathEntry.Path != "" {
  188. // Load the child Manifest add the entry there
  189. newPath := path[len(longestPathEntry.Path):]
  190. newHash := updateEntryInManifest(ctx, longestPathEntry.Hash, newPath, hash, ctype)
  191. // Replace the hash for parent Manifests
  192. newMRoot := &api.Manifest{}
  193. for _, entry := range mroot.Entries {
  194. if longestPathEntry.Path == entry.Path {
  195. entry.Hash = newHash
  196. }
  197. newMRoot.Entries = append(newMRoot.Entries, entry)
  198. }
  199. mroot = newMRoot
  200. }
  201. if newEntry.Path != "" {
  202. // Replace the hash for leaf Manifest
  203. newMRoot := &api.Manifest{}
  204. for _, entry := range mroot.Entries {
  205. if newEntry.Path == entry.Path {
  206. myEntry := api.ManifestEntry{
  207. Hash: hash,
  208. Path: entry.Path,
  209. ContentType: ctype,
  210. }
  211. newMRoot.Entries = append(newMRoot.Entries, myEntry)
  212. } else {
  213. newMRoot.Entries = append(newMRoot.Entries, entry)
  214. }
  215. }
  216. mroot = newMRoot
  217. }
  218. newManifestHash, err := client.UploadManifest(mroot)
  219. if err != nil {
  220. utils.Fatalf("Manifest upload failed: %v", err)
  221. }
  222. return newManifestHash
  223. }
  224. func removeEntryFromManifest(ctx *cli.Context, mhash, path string) string {
  225. var (
  226. bzzapi = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
  227. client = swarm.NewClient(bzzapi)
  228. entryToRemove = api.ManifestEntry{}
  229. longestPathEntry = api.ManifestEntry{}
  230. )
  231. mroot, err := client.DownloadManifest(mhash)
  232. if err != nil {
  233. utils.Fatalf("Manifest download failed: %v", err)
  234. }
  235. // See if we path is in this Manifest or do we have to dig deeper
  236. for _, entry := range mroot.Entries {
  237. if path == entry.Path {
  238. entryToRemove = entry
  239. } else {
  240. if entry.ContentType == "application/bzz-manifest+json" {
  241. prfxlen := strings.HasPrefix(path, entry.Path)
  242. if prfxlen && len(path) > len(longestPathEntry.Path) {
  243. longestPathEntry = entry
  244. }
  245. }
  246. }
  247. }
  248. if longestPathEntry.Path == "" && entryToRemove.Path == "" {
  249. utils.Fatalf("Path %s not present in the Manifest, not removing anything", path)
  250. }
  251. if longestPathEntry.Path != "" {
  252. // Load the child Manifest remove the entry there
  253. newPath := path[len(longestPathEntry.Path):]
  254. newHash := removeEntryFromManifest(ctx, longestPathEntry.Hash, newPath)
  255. // Replace the hash for parent Manifests
  256. newMRoot := &api.Manifest{}
  257. for _, entry := range mroot.Entries {
  258. if longestPathEntry.Path == entry.Path {
  259. entry.Hash = newHash
  260. }
  261. newMRoot.Entries = append(newMRoot.Entries, entry)
  262. }
  263. mroot = newMRoot
  264. }
  265. if entryToRemove.Path != "" {
  266. // remove the entry in this Manifest
  267. newMRoot := &api.Manifest{}
  268. for _, entry := range mroot.Entries {
  269. if entryToRemove.Path != entry.Path {
  270. newMRoot.Entries = append(newMRoot.Entries, entry)
  271. }
  272. }
  273. mroot = newMRoot
  274. }
  275. newManifestHash, err := client.UploadManifest(mroot)
  276. if err != nil {
  277. utils.Fatalf("Manifest upload failed: %v", err)
  278. }
  279. return newManifestHash
  280. }