github.com/cheng762/platon-go@v1.8.17-0.20190529111256-7deff2d7be26/cmd/swarm/manifest.go (about)

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