github.com/AlekSi/nut@v0.3.1-0.20130607203728-cce108d4135e/nut/get.go (about) 1 package main 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 "go/build" 8 "io/ioutil" 9 "log" 10 "net" 11 "net/http" 12 "net/url" 13 "path/filepath" 14 "sort" 15 "strings" 16 17 . "github.com/AlekSi/nut" 18 ) 19 20 var ( 21 cmdGet = &Command{ 22 Run: runGet, 23 UsageLine: "get [-p prefix] [-v] [name, import path or URL]", 24 Short: "download and install nut and dependencies", 25 } 26 27 getP string 28 getV bool 29 ) 30 31 func init() { 32 cmdGet.Long = ` 33 Downloads and installs nut and dependencies from http://gonuts.io/ or specified URL. 34 35 Examples: 36 nut install aleksi/nut 37 nut install aleksi/nut/0.2.0 38 nut install gonuts.io/aleksi/nut 39 nut install gonuts.io/aleksi/nut/0.2.0 40 nut install http://gonuts.io/aleksi/nut 41 nut install http://gonuts.io/aleksi/nut/0.2.0 42 ` 43 44 cmdGet.Flag.StringVar(&getP, "p", "", "install prefix in workspace, uses hostname from URL if omitted") 45 cmdGet.Flag.BoolVar(&getV, "v", false, vHelp) 46 } 47 48 // Parse argument, return URL to get nut from and install prefix. 49 func ParseArg(s string) (u *url.URL, prefix string) { 50 var p []string 51 var host string 52 var ok bool 53 54 // full URL - as is 55 if strings.HasPrefix(s, "http://") || strings.HasPrefix(s, "https://") { 56 goto parse 57 } 58 59 p = strings.Split(s, "/") 60 if len(p) > 0 { 61 prefix = p[0] 62 host, ok = NutImportPrefixes[prefix] 63 } 64 if ok { 65 // import path style 66 p[0] = "http://" + host 67 s = strings.Join(p, "/") 68 } else { 69 // short style 70 prefix = "gonuts.io" 71 host = NutImportPrefixes[prefix] 72 s = fmt.Sprintf("http://%s/%s", host, s) 73 } 74 75 parse: 76 u, err := url.Parse(s) 77 FatalIfErr(err) 78 if prefix == "" { 79 prefix = u.Host 80 if strings.Contains(prefix, ":") { 81 prefix, _, err = net.SplitHostPort(prefix) 82 FatalIfErr(err) 83 } 84 if strings.HasPrefix(prefix, "www.") { 85 prefix = prefix[4:] 86 } 87 } 88 89 return 90 } 91 92 func get(url *url.URL) (b []byte, err error) { 93 if getV { 94 log.Printf("Getting %s ...", url) 95 } 96 97 req, err := http.NewRequest("GET", url.String(), nil) 98 if err != nil { 99 return 100 } 101 req.Header.Set("User-Agent", "nut getter") 102 req.Header.Set("Accept", "application/zip") 103 104 res, err := http.DefaultClient.Do(req) 105 if err != nil { 106 return 107 } 108 defer res.Body.Close() 109 110 b, err = ioutil.ReadAll(res.Body) 111 if err != nil { 112 return 113 } 114 115 if res.StatusCode/100 != 2 { 116 err = fmt.Errorf("Status code %d", res.StatusCode) 117 return 118 } 119 120 if getV { 121 log.Printf("Status code %d", res.StatusCode) 122 } 123 124 return 125 } 126 127 func runGet(cmd *Command) { 128 if !getV { 129 getV = Config.V 130 } 131 132 args := cmd.Flag.Args() 133 134 // zero arguments is a special case – install dependencies for package in current directory 135 if len(args) == 0 { 136 pack, err := build.ImportDir(".", 0) 137 FatalIfErr(err) 138 args = NutImports(pack.Imports) 139 if getV && len(args) != 0 { 140 log.Printf("%s depends on nuts: %s", pack.Name, strings.Join(args, ",")) 141 } 142 } 143 144 urlsToPaths := make(map[string]string, len(args)) 145 for len(args) != 0 { 146 arg := args[0] 147 args = args[1:] 148 149 url, prefix := ParseArg(arg) 150 151 // do not download twice 152 _, present := urlsToPaths[url.String()] 153 if present { 154 continue 155 } 156 157 b, err := get(url) 158 if err != nil { 159 log.Print(err) 160 161 var body map[string]interface{} 162 err = json.Unmarshal(b, &body) 163 if err != nil { 164 log.Print(err) 165 } 166 m, ok := body["Message"] 167 if ok { 168 log.Fatalf("%s", m) 169 } else { 170 log.Fatalf("Response: %#q", body) 171 } 172 } 173 174 nf := new(NutFile) 175 _, err = nf.ReadFrom(bytes.NewReader(b)) 176 FatalIfErr(err) 177 deps := NutImports(nf.Imports) 178 if getV && len(deps) != 0 { 179 log.Printf("%s depends on nuts: %s", nf.Name, strings.Join(deps, ", ")) 180 } 181 args = append(args, deps...) 182 183 p := getP 184 if p == "" { 185 p = prefix 186 } 187 fileName := WriteNut(b, p, getV) 188 path := nf.ImportPath(p) 189 UnpackNut(fileName, filepath.Join(SrcDir, path), true, getV) 190 urlsToPaths[url.String()] = path 191 } 192 193 // install in lexical order (useful in integration tests) 194 paths := make([]string, 0, len(urlsToPaths)) 195 for _, path := range urlsToPaths { 196 paths = append(paths, path) 197 } 198 sort.Strings(paths) 199 for _, path := range paths { 200 InstallPackage(path, getV) 201 } 202 }