github.com/shyftnetwork/go-empyrean@v1.8.3-0.20191127201940-fbfca9338f04/cmd/swarm/upload.go (about) 1 // Copyright 2016 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 bzzup uploads files to the swarm HTTP API. 18 package main 19 20 import ( 21 "errors" 22 "fmt" 23 "io" 24 "io/ioutil" 25 "os" 26 "os/user" 27 "path" 28 "path/filepath" 29 "strconv" 30 "strings" 31 32 "github.com/ShyftNetwork/go-empyrean/cmd/utils" 33 "github.com/ShyftNetwork/go-empyrean/log" 34 swarm "github.com/ShyftNetwork/go-empyrean/swarm/api/client" 35 "gopkg.in/urfave/cli.v1" 36 ) 37 38 var upCommand = cli.Command{ 39 Action: upload, 40 CustomHelpTemplate: helpTemplate, 41 Name: "up", 42 Usage: "uploads a file or directory to swarm using the HTTP API", 43 ArgsUsage: "<file>", 44 Flags: []cli.Flag{SwarmEncryptedFlag}, 45 Description: "uploads a file or directory to swarm using the HTTP API and prints the root hash", 46 } 47 48 func upload(ctx *cli.Context) { 49 args := ctx.Args() 50 var ( 51 bzzapi = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/") 52 recursive = ctx.GlobalBool(SwarmRecursiveFlag.Name) 53 wantManifest = ctx.GlobalBoolT(SwarmWantManifestFlag.Name) 54 defaultPath = ctx.GlobalString(SwarmUploadDefaultPath.Name) 55 fromStdin = ctx.GlobalBool(SwarmUpFromStdinFlag.Name) 56 mimeType = ctx.GlobalString(SwarmUploadMimeType.Name) 57 client = swarm.NewClient(bzzapi) 58 toEncrypt = ctx.Bool(SwarmEncryptedFlag.Name) 59 autoDefaultPath = false 60 file string 61 ) 62 if autoDefaultPathString := os.Getenv(SWARM_AUTO_DEFAULTPATH); autoDefaultPathString != "" { 63 b, err := strconv.ParseBool(autoDefaultPathString) 64 if err != nil { 65 utils.Fatalf("invalid environment variable %s: %v", SWARM_AUTO_DEFAULTPATH, err) 66 } 67 autoDefaultPath = b 68 } 69 if len(args) != 1 { 70 if fromStdin { 71 tmp, err := ioutil.TempFile("", "swarm-stdin") 72 if err != nil { 73 utils.Fatalf("error create tempfile: %s", err) 74 } 75 defer os.Remove(tmp.Name()) 76 n, err := io.Copy(tmp, os.Stdin) 77 if err != nil { 78 utils.Fatalf("error copying stdin to tempfile: %s", err) 79 } else if n == 0 { 80 utils.Fatalf("error reading from stdin: zero length") 81 } 82 file = tmp.Name() 83 } else { 84 utils.Fatalf("Need filename as the first and only argument") 85 } 86 } else { 87 file = expandPath(args[0]) 88 } 89 90 if !wantManifest { 91 f, err := swarm.Open(file) 92 if err != nil { 93 utils.Fatalf("Error opening file: %s", err) 94 } 95 defer f.Close() 96 hash, err := client.UploadRaw(f, f.Size, toEncrypt) 97 if err != nil { 98 utils.Fatalf("Upload failed: %s", err) 99 } 100 fmt.Println(hash) 101 return 102 } 103 104 stat, err := os.Stat(file) 105 if err != nil { 106 utils.Fatalf("Error opening file: %s", err) 107 } 108 109 // define a function which either uploads a directory or single file 110 // based on the type of the file being uploaded 111 var doUpload func() (hash string, err error) 112 if stat.IsDir() { 113 doUpload = func() (string, error) { 114 if !recursive { 115 return "", errors.New("Argument is a directory and recursive upload is disabled") 116 } 117 if autoDefaultPath && defaultPath == "" { 118 defaultEntryCandidate := path.Join(file, "index.html") 119 log.Debug("trying to find default path", "path", defaultEntryCandidate) 120 defaultEntryStat, err := os.Stat(defaultEntryCandidate) 121 if err == nil && !defaultEntryStat.IsDir() { 122 log.Debug("setting auto detected default path", "path", defaultEntryCandidate) 123 defaultPath = defaultEntryCandidate 124 } 125 } 126 if defaultPath != "" { 127 // construct absolute default path 128 absDefaultPath, _ := filepath.Abs(defaultPath) 129 absFile, _ := filepath.Abs(file) 130 // make sure absolute directory ends with only one "/" 131 // to trim it from absolute default path and get relative default path 132 absFile = strings.TrimRight(absFile, "/") + "/" 133 if absDefaultPath != "" && absFile != "" && strings.HasPrefix(absDefaultPath, absFile) { 134 defaultPath = strings.TrimPrefix(absDefaultPath, absFile) 135 } 136 } 137 return client.UploadDirectory(file, defaultPath, "", toEncrypt) 138 } 139 } else { 140 doUpload = func() (string, error) { 141 f, err := swarm.Open(file) 142 if err != nil { 143 return "", fmt.Errorf("error opening file: %s", err) 144 } 145 defer f.Close() 146 if mimeType != "" { 147 f.ContentType = mimeType 148 } 149 return client.Upload(f, "", toEncrypt) 150 } 151 } 152 hash, err := doUpload() 153 if err != nil { 154 utils.Fatalf("Upload failed: %s", err) 155 } 156 fmt.Println(hash) 157 } 158 159 // Expands a file path 160 // 1. replace tilde with users home dir 161 // 2. expands embedded environment variables 162 // 3. cleans the path, e.g. /a/b/../c -> /a/c 163 // Note, it has limitations, e.g. ~someuser/tmp will not be expanded 164 func expandPath(p string) string { 165 if i := strings.Index(p, ":"); i > 0 { 166 return p 167 } 168 if i := strings.Index(p, "@"); i > 0 { 169 return p 170 } 171 if strings.HasPrefix(p, "~/") || strings.HasPrefix(p, "~\\") { 172 if home := homeDir(); home != "" { 173 p = home + p[1:] 174 } 175 } 176 return path.Clean(os.ExpandEnv(p)) 177 } 178 179 func homeDir() string { 180 if home := os.Getenv("HOME"); home != "" { 181 return home 182 } 183 if usr, err := user.Current(); err == nil { 184 return usr.HomeDir 185 } 186 return "" 187 }