manifest.go 9.6 KB

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