Manifest cli fix and upload defaultpath only once (#17375)
* cmd/swarm: fix manifest subcommands and add tests * cmd/swarm: manifest update: update default entry for non-encrypted uploads * swarm/api: upload defaultpath file only once * swarm/api/client: improve UploadDirectory default path handling * cmd/swarm: support absolute and relative default path values * cmd/swarm: fix a typo in test * cmd/swarm: check encrypted uploads in manifest update tests
This commit is contained in:
committed by
Balint Gabor
parent
3ec5dda4d2
commit
6d1e292eef
@ -18,10 +18,8 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"mime"
|
||||
"path/filepath"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||
@ -30,127 +28,118 @@ import (
|
||||
"gopkg.in/urfave/cli.v1"
|
||||
)
|
||||
|
||||
const bzzManifestJSON = "application/bzz-manifest+json"
|
||||
|
||||
func add(ctx *cli.Context) {
|
||||
// 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 at least three arguments <MHASH> <path> <HASH> [<content-type>]")
|
||||
if len(args) != 3 {
|
||||
utils.Fatalf("Need exactly three arguments <MHASH> <path> <HASH>")
|
||||
}
|
||||
|
||||
var (
|
||||
mhash = args[0]
|
||||
path = args[1]
|
||||
hash = args[2]
|
||||
|
||||
ctype string
|
||||
wantManifest = ctx.GlobalBoolT(SwarmWantManifestFlag.Name)
|
||||
mroot api.Manifest
|
||||
)
|
||||
|
||||
if len(args) > 3 {
|
||||
ctype = args[3]
|
||||
} else {
|
||||
ctype = mime.TypeByExtension(filepath.Ext(path))
|
||||
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(ctx, mhash, path, hash, ctype)
|
||||
newManifest := addEntryToManifest(client, mhash, path, m.Entries[0])
|
||||
fmt.Println(newManifest)
|
||||
|
||||
if !wantManifest {
|
||||
// Print the manifest. This is the only output to stdout.
|
||||
mrootJSON, _ := json.MarshalIndent(mroot, "", " ")
|
||||
fmt.Println(string(mrootJSON))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func update(ctx *cli.Context) {
|
||||
|
||||
// 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 at least three arguments <MHASH> <path> <HASH>")
|
||||
if len(args) != 3 {
|
||||
utils.Fatalf("Need exactly three arguments <MHASH> <path> <HASH>")
|
||||
}
|
||||
|
||||
var (
|
||||
mhash = args[0]
|
||||
path = args[1]
|
||||
hash = args[2]
|
||||
|
||||
ctype string
|
||||
wantManifest = ctx.GlobalBoolT(SwarmWantManifestFlag.Name)
|
||||
mroot api.Manifest
|
||||
)
|
||||
if len(args) > 3 {
|
||||
ctype = args[3]
|
||||
} else {
|
||||
ctype = mime.TypeByExtension(filepath.Ext(path))
|
||||
|
||||
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 := updateEntryInManifest(ctx, mhash, path, hash, ctype)
|
||||
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)
|
||||
|
||||
if !wantManifest {
|
||||
// Print the manifest. This is the only output to stdout.
|
||||
mrootJSON, _ := json.MarshalIndent(mroot, "", " ")
|
||||
fmt.Println(string(mrootJSON))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func remove(ctx *cli.Context) {
|
||||
// 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 at least two arguments <MHASH> <path>")
|
||||
if len(args) != 2 {
|
||||
utils.Fatalf("Need exactly two arguments <MHASH> <path>")
|
||||
}
|
||||
|
||||
var (
|
||||
mhash = args[0]
|
||||
path = args[1]
|
||||
|
||||
wantManifest = ctx.GlobalBoolT(SwarmWantManifestFlag.Name)
|
||||
mroot api.Manifest
|
||||
)
|
||||
|
||||
newManifest := removeEntryFromManifest(ctx, mhash, path)
|
||||
fmt.Println(newManifest)
|
||||
bzzapi := strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
|
||||
client := swarm.NewClient(bzzapi)
|
||||
|
||||
if !wantManifest {
|
||||
// Print the manifest. This is the only output to stdout.
|
||||
mrootJSON, _ := json.MarshalIndent(mroot, "", " ")
|
||||
fmt.Println(string(mrootJSON))
|
||||
return
|
||||
}
|
||||
newManifest := removeEntryFromManifest(client, mhash, path)
|
||||
fmt.Println(newManifest)
|
||||
}
|
||||
|
||||
func addEntryToManifest(ctx *cli.Context, mhash, path, hash, ctype string) string {
|
||||
|
||||
var (
|
||||
bzzapi = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
|
||||
client = swarm.NewClient(bzzapi)
|
||||
longestPathEntry = api.ManifestEntry{}
|
||||
)
|
||||
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)
|
||||
}
|
||||
|
||||
//TODO: check if the "hash" to add is valid and present in swarm
|
||||
_, _, err = client.DownloadManifest(hash)
|
||||
if err != nil {
|
||||
utils.Fatalf("Hash to add is not present: %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 {
|
||||
for _, e := range mroot.Entries {
|
||||
if path == e.Path {
|
||||
utils.Fatalf("Path %s already present, not adding anything", path)
|
||||
} else {
|
||||
if entry.ContentType == bzzManifestJSON {
|
||||
prfxlen := strings.HasPrefix(path, entry.Path)
|
||||
if e.ContentType == api.ManifestType {
|
||||
prfxlen := strings.HasPrefix(path, e.Path)
|
||||
if prfxlen && len(path) > len(longestPathEntry.Path) {
|
||||
longestPathEntry = entry
|
||||
longestPathEntry = e
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -159,25 +148,21 @@ func addEntryToManifest(ctx *cli.Context, mhash, path, hash, ctype string) strin
|
||||
if longestPathEntry.Path != "" {
|
||||
// Load the child Manifest add the entry there
|
||||
newPath := path[len(longestPathEntry.Path):]
|
||||
newHash := addEntryToManifest(ctx, longestPathEntry.Hash, newPath, hash, ctype)
|
||||
newHash := addEntryToManifest(client, longestPathEntry.Hash, newPath, entry)
|
||||
|
||||
// Replace the hash for parent Manifests
|
||||
newMRoot := &api.Manifest{}
|
||||
for _, entry := range mroot.Entries {
|
||||
if longestPathEntry.Path == entry.Path {
|
||||
entry.Hash = newHash
|
||||
for _, e := range mroot.Entries {
|
||||
if longestPathEntry.Path == e.Path {
|
||||
e.Hash = newHash
|
||||
}
|
||||
newMRoot.Entries = append(newMRoot.Entries, entry)
|
||||
newMRoot.Entries = append(newMRoot.Entries, e)
|
||||
}
|
||||
mroot = newMRoot
|
||||
} else {
|
||||
// Add the entry in the leaf Manifest
|
||||
newEntry := api.ManifestEntry{
|
||||
Hash: hash,
|
||||
Path: path,
|
||||
ContentType: ctype,
|
||||
}
|
||||
mroot.Entries = append(mroot.Entries, newEntry)
|
||||
entry.Path = path
|
||||
mroot.Entries = append(mroot.Entries, entry)
|
||||
}
|
||||
|
||||
newManifestHash, err := client.UploadManifest(mroot, isEncrypted)
|
||||
@ -185,14 +170,16 @@ func addEntryToManifest(ctx *cli.Context, mhash, path, hash, ctype string) strin
|
||||
utils.Fatalf("Manifest upload failed: %v", err)
|
||||
}
|
||||
return newManifestHash
|
||||
|
||||
}
|
||||
|
||||
func updateEntryInManifest(ctx *cli.Context, mhash, path, hash, ctype string) string {
|
||||
|
||||
// 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 (
|
||||
bzzapi = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
|
||||
client = swarm.NewClient(bzzapi)
|
||||
newEntry = api.ManifestEntry{}
|
||||
longestPathEntry = api.ManifestEntry{}
|
||||
)
|
||||
@ -202,17 +189,18 @@ func updateEntryInManifest(ctx *cli.Context, mhash, path, hash, ctype string) st
|
||||
utils.Fatalf("Manifest download failed: %v", err)
|
||||
}
|
||||
|
||||
//TODO: check if the "hash" with which to update is valid and present in swarm
|
||||
|
||||
// See if we path is in this Manifest or do we have to dig deeper
|
||||
for _, entry := range mroot.Entries {
|
||||
if path == entry.Path {
|
||||
newEntry = entry
|
||||
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 entry.ContentType == bzzManifestJSON {
|
||||
prfxlen := strings.HasPrefix(path, entry.Path)
|
||||
if e.ContentType == api.ManifestType {
|
||||
prfxlen := strings.HasPrefix(path, e.Path)
|
||||
if prfxlen && len(path) > len(longestPathEntry.Path) {
|
||||
longestPathEntry = entry
|
||||
longestPathEntry = e
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -225,50 +213,50 @@ func updateEntryInManifest(ctx *cli.Context, mhash, path, hash, ctype string) st
|
||||
if longestPathEntry.Path != "" {
|
||||
// Load the child Manifest add the entry there
|
||||
newPath := path[len(longestPathEntry.Path):]
|
||||
newHash := updateEntryInManifest(ctx, longestPathEntry.Hash, newPath, hash, ctype)
|
||||
var newHash string
|
||||
newHash, oldHash, _ = updateEntryInManifest(client, longestPathEntry.Hash, newPath, entry, false)
|
||||
|
||||
// Replace the hash for parent Manifests
|
||||
newMRoot := &api.Manifest{}
|
||||
for _, entry := range mroot.Entries {
|
||||
if longestPathEntry.Path == entry.Path {
|
||||
entry.Hash = newHash
|
||||
for _, e := range mroot.Entries {
|
||||
if longestPathEntry.Path == e.Path {
|
||||
e.Hash = newHash
|
||||
}
|
||||
newMRoot.Entries = append(newMRoot.Entries, entry)
|
||||
newMRoot.Entries = append(newMRoot.Entries, e)
|
||||
|
||||
}
|
||||
mroot = newMRoot
|
||||
}
|
||||
|
||||
if newEntry.Path != "" {
|
||||
// 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 _, entry := range mroot.Entries {
|
||||
if newEntry.Path == entry.Path {
|
||||
myEntry := api.ManifestEntry{
|
||||
Hash: hash,
|
||||
Path: entry.Path,
|
||||
ContentType: ctype,
|
||||
}
|
||||
newMRoot.Entries = append(newMRoot.Entries, myEntry)
|
||||
} else {
|
||||
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)
|
||||
newManifestHash, err = client.UploadManifest(mroot, isEncrypted)
|
||||
if err != nil {
|
||||
utils.Fatalf("Manifest upload failed: %v", err)
|
||||
}
|
||||
return newManifestHash
|
||||
return newManifestHash, oldHash, defaultEntryUpdated
|
||||
}
|
||||
|
||||
func removeEntryFromManifest(ctx *cli.Context, mhash, path string) string {
|
||||
|
||||
func removeEntryFromManifest(client *swarm.Client, mhash, path string) string {
|
||||
var (
|
||||
bzzapi = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
|
||||
client = swarm.NewClient(bzzapi)
|
||||
entryToRemove = api.ManifestEntry{}
|
||||
longestPathEntry = api.ManifestEntry{}
|
||||
)
|
||||
@ -283,7 +271,7 @@ func removeEntryFromManifest(ctx *cli.Context, mhash, path string) string {
|
||||
if path == entry.Path {
|
||||
entryToRemove = entry
|
||||
} else {
|
||||
if entry.ContentType == bzzManifestJSON {
|
||||
if entry.ContentType == api.ManifestType {
|
||||
prfxlen := strings.HasPrefix(path, entry.Path)
|
||||
if prfxlen && len(path) > len(longestPathEntry.Path) {
|
||||
longestPathEntry = entry
|
||||
@ -299,7 +287,7 @@ func removeEntryFromManifest(ctx *cli.Context, mhash, path string) string {
|
||||
if longestPathEntry.Path != "" {
|
||||
// Load the child Manifest remove the entry there
|
||||
newPath := path[len(longestPathEntry.Path):]
|
||||
newHash := removeEntryFromManifest(ctx, longestPathEntry.Hash, newPath)
|
||||
newHash := removeEntryFromManifest(client, longestPathEntry.Hash, newPath)
|
||||
|
||||
// Replace the hash for parent Manifests
|
||||
newMRoot := &api.Manifest{}
|
||||
|
Reference in New Issue
Block a user