manifest.go 8.7 KB

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