| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353 |
- // Copyright 2017 The go-ethereum Authors
- // This file is part of go-ethereum.
- //
- // go-ethereum is free software: you can redistribute it and/or modify
- // it under the terms of the GNU General Public License as published by
- // the Free Software Foundation, either version 3 of the License, or
- // (at your option) any later version.
- //
- // go-ethereum is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- // GNU General Public License for more details.
- //
- // You should have received a copy of the GNU General Public License
- // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
- // Command MANIFEST update
- package main
- import (
- "fmt"
- "os"
- "strings"
- "github.com/ethereum/go-ethereum/cmd/utils"
- "github.com/ethereum/go-ethereum/swarm/api"
- swarm "github.com/ethereum/go-ethereum/swarm/api/client"
- "gopkg.in/urfave/cli.v1"
- )
- var manifestCommand = cli.Command{
- Name: "manifest",
- CustomHelpTemplate: helpTemplate,
- Usage: "perform operations on swarm manifests",
- ArgsUsage: "COMMAND",
- Description: "Updates a MANIFEST by adding/removing/updating the hash of a path.\nCOMMAND could be: add, update, remove",
- Subcommands: []cli.Command{
- {
- Action: manifestAdd,
- CustomHelpTemplate: helpTemplate,
- Name: "add",
- Usage: "add a new path to the manifest",
- ArgsUsage: "<MANIFEST> <path> <hash>",
- Description: "Adds a new path to the manifest",
- },
- {
- Action: manifestUpdate,
- CustomHelpTemplate: helpTemplate,
- Name: "update",
- Usage: "update the hash for an already existing path in the manifest",
- ArgsUsage: "<MANIFEST> <path> <newhash>",
- Description: "Update the hash for an already existing path in the manifest",
- },
- {
- Action: manifestRemove,
- CustomHelpTemplate: helpTemplate,
- Name: "remove",
- Usage: "removes a path from the manifest",
- ArgsUsage: "<MANIFEST> <path>",
- Description: "Removes a path from the manifest",
- },
- },
- }
- // manifestAdd adds a new entry to the manifest at the given path.
- // New entry hash, the last argument, must be the hash of a manifest
- // with only one entry, which meta-data will be added to the original manifest.
- // On success, this function will print new (updated) manifest's hash.
- func manifestAdd(ctx *cli.Context) {
- args := ctx.Args()
- if len(args) != 3 {
- utils.Fatalf("Need exactly three arguments <MHASH> <path> <HASH>")
- }
- var (
- mhash = args[0]
- path = args[1]
- hash = args[2]
- )
- bzzapi := strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
- client := swarm.NewClient(bzzapi)
- m, _, err := client.DownloadManifest(hash)
- if err != nil {
- utils.Fatalf("Error downloading manifest to add: %v", err)
- }
- l := len(m.Entries)
- if l == 0 {
- utils.Fatalf("No entries in manifest %s", hash)
- } else if l > 1 {
- utils.Fatalf("Too many entries in manifest %s", hash)
- }
- newManifest := addEntryToManifest(client, mhash, path, m.Entries[0])
- fmt.Println(newManifest)
- }
- // manifestUpdate replaces an existing entry of the manifest at the given path.
- // New entry hash, the last argument, must be the hash of a manifest
- // with only one entry, which meta-data will be added to the original manifest.
- // On success, this function will print hash of the updated manifest.
- func manifestUpdate(ctx *cli.Context) {
- args := ctx.Args()
- if len(args) != 3 {
- utils.Fatalf("Need exactly three arguments <MHASH> <path> <HASH>")
- }
- var (
- mhash = args[0]
- path = args[1]
- hash = args[2]
- )
- bzzapi := strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
- client := swarm.NewClient(bzzapi)
- m, _, err := client.DownloadManifest(hash)
- if err != nil {
- utils.Fatalf("Error downloading manifest to update: %v", err)
- }
- l := len(m.Entries)
- if l == 0 {
- utils.Fatalf("No entries in manifest %s", hash)
- } else if l > 1 {
- utils.Fatalf("Too many entries in manifest %s", hash)
- }
- newManifest, _, defaultEntryUpdated := updateEntryInManifest(client, mhash, path, m.Entries[0], true)
- if defaultEntryUpdated {
- // Print informational message to stderr
- // allowing the user to get the new manifest hash from stdout
- // without the need to parse the complete output.
- fmt.Fprintln(os.Stderr, "Manifest default entry is updated, too")
- }
- fmt.Println(newManifest)
- }
- // manifestRemove removes an existing entry of the manifest at the given path.
- // On success, this function will print hash of the manifest which does not
- // contain the path.
- func manifestRemove(ctx *cli.Context) {
- args := ctx.Args()
- if len(args) != 2 {
- utils.Fatalf("Need exactly two arguments <MHASH> <path>")
- }
- var (
- mhash = args[0]
- path = args[1]
- )
- bzzapi := strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
- client := swarm.NewClient(bzzapi)
- newManifest := removeEntryFromManifest(client, mhash, path)
- fmt.Println(newManifest)
- }
- func addEntryToManifest(client *swarm.Client, mhash, path string, entry api.ManifestEntry) string {
- var longestPathEntry = api.ManifestEntry{}
- mroot, isEncrypted, err := client.DownloadManifest(mhash)
- if err != nil {
- utils.Fatalf("Manifest download failed: %v", err)
- }
- // See if we path is in this Manifest or do we have to dig deeper
- for _, e := range mroot.Entries {
- if path == e.Path {
- utils.Fatalf("Path %s already present, not adding anything", path)
- } else {
- if e.ContentType == api.ManifestType {
- prfxlen := strings.HasPrefix(path, e.Path)
- if prfxlen && len(path) > len(longestPathEntry.Path) {
- longestPathEntry = e
- }
- }
- }
- }
- if longestPathEntry.Path != "" {
- // Load the child Manifest add the entry there
- newPath := path[len(longestPathEntry.Path):]
- newHash := addEntryToManifest(client, longestPathEntry.Hash, newPath, entry)
- // Replace the hash for parent Manifests
- newMRoot := &api.Manifest{}
- for _, e := range mroot.Entries {
- if longestPathEntry.Path == e.Path {
- e.Hash = newHash
- }
- newMRoot.Entries = append(newMRoot.Entries, e)
- }
- mroot = newMRoot
- } else {
- // Add the entry in the leaf Manifest
- entry.Path = path
- mroot.Entries = append(mroot.Entries, entry)
- }
- newManifestHash, err := client.UploadManifest(mroot, isEncrypted)
- if err != nil {
- utils.Fatalf("Manifest upload failed: %v", err)
- }
- return newManifestHash
- }
- // updateEntryInManifest updates an existing entry o path with a new one in the manifest with provided mhash
- // finding the path recursively through all nested manifests. Argument isRoot is used for default
- // entry update detection. If the updated entry has the same hash as the default entry, then the
- // default entry in root manifest will be updated too.
- // Returned values are the new manifest hash, hash of the entry that was replaced by the new entry and
- // a a bool that is true if default entry is updated.
- func updateEntryInManifest(client *swarm.Client, mhash, path string, entry api.ManifestEntry, isRoot bool) (newManifestHash, oldHash string, defaultEntryUpdated bool) {
- var (
- newEntry = api.ManifestEntry{}
- longestPathEntry = api.ManifestEntry{}
- )
- mroot, isEncrypted, err := client.DownloadManifest(mhash)
- if err != nil {
- utils.Fatalf("Manifest download failed: %v", err)
- }
- // See if we path is in this Manifest or do we have to dig deeper
- for _, e := range mroot.Entries {
- if path == e.Path {
- newEntry = e
- // keep the reference of the hash of the entry that should be replaced
- // for default entry detection
- oldHash = e.Hash
- } else {
- if e.ContentType == api.ManifestType {
- prfxlen := strings.HasPrefix(path, e.Path)
- if prfxlen && len(path) > len(longestPathEntry.Path) {
- longestPathEntry = e
- }
- }
- }
- }
- if longestPathEntry.Path == "" && newEntry.Path == "" {
- utils.Fatalf("Path %s not present in the Manifest, not setting anything", path)
- }
- if longestPathEntry.Path != "" {
- // Load the child Manifest add the entry there
- newPath := path[len(longestPathEntry.Path):]
- var newHash string
- newHash, oldHash, _ = updateEntryInManifest(client, longestPathEntry.Hash, newPath, entry, false)
- // Replace the hash for parent Manifests
- newMRoot := &api.Manifest{}
- for _, e := range mroot.Entries {
- if longestPathEntry.Path == e.Path {
- e.Hash = newHash
- }
- newMRoot.Entries = append(newMRoot.Entries, e)
- }
- mroot = newMRoot
- }
- // update the manifest if the new entry is found and
- // check if default entry should be updated
- if newEntry.Path != "" || isRoot {
- // Replace the hash for leaf Manifest
- newMRoot := &api.Manifest{}
- for _, e := range mroot.Entries {
- if newEntry.Path == e.Path {
- entry.Path = e.Path
- newMRoot.Entries = append(newMRoot.Entries, entry)
- } else if isRoot && e.Path == "" && e.Hash == oldHash {
- entry.Path = e.Path
- newMRoot.Entries = append(newMRoot.Entries, entry)
- defaultEntryUpdated = true
- } else {
- newMRoot.Entries = append(newMRoot.Entries, e)
- }
- }
- mroot = newMRoot
- }
- newManifestHash, err = client.UploadManifest(mroot, isEncrypted)
- if err != nil {
- utils.Fatalf("Manifest upload failed: %v", err)
- }
- return newManifestHash, oldHash, defaultEntryUpdated
- }
- func removeEntryFromManifest(client *swarm.Client, mhash, path string) string {
- var (
- entryToRemove = api.ManifestEntry{}
- longestPathEntry = api.ManifestEntry{}
- )
- mroot, isEncrypted, err := client.DownloadManifest(mhash)
- if err != nil {
- utils.Fatalf("Manifest download failed: %v", err)
- }
- // See if we path is in this Manifest or do we have to dig deeper
- for _, entry := range mroot.Entries {
- if path == entry.Path {
- entryToRemove = entry
- } else {
- if entry.ContentType == api.ManifestType {
- prfxlen := strings.HasPrefix(path, entry.Path)
- if prfxlen && len(path) > len(longestPathEntry.Path) {
- longestPathEntry = entry
- }
- }
- }
- }
- if longestPathEntry.Path == "" && entryToRemove.Path == "" {
- utils.Fatalf("Path %s not present in the Manifest, not removing anything", path)
- }
- if longestPathEntry.Path != "" {
- // Load the child Manifest remove the entry there
- newPath := path[len(longestPathEntry.Path):]
- newHash := removeEntryFromManifest(client, longestPathEntry.Hash, newPath)
- // Replace the hash for parent Manifests
- newMRoot := &api.Manifest{}
- for _, entry := range mroot.Entries {
- if longestPathEntry.Path == entry.Path {
- entry.Hash = newHash
- }
- newMRoot.Entries = append(newMRoot.Entries, entry)
- }
- mroot = newMRoot
- }
- if entryToRemove.Path != "" {
- // remove the entry in this Manifest
- newMRoot := &api.Manifest{}
- for _, entry := range mroot.Entries {
- if entryToRemove.Path != entry.Path {
- newMRoot.Entries = append(newMRoot.Entries, entry)
- }
- }
- mroot = newMRoot
- }
- newManifestHash, err := client.UploadManifest(mroot, isEncrypted)
- if err != nil {
- utils.Fatalf("Manifest upload failed: %v", err)
- }
- return newManifestHash
- }
|