github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/cmd/swarm/manifest.go (about)

     1  
     2  //<developer>
     3  //    <name>linapex 曹一峰</name>
     4  //    <email>linapex@163.com</email>
     5  //    <wx>superexc</wx>
     6  //    <qqgroup>128148617</qqgroup>
     7  //    <url>https://jsq.ink</url>
     8  //    <role>pku engineer</role>
     9  //    <date>2019-03-16 19:16:33</date>
    10  //</624450071156494336>
    11  
    12  
    13  //命令清单更新
    14  package main
    15  
    16  import (
    17  	"fmt"
    18  	"os"
    19  	"strings"
    20  
    21  	"github.com/ethereum/go-ethereum/cmd/utils"
    22  	"github.com/ethereum/go-ethereum/swarm/api"
    23  	swarm "github.com/ethereum/go-ethereum/swarm/api/client"
    24  	"gopkg.in/urfave/cli.v1"
    25  )
    26  
    27  var manifestCommand = cli.Command{
    28  	Name:               "manifest",
    29  	CustomHelpTemplate: helpTemplate,
    30  	Usage:              "perform operations on swarm manifests",
    31  	ArgsUsage:          "COMMAND",
    32  	Description:        "Updates a MANIFEST by adding/removing/updating the hash of a path.\nCOMMAND could be: add, update, remove",
    33  	Subcommands: []cli.Command{
    34  		{
    35  			Action:             manifestAdd,
    36  			CustomHelpTemplate: helpTemplate,
    37  			Name:               "add",
    38  			Usage:              "add a new path to the manifest",
    39  			ArgsUsage:          "<MANIFEST> <path> <hash>",
    40  			Description:        "Adds a new path to the manifest",
    41  		},
    42  		{
    43  			Action:             manifestUpdate,
    44  			CustomHelpTemplate: helpTemplate,
    45  			Name:               "update",
    46  			Usage:              "update the hash for an already existing path in the manifest",
    47  			ArgsUsage:          "<MANIFEST> <path> <newhash>",
    48  			Description:        "Update the hash for an already existing path in the manifest",
    49  		},
    50  		{
    51  			Action:             manifestRemove,
    52  			CustomHelpTemplate: helpTemplate,
    53  			Name:               "remove",
    54  			Usage:              "removes a path from the manifest",
    55  			ArgsUsage:          "<MANIFEST> <path>",
    56  			Description:        "Removes a path from the manifest",
    57  		},
    58  	},
    59  }
    60  
    61  //manifestAdd在给定路径向清单添加新条目。
    62  //最后一个参数new entry hash必须是清单的hash
    63  //只有一个条目,这些元数据将添加到原始清单中。
    64  //
    65  func manifestAdd(ctx *cli.Context) {
    66  	args := ctx.Args()
    67  	if len(args) != 3 {
    68  		utils.Fatalf("Need exactly three arguments <MHASH> <path> <HASH>")
    69  	}
    70  
    71  	var (
    72  		mhash = args[0]
    73  		path  = args[1]
    74  		hash  = args[2]
    75  	)
    76  
    77  	bzzapi := strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
    78  	client := swarm.NewClient(bzzapi)
    79  
    80  	m, _, err := client.DownloadManifest(hash)
    81  	if err != nil {
    82  		utils.Fatalf("Error downloading manifest to add: %v", err)
    83  	}
    84  	l := len(m.Entries)
    85  	if l == 0 {
    86  		utils.Fatalf("No entries in manifest %s", hash)
    87  	} else if l > 1 {
    88  		utils.Fatalf("Too many entries in manifest %s", hash)
    89  	}
    90  
    91  	newManifest := addEntryToManifest(client, mhash, path, m.Entries[0])
    92  	fmt.Println(newManifest)
    93  }
    94  
    95  //清单更新将替换给定路径上清单的现有条目。
    96  //最后一个参数new entry hash必须是清单的hash
    97  //只有一个条目,这些元数据将添加到原始清单中。
    98  //成功后,此函数将打印更新清单的哈希。
    99  func manifestUpdate(ctx *cli.Context) {
   100  	args := ctx.Args()
   101  	if len(args) != 3 {
   102  		utils.Fatalf("Need exactly three arguments <MHASH> <path> <HASH>")
   103  	}
   104  
   105  	var (
   106  		mhash = args[0]
   107  		path  = args[1]
   108  		hash  = args[2]
   109  	)
   110  
   111  	bzzapi := strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
   112  	client := swarm.NewClient(bzzapi)
   113  
   114  	m, _, err := client.DownloadManifest(hash)
   115  	if err != nil {
   116  		utils.Fatalf("Error downloading manifest to update: %v", err)
   117  	}
   118  	l := len(m.Entries)
   119  	if l == 0 {
   120  		utils.Fatalf("No entries in manifest %s", hash)
   121  	} else if l > 1 {
   122  		utils.Fatalf("Too many entries in manifest %s", hash)
   123  	}
   124  
   125  	newManifest, _, defaultEntryUpdated := updateEntryInManifest(client, mhash, path, m.Entries[0], true)
   126  	if defaultEntryUpdated {
   127  //将信息消息打印到stderr
   128  //允许用户从stdout获取新清单哈希
   129  //不需要解析完整的输出。
   130  		fmt.Fprintln(os.Stderr, "Manifest default entry is updated, too")
   131  	}
   132  	fmt.Println(newManifest)
   133  }
   134  
   135  //manifestremove删除给定路径上清单的现有条目。
   136  //成功后,此函数将打印清单的哈希,但该哈希没有
   137  //包含路径。
   138  func manifestRemove(ctx *cli.Context) {
   139  	args := ctx.Args()
   140  	if len(args) != 2 {
   141  		utils.Fatalf("Need exactly two arguments <MHASH> <path>")
   142  	}
   143  
   144  	var (
   145  		mhash = args[0]
   146  		path  = args[1]
   147  	)
   148  
   149  	bzzapi := strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
   150  	client := swarm.NewClient(bzzapi)
   151  
   152  	newManifest := removeEntryFromManifest(client, mhash, path)
   153  	fmt.Println(newManifest)
   154  }
   155  
   156  func addEntryToManifest(client *swarm.Client, mhash, path string, entry api.ManifestEntry) string {
   157  	var longestPathEntry = api.ManifestEntry{}
   158  
   159  	mroot, isEncrypted, err := client.DownloadManifest(mhash)
   160  	if err != nil {
   161  		utils.Fatalf("Manifest download failed: %v", err)
   162  	}
   163  
   164  //看看我们的道路是否在这张清单中,或者我们需要更深入地挖掘
   165  	for _, e := range mroot.Entries {
   166  		if path == e.Path {
   167  			utils.Fatalf("Path %s already present, not adding anything", path)
   168  		} else {
   169  			if e.ContentType == api.ManifestType {
   170  				prfxlen := strings.HasPrefix(path, e.Path)
   171  				if prfxlen && len(path) > len(longestPathEntry.Path) {
   172  					longestPathEntry = e
   173  				}
   174  			}
   175  		}
   176  	}
   177  
   178  	if longestPathEntry.Path != "" {
   179  //加载子清单在其中添加条目
   180  		newPath := path[len(longestPathEntry.Path):]
   181  		newHash := addEntryToManifest(client, longestPathEntry.Hash, newPath, entry)
   182  
   183  //替换父清单的哈希
   184  		newMRoot := &api.Manifest{}
   185  		for _, e := range mroot.Entries {
   186  			if longestPathEntry.Path == e.Path {
   187  				e.Hash = newHash
   188  			}
   189  			newMRoot.Entries = append(newMRoot.Entries, e)
   190  		}
   191  		mroot = newMRoot
   192  	} else {
   193  //在叶清单中添加条目
   194  		entry.Path = path
   195  		mroot.Entries = append(mroot.Entries, entry)
   196  	}
   197  
   198  	newManifestHash, err := client.UploadManifest(mroot, isEncrypted)
   199  	if err != nil {
   200  		utils.Fatalf("Manifest upload failed: %v", err)
   201  	}
   202  	return newManifestHash
   203  }
   204  
   205  //
   206  //通过所有嵌套清单递归查找路径。参数isroot用于默认值
   207  //条目更新检测。如果更新的条目与默认条目具有相同的哈希,则
   208  //
   209  //
   210  //一个布尔值,如果更新默认条目,则为真。
   211  func updateEntryInManifest(client *swarm.Client, mhash, path string, entry api.ManifestEntry, isRoot bool) (newManifestHash, oldHash string, defaultEntryUpdated bool) {
   212  	var (
   213  		newEntry         = api.ManifestEntry{}
   214  		longestPathEntry = api.ManifestEntry{}
   215  	)
   216  
   217  	mroot, isEncrypted, err := client.DownloadManifest(mhash)
   218  	if err != nil {
   219  		utils.Fatalf("Manifest download failed: %v", err)
   220  	}
   221  
   222  //看看我们的道路是否在这张清单中,或者我们需要更深入地挖掘
   223  	for _, e := range mroot.Entries {
   224  		if path == e.Path {
   225  			newEntry = e
   226  //
   227  //
   228  			oldHash = e.Hash
   229  		} else {
   230  			if e.ContentType == api.ManifestType {
   231  				prfxlen := strings.HasPrefix(path, e.Path)
   232  				if prfxlen && len(path) > len(longestPathEntry.Path) {
   233  					longestPathEntry = e
   234  				}
   235  			}
   236  		}
   237  	}
   238  
   239  	if longestPathEntry.Path == "" && newEntry.Path == "" {
   240  		utils.Fatalf("Path %s not present in the Manifest, not setting anything", path)
   241  	}
   242  
   243  	if longestPathEntry.Path != "" {
   244  //加载子清单在其中添加条目
   245  		newPath := path[len(longestPathEntry.Path):]
   246  		var newHash string
   247  		newHash, oldHash, _ = updateEntryInManifest(client, longestPathEntry.Hash, newPath, entry, false)
   248  
   249  //替换父清单的哈希
   250  		newMRoot := &api.Manifest{}
   251  		for _, e := range mroot.Entries {
   252  			if longestPathEntry.Path == e.Path {
   253  				e.Hash = newHash
   254  			}
   255  			newMRoot.Entries = append(newMRoot.Entries, e)
   256  
   257  		}
   258  		mroot = newMRoot
   259  	}
   260  
   261  //
   262  //检查是否应更新默认条目
   263  	if newEntry.Path != "" || isRoot {
   264  //替换叶清单的哈希
   265  		newMRoot := &api.Manifest{}
   266  		for _, e := range mroot.Entries {
   267  			if newEntry.Path == e.Path {
   268  				entry.Path = e.Path
   269  				newMRoot.Entries = append(newMRoot.Entries, entry)
   270  			} else if isRoot && e.Path == "" && e.Hash == oldHash {
   271  				entry.Path = e.Path
   272  				newMRoot.Entries = append(newMRoot.Entries, entry)
   273  				defaultEntryUpdated = true
   274  			} else {
   275  				newMRoot.Entries = append(newMRoot.Entries, e)
   276  			}
   277  		}
   278  		mroot = newMRoot
   279  	}
   280  
   281  	newManifestHash, err = client.UploadManifest(mroot, isEncrypted)
   282  	if err != nil {
   283  		utils.Fatalf("Manifest upload failed: %v", err)
   284  	}
   285  	return newManifestHash, oldHash, defaultEntryUpdated
   286  }
   287  
   288  func removeEntryFromManifest(client *swarm.Client, mhash, path string) string {
   289  	var (
   290  		entryToRemove    = api.ManifestEntry{}
   291  		longestPathEntry = api.ManifestEntry{}
   292  	)
   293  
   294  	mroot, isEncrypted, err := client.DownloadManifest(mhash)
   295  	if err != nil {
   296  		utils.Fatalf("Manifest download failed: %v", err)
   297  	}
   298  
   299  //看看我们的道路是否在这张清单中,或者我们需要更深入地挖掘
   300  	for _, entry := range mroot.Entries {
   301  		if path == entry.Path {
   302  			entryToRemove = entry
   303  		} else {
   304  			if entry.ContentType == api.ManifestType {
   305  				prfxlen := strings.HasPrefix(path, entry.Path)
   306  				if prfxlen && len(path) > len(longestPathEntry.Path) {
   307  					longestPathEntry = entry
   308  				}
   309  			}
   310  		}
   311  	}
   312  
   313  	if longestPathEntry.Path == "" && entryToRemove.Path == "" {
   314  		utils.Fatalf("Path %s not present in the Manifest, not removing anything", path)
   315  	}
   316  
   317  	if longestPathEntry.Path != "" {
   318  //加载子清单删除其中的项
   319  		newPath := path[len(longestPathEntry.Path):]
   320  		newHash := removeEntryFromManifest(client, longestPathEntry.Hash, newPath)
   321  
   322  //替换父清单的哈希
   323  		newMRoot := &api.Manifest{}
   324  		for _, entry := range mroot.Entries {
   325  			if longestPathEntry.Path == entry.Path {
   326  				entry.Hash = newHash
   327  			}
   328  			newMRoot.Entries = append(newMRoot.Entries, entry)
   329  		}
   330  		mroot = newMRoot
   331  	}
   332  
   333  	if entryToRemove.Path != "" {
   334  //删除此清单中的条目
   335  		newMRoot := &api.Manifest{}
   336  		for _, entry := range mroot.Entries {
   337  			if entryToRemove.Path != entry.Path {
   338  				newMRoot.Entries = append(newMRoot.Entries, entry)
   339  			}
   340  		}
   341  		mroot = newMRoot
   342  	}
   343  
   344  	newManifestHash, err := client.UploadManifest(mroot, isEncrypted)
   345  	if err != nil {
   346  		utils.Fatalf("Manifest upload failed: %v", err)
   347  	}
   348  	return newManifestHash
   349  }
   350