|
@@ -0,0 +1,360 @@
|
|
|
|
|
+// Copyright 2016 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 (
|
|
|
|
|
+ "gopkg.in/urfave/cli.v1"
|
|
|
|
|
+ "log"
|
|
|
|
|
+ "mime"
|
|
|
|
|
+ "path/filepath"
|
|
|
|
|
+ "strings"
|
|
|
|
|
+ "fmt"
|
|
|
|
|
+ "encoding/json"
|
|
|
|
|
+)
|
|
|
|
|
+
|
|
|
|
|
+func add(ctx *cli.Context) {
|
|
|
|
|
+
|
|
|
|
|
+ args := ctx.Args()
|
|
|
|
|
+ if len(args) < 3 {
|
|
|
|
|
+ log.Fatal("need atleast three arguments <MHASH> <path> <HASH> [<content-type>]")
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ var (
|
|
|
|
|
+ mhash = args[0]
|
|
|
|
|
+ path = args[1]
|
|
|
|
|
+ hash = args[2]
|
|
|
|
|
+
|
|
|
|
|
+ ctype string
|
|
|
|
|
+ wantManifest = ctx.GlobalBoolT(SwarmWantManifestFlag.Name)
|
|
|
|
|
+ mroot manifest
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ if len(args) > 3 {
|
|
|
|
|
+ ctype = args[3]
|
|
|
|
|
+ } else {
|
|
|
|
|
+ ctype = mime.TypeByExtension(filepath.Ext(path))
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ newManifest := addEntryToManifest (ctx, mhash, path, hash, ctype)
|
|
|
|
|
+ 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) {
|
|
|
|
|
+
|
|
|
|
|
+ args := ctx.Args()
|
|
|
|
|
+ if len(args) < 3 {
|
|
|
|
|
+ log.Fatal("need atleast three arguments <MHASH> <path> <HASH>")
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ var (
|
|
|
|
|
+ mhash = args[0]
|
|
|
|
|
+ path = args[1]
|
|
|
|
|
+ hash = args[2]
|
|
|
|
|
+
|
|
|
|
|
+ ctype string
|
|
|
|
|
+ wantManifest = ctx.GlobalBoolT(SwarmWantManifestFlag.Name)
|
|
|
|
|
+ mroot manifest
|
|
|
|
|
+ )
|
|
|
|
|
+ if len(args) > 3 {
|
|
|
|
|
+ ctype = args[3]
|
|
|
|
|
+ } else {
|
|
|
|
|
+ ctype = mime.TypeByExtension(filepath.Ext(path))
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ newManifest := updateEntryInManifest (ctx, mhash, path, hash, ctype)
|
|
|
|
|
+ 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) {
|
|
|
|
|
+ args := ctx.Args()
|
|
|
|
|
+ if len(args) < 2 {
|
|
|
|
|
+ log.Fatal("need atleast two arguments <MHASH> <path>")
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ var (
|
|
|
|
|
+ mhash = args[0]
|
|
|
|
|
+ path = args[1]
|
|
|
|
|
+
|
|
|
|
|
+ wantManifest = ctx.GlobalBoolT(SwarmWantManifestFlag.Name)
|
|
|
|
|
+ mroot manifest
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ newManifest := removeEntryFromManifest (ctx, mhash, path)
|
|
|
|
|
+ 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 addEntryToManifest(ctx *cli.Context, mhash , path, hash , ctype string) string {
|
|
|
|
|
+
|
|
|
|
|
+ var (
|
|
|
|
|
+ bzzapi = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
|
|
|
|
|
+ client = &client{api: bzzapi}
|
|
|
|
|
+ longestPathEntry = manifestEntry{
|
|
|
|
|
+ Path: "",
|
|
|
|
|
+ Hash: "",
|
|
|
|
|
+ ContentType: "",
|
|
|
|
|
+ }
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ mroot, err := client.downloadManifest(mhash)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ log.Fatalln("manifest download failed:", err)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ //TODO: check if the "hash" to add is valid and present in swarm
|
|
|
|
|
+ _, err = client.downloadManifest(hash)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ log.Fatalln("hash to add is not present:", 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 {
|
|
|
|
|
+ log.Fatal(path, "Already present, not adding anything")
|
|
|
|
|
+ }else {
|
|
|
|
|
+ if entry.ContentType == "application/bzz-manifest+json" {
|
|
|
|
|
+ prfxlen := strings.HasPrefix(path, entry.Path)
|
|
|
|
|
+ if prfxlen && len(path) > len(longestPathEntry.Path) {
|
|
|
|
|
+ longestPathEntry = entry
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if longestPathEntry.Path != "" {
|
|
|
|
|
+ // Load the child Manifest add the entry there
|
|
|
|
|
+ newPath := path[len(longestPathEntry.Path):]
|
|
|
|
|
+ newHash := addEntryToManifest (ctx, longestPathEntry.Hash, newPath, hash, ctype)
|
|
|
|
|
+
|
|
|
|
|
+ // Replace the hash for parent Manifests
|
|
|
|
|
+ newMRoot := manifest{}
|
|
|
|
|
+ for _, entry := range mroot.Entries {
|
|
|
|
|
+ if longestPathEntry.Path == entry.Path {
|
|
|
|
|
+ entry.Hash = newHash
|
|
|
|
|
+ }
|
|
|
|
|
+ newMRoot.Entries = append(newMRoot.Entries, entry)
|
|
|
|
|
+ }
|
|
|
|
|
+ mroot = newMRoot
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // Add the entry in the leaf Manifest
|
|
|
|
|
+ newEntry := manifestEntry{
|
|
|
|
|
+ Path: path,
|
|
|
|
|
+ Hash: hash,
|
|
|
|
|
+ ContentType: ctype,
|
|
|
|
|
+ }
|
|
|
|
|
+ mroot.Entries = append(mroot.Entries, newEntry)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ newManifestHash, err := client.uploadManifest(mroot)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ log.Fatalln("manifest upload failed:", err)
|
|
|
|
|
+ }
|
|
|
|
|
+ return newManifestHash
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func updateEntryInManifest(ctx *cli.Context, mhash , path, hash , ctype string) string {
|
|
|
|
|
+
|
|
|
|
|
+ var (
|
|
|
|
|
+ bzzapi = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
|
|
|
|
|
+ client = &client{api: bzzapi}
|
|
|
|
|
+ newEntry = manifestEntry{
|
|
|
|
|
+ Path: "",
|
|
|
|
|
+ Hash: "",
|
|
|
|
|
+ ContentType: "",
|
|
|
|
|
+ }
|
|
|
|
|
+ longestPathEntry = manifestEntry{
|
|
|
|
|
+ Path: "",
|
|
|
|
|
+ Hash: "",
|
|
|
|
|
+ ContentType: "",
|
|
|
|
|
+ }
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ mroot, err := client.downloadManifest(mhash)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ log.Fatalln("manifest download failed:", 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
|
|
|
|
|
+ }else {
|
|
|
|
|
+ if entry.ContentType == "application/bzz-manifest+json" {
|
|
|
|
|
+ prfxlen := strings.HasPrefix(path, entry.Path)
|
|
|
|
|
+ if prfxlen && len(path) > len(longestPathEntry.Path) {
|
|
|
|
|
+ longestPathEntry = entry
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if longestPathEntry.Path == "" && newEntry.Path == "" {
|
|
|
|
|
+ log.Fatal(path, " Path not present in the Manifest, not setting anything")
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if longestPathEntry.Path != "" {
|
|
|
|
|
+ // Load the child Manifest add the entry there
|
|
|
|
|
+ newPath := path[len(longestPathEntry.Path):]
|
|
|
|
|
+ newHash := updateEntryInManifest (ctx, longestPathEntry.Hash, newPath, hash, ctype)
|
|
|
|
|
+
|
|
|
|
|
+ // Replace the hash for parent Manifests
|
|
|
|
|
+ newMRoot := manifest{}
|
|
|
|
|
+ for _, entry := range mroot.Entries {
|
|
|
|
|
+ if longestPathEntry.Path == entry.Path {
|
|
|
|
|
+ entry.Hash = newHash
|
|
|
|
|
+ }
|
|
|
|
|
+ newMRoot.Entries = append(newMRoot.Entries, entry)
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+ mroot = newMRoot
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if newEntry.Path != "" {
|
|
|
|
|
+ // Replace the hash for leaf Manifest
|
|
|
|
|
+ newMRoot := manifest{}
|
|
|
|
|
+ for _, entry := range mroot.Entries {
|
|
|
|
|
+ if newEntry.Path == entry.Path {
|
|
|
|
|
+ myEntry := manifestEntry{
|
|
|
|
|
+ Path: entry.Path,
|
|
|
|
|
+ Hash: hash,
|
|
|
|
|
+ ContentType: ctype,
|
|
|
|
|
+ }
|
|
|
|
|
+ newMRoot.Entries = append(newMRoot.Entries, myEntry)
|
|
|
|
|
+ } else {
|
|
|
|
|
+ newMRoot.Entries = append(newMRoot.Entries, entry)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ mroot = newMRoot
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ newManifestHash, err := client.uploadManifest(mroot)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ log.Fatalln("manifest upload failed:", err)
|
|
|
|
|
+ }
|
|
|
|
|
+ return newManifestHash
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func removeEntryFromManifest(ctx *cli.Context, mhash , path string) string {
|
|
|
|
|
+
|
|
|
|
|
+ var (
|
|
|
|
|
+ bzzapi = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
|
|
|
|
|
+ client = &client{api: bzzapi}
|
|
|
|
|
+ entryToRemove = manifestEntry{
|
|
|
|
|
+ Path: "",
|
|
|
|
|
+ Hash: "",
|
|
|
|
|
+ ContentType: "",
|
|
|
|
|
+ }
|
|
|
|
|
+ longestPathEntry = manifestEntry{
|
|
|
|
|
+ Path: "",
|
|
|
|
|
+ Hash: "",
|
|
|
|
|
+ ContentType: "",
|
|
|
|
|
+ }
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ mroot, err := client.downloadManifest(mhash)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ log.Fatalln("manifest download failed:", 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 == "application/bzz-manifest+json" {
|
|
|
|
|
+ prfxlen := strings.HasPrefix(path, entry.Path)
|
|
|
|
|
+ if prfxlen && len(path) > len(longestPathEntry.Path) {
|
|
|
|
|
+ longestPathEntry = entry
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if longestPathEntry.Path == "" && entryToRemove.Path == "" {
|
|
|
|
|
+ log.Fatal(path, "Path not present in the Manifest, not removing anything")
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if longestPathEntry.Path != "" {
|
|
|
|
|
+ // Load the child Manifest remove the entry there
|
|
|
|
|
+ newPath := path[len(longestPathEntry.Path):]
|
|
|
|
|
+ newHash := removeEntryFromManifest (ctx, longestPathEntry.Hash, newPath)
|
|
|
|
|
+
|
|
|
|
|
+ // Replace the hash for parent Manifests
|
|
|
|
|
+ newMRoot := 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 := manifest{}
|
|
|
|
|
+ for _, entry := range mroot.Entries {
|
|
|
|
|
+ if entryToRemove.Path != entry.Path {
|
|
|
|
|
+ newMRoot.Entries = append(newMRoot.Entries, entry)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ mroot = newMRoot
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ newManifestHash, err := client.uploadManifest(mroot)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ log.Fatalln("manifest upload failed:", err)
|
|
|
|
|
+ }
|
|
|
|
|
+ return newManifestHash
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+}
|
|
|
|
|
+
|