361 lines
		
	
	
		
			8.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			361 lines
		
	
	
		
			8.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // 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
 | |
| 
 | |
| 
 | |
| }
 | |
| 
 |