github.com/sberex/go-sberex@v1.8.2-0.20181113200658-ed96ac38f7d7/cmd/swarm/manifest.go (about)

     1  // This file is part of the go-sberex library. The go-sberex library is 
     2  // free software: you can redistribute it and/or modify it under the terms 
     3  // of the GNU Lesser General Public License as published by the Free 
     4  // Software Foundation, either version 3 of the License, or (at your option)
     5  // any later version.
     6  //
     7  // The go-sberex library is distributed in the hope that it will be useful, 
     8  // but WITHOUT ANY WARRANTY; without even the implied warranty of
     9  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 
    10  // General Public License <http://www.gnu.org/licenses/> for more details.
    11  
    12  // Command  MANIFEST update
    13  package main
    14  
    15  import (
    16  	"encoding/json"
    17  	"fmt"
    18  	"mime"
    19  	"path/filepath"
    20  	"strings"
    21  
    22  	"github.com/Sberex/go-sberex/cmd/utils"
    23  	"github.com/Sberex/go-sberex/swarm/api"
    24  	swarm "github.com/Sberex/go-sberex/swarm/api/client"
    25  	"gopkg.in/urfave/cli.v1"
    26  )
    27  
    28  const bzzManifestJSON = "application/bzz-manifest+json"
    29  
    30  func add(ctx *cli.Context) {
    31  	args := ctx.Args()
    32  	if len(args) < 3 {
    33  		utils.Fatalf("Need atleast three arguments <MHASH> <path> <HASH> [<content-type>]")
    34  	}
    35  
    36  	var (
    37  		mhash = args[0]
    38  		path  = args[1]
    39  		hash  = args[2]
    40  
    41  		ctype        string
    42  		wantManifest = ctx.GlobalBoolT(SwarmWantManifestFlag.Name)
    43  		mroot        api.Manifest
    44  	)
    45  
    46  	if len(args) > 3 {
    47  		ctype = args[3]
    48  	} else {
    49  		ctype = mime.TypeByExtension(filepath.Ext(path))
    50  	}
    51  
    52  	newManifest := addEntryToManifest(ctx, mhash, path, hash, ctype)
    53  	fmt.Println(newManifest)
    54  
    55  	if !wantManifest {
    56  		// Print the manifest. This is the only output to stdout.
    57  		mrootJSON, _ := json.MarshalIndent(mroot, "", "  ")
    58  		fmt.Println(string(mrootJSON))
    59  		return
    60  	}
    61  }
    62  
    63  func update(ctx *cli.Context) {
    64  
    65  	args := ctx.Args()
    66  	if len(args) < 3 {
    67  		utils.Fatalf("Need atleast three arguments <MHASH> <path> <HASH>")
    68  	}
    69  
    70  	var (
    71  		mhash = args[0]
    72  		path  = args[1]
    73  		hash  = args[2]
    74  
    75  		ctype        string
    76  		wantManifest = ctx.GlobalBoolT(SwarmWantManifestFlag.Name)
    77  		mroot        api.Manifest
    78  	)
    79  	if len(args) > 3 {
    80  		ctype = args[3]
    81  	} else {
    82  		ctype = mime.TypeByExtension(filepath.Ext(path))
    83  	}
    84  
    85  	newManifest := updateEntryInManifest(ctx, mhash, path, hash, ctype)
    86  	fmt.Println(newManifest)
    87  
    88  	if !wantManifest {
    89  		// Print the manifest. This is the only output to stdout.
    90  		mrootJSON, _ := json.MarshalIndent(mroot, "", "  ")
    91  		fmt.Println(string(mrootJSON))
    92  		return
    93  	}
    94  }
    95  
    96  func remove(ctx *cli.Context) {
    97  	args := ctx.Args()
    98  	if len(args) < 2 {
    99  		utils.Fatalf("Need atleast two arguments <MHASH> <path>")
   100  	}
   101  
   102  	var (
   103  		mhash = args[0]
   104  		path  = args[1]
   105  
   106  		wantManifest = ctx.GlobalBoolT(SwarmWantManifestFlag.Name)
   107  		mroot        api.Manifest
   108  	)
   109  
   110  	newManifest := removeEntryFromManifest(ctx, mhash, path)
   111  	fmt.Println(newManifest)
   112  
   113  	if !wantManifest {
   114  		// Print the manifest. This is the only output to stdout.
   115  		mrootJSON, _ := json.MarshalIndent(mroot, "", "  ")
   116  		fmt.Println(string(mrootJSON))
   117  		return
   118  	}
   119  }
   120  
   121  func addEntryToManifest(ctx *cli.Context, mhash, path, hash, ctype string) string {
   122  
   123  	var (
   124  		bzzapi           = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
   125  		client           = swarm.NewClient(bzzapi)
   126  		longestPathEntry = api.ManifestEntry{}
   127  	)
   128  
   129  	mroot, err := client.DownloadManifest(mhash)
   130  	if err != nil {
   131  		utils.Fatalf("Manifest download failed: %v", err)
   132  	}
   133  
   134  	//TODO: check if the "hash" to add is valid and present in swarm
   135  	_, err = client.DownloadManifest(hash)
   136  	if err != nil {
   137  		utils.Fatalf("Hash to add is not present: %v", err)
   138  	}
   139  
   140  	// See if we path is in this Manifest or do we have to dig deeper
   141  	for _, entry := range mroot.Entries {
   142  		if path == entry.Path {
   143  			utils.Fatalf("Path %s already present, not adding anything", path)
   144  		} else {
   145  			if entry.ContentType == bzzManifestJSON {
   146  				prfxlen := strings.HasPrefix(path, entry.Path)
   147  				if prfxlen && len(path) > len(longestPathEntry.Path) {
   148  					longestPathEntry = entry
   149  				}
   150  			}
   151  		}
   152  	}
   153  
   154  	if longestPathEntry.Path != "" {
   155  		// Load the child Manifest add the entry there
   156  		newPath := path[len(longestPathEntry.Path):]
   157  		newHash := addEntryToManifest(ctx, longestPathEntry.Hash, newPath, hash, ctype)
   158  
   159  		// Replace the hash for parent Manifests
   160  		newMRoot := &api.Manifest{}
   161  		for _, entry := range mroot.Entries {
   162  			if longestPathEntry.Path == entry.Path {
   163  				entry.Hash = newHash
   164  			}
   165  			newMRoot.Entries = append(newMRoot.Entries, entry)
   166  		}
   167  		mroot = newMRoot
   168  	} else {
   169  		// Add the entry in the leaf Manifest
   170  		newEntry := api.ManifestEntry{
   171  			Hash:        hash,
   172  			Path:        path,
   173  			ContentType: ctype,
   174  		}
   175  		mroot.Entries = append(mroot.Entries, newEntry)
   176  	}
   177  
   178  	newManifestHash, err := client.UploadManifest(mroot)
   179  	if err != nil {
   180  		utils.Fatalf("Manifest upload failed: %v", err)
   181  	}
   182  	return newManifestHash
   183  
   184  }
   185  
   186  func updateEntryInManifest(ctx *cli.Context, mhash, path, hash, ctype string) string {
   187  
   188  	var (
   189  		bzzapi           = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
   190  		client           = swarm.NewClient(bzzapi)
   191  		newEntry         = api.ManifestEntry{}
   192  		longestPathEntry = api.ManifestEntry{}
   193  	)
   194  
   195  	mroot, err := client.DownloadManifest(mhash)
   196  	if err != nil {
   197  		utils.Fatalf("Manifest download failed: %v", err)
   198  	}
   199  
   200  	//TODO: check if the "hash" with which to update is valid and present in swarm
   201  
   202  	// See if we path is in this Manifest or do we have to dig deeper
   203  	for _, entry := range mroot.Entries {
   204  		if path == entry.Path {
   205  			newEntry = entry
   206  		} else {
   207  			if entry.ContentType == bzzManifestJSON {
   208  				prfxlen := strings.HasPrefix(path, entry.Path)
   209  				if prfxlen && len(path) > len(longestPathEntry.Path) {
   210  					longestPathEntry = entry
   211  				}
   212  			}
   213  		}
   214  	}
   215  
   216  	if longestPathEntry.Path == "" && newEntry.Path == "" {
   217  		utils.Fatalf("Path %s not present in the Manifest, not setting anything", path)
   218  	}
   219  
   220  	if longestPathEntry.Path != "" {
   221  		// Load the child Manifest add the entry there
   222  		newPath := path[len(longestPathEntry.Path):]
   223  		newHash := updateEntryInManifest(ctx, longestPathEntry.Hash, newPath, hash, ctype)
   224  
   225  		// Replace the hash for parent Manifests
   226  		newMRoot := &api.Manifest{}
   227  		for _, entry := range mroot.Entries {
   228  			if longestPathEntry.Path == entry.Path {
   229  				entry.Hash = newHash
   230  			}
   231  			newMRoot.Entries = append(newMRoot.Entries, entry)
   232  
   233  		}
   234  		mroot = newMRoot
   235  	}
   236  
   237  	if newEntry.Path != "" {
   238  		// Replace the hash for leaf Manifest
   239  		newMRoot := &api.Manifest{}
   240  		for _, entry := range mroot.Entries {
   241  			if newEntry.Path == entry.Path {
   242  				myEntry := api.ManifestEntry{
   243  					Hash:        hash,
   244  					Path:        entry.Path,
   245  					ContentType: ctype,
   246  				}
   247  				newMRoot.Entries = append(newMRoot.Entries, myEntry)
   248  			} else {
   249  				newMRoot.Entries = append(newMRoot.Entries, entry)
   250  			}
   251  		}
   252  		mroot = newMRoot
   253  	}
   254  
   255  	newManifestHash, err := client.UploadManifest(mroot)
   256  	if err != nil {
   257  		utils.Fatalf("Manifest upload failed: %v", err)
   258  	}
   259  	return newManifestHash
   260  }
   261  
   262  func removeEntryFromManifest(ctx *cli.Context, mhash, path string) string {
   263  
   264  	var (
   265  		bzzapi           = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
   266  		client           = swarm.NewClient(bzzapi)
   267  		entryToRemove    = api.ManifestEntry{}
   268  		longestPathEntry = api.ManifestEntry{}
   269  	)
   270  
   271  	mroot, err := client.DownloadManifest(mhash)
   272  	if err != nil {
   273  		utils.Fatalf("Manifest download failed: %v", err)
   274  	}
   275  
   276  	// See if we path is in this Manifest or do we have to dig deeper
   277  	for _, entry := range mroot.Entries {
   278  		if path == entry.Path {
   279  			entryToRemove = entry
   280  		} else {
   281  			if entry.ContentType == bzzManifestJSON {
   282  				prfxlen := strings.HasPrefix(path, entry.Path)
   283  				if prfxlen && len(path) > len(longestPathEntry.Path) {
   284  					longestPathEntry = entry
   285  				}
   286  			}
   287  		}
   288  	}
   289  
   290  	if longestPathEntry.Path == "" && entryToRemove.Path == "" {
   291  		utils.Fatalf("Path %s not present in the Manifest, not removing anything", path)
   292  	}
   293  
   294  	if longestPathEntry.Path != "" {
   295  		// Load the child Manifest remove the entry there
   296  		newPath := path[len(longestPathEntry.Path):]
   297  		newHash := removeEntryFromManifest(ctx, longestPathEntry.Hash, newPath)
   298  
   299  		// Replace the hash for parent Manifests
   300  		newMRoot := &api.Manifest{}
   301  		for _, entry := range mroot.Entries {
   302  			if longestPathEntry.Path == entry.Path {
   303  				entry.Hash = newHash
   304  			}
   305  			newMRoot.Entries = append(newMRoot.Entries, entry)
   306  		}
   307  		mroot = newMRoot
   308  	}
   309  
   310  	if entryToRemove.Path != "" {
   311  		// remove the entry in this Manifest
   312  		newMRoot := &api.Manifest{}
   313  		for _, entry := range mroot.Entries {
   314  			if entryToRemove.Path != entry.Path {
   315  				newMRoot.Entries = append(newMRoot.Entries, entry)
   316  			}
   317  		}
   318  		mroot = newMRoot
   319  	}
   320  
   321  	newManifestHash, err := client.UploadManifest(mroot)
   322  	if err != nil {
   323  		utils.Fatalf("Manifest upload failed: %v", err)
   324  	}
   325  	return newManifestHash
   326  }