github.com/slspeek/camlistore_namedsearch@v0.0.0-20140519202248-ed6f70f7721a/cmd/camput/camput.go (about) 1 /* 2 Copyright 2011 Google Inc. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package main 18 19 import ( 20 "flag" 21 "fmt" 22 "log" 23 "net/http" 24 "net/url" 25 "os" 26 "strconv" 27 "strings" 28 "sync" 29 30 "camlistore.org/pkg/blobserver/dir" 31 "camlistore.org/pkg/client" 32 "camlistore.org/pkg/cmdmain" 33 "camlistore.org/pkg/httputil" 34 "camlistore.org/pkg/syncutil" 35 ) 36 37 const buffered = 16 // arbitrary 38 39 var ( 40 flagProxyLocal = false 41 flagHTTP = flag.Bool("verbose_http", false, "show HTTP request summaries") 42 flagHaveCache = true 43 flagBlobDir = flag.String("blobdir", "", "If non-empty, the local directory to put blobs, instead of sending them over the network. If the string \"discard\", no blobs are written or sent over the network anywhere.") 44 ) 45 46 var ( 47 uploaderOnce sync.Once 48 uploader *Uploader // initialized by getUploader 49 ) 50 51 var debugFlagOnce sync.Once 52 53 func registerDebugFlags() { 54 flag.BoolVar(&flagProxyLocal, "proxy_local", false, "If true, the HTTP_PROXY environment is also used for localhost requests. This can be helpful during debugging.") 55 flag.BoolVar(&flagHaveCache, "havecache", true, "Use the 'have cache', a cache keeping track of what blobs the remote server should already have from previous uploads.") 56 } 57 58 func init() { 59 if debug, _ := strconv.ParseBool(os.Getenv("CAMLI_DEBUG")); debug { 60 debugFlagOnce.Do(registerDebugFlags) 61 } 62 cmdmain.ExtraFlagRegistration = client.AddFlags 63 cmdmain.PreExit = func() { 64 if up := uploader; up != nil { 65 up.Close() 66 stats := up.Stats() 67 if *cmdmain.FlagVerbose { 68 log.Printf("Client stats: %s", stats.String()) 69 if up.transport != nil { 70 log.Printf(" #HTTP reqs: %d", up.transport.Requests()) 71 } 72 } 73 } 74 75 // So multiple cmd/camput TestFoo funcs run, each with 76 // an fresh (and not previously closed) Uploader: 77 uploader = nil 78 uploaderOnce = sync.Once{} 79 } 80 } 81 82 func getUploader() *Uploader { 83 uploaderOnce.Do(initUploader) 84 return uploader 85 } 86 87 func initUploader() { 88 up := newUploader() 89 if flagHaveCache && *flagBlobDir == "" { 90 gen, err := up.StorageGeneration() 91 if err != nil { 92 log.Printf("WARNING: not using local server inventory cache; failed to retrieve server's storage generation: %v", err) 93 } else { 94 up.haveCache = NewKvHaveCache(gen) 95 up.Client.SetHaveCache(up.haveCache) 96 } 97 } 98 uploader = up 99 } 100 101 func handleResult(what string, pr *client.PutResult, err error) error { 102 if err != nil { 103 log.Printf("Error putting %s: %s", what, err) 104 cmdmain.ExitWithFailure = true 105 return err 106 } 107 fmt.Fprintln(cmdmain.Stdout, pr.BlobRef.String()) 108 return nil 109 } 110 111 func getenvEitherCase(k string) string { 112 if v := os.Getenv(strings.ToUpper(k)); v != "" { 113 return v 114 } 115 return os.Getenv(strings.ToLower(k)) 116 } 117 118 // proxyFromEnvironment is similar to http.ProxyFromEnvironment but it skips 119 // $NO_PROXY blacklist so it proxies every requests, including localhost 120 // requests. 121 func proxyFromEnvironment(req *http.Request) (*url.URL, error) { 122 proxy := getenvEitherCase("HTTP_PROXY") 123 if proxy == "" { 124 return nil, nil 125 } 126 proxyURL, err := url.Parse(proxy) 127 if err != nil || proxyURL.Scheme == "" { 128 if u, err := url.Parse("http://" + proxy); err == nil { 129 proxyURL = u 130 err = nil 131 } 132 } 133 if err != nil { 134 return nil, fmt.Errorf("invalid proxy address %q: %v", proxy, err) 135 } 136 return proxyURL, nil 137 } 138 139 func newUploader() *Uploader { 140 var cc *client.Client 141 var httpStats *httputil.StatsTransport 142 if d := *flagBlobDir; d != "" { 143 ss, err := dir.New(d) 144 if err != nil && d == "discard" { 145 ss = discardStorage{} 146 err = nil 147 } 148 if err != nil { 149 log.Fatalf("Error using dir %s as storage: %v", d, err) 150 } 151 cc = client.NewStorageClient(ss) 152 } else { 153 cc = client.NewOrFail() 154 proxy := http.ProxyFromEnvironment 155 if flagProxyLocal { 156 proxy = proxyFromEnvironment 157 } 158 tr := cc.TransportForConfig( 159 &client.TransportConfig{ 160 Proxy: proxy, 161 Verbose: *flagHTTP, 162 }) 163 httpStats, _ = tr.(*httputil.StatsTransport) 164 cc.SetHTTPClient(&http.Client{Transport: tr}) 165 } 166 if !*cmdmain.FlagVerbose { 167 cc.SetLogger(nil) 168 } 169 170 pwd, err := os.Getwd() 171 if err != nil { 172 log.Fatalf("os.Getwd: %v", err) 173 } 174 175 return &Uploader{ 176 Client: cc, 177 transport: httpStats, 178 pwd: pwd, 179 fdGate: syncutil.NewGate(100), // gate things that waste fds, assuming a low system limit 180 } 181 } 182 183 func main() { 184 cmdmain.Main() 185 }