├── .github └── ISSUE_TEMPLATE.md ├── .gitignore ├── .gitmodules ├── .travis.yml ├── LICENSE.md ├── README.md ├── api.go ├── assets └── .keep ├── cmd_cleanup.go ├── cmd_daemon.go ├── cmd_dlite.go ├── cmd_init.go ├── cmd_ip.go ├── cmd_setup.go ├── cmd_ssh.go ├── cmd_start.go ├── cmd_status.go ├── cmd_stop.go ├── cmd_tty.go ├── cmd_uninstall.go ├── config.go ├── daemon.go ├── disk.go ├── dns.go ├── gen_assets.go ├── helpers.go ├── http_logger.go ├── listeners.go ├── net.go ├── nfs.go ├── os.go ├── proxy.go ├── ssh.go ├── tar.go ├── ui.go ├── vendor ├── github.com │ ├── blang │ │ └── semver │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── json.go │ │ │ ├── range.go │ │ │ ├── semver.go │ │ │ ├── sort.go │ │ │ └── sql.go │ ├── briandowns │ │ └── spinner │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── character_sets.go │ │ │ └── spinner.go │ ├── fatih │ │ └── color │ │ │ ├── LICENSE.md │ │ │ ├── README.md │ │ │ ├── color.go │ │ │ └── doc.go │ ├── howeyc │ │ └── fsnotify │ │ │ ├── AUTHORS │ │ │ ├── CHANGELOG.md │ │ │ ├── CONTRIBUTING.md │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── fsnotify.go │ │ │ ├── fsnotify_bsd.go │ │ │ ├── fsnotify_linux.go │ │ │ ├── fsnotify_open_bsd.go │ │ │ ├── fsnotify_open_darwin.go │ │ │ └── fsnotify_windows.go │ ├── kardianos │ │ └── osext │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── osext.go │ │ │ ├── osext_plan9.go │ │ │ ├── osext_procfs.go │ │ │ ├── osext_sysctl.go │ │ │ └── osext_windows.go │ ├── mattn │ │ ├── go-colorable │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── colorable_others.go │ │ │ ├── colorable_windows.go │ │ │ └── noncolorable.go │ │ └── go-isatty │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── doc.go │ │ │ ├── isatty_appengine.go │ │ │ ├── isatty_bsd.go │ │ │ ├── isatty_linux.go │ │ │ ├── isatty_solaris.go │ │ │ └── isatty_windows.go │ ├── miekg │ │ └── dns │ │ │ ├── AUTHORS │ │ │ ├── CONTRIBUTORS │ │ │ ├── COPYRIGHT │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── client.go │ │ │ ├── clientconfig.go │ │ │ ├── dane.go │ │ │ ├── defaults.go │ │ │ ├── dns.go │ │ │ ├── dnssec.go │ │ │ ├── dnssec_keygen.go │ │ │ ├── dnssec_keyscan.go │ │ │ ├── dnssec_privkey.go │ │ │ ├── doc.go │ │ │ ├── edns.go │ │ │ ├── format.go │ │ │ ├── generate.go │ │ │ ├── labels.go │ │ │ ├── msg.go │ │ │ ├── msg_generate.go │ │ │ ├── msg_helpers.go │ │ │ ├── nsecx.go │ │ │ ├── privaterr.go │ │ │ ├── rawmsg.go │ │ │ ├── reverse.go │ │ │ ├── sanitize.go │ │ │ ├── scan.go │ │ │ ├── scan_rr.go │ │ │ ├── scanner.go │ │ │ ├── server.go │ │ │ ├── sig0.go │ │ │ ├── singleinflight.go │ │ │ ├── smimea.go │ │ │ ├── tlsa.go │ │ │ ├── tsig.go │ │ │ ├── types.go │ │ │ ├── types_generate.go │ │ │ ├── udp.go │ │ │ ├── udp_linux.go │ │ │ ├── udp_other.go │ │ │ ├── udp_plan9.go │ │ │ ├── udp_windows.go │ │ │ ├── update.go │ │ │ ├── xfr.go │ │ │ ├── zmsg.go │ │ │ └── ztypes.go │ ├── satori │ │ └── go.uuid │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ └── uuid.go │ ├── tsuru │ │ └── config │ │ │ ├── CONTRIBUTORS │ │ │ ├── LICENSE │ │ │ ├── README.markdown │ │ │ ├── checker.go │ │ │ └── config.go │ └── urfave │ │ └── cli │ │ ├── CHANGELOG.md │ │ ├── LICENSE │ │ ├── README.md │ │ ├── app.go │ │ ├── appveyor.yml │ │ ├── category.go │ │ ├── cli.go │ │ ├── command.go │ │ ├── context.go │ │ ├── errors.go │ │ ├── flag-types.json │ │ ├── flag.go │ │ ├── flag_generated.go │ │ ├── funcs.go │ │ ├── generate-flag-types │ │ ├── help.go │ │ └── runtests ├── gopkg.in │ └── yaml.v1 │ │ ├── LICENSE │ │ ├── LICENSE.libyaml │ │ ├── README.md │ │ ├── apic.go │ │ ├── decode.go │ │ ├── emitterc.go │ │ ├── encode.go │ │ ├── parserc.go │ │ ├── readerc.go │ │ ├── resolve.go │ │ ├── scannerc.go │ │ ├── sorter.go │ │ ├── writerc.go │ │ ├── yaml.go │ │ ├── yamlh.go │ │ └── yamlprivateh.go └── vendor.json └── vm.go /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Bug Reports 2 | 3 | - dlite version in use (run `dlite --version`): 4 | 5 | - expected behavior: 6 | 7 | - actual behavior: 8 | 9 | - steps to reproduce 10 | 11 | ## Feature Requests 12 | 13 | briefly describe the new feature you'd like to see, as well as a use case that employs it. any details or references you can provide would also be helpful. 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dlite 2 | assets.go 3 | assets 4 | .DS_Store 5 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "hyperkit"] 2 | path = hyperkit 3 | url = git://github.com/docker/hyperkit 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | os: osx 2 | language: go 3 | osx_image: xcode8 4 | 5 | before_install: 6 | - brew update 7 | - brew outdated golang || brew upgrade golang 8 | - brew install opam libev 9 | - opam init -y 10 | - go version 11 | 12 | install: 13 | - eval `opam config env` 14 | - opam install -y uri qcow.0.7.0 conf-libev logs fmt 15 | - go get -u github.com/jteeuwen/go-bindata/... 16 | 17 | script: 18 | - go generate 19 | - go build 20 | - ./dlite --version || true 21 | 22 | notifications: 23 | email: 24 | on_success: never 25 | on_failure: always 26 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Nathan LaFreniere 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DLite 2 | 3 | THIS PROJECT NEEDS A NEW MAINTAINER - I have stopped using OSX and no longer have time to continue to work on this. Open an issue if you're interested. 4 | 5 | this branch represents the latest *beta* version. the stable version can be found in the legacy branch. 6 | 7 | ## Building 8 | 9 | install dependencies 10 | 11 | ```sh 12 | brew install opam golang libev 13 | opam init 14 | eval `opam config env` 15 | opam install uri qcow.0.7.0 conf-libev logs fmt qcow-format 16 | go get -u github.com/jteeuwen/go-bindata/... 17 | git submodule init 18 | git submodule update 19 | ``` 20 | 21 | update dependencies (use this if you've already built the project before) 22 | 23 | ```sh 24 | git submodule foreach git pull origin master 25 | opam update 26 | opam upgrade 27 | ``` 28 | 29 | build the binary 30 | 31 | ```sh 32 | go generate 33 | go build 34 | ``` 35 | -------------------------------------------------------------------------------- /api.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "net" 7 | "net/http" 8 | "os" 9 | ) 10 | 11 | type API struct { 12 | done chan bool 13 | daemon *Daemon 14 | } 15 | 16 | func extractUser(r *http.Request) (*User, error) { 17 | userHeader, ok := r.Header["X-Username"] 18 | if !ok { 19 | return nil, fmt.Errorf("Missing X-Username header") 20 | } 21 | 22 | return lookupUser(userHeader[0]) 23 | } 24 | 25 | func (a *API) start(w http.ResponseWriter, r *http.Request) { 26 | if r.Method != "POST" { 27 | w.WriteHeader(http.StatusMethodNotAllowed) 28 | w.Write([]byte("Method not allowed")) 29 | return 30 | } 31 | 32 | if a.daemon.VM != nil { 33 | w.WriteHeader(http.StatusConflict) 34 | w.Write([]byte("Conflict")) 35 | return 36 | } 37 | 38 | user, err := extractUser(r) 39 | if err != nil { 40 | w.WriteHeader(http.StatusUnauthorized) 41 | w.Write([]byte("Unauthorized")) 42 | return 43 | } 44 | 45 | a.daemon.VM, err = NewVM(user) 46 | if err != nil { 47 | w.WriteHeader(http.StatusInternalServerError) 48 | w.Write([]byte(err.Error())) 49 | return 50 | } 51 | 52 | err = a.daemon.VM.Start() 53 | if err != nil { 54 | w.WriteHeader(http.StatusInternalServerError) 55 | w.Write([]byte(err.Error())) 56 | return 57 | } 58 | 59 | w.WriteHeader(http.StatusOK) 60 | // w.Write([]byte(fmt.Sprintf("Virtual machine started, tty available at %s", a.daemon.VM.TTY))) 61 | } 62 | 63 | func (a *API) started(w http.ResponseWriter, r *http.Request) { 64 | if r.Method != "POST" { 65 | w.WriteHeader(http.StatusMethodNotAllowed) 66 | w.Write([]byte("Method not allowed")) 67 | return 68 | } 69 | 70 | if a.daemon.VM == nil { 71 | w.WriteHeader(http.StatusBadRequest) 72 | w.Write([]byte("Virtual machine has not been started")) 73 | return 74 | } 75 | 76 | a.daemon.VM.Started = true 77 | w.Write([]byte("Virtual machine flagged as started")) 78 | } 79 | 80 | func (a *API) stop(w http.ResponseWriter, r *http.Request) { 81 | if r.Method != "POST" { 82 | w.WriteHeader(http.StatusMethodNotAllowed) 83 | w.Write([]byte("Method not allowed")) 84 | return 85 | } 86 | 87 | if a.daemon.VM == nil { 88 | w.WriteHeader(http.StatusBadRequest) 89 | w.Write([]byte("Virtual machine is not running")) 90 | return 91 | } 92 | 93 | a.daemon.VM.Started = false 94 | a.daemon.VM.Ready = false 95 | a.daemon.VM.Stop() 96 | a.daemon.VM = nil 97 | 98 | w.WriteHeader(http.StatusOK) 99 | // w.Write([]byte("Virtual machine shut down")) 100 | } 101 | 102 | func (a *API) status(w http.ResponseWriter, r *http.Request) { 103 | w.Header().Set("Content-Type", "application/json") 104 | if a.daemon.VM == nil { 105 | user, err := extractUser(r) 106 | if err != nil { 107 | w.WriteHeader(http.StatusUnauthorized) 108 | w.Write([]byte("\"message\": \"Unauthorized\"")) 109 | return 110 | } 111 | 112 | status, err := EmptyStatus(*user) 113 | if err != nil { 114 | statusErr := VMStatusError{ 115 | Status: "error", 116 | Message: err.Error(), 117 | } 118 | js, _ := json.Marshal(statusErr) 119 | 120 | w.WriteHeader(http.StatusInternalServerError) 121 | w.Write(js) 122 | return 123 | } 124 | 125 | js, _ := json.Marshal(status) 126 | 127 | w.WriteHeader(http.StatusOK) 128 | w.Write(js) 129 | return 130 | } 131 | 132 | status, err := a.daemon.VM.Status() 133 | if err != nil { 134 | statusErr := VMStatusError{ 135 | Status: "error", 136 | Message: err.Error(), 137 | } 138 | js, _ := json.Marshal(statusErr) 139 | 140 | w.WriteHeader(http.StatusInternalServerError) 141 | w.Write(js) 142 | return 143 | } 144 | 145 | js, err := json.Marshal(status) 146 | if err != nil { 147 | statusErr := VMStatusError{ 148 | Status: "error", 149 | Message: err.Error(), 150 | } 151 | js, _ := json.Marshal(statusErr) 152 | 153 | w.WriteHeader(http.StatusInternalServerError) 154 | w.Write(js) 155 | return 156 | } 157 | 158 | w.WriteHeader(http.StatusOK) 159 | w.Write(js) 160 | } 161 | 162 | func (a *API) Listen() error { 163 | addr, err := net.ResolveTCPAddr("tcp", "0.0.0.0:1050") 164 | if err != nil { 165 | return err 166 | } 167 | 168 | raw, err := net.ListenTCP("tcp", addr) 169 | if err != nil { 170 | return err 171 | } 172 | 173 | listener := &tcpListener{ 174 | TCPListener: raw, 175 | done: a.done, 176 | } 177 | 178 | mux := http.NewServeMux() 179 | mux.HandleFunc("/start", a.start) 180 | mux.HandleFunc("/started", a.started) 181 | mux.HandleFunc("/stop", a.stop) 182 | mux.HandleFunc("/status", a.status) 183 | mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 184 | w.WriteHeader(http.StatusNotFound) 185 | }) 186 | 187 | loggedMux := newLoggedHandler(mux, os.Stdout) 188 | server := &http.Server{ 189 | Handler: loggedMux, 190 | } 191 | 192 | return server.Serve(listener) 193 | } 194 | 195 | func (a *API) Stop() { 196 | a.done <- true 197 | } 198 | 199 | func NewAPI(daemon *Daemon) *API { 200 | return &API{ 201 | daemon: daemon, 202 | done: make(chan bool), 203 | } 204 | } 205 | -------------------------------------------------------------------------------- /assets/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nlf/dlite/d0ee08c326039e7c8e8586580fd4536e38ec9fdb/assets/.keep -------------------------------------------------------------------------------- /cmd_cleanup.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | 7 | "github.com/urfave/cli" 8 | ) 9 | 10 | var cleanupCommand = cli.Command{ 11 | Name: "cleanup", 12 | Hidden: true, 13 | Flags: []cli.Flag{ 14 | cli.StringFlag{ 15 | Name: "hostname", 16 | }, 17 | cli.StringFlag{ 18 | Name: "home", 19 | }, 20 | }, 21 | Action: func(ctx *cli.Context) error { 22 | err := ensureRoot() 23 | if err != nil { 24 | return err 25 | } 26 | 27 | hostname := ctx.String("hostname") 28 | if hostname == "" { 29 | return cli.NewExitError("Must specify hostname", 1) 30 | } 31 | domain := getDomain(hostname) 32 | 33 | home := ctx.String("home") 34 | if home == "" { 35 | return cli.NewExitError("Must specify home", 1) 36 | } 37 | 38 | if err := spin(fmt.Sprintf("Removing /etc/resolver/%s", domain), func() error { 39 | return os.Remove(fmt.Sprintf("/etc/resolver/%s", domain)) 40 | }); err.ExitCode() != 0 { 41 | return err 42 | } 43 | 44 | if err := spin("Modifying /etc/exports", func() error { 45 | return removeNFS(home) 46 | }); err.ExitCode() != 0 { 47 | return err 48 | } 49 | 50 | return spin("Removing /Library/LaunchDaemons/local.dlite.plist", func() error { 51 | return removeDaemon() 52 | }) 53 | }, 54 | } 55 | -------------------------------------------------------------------------------- /cmd_daemon.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/urfave/cli" 5 | ) 6 | 7 | var daemonCommand = cli.Command{ 8 | Name: "daemon", 9 | Hidden: true, 10 | Action: func(ctx *cli.Context) error { 11 | d := NewDaemon() 12 | d.Start() 13 | errs := d.Wait() 14 | for _, err := range errs { 15 | if err != nil && err.Error() != "Shutting down privileged daemon" { 16 | return cli.NewExitError(err.Error(), 1) 17 | } 18 | } 19 | 20 | return nil 21 | }, 22 | } 23 | -------------------------------------------------------------------------------- /cmd_dlite.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "os" 5 | 6 | "github.com/urfave/cli" 7 | ) 8 | 9 | const VERSION = "2.0.0-beta9" 10 | 11 | func main() { 12 | app := cli.NewApp() 13 | app.Version = VERSION 14 | app.Usage = "the easiest way to use docker on macOS" 15 | app.HideHelp = true 16 | app.UsageText = "dlite " 17 | 18 | app.Commands = []cli.Command{ 19 | daemonCommand, 20 | setupCommand, 21 | initCommand, 22 | cleanupCommand, 23 | uninstallCommand, 24 | startCommand, 25 | stopCommand, 26 | statusCommand, 27 | ipCommand, 28 | sshCommand, 29 | ttyCommand, 30 | } 31 | 32 | app.Run(os.Args) 33 | } 34 | -------------------------------------------------------------------------------- /cmd_init.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "os" 7 | "path/filepath" 8 | 9 | "github.com/satori/go.uuid" 10 | "github.com/tsuru/config" 11 | "github.com/urfave/cli" 12 | ) 13 | 14 | var initCommand = cli.Command{ 15 | Name: "init", 16 | Usage: "initialize your dlite installation", 17 | Description: "perform setup of dlite for the currently logged in user", 18 | Action: func(ctx *cli.Context) error { 19 | currentUser := getUser() 20 | configPath := getPath(currentUser) 21 | binPath := filepath.Join(configPath, "bin") 22 | configFile := filepath.Join(configPath, "config.yaml") 23 | diskFile := filepath.Join(configPath, "disk.qcow") 24 | cfg := Config{} 25 | 26 | err := config.ReadConfigFile(configFile) 27 | if err == nil { 28 | fmt.Println("WARNING: It appears you have already initialized dlite. Continuing will destroy your current virtual machine and its configuration.") 29 | if !confirm("Continue? (y/n)") { 30 | return cli.NewExitError("Aborting initialization...", 1) 31 | } 32 | } 33 | 34 | fmt.Println("") 35 | 36 | err = os.RemoveAll(configPath) 37 | if err != nil { 38 | return cli.NewExitError(err.Error(), 1) 39 | } 40 | 41 | err = os.MkdirAll(configPath, 0755) 42 | if err != nil { 43 | return cli.NewExitError(err.Error(), 1) 44 | } 45 | 46 | cfg.Id = uuid.NewV1().String() 47 | 48 | cfg.Hostname = askString("Virtual machine hostname", "local.docker") 49 | cfg.Disk = askInt("Disk size (in gigabytes)", 20) 50 | cfg.Cpu = askInt("CPU cores to allocate to VM", 2) 51 | cfg.Memory = askInt("Memory to allocate to VM (in gigabytes)", 2) 52 | 53 | host, _ := getHostAddress() 54 | cfg.DNS = askString("DNS server", host) 55 | cfg.Docker = askString("Docker version", "latest") 56 | cfg.Extra = ask("Extra flags to pass to the docker daemon") 57 | cfg.Route = askBool("Allow direct connections to containers", true) 58 | 59 | fmt.Println("") 60 | 61 | if err := spin("Saving configuration", func() error { 62 | return writeConfig(configPath, cfg) 63 | }); err.ExitCode() != 0 { 64 | return err 65 | } 66 | 67 | if err := spin("Creating ssh key pair", func() error { 68 | return generateKeys(currentUser) 69 | }); err.ExitCode() != 0 { 70 | return err 71 | } 72 | 73 | if err := spin("Adding host to ssh config", func() error { 74 | return addSSHConfig(currentUser, cfg.Hostname) 75 | }); err.ExitCode() != 0 { 76 | return err 77 | } 78 | 79 | if err := spin("Creating tool binaries", func() error { 80 | err := os.MkdirAll(binPath, 0755) 81 | if err != nil { 82 | return err 83 | } 84 | 85 | for _, tool := range []string{"com.docker.hyperkit", "qcow-tool"} { 86 | bin, err := Asset(tool) 87 | if err != nil { 88 | return err 89 | } 90 | err = ioutil.WriteFile(filepath.Join(binPath, tool), bin, 0755) 91 | if err != nil { 92 | return err 93 | } 94 | } 95 | 96 | return nil 97 | }); err.ExitCode() != 0 { 98 | return err 99 | } 100 | 101 | if err := spin("Creating disk", func() error { 102 | return buildDisk(filepath.Join(binPath, "qcow-tool"), diskFile, cfg.Disk, currentUser.Uid, currentUser.Gid) 103 | }); err.ExitCode() != 0 { 104 | return err 105 | } 106 | 107 | if err := spin("Downloading OS", func() error { 108 | return downloadOS(configPath) 109 | }); err.ExitCode() != 0 { 110 | return err 111 | } 112 | 113 | fmt.Println("") 114 | fmt.Println("Next we'll run a few steps that require sudo, you may be prompted for your password.") 115 | return runSetup(cfg.Hostname, currentUser.Home) 116 | }, 117 | } 118 | -------------------------------------------------------------------------------- /cmd_ip.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/urfave/cli" 7 | ) 8 | 9 | var ipCommand = cli.Command{ 10 | Name: "ip", 11 | Usage: "display the virtual machine's IP", 12 | Description: "lookup and print the IP address of the virtual machine", 13 | Action: func(ctx *cli.Context) error { 14 | status, err := statusRequest() 15 | if err != nil { 16 | return err 17 | } 18 | 19 | if !status.Started { 20 | return cli.NewExitError("Virtual machine not running", 1) 21 | } 22 | 23 | fmt.Println(status.IP) 24 | return nil 25 | }, 26 | } 27 | -------------------------------------------------------------------------------- /cmd_setup.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/urfave/cli" 7 | ) 8 | 9 | var setupCommand = cli.Command{ 10 | Name: "setup", 11 | Hidden: true, 12 | Flags: []cli.Flag{ 13 | cli.StringFlag{ 14 | Name: "hostname", 15 | }, 16 | cli.StringFlag{ 17 | Name: "home", 18 | }, 19 | }, 20 | Action: func(ctx *cli.Context) error { 21 | err := ensureRoot() 22 | if err != nil { 23 | return err 24 | } 25 | 26 | hostname := ctx.String("hostname") 27 | if hostname == "" { 28 | return cli.NewExitError("Must specify hostname", 1) 29 | } 30 | domain := getDomain(hostname) 31 | 32 | home := ctx.String("home") 33 | if home == "" { 34 | return cli.NewExitError("Must specify home", 1) 35 | } 36 | 37 | if err := spin(fmt.Sprintf("Creating /etc/resolver/%s", domain), func() error { 38 | return installResolver(hostname) 39 | }); err.ExitCode() != 0 { 40 | return err 41 | } 42 | 43 | if err := spin("Modifying /etc/exports", func() error { 44 | return ensureNFS(home) 45 | }); err.ExitCode() != 0 { 46 | return err 47 | } 48 | 49 | return spin("Creating /Library/LaunchDaemons/local.dlite.plist", func() error { 50 | return installDaemon() 51 | }) 52 | }, 53 | } 54 | -------------------------------------------------------------------------------- /cmd_ssh.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "os" 5 | "os/exec" 6 | "syscall" 7 | 8 | "github.com/urfave/cli" 9 | ) 10 | 11 | var sshCommand = cli.Command{ 12 | Name: "ssh", 13 | Usage: "start an ssh session with your vm", 14 | Description: "login to your virtual machine using ssh, this is a convenience shortcut", 15 | Action: func(ctx *cli.Context) error { 16 | currentUser := getUser() 17 | 18 | cfg, err := readConfig(getPath(currentUser)) 19 | if err != nil { 20 | return cli.NewExitError(err.Error(), 1) 21 | } 22 | 23 | bin, err := exec.LookPath("ssh") 24 | if err != nil { 25 | return cli.NewExitError(err.Error(), 1) 26 | } 27 | 28 | err = syscall.Exec(bin, []string{"ssh", cfg.Hostname}, os.Environ()) 29 | if err != nil { 30 | return cli.NewExitError(err.Error(), 1) 31 | } 32 | 33 | return nil 34 | }, 35 | } 36 | -------------------------------------------------------------------------------- /cmd_start.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/urfave/cli" 5 | ) 6 | 7 | var startCommand = cli.Command{ 8 | Name: "start", 9 | Usage: "start the virtual machine", 10 | Description: "start the virtual machine, exits once booting is complete", 11 | Action: func(ctx *cli.Context) error { 12 | return spin("Starting the virtual machine", func() error { 13 | return stringRequest("start") 14 | }) 15 | }, 16 | } 17 | -------------------------------------------------------------------------------- /cmd_status.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/urfave/cli" 7 | ) 8 | 9 | var statusCommand = cli.Command{ 10 | Name: "status", 11 | Usage: "print the virtual machine's status", 12 | Description: "fetch and print the configuration and status of the virtual machine", 13 | Action: func(ctx *cli.Context) error { 14 | status, err := statusRequest() 15 | if err != nil { 16 | return err 17 | } 18 | 19 | if status.Started { 20 | fmt.Println("vm_state: started") 21 | fmt.Printf("ip_address: %s\n", status.IP) 22 | fmt.Printf("pid: %d\n", status.Pid) 23 | } else { 24 | fmt.Println("vm_state: stopped") 25 | } 26 | fmt.Printf("id: %s\n", status.Id) 27 | fmt.Printf("hostname: %s\n", status.Hostname) 28 | fmt.Printf("disk_size: %d\n", status.Disk) 29 | fmt.Printf("disk_path: %s\n", status.DiskPath) 30 | fmt.Printf("cpu_cores: %d\n", status.Cpu) 31 | fmt.Printf("memory: %d\n", status.Memory) 32 | fmt.Printf("dns_server: %s\n", status.DNS) 33 | fmt.Printf("docker_version: %s\n", status.Docker) 34 | fmt.Printf("docker_args: %s\n", status.Extra) 35 | 36 | return nil 37 | }, 38 | } 39 | -------------------------------------------------------------------------------- /cmd_stop.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/urfave/cli" 5 | ) 6 | 7 | var stopCommand = cli.Command{ 8 | Name: "stop", 9 | Usage: "stop the virtual machine", 10 | Description: "stop the virtual machine, exits once the process has ended", 11 | Action: func(ctx *cli.Context) error { 12 | return spin("Stopping the virtual machine", func() error { 13 | return stringRequest("stop") 14 | }) 15 | }, 16 | } 17 | -------------------------------------------------------------------------------- /cmd_tty.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "os" 5 | "os/exec" 6 | "path/filepath" 7 | "syscall" 8 | 9 | "github.com/urfave/cli" 10 | ) 11 | 12 | var ttyCommand = cli.Command{ 13 | Name: "tty", 14 | Usage: "open a terminal to the virtual machine", 15 | Description: "use screen to open a virtual terminal connected to the dlite vm, for most cases SSH is recommended but this can be useful for debugging", 16 | Action: func(ctx *cli.Context) error { 17 | currentUser := getUser() 18 | 19 | ttyPath := filepath.Join(getPath(currentUser), "vm.tty") 20 | bin, err := exec.LookPath("screen") 21 | if err != nil { 22 | return cli.NewExitError(err.Error(), 1) 23 | } 24 | 25 | err = syscall.Exec(bin, []string{"screen", ttyPath}, os.Environ()) 26 | if err != nil { 27 | return cli.NewExitError(err.Error(), 1) 28 | } 29 | 30 | return nil 31 | }, 32 | } 33 | -------------------------------------------------------------------------------- /cmd_uninstall.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | 7 | "github.com/urfave/cli" 8 | ) 9 | 10 | var uninstallCommand = cli.Command{ 11 | Name: "uninstall", 12 | Usage: "completely remove dlite", 13 | Description: "remove the user's virtual machine as well as the system service and reset all configuration changes", 14 | Action: func(ctx *cli.Context) error { 15 | var hostname string 16 | var home string 17 | 18 | if err := spin("Removing virtual machine", func() error { 19 | stringRequest("stop") 20 | 21 | currentUser := getUser() 22 | home = currentUser.Home 23 | 24 | basePath := getPath(currentUser) 25 | cfg, err := readConfig(basePath) 26 | if err != nil { 27 | return err 28 | } 29 | 30 | hostname = cfg.Hostname 31 | 32 | err = removeSSHConfig(currentUser, hostname) 33 | if err != nil { 34 | return err 35 | } 36 | 37 | return os.RemoveAll(basePath) 38 | }); err.ExitCode() != 0 { 39 | return err 40 | } 41 | 42 | fmt.Println("") 43 | fmt.Println("Next we'll run a few steps that require sudo, you may be prompted for your password.") 44 | return runCleanup(hostname, home) 45 | }, 46 | } 47 | -------------------------------------------------------------------------------- /config.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "path/filepath" 5 | 6 | "github.com/tsuru/config" 7 | ) 8 | 9 | type Config struct { 10 | Id string `json:"id"` 11 | Hostname string `json:"hostname"` 12 | Disk int `json:"disk_size"` 13 | DiskPath string `json:"disk_path"` 14 | Cpu int `json:"cpu_cores"` 15 | Memory int `json:"memory"` 16 | DNS string `json:"dns_server"` 17 | Docker string `json:"docker_version"` 18 | Extra string `json:"docker_args"` 19 | Route bool `json:"route"` 20 | } 21 | 22 | func readConfig(path string) (Config, error) { 23 | cfg := Config{} 24 | configFile := filepath.Join(path, "config.yaml") 25 | 26 | err := config.ReadConfigFile(configFile) 27 | if err != nil { 28 | return cfg, err 29 | } 30 | 31 | cfg.Id, err = config.GetString("id") 32 | if err != nil { 33 | return cfg, err 34 | } 35 | 36 | cfg.Hostname, err = config.GetString("hostname") 37 | if err != nil { 38 | return cfg, err 39 | } 40 | 41 | cfg.DiskPath = filepath.Join(path, "disk.qcow") 42 | cfg.Disk, err = config.GetInt("disk") 43 | if err != nil { 44 | return cfg, err 45 | } 46 | 47 | cfg.Cpu, err = config.GetInt("cpu") 48 | if err != nil { 49 | return cfg, err 50 | } 51 | 52 | cfg.Memory, err = config.GetInt("memory") 53 | if err != nil { 54 | return cfg, err 55 | } 56 | 57 | cfg.DNS, err = config.GetString("dns") 58 | if err != nil { 59 | return cfg, err 60 | } 61 | 62 | cfg.Docker, err = config.GetString("docker") 63 | if err != nil { 64 | return cfg, err 65 | } 66 | 67 | cfg.Extra, err = config.GetString("extra") 68 | if err != nil { 69 | return cfg, err 70 | } 71 | 72 | cfg.Route, err = config.GetBool("route") 73 | return cfg, err 74 | } 75 | 76 | func writeConfig(path string, cfg Config) error { 77 | configFile := filepath.Join(path, "config.yaml") 78 | 79 | config.Set("id", cfg.Id) 80 | config.Set("hostname", cfg.Hostname) 81 | config.Set("disk", cfg.Disk) 82 | config.Set("cpu", cfg.Cpu) 83 | config.Set("memory", cfg.Memory) 84 | config.Set("dns", cfg.DNS) 85 | config.Set("docker", cfg.Docker) 86 | config.Set("extra", cfg.Extra) 87 | config.Set("route", cfg.Route) 88 | 89 | return config.WriteConfigFile(configFile, 0644) 90 | } 91 | -------------------------------------------------------------------------------- /daemon.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "os" 7 | "os/exec" 8 | "os/signal" 9 | "syscall" 10 | 11 | "github.com/kardianos/osext" 12 | ) 13 | 14 | type Daemon struct { 15 | Proxy *Proxy 16 | API *API 17 | VM *VM 18 | DNS *DNS 19 | Error chan error 20 | } 21 | 22 | func (d *Daemon) Start() { 23 | shutdown := make(chan os.Signal, 1) 24 | signal.Notify(shutdown, syscall.SIGINT, syscall.SIGTERM, syscall.SIGKILL) 25 | go func() { 26 | <-shutdown 27 | d.Shutdown() 28 | }() 29 | 30 | go func() { 31 | err := d.Proxy.Listen() 32 | if err != nil { 33 | if err.Error() != "Server closed" { 34 | d.Error <- err 35 | d.Shutdown() 36 | } else { 37 | d.Error <- nil 38 | } 39 | } 40 | }() 41 | 42 | go func() { 43 | err := d.API.Listen() 44 | if err != nil { 45 | if err.Error() != "Server closed" { 46 | d.Error <- err 47 | d.Shutdown() 48 | } else { 49 | d.Error <- nil 50 | } 51 | } 52 | }() 53 | 54 | go func() { 55 | err := d.DNS.Start() 56 | if err != nil { 57 | d.Shutdown() 58 | } 59 | }() 60 | } 61 | 62 | func (d *Daemon) Shutdown() { 63 | if d.VM != nil { 64 | d.VM.Stop() 65 | } 66 | d.Proxy.Stop() 67 | d.API.Stop() 68 | d.DNS.Stop() 69 | d.Error <- fmt.Errorf("Shutting down privileged daemon") 70 | } 71 | 72 | func (d *Daemon) Wait() []error { 73 | err1 := <-d.Error 74 | err2 := <-d.Error 75 | return []error{err1, err2} 76 | } 77 | 78 | func NewDaemon() *Daemon { 79 | daemon := &Daemon{} 80 | proxy := NewProxy(daemon) 81 | api := NewAPI(daemon) 82 | dns := NewDNS(daemon) 83 | 84 | daemon.Proxy = proxy 85 | daemon.API = api 86 | daemon.DNS = dns 87 | daemon.Error = make(chan error, 2) 88 | return daemon 89 | } 90 | 91 | const template = ` 92 | 93 | 94 | 95 | 96 | Label 97 | local.dlite 98 | ProgramArguments 99 | 100 | %s 101 | daemon 102 | 103 | RunAtLoad 104 | 105 | 106 | 107 | ` 108 | 109 | const plistPath = "/Library/LaunchDaemons/local.dlite.plist" 110 | 111 | func installDaemon() error { 112 | exe, err := osext.Executable() 113 | if err != nil { 114 | return err 115 | } 116 | 117 | plist := fmt.Sprintf(template, exe) 118 | err = ioutil.WriteFile(plistPath, []byte(plist), 0644) 119 | if err != nil { 120 | return err 121 | } 122 | 123 | return exec.Command("launchctl", "load", plistPath).Run() 124 | } 125 | 126 | func removeDaemon() error { 127 | exec.Command("lauunchctl", "unload", plistPath).Run() 128 | return os.Remove(plistPath) 129 | } 130 | -------------------------------------------------------------------------------- /disk.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os/exec" 6 | ) 7 | 8 | func buildDisk(bin, path string, size, uid, gid int) error { 9 | return exec.Command(bin, "create", fmt.Sprintf("--size=%dGiB", size), path).Run() 10 | } 11 | -------------------------------------------------------------------------------- /dns.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "net" 7 | "os" 8 | "strings" 9 | 10 | "github.com/miekg/dns" 11 | ) 12 | 13 | type DNS struct { 14 | daemon *Daemon 15 | server *dns.Server 16 | } 17 | 18 | func (d *DNS) handleRequest(w dns.ResponseWriter, r *dns.Msg) { 19 | msg := &dns.Msg{} 20 | msg.SetReply(r) 21 | 22 | if d.daemon.VM == nil { 23 | msg.SetRcode(r, dns.RcodeNameError) 24 | w.WriteMsg(msg) 25 | return 26 | } 27 | 28 | userPath := getPath(*d.daemon.VM.Owner) 29 | cfg, err := readConfig(userPath) 30 | if err != nil { 31 | msg.SetRcode(r, dns.RcodeServerFailure) 32 | w.WriteMsg(msg) 33 | return 34 | } 35 | 36 | hostname := fmt.Sprintf("%s.", cfg.Hostname) 37 | domain := fmt.Sprintf("%s.", getDomain(cfg.Hostname)) 38 | 39 | q := r.Question[0] 40 | if q.Qtype != dns.TypeA { 41 | msg.SetRcode(r, dns.RcodeNotImplemented) 42 | } else { 43 | if !strings.HasSuffix(q.Name, domain) { 44 | msg.SetRcode(r, dns.RcodeNameError) 45 | w.WriteMsg(msg) 46 | return 47 | } 48 | 49 | if q.Name == hostname { 50 | ip, err := d.daemon.VM.IP() 51 | if err != nil { 52 | msg.SetRcode(r, dns.RcodeNameError) 53 | w.WriteMsg(msg) 54 | return 55 | } 56 | 57 | record := &dns.A{ 58 | Hdr: dns.RR_Header{ 59 | Name: q.Name, 60 | Rrtype: dns.TypeA, 61 | Class: dns.ClassINET, 62 | Ttl: 0, 63 | }, 64 | A: net.ParseIP(ip).To4(), 65 | } 66 | 67 | msg.Answer = append(msg.Answer, record) 68 | } else if cfg.Route { 69 | cleaned := strings.TrimSuffix(q.Name, fmt.Sprintf(".%s", domain)) 70 | ip, err := d.daemon.VM.findContainer(cleaned) 71 | if err != nil { 72 | msg.SetRcode(r, dns.RcodeNameError) 73 | w.WriteMsg(msg) 74 | return 75 | } 76 | 77 | record := &dns.A{ 78 | Hdr: dns.RR_Header{ 79 | Name: q.Name, 80 | Rrtype: dns.TypeA, 81 | Class: dns.ClassINET, 82 | Ttl: 0, 83 | }, 84 | A: net.ParseIP(ip).To4(), 85 | } 86 | 87 | msg.Answer = append(msg.Answer, record) 88 | } else { 89 | msg.SetRcode(r, dns.RcodeNameError) 90 | } 91 | } 92 | 93 | w.WriteMsg(msg) 94 | } 95 | 96 | func (d *DNS) Start() error { 97 | dns.HandleFunc(".", d.handleRequest) 98 | d.server = &dns.Server{ 99 | Addr: ":1053", 100 | Net: "udp", 101 | } 102 | 103 | return d.server.ListenAndServe() 104 | } 105 | 106 | func (d *DNS) Stop() error { 107 | return d.server.Shutdown() 108 | } 109 | 110 | func NewDNS(daemon *Daemon) *DNS { 111 | return &DNS{ 112 | daemon: daemon, 113 | } 114 | } 115 | 116 | func installResolver(hostname string) error { 117 | err := os.MkdirAll("/etc/resolver", 0755) 118 | if err != nil { 119 | return err 120 | } 121 | 122 | domain := getDomain(hostname) 123 | file := fmt.Sprintf("/etc/resolver/%s", domain) 124 | resolver := "nameserver 127.0.0.1\nport 1053" 125 | return ioutil.WriteFile(file, []byte(resolver), 0644) 126 | } 127 | -------------------------------------------------------------------------------- /gen_assets.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // build hyperkit 4 | //go:generate make -C hyperkit 5 | 6 | // copy binary assets 7 | //go:generate sh -c "cp `which qcow-tool` assets/" 8 | //go:generate cp hyperkit/build/com.docker.hyperkit assets/ 9 | 10 | // generate bundled assets 11 | //go:generate go-bindata -pkg main -o assets.go -prefix assets assets/ 12 | -------------------------------------------------------------------------------- /helpers.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "io/ioutil" 7 | "net" 8 | "net/http" 9 | "net/url" 10 | "os" 11 | "os/exec" 12 | "os/user" 13 | "path/filepath" 14 | "strconv" 15 | "syscall" 16 | 17 | "github.com/kardianos/osext" 18 | "github.com/urfave/cli" 19 | ) 20 | 21 | type User struct { 22 | Name string 23 | Home string 24 | Uid int 25 | Gid int 26 | } 27 | 28 | func lookupUser(username string) (*User, error) { 29 | rawUser, err := user.Lookup(username) 30 | if err != nil { 31 | return nil, err 32 | } 33 | 34 | uid, err := strconv.Atoi(rawUser.Uid) 35 | if err != nil { 36 | return nil, err 37 | } 38 | 39 | gid, err := strconv.Atoi(rawUser.Gid) 40 | if err != nil { 41 | return nil, err 42 | } 43 | 44 | return &User{ 45 | Name: rawUser.Username, 46 | Home: rawUser.HomeDir, 47 | Uid: uid, 48 | Gid: gid, 49 | }, nil 50 | } 51 | 52 | func getUser() User { 53 | currentUser, err := user.Current() 54 | if err != nil { 55 | fmt.Println(err) 56 | os.Exit(1) 57 | } 58 | 59 | uid, err := strconv.Atoi(currentUser.Uid) 60 | if err != nil { 61 | fmt.Println(err) 62 | os.Exit(1) 63 | } 64 | 65 | gid, err := strconv.Atoi(currentUser.Gid) 66 | if err != nil { 67 | fmt.Println(err) 68 | os.Exit(1) 69 | } 70 | 71 | return User{ 72 | Name: currentUser.Username, 73 | Home: currentUser.HomeDir, 74 | Uid: uid, 75 | Gid: gid, 76 | } 77 | } 78 | 79 | func getPath(user User) string { 80 | return filepath.Join(user.Home, ".dlite") 81 | } 82 | 83 | func getRequestError(err error) string { 84 | urlError, ok := err.(*url.Error) 85 | if ok { 86 | netError, ok := urlError.Err.(*net.OpError) 87 | if ok { 88 | sysError, ok := netError.Err.(*os.SyscallError) 89 | if ok { 90 | if sysError.Err == syscall.ECONNREFUSED { 91 | return "Connection refused - is the dlite daemon running?" 92 | } 93 | } 94 | 95 | if netError.Timeout() { 96 | return "Request timed out, please try again" 97 | } 98 | } 99 | } 100 | 101 | return err.Error() 102 | } 103 | 104 | func statusRequest() (*VMStatus, *cli.ExitError) { 105 | user := getUser() 106 | req, err := http.NewRequest("GET", "http://127.0.0.1:1050/status", nil) 107 | if err != nil { 108 | return nil, cli.NewExitError(err.Error(), 1) 109 | } 110 | 111 | req.Header.Add("X-Username", user.Name) 112 | client := &http.Client{} 113 | res, err := client.Do(req) 114 | if err != nil { 115 | return nil, cli.NewExitError(getRequestError(err), 1) 116 | } 117 | 118 | defer res.Body.Close() 119 | decoder := json.NewDecoder(res.Body) 120 | if res.StatusCode < 200 || res.StatusCode >= 400 { 121 | status := VMStatusError{} 122 | err := decoder.Decode(&status) 123 | if err != nil { 124 | return nil, cli.NewExitError(err.Error(), 1) 125 | } 126 | 127 | return nil, cli.NewExitError(status.Message, 1) 128 | } 129 | 130 | status := VMStatus{} 131 | err = decoder.Decode(&status) 132 | if err != nil { 133 | return nil, cli.NewExitError(err.Error(), 1) 134 | } 135 | 136 | return &status, nil 137 | } 138 | 139 | func stringRequest(action string) *cli.ExitError { 140 | user := getUser() 141 | req, err := http.NewRequest("POST", fmt.Sprintf("http://127.0.0.1:1050/%s", action), nil) 142 | if err != nil { 143 | return cli.NewExitError(err.Error(), 1) 144 | } 145 | 146 | req.Header.Add("X-Username", user.Name) 147 | client := &http.Client{} 148 | res, err := client.Do(req) 149 | if err != nil { 150 | return cli.NewExitError(err.Error(), 1) 151 | } 152 | 153 | defer res.Body.Close() 154 | body, err := ioutil.ReadAll(res.Body) 155 | if err != nil { 156 | return cli.NewExitError(err.Error(), 1) 157 | } 158 | 159 | code := 0 160 | if res.StatusCode < 200 || res.StatusCode >= 400 { 161 | code = 1 162 | } 163 | 164 | return cli.NewExitError(string(body), code) 165 | } 166 | 167 | func runSetup(hostname, home string) *cli.ExitError { 168 | exe, err := osext.Executable() 169 | if err != nil { 170 | return cli.NewExitError(err.Error(), 1) 171 | } 172 | 173 | output, err := exec.Command("sudo", exe, "setup", "--hostname", hostname, "--home", home).Output() 174 | code := 0 175 | if err != nil { 176 | code = 1 177 | } 178 | return cli.NewExitError(string(output), code) 179 | } 180 | 181 | func runCleanup(hostname, home string) *cli.ExitError { 182 | exe, err := osext.Executable() 183 | if err != nil { 184 | return cli.NewExitError(err.Error(), 1) 185 | } 186 | 187 | output, err := exec.Command("sudo", exe, "cleanup", "--hostname", hostname, "--home", home).Output() 188 | code := 0 189 | if err != nil { 190 | code = 1 191 | } 192 | return cli.NewExitError(string(output), code) 193 | } 194 | 195 | func ensureRoot() *cli.ExitError { 196 | if uid := os.Geteuid(); uid != 0 { 197 | return cli.NewExitError("This command requires sudo", 1) 198 | } 199 | 200 | if uid := os.Getenv("SUDO_UID"); uid == "" { 201 | return cli.NewExitError("This command requires sudo", 1) 202 | } 203 | 204 | return nil 205 | } 206 | -------------------------------------------------------------------------------- /http_logger.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "net/http" 7 | "strings" 8 | "time" 9 | ) 10 | 11 | type LoggedRequest struct { 12 | http.ResponseWriter 13 | 14 | req *http.Request 15 | output io.Writer 16 | code int 17 | start time.Time 18 | finish time.Time 19 | } 20 | 21 | func (l *LoggedRequest) WriteHeader(code int) { 22 | l.code = code 23 | l.ResponseWriter.WriteHeader(code) 24 | } 25 | 26 | func (l *LoggedRequest) printLog() { 27 | ip := l.req.RemoteAddr 28 | if colon := strings.LastIndex(ip, ":"); colon > -1 { 29 | ip = ip[:colon] 30 | } 31 | 32 | elapsed := l.finish.Sub(l.start).Nanoseconds() / 1000 33 | finish := l.finish.Format("010206.150405") 34 | fmt.Fprintf(l.output, "%s %s %s %s [%d] %dms\n", ip, finish, l.req.Method, l.req.RequestURI, l.code, elapsed) 35 | } 36 | 37 | type LoggingHandler struct { 38 | handler http.Handler 39 | output io.Writer 40 | } 41 | 42 | func (h *LoggingHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) { 43 | entry := &LoggedRequest{ 44 | ResponseWriter: rw, 45 | output: h.output, 46 | req: r, 47 | start: time.Now(), 48 | } 49 | 50 | entry.start = time.Now() 51 | h.handler.ServeHTTP(entry, r) 52 | entry.finish = time.Now() 53 | entry.printLog() 54 | } 55 | 56 | func newLoggedHandler(handler http.Handler, output io.Writer) http.Handler { 57 | return &LoggingHandler{ 58 | handler: handler, 59 | output: output, 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /listeners.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | "time" 7 | ) 8 | 9 | type tcpListener struct { 10 | *net.TCPListener 11 | done chan bool 12 | } 13 | 14 | func (l *tcpListener) Accept() (net.Conn, error) { 15 | for { 16 | l.SetDeadline(time.Now().Add(time.Second)) 17 | select { 18 | case <-l.done: 19 | return nil, fmt.Errorf("Server closed") 20 | default: 21 | } 22 | 23 | newConn, err := l.TCPListener.Accept() 24 | if err != nil { 25 | netErr, ok := err.(net.Error) 26 | if ok && netErr.Timeout() && netErr.Temporary() { 27 | continue 28 | } 29 | } 30 | 31 | return newConn, err 32 | } 33 | } 34 | 35 | func (l *tcpListener) Close() error { 36 | close(l.done) 37 | return nil 38 | } 39 | 40 | type unixListener struct { 41 | *net.UnixListener 42 | done chan bool 43 | } 44 | 45 | func (s *unixListener) Accept() (net.Conn, error) { 46 | for { 47 | s.SetDeadline(time.Now().Add(time.Second)) 48 | select { 49 | case <-s.done: 50 | return nil, fmt.Errorf("Server closed") 51 | default: 52 | } 53 | 54 | newConn, err := s.UnixListener.Accept() 55 | if err != nil { 56 | netErr, ok := err.(net.Error) 57 | if ok && netErr.Timeout() && netErr.Temporary() { 58 | continue 59 | } 60 | } 61 | 62 | return newConn, err 63 | } 64 | } 65 | 66 | func (s *unixListener) Close() error { 67 | close(s.done) 68 | return nil 69 | } 70 | -------------------------------------------------------------------------------- /net.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "net" 5 | "os/exec" 6 | "strings" 7 | ) 8 | 9 | func getNetAddress() (string, error) { 10 | rawAddr, _ := getHostAddress() 11 | addr := net.ParseIP(rawAddr) 12 | 13 | rawMask, _ := getNetMask() 14 | mask := net.IPMask(net.ParseIP(rawMask).To4()) 15 | 16 | return addr.Mask(mask).String(), nil 17 | } 18 | 19 | func getHostAddress() (string, error) { 20 | addr, err := exec.Command("defaults", "read", "/Library/Preferences/SystemConfiguration/com.apple.vmnet.plist", "Shared_Net_Address").Output() 21 | if err != nil { 22 | return "192.168.64.1", err 23 | } 24 | 25 | return strings.TrimSpace(string(addr)), nil 26 | } 27 | 28 | func getNetMask() (string, error) { 29 | mask, err := exec.Command("defaults", "read", "/Library/Preferences/SystemConfiguration/com.apple.vmnet.plist", "Shared_Net_Mask").Output() 30 | if err != nil { 31 | return "255.255.255.0", err 32 | } 33 | 34 | return strings.TrimSpace(string(mask)), nil 35 | } 36 | 37 | func getDomain(hostname string) string { 38 | var domain string 39 | 40 | lastDot := strings.LastIndex(hostname, ".") 41 | if lastDot > -1 { 42 | domain = hostname[lastDot+1:] 43 | } else { 44 | domain = hostname 45 | } 46 | 47 | return domain 48 | } 49 | -------------------------------------------------------------------------------- /nfs.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "os" 7 | "os/exec" 8 | "regexp" 9 | "strings" 10 | ) 11 | 12 | func ensureNFS(home string) error { 13 | addr, err := getNetAddress() 14 | if err != nil { 15 | return err 16 | } 17 | 18 | mask, _ := getNetMask() 19 | export := fmt.Sprintf("%s -network %s -mask %s -alldirs -maproot=root:wheel", home, addr, mask) 20 | 21 | if _, err = os.Stat("/etc/exports"); os.IsNotExist(err) { 22 | err := ioutil.WriteFile("/etc/exports", []byte(""), 0644) 23 | if err != nil { 24 | return err 25 | } 26 | } 27 | 28 | rawExports, err := ioutil.ReadFile("/etc/exports") 29 | if err != nil { 30 | return err 31 | } 32 | 33 | needsExport := true 34 | for _, line := range strings.Split(string(rawExports), "\n") { 35 | if strings.HasPrefix(line, export) { 36 | needsExport = false 37 | break 38 | } 39 | } 40 | 41 | if needsExport { 42 | file, err := os.OpenFile("/etc/exports", os.O_APPEND|os.O_WRONLY, 0644) 43 | if err != nil { 44 | return err 45 | } 46 | 47 | defer file.Close() 48 | 49 | _, err = file.WriteString(export + "\n") 50 | if err != nil { 51 | return err 52 | } 53 | } 54 | 55 | output, err := exec.Command("nfsd", "checkexports").Output() 56 | if err != nil { 57 | return fmt.Errorf("There was a problem updating the /etc/exports file, please resolve the issue and run 'sudo nfsd restart'\n%s", string(output)) 58 | } 59 | 60 | output, _ = exec.Command("nfsd", "status").Output() 61 | enabled := false 62 | running := false 63 | for _, line := range strings.Split(string(output), "\n") { 64 | if strings.Contains(line, "is enabled") { 65 | enabled = true 66 | } else if strings.Contains(line, "is running") { 67 | running = true 68 | } 69 | } 70 | 71 | if !enabled { 72 | output, err = exec.Command("nfsd", "enable").Output() 73 | } else if !running { 74 | output, err = exec.Command("nfsd", "start").Output() 75 | } else { 76 | output, err = exec.Command("nfsd", "restart").Output() 77 | } 78 | 79 | if err != nil { 80 | return fmt.Errorf(string(output)) 81 | } 82 | return nil 83 | } 84 | 85 | func removeNFS(home string) error { 86 | addr, err := getNetAddress() 87 | if err != nil { 88 | return err 89 | } 90 | 91 | mask, _ := getNetMask() 92 | export := fmt.Sprintf("%s -network %s -mask %s -alldirs -maproot=root:wheel", home, addr, mask) 93 | 94 | rawExports, err := ioutil.ReadFile("/etc/exports") 95 | if err != nil { 96 | return err 97 | } 98 | 99 | exportMatcher := regexp.MustCompile(fmt.Sprintf("(?m)^%s\n?$", export)) 100 | newExports := exportMatcher.ReplaceAllString(string(rawExports), "") 101 | 102 | err = ioutil.WriteFile("/etc/exports", []byte(newExports), 0644) 103 | if err != nil { 104 | return err 105 | } 106 | 107 | output, err := exec.Command("nfsd", "restart").Output() 108 | if err != nil { 109 | return fmt.Errorf(string(output)) 110 | } 111 | 112 | return nil 113 | } 114 | -------------------------------------------------------------------------------- /os.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "io" 6 | "net/http" 7 | "os" 8 | "path" 9 | "sort" 10 | "strconv" 11 | "strings" 12 | 13 | "github.com/blang/semver" 14 | ) 15 | 16 | var allowedRange = semver.MustParseRange(">=1.0.0-beta0") 17 | 18 | type File struct { 19 | Name string `json:"name"` 20 | Url string `json:"browser_download_url"` 21 | } 22 | 23 | type Release struct { 24 | Version semver.Version 25 | Tag string `json:"tag_name"` 26 | Files []File `json:"assets"` 27 | } 28 | type Releases []Release 29 | 30 | func (rs Releases) Len() int { 31 | return len(rs) 32 | } 33 | 34 | func (rs Releases) Less(i, j int) bool { 35 | return rs[i].Version.LT(rs[j].Version) 36 | } 37 | 38 | func (rs Releases) Swap(i, j int) { 39 | rs[i], rs[j] = rs[j], rs[i] 40 | } 41 | 42 | func getOSReleases() (Releases, error) { 43 | res, err := http.Get("https://api.github.com/repos/nlf/dlite-os/releases") 44 | if err != nil { 45 | return nil, err 46 | } 47 | 48 | defer res.Body.Close() 49 | releases := Releases{} 50 | decoder := json.NewDecoder(res.Body) 51 | err = decoder.Decode(&releases) 52 | if err != nil { 53 | return nil, err 54 | } 55 | 56 | allowedReleases := Releases{} 57 | for _, release := range releases { 58 | release.Version = semver.MustParse(strings.TrimPrefix(release.Tag, "v")) 59 | if allowedRange(release.Version) { 60 | allowedReleases = append(allowedReleases, release) 61 | } 62 | } 63 | 64 | sort.Sort(allowedReleases) 65 | return allowedReleases, nil 66 | } 67 | 68 | func getLatestOSRelease() (Release, error) { 69 | releases, err := getOSReleases() 70 | if err != nil { 71 | return Release{}, err 72 | } 73 | 74 | return releases[len(releases)-1], nil 75 | } 76 | 77 | func downloadOS(target string) error { 78 | latest, err := getLatestOSRelease() 79 | if err != nil { 80 | return err 81 | } 82 | 83 | for _, file := range latest.Files { 84 | tempPath := path.Join(target, file.Name) 85 | output, err := os.Create(tempPath) 86 | if err != nil { 87 | return err 88 | } 89 | 90 | res, err := http.Get(file.Url) 91 | defer res.Body.Close() 92 | if err != nil { 93 | return err 94 | } 95 | 96 | length, err := strconv.ParseInt(res.Header.Get("Content-Length"), 10, 64) 97 | if err != nil { 98 | return err 99 | } 100 | 101 | _, err = io.CopyN(output, res.Body, length) 102 | if err != nil { 103 | return err 104 | } 105 | } 106 | 107 | return nil 108 | } 109 | -------------------------------------------------------------------------------- /proxy.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "net" 7 | "net/http" 8 | "os" 9 | ) 10 | 11 | type Proxy struct { 12 | done chan bool 13 | daemon *Daemon 14 | } 15 | 16 | func (p *Proxy) cleanup() error { 17 | _, err := os.Stat("/var/run/docker.sock") 18 | if err == nil { 19 | err = os.Remove("/var/run/docker.sock") 20 | return err 21 | } 22 | 23 | return nil 24 | } 25 | 26 | func (p *Proxy) proxy(w http.ResponseWriter, r *http.Request) { 27 | if p.daemon.VM == nil { 28 | w.WriteHeader(http.StatusServiceUnavailable) 29 | w.Write([]byte("The virtual machine has not been started")) 30 | return 31 | } 32 | 33 | addr, err := p.daemon.VM.Address() 34 | if err != nil { 35 | w.WriteHeader(http.StatusServiceUnavailable) 36 | w.Write([]byte("Unable to locate the virtual machine")) 37 | return 38 | } 39 | 40 | backend, err := net.DialTCP("tcp", nil, addr) 41 | if err != nil { 42 | w.WriteHeader(http.StatusServiceUnavailable) 43 | w.Write([]byte("Unable to connect to the virtual machine")) 44 | return 45 | } 46 | defer backend.Close() 47 | 48 | r.URL.Scheme = "http" 49 | r.URL.Host = fmt.Sprintf("%s:%d", addr.IP.String(), addr.Port) 50 | 51 | hijacker, ok := w.(http.Hijacker) 52 | if !ok { 53 | w.WriteHeader(http.StatusServiceUnavailable) 54 | w.Write([]byte("Unable to create hijacker")) 55 | return 56 | } 57 | 58 | conn, _, err := hijacker.Hijack() 59 | if err != nil { 60 | w.WriteHeader(http.StatusServiceUnavailable) 61 | w.Write([]byte("Unable to hijack connection")) 62 | return 63 | } 64 | 65 | r.Write(backend) 66 | finished := make(chan error, 1) 67 | 68 | go func(backend *net.TCPConn, conn net.Conn, finished chan error) { 69 | buf := make([]byte, 8092) 70 | _, err := io.CopyBuffer(backend, conn, buf) 71 | backend.CloseWrite() 72 | finished <- err 73 | }(backend, conn, finished) 74 | 75 | go func(backend *net.TCPConn, conn net.Conn, finished chan error) { 76 | buf := make([]byte, 8092) 77 | _, err := io.CopyBuffer(conn, backend, buf) 78 | conn.Close() 79 | finished <- err 80 | }(backend, conn, finished) 81 | 82 | <-finished 83 | <-finished 84 | } 85 | 86 | func (p *Proxy) Listen() error { 87 | err := p.cleanup() 88 | if err != nil { 89 | return err 90 | } 91 | 92 | addr, err := net.ResolveUnixAddr("unix", "/var/run/docker.sock") 93 | if err != nil { 94 | return err 95 | } 96 | 97 | raw, err := net.ListenUnix("unix", addr) 98 | if err != nil { 99 | return err 100 | } 101 | 102 | listener := &unixListener{ 103 | UnixListener: raw, 104 | done: p.done, 105 | } 106 | 107 | err = os.Chmod("/var/run/docker.sock", 0777) 108 | if err != nil { 109 | return err 110 | } 111 | 112 | server := http.Server{ 113 | Handler: http.HandlerFunc(p.proxy), 114 | } 115 | 116 | return server.Serve(listener) 117 | } 118 | 119 | func (p *Proxy) Stop() { 120 | p.done <- true 121 | p.cleanup() 122 | } 123 | 124 | func NewProxy(daemon *Daemon) *Proxy { 125 | return &Proxy{ 126 | daemon: daemon, 127 | done: make(chan bool), 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /ssh.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "os" 7 | "os/exec" 8 | "path/filepath" 9 | "regexp" 10 | "strings" 11 | ) 12 | 13 | func generateKeys(user User) error { 14 | base := getPath(user) 15 | output, err := exec.Command("ssh-keygen", "-f", fmt.Sprintf("%s/key", base), "-P", "").CombinedOutput() 16 | if err != nil { 17 | return fmt.Errorf(string(output)) 18 | } 19 | 20 | return nil 21 | } 22 | 23 | func addSSHConfig(user User, hostname string) error { 24 | configPath := filepath.Join(user.Home, ".ssh", "config") 25 | if _, err := os.Stat(configPath); os.IsNotExist(err) { 26 | err := ioutil.WriteFile(configPath, []byte(""), 0644) 27 | if err != nil { 28 | return err 29 | } 30 | } 31 | 32 | config, err := ioutil.ReadFile(configPath) 33 | if err != nil { 34 | return err 35 | } 36 | 37 | hasHost := strings.Index(string(config), fmt.Sprintf("Host %s", hostname)) 38 | if hasHost != -1 { 39 | return nil 40 | } 41 | 42 | keyfile := filepath.Join(getPath(user), "key") 43 | newConfig := string(config) 44 | newConfig += fmt.Sprintf("Host %s\n User docker\n IdentityFile %s", hostname, keyfile) 45 | return ioutil.WriteFile(configPath, []byte(newConfig), 0644) 46 | } 47 | 48 | func removeSSHConfig(user User, hostname string) error { 49 | configPath := filepath.Join(user.Home, ".ssh", "config") 50 | config, err := ioutil.ReadFile(configPath) 51 | if err != nil { 52 | return err 53 | } 54 | 55 | keyfile := filepath.Join(getPath(user), "key") 56 | hostConfig := fmt.Sprintf("Host %s\n User docker\n IdentityFile %s", hostname, keyfile) 57 | 58 | hostMatcher := regexp.MustCompile(fmt.Sprintf("(?m)^%s?$", hostConfig)) 59 | newConfig := hostMatcher.ReplaceAllString(string(config), "") 60 | 61 | return ioutil.WriteFile(configPath, []byte(newConfig), 0644) 62 | } 63 | -------------------------------------------------------------------------------- /tar.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "archive/tar" 5 | "bytes" 6 | "compress/gzip" 7 | "encoding/base64" 8 | "fmt" 9 | "io" 10 | "os" 11 | "path/filepath" 12 | ) 13 | 14 | func generateTarball(user User) ([]byte, error) { 15 | basePath := getPath(user) 16 | cfg, err := readConfig(basePath) 17 | if err != nil { 18 | return nil, err 19 | } 20 | 21 | buf := &bytes.Buffer{} 22 | gz := gzip.NewWriter(buf) 23 | tarball := tar.NewWriter(gz) 24 | 25 | hostname := []byte(cfg.Hostname) 26 | hostnameHeader := &tar.Header{ 27 | Name: "/etc/hostname", 28 | Mode: 0644, 29 | Size: int64(len(hostname)), 30 | Uid: 0, 31 | Gid: 10, 32 | } 33 | 34 | err = tarball.WriteHeader(hostnameHeader) 35 | if err != nil { 36 | return nil, err 37 | } 38 | 39 | _, err = tarball.Write(hostname) 40 | if err != nil { 41 | return nil, err 42 | } 43 | 44 | hosts := []byte(fmt.Sprintf("127.0.0.1 localhost %s", cfg.Hostname)) 45 | hostsHeader := &tar.Header{ 46 | Name: "/etc/hosts", 47 | Mode: 0644, 48 | Size: int64(len(hosts)), 49 | Uid: 0, 50 | Gid: 10, 51 | } 52 | 53 | err = tarball.WriteHeader(hostsHeader) 54 | if err != nil { 55 | return nil, err 56 | } 57 | 58 | _, err = tarball.Write(hosts) 59 | if err != nil { 60 | return nil, err 61 | } 62 | 63 | ifaces := []byte(fmt.Sprintf("auto lo\niface lo inet loopback\n\nauto eth0\niface eth0 inet dhcp\nhostname %s", cfg.Id)) 64 | ifacesHeader := &tar.Header{ 65 | Name: "/etc/network/interfaces", 66 | Mode: 0644, 67 | Size: int64(len(ifaces)), 68 | Uid: 0, 69 | Gid: 10, 70 | } 71 | 72 | err = tarball.WriteHeader(ifacesHeader) 73 | if err != nil { 74 | return nil, err 75 | } 76 | 77 | _, err = tarball.Write(ifaces) 78 | if err != nil { 79 | return nil, err 80 | } 81 | 82 | dns := []byte(fmt.Sprintf("nameserver %s", cfg.DNS)) 83 | dnsHeader := &tar.Header{ 84 | Name: "/etc/resolv.conf", 85 | Mode: 0644, 86 | Size: int64(len(dns)), 87 | Uid: 0, 88 | Gid: 10, 89 | } 90 | 91 | err = tarball.WriteHeader(dnsHeader) 92 | if err != nil { 93 | return nil, err 94 | } 95 | 96 | _, err = tarball.Write(dns) 97 | if err != nil { 98 | return nil, err 99 | } 100 | 101 | hostIp, _ := getHostAddress() 102 | hostIpBytes := []byte(hostIp) 103 | hostIpHeader := &tar.Header{ 104 | Name: "/etc/dlite/host_ip", 105 | Mode: 0600, 106 | Size: int64(len(hostIpBytes)), 107 | Uid: 0, 108 | Gid: 10, 109 | } 110 | 111 | err = tarball.WriteHeader(hostIpHeader) 112 | if err != nil { 113 | return nil, err 114 | } 115 | 116 | _, err = tarball.Write(hostIpBytes) 117 | if err != nil { 118 | return nil, err 119 | } 120 | 121 | username := []byte(user.Name) 122 | usernameHeader := &tar.Header{ 123 | Name: "/etc/dlite/username", 124 | Mode: 0600, 125 | Size: int64(len(username)), 126 | Uid: 0, 127 | Gid: 10, 128 | } 129 | 130 | err = tarball.WriteHeader(usernameHeader) 131 | if err != nil { 132 | return nil, err 133 | } 134 | 135 | _, err = tarball.Write(username) 136 | if err != nil { 137 | return nil, err 138 | } 139 | 140 | userId := []byte(fmt.Sprintf("%d", user.Uid)) 141 | userIdHeader := &tar.Header{ 142 | Name: "/etc/dlite/userid", 143 | Mode: 0600, 144 | Size: int64(len(userId)), 145 | Uid: 0, 146 | Gid: 10, 147 | } 148 | 149 | err = tarball.WriteHeader(userIdHeader) 150 | if err != nil { 151 | return nil, err 152 | } 153 | 154 | _, err = tarball.Write(userId) 155 | if err != nil { 156 | return nil, err 157 | } 158 | 159 | dockerVersion := []byte(cfg.Docker) 160 | dockerVersionHeader := &tar.Header{ 161 | Name: "/etc/dlite/docker_version", 162 | Mode: 0600, 163 | Size: int64(len(dockerVersion)), 164 | Uid: 0, 165 | Gid: 10, 166 | } 167 | 168 | err = tarball.WriteHeader(dockerVersionHeader) 169 | if err != nil { 170 | return nil, err 171 | } 172 | 173 | _, err = tarball.Write(dockerVersion) 174 | if err != nil { 175 | return nil, err 176 | } 177 | 178 | dockerArgs := []byte(cfg.Extra) 179 | dockerArgsHeader := &tar.Header{ 180 | Name: "/etc/dlite/docker_args", 181 | Mode: 0600, 182 | Size: int64(len(dockerArgs)), 183 | Uid: 0, 184 | Gid: 10, 185 | } 186 | 187 | err = tarball.WriteHeader(dockerArgsHeader) 188 | if err != nil { 189 | return nil, err 190 | } 191 | 192 | _, err = tarball.Write(dockerArgs) 193 | if err != nil { 194 | return nil, err 195 | } 196 | 197 | sshDirHeader := &tar.Header{ 198 | Name: "/home/docker/.ssh", 199 | Mode: 0700, 200 | Typeflag: tar.TypeDir, 201 | Uid: 1000, 202 | Gid: 1000, 203 | } 204 | 205 | err = tarball.WriteHeader(sshDirHeader) 206 | if err != nil { 207 | return nil, err 208 | } 209 | 210 | keyFile, err := os.Open(filepath.Join(basePath, "key.pub")) 211 | if err != nil { 212 | return nil, err 213 | } 214 | 215 | keyStat, err := keyFile.Stat() 216 | if err != nil { 217 | return nil, err 218 | } 219 | 220 | keysHeader := &tar.Header{ 221 | Name: "/home/docker/.ssh/authorized_keys", 222 | Mode: 0600, 223 | Size: keyStat.Size(), 224 | Uid: 1000, 225 | Gid: 1000, 226 | } 227 | 228 | err = tarball.WriteHeader(keysHeader) 229 | if err != nil { 230 | return nil, err 231 | } 232 | 233 | _, err = io.Copy(tarball, keyFile) 234 | if err != nil { 235 | return nil, err 236 | } 237 | 238 | tarball.Close() 239 | gz.Close() 240 | 241 | return buf.Bytes(), nil 242 | } 243 | 244 | func GetBootstrapData(user User) (string, error) { 245 | tarball, err := generateTarball(user) 246 | if err != nil { 247 | return "", err 248 | } 249 | 250 | return base64.StdEncoding.EncodeToString(tarball), nil 251 | } 252 | -------------------------------------------------------------------------------- /ui.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | "strings" 7 | "time" 8 | 9 | "github.com/briandowns/spinner" 10 | "github.com/urfave/cli" 11 | ) 12 | 13 | func ask(question string) string { 14 | var answer string 15 | fmt.Printf("%s: ", question) 16 | fmt.Scanln(&answer) 17 | return answer 18 | } 19 | 20 | func askString(question, def string) string { 21 | prompt := question 22 | if def != "" { 23 | prompt += fmt.Sprintf(" [%s]", def) 24 | } 25 | res := ask(prompt) 26 | if res == "" { 27 | return def 28 | } 29 | 30 | return res 31 | } 32 | 33 | func askInt(question string, def int) int { 34 | prompt := fmt.Sprintf("%s [%d]", question, def) 35 | res := ask(prompt) 36 | if res == "" { 37 | return def 38 | } 39 | 40 | i, err := strconv.Atoi(res) 41 | if err != nil { 42 | return askInt(question, def) 43 | } 44 | 45 | return i 46 | } 47 | 48 | func askBool(question string, def bool) bool { 49 | defString := "yes" 50 | if !def { 51 | defString = "no" 52 | } 53 | 54 | prompt := fmt.Sprintf("%s [%v]", question, defString) 55 | res := ask(prompt) 56 | 57 | switch strings.ToLower(res) { 58 | case "yes", "y": 59 | return true 60 | case "no", "n": 61 | return false 62 | case "": 63 | return def 64 | default: 65 | return askBool(question, def) 66 | } 67 | } 68 | 69 | func confirm(question string) bool { 70 | answer := ask(question) 71 | 72 | switch strings.ToLower(answer) { 73 | case "yes", "y": 74 | return true 75 | case "no", "n": 76 | return false 77 | default: 78 | return confirm(question) 79 | } 80 | } 81 | 82 | func spin(prefix string, f func() error) *cli.ExitError { 83 | spin := spinner.New(spinner.CharSets[9], time.Millisecond*100) 84 | spin.Prefix = fmt.Sprintf("%s: ", prefix) 85 | spin.Start() 86 | err := f() 87 | spin.Stop() 88 | if err != nil { 89 | cliError, ok := err.(*cli.ExitError) 90 | if ok { 91 | if cliError.ExitCode() != 0 { 92 | fmt.Printf("\r%s: ERROR!\n", prefix) 93 | return cliError 94 | } 95 | 96 | fmt.Printf("\r%s: done\n", prefix) 97 | return cli.NewExitError("", 0) 98 | } 99 | fmt.Printf("\r%s: ERROR!\n", prefix) 100 | return cli.NewExitError(err.Error(), 1) 101 | } 102 | 103 | fmt.Printf("\r%s: done\n", prefix) 104 | return cli.NewExitError("", 0) 105 | } 106 | -------------------------------------------------------------------------------- /vendor/github.com/blang/semver/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2014 Benedikt Lang 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /vendor/github.com/blang/semver/json.go: -------------------------------------------------------------------------------- 1 | package semver 2 | 3 | import ( 4 | "encoding/json" 5 | ) 6 | 7 | // MarshalJSON implements the encoding/json.Marshaler interface. 8 | func (v Version) MarshalJSON() ([]byte, error) { 9 | return json.Marshal(v.String()) 10 | } 11 | 12 | // UnmarshalJSON implements the encoding/json.Unmarshaler interface. 13 | func (v *Version) UnmarshalJSON(data []byte) (err error) { 14 | var versionString string 15 | 16 | if err = json.Unmarshal(data, &versionString); err != nil { 17 | return 18 | } 19 | 20 | *v, err = Parse(versionString) 21 | 22 | return 23 | } 24 | -------------------------------------------------------------------------------- /vendor/github.com/blang/semver/sort.go: -------------------------------------------------------------------------------- 1 | package semver 2 | 3 | import ( 4 | "sort" 5 | ) 6 | 7 | // Versions represents multiple versions. 8 | type Versions []Version 9 | 10 | // Len returns length of version collection 11 | func (s Versions) Len() int { 12 | return len(s) 13 | } 14 | 15 | // Swap swaps two versions inside the collection by its indices 16 | func (s Versions) Swap(i, j int) { 17 | s[i], s[j] = s[j], s[i] 18 | } 19 | 20 | // Less checks if version at index i is less than version at index j 21 | func (s Versions) Less(i, j int) bool { 22 | return s[i].LT(s[j]) 23 | } 24 | 25 | // Sort sorts a slice of versions 26 | func Sort(versions []Version) { 27 | sort.Sort(Versions(versions)) 28 | } 29 | -------------------------------------------------------------------------------- /vendor/github.com/blang/semver/sql.go: -------------------------------------------------------------------------------- 1 | package semver 2 | 3 | import ( 4 | "database/sql/driver" 5 | "fmt" 6 | ) 7 | 8 | // Scan implements the database/sql.Scanner interface. 9 | func (v *Version) Scan(src interface{}) (err error) { 10 | var str string 11 | switch src := src.(type) { 12 | case string: 13 | str = src 14 | case []byte: 15 | str = string(src) 16 | default: 17 | return fmt.Errorf("Version.Scan: cannot convert %T to string.", src) 18 | } 19 | 20 | if t, err := Parse(str); err == nil { 21 | *v = t 22 | } 23 | 24 | return 25 | } 26 | 27 | // Value implements the database/sql/driver.Valuer interface. 28 | func (v Version) Value() (driver.Value, error) { 29 | return v.String(), nil 30 | } 31 | -------------------------------------------------------------------------------- /vendor/github.com/briandowns/spinner/character_sets.go: -------------------------------------------------------------------------------- 1 | package spinner 2 | 3 | // CharSets contains the available character sets 4 | var CharSets = map[int][]string{ 5 | 0: {"←", "↖", "↑", "↗", "→", "↘", "↓", "↙"}, 6 | 1: {"▁", "▃", "▄", "▅", "▆", "▇", "█", "▇", "▆", "▅", "▄", "▃", "▁"}, 7 | 2: {"▖", "▘", "▝", "▗"}, 8 | 3: {"┤", "┘", "┴", "└", "├", "┌", "┬", "┐"}, 9 | 4: {"◢", "◣", "◤", "◥"}, 10 | 5: {"◰", "◳", "◲", "◱"}, 11 | 6: {"◴", "◷", "◶", "◵"}, 12 | 7: {"◐", "◓", "◑", "◒"}, 13 | 8: {".", "o", "O", "@", "*"}, 14 | 9: {"|", "/", "-", "\\"}, 15 | 10: {"◡◡", "⊙⊙", "◠◠"}, 16 | 11: {"⣾", "⣽", "⣻", "⢿", "⡿", "⣟", "⣯", "⣷"}, 17 | 12: {">))'>", " >))'>", " >))'>", " >))'>", " >))'>", " <'((<", " <'((<", " <'((<"}, 18 | 13: {"⠁", "⠂", "⠄", "⡀", "⢀", "⠠", "⠐", "⠈"}, 19 | 14: {"⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"}, 20 | 15: {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"}, 21 | 16: {"▉", "▊", "▋", "▌", "▍", "▎", "▏", "▎", "▍", "▌", "▋", "▊", "▉"}, 22 | 17: {"■", "□", "▪", "▫"}, 23 | 18: {"←", "↑", "→", "↓"}, 24 | 19: {"╫", "╪"}, 25 | 20: {"⇐", "⇖", "⇑", "⇗", "⇒", "⇘", "⇓", "⇙"}, 26 | 21: {"⠁", "⠁", "⠉", "⠙", "⠚", "⠒", "⠂", "⠂", "⠒", "⠲", "⠴", "⠤", "⠄", "⠄", "⠤", "⠠", "⠠", "⠤", "⠦", "⠖", "⠒", "⠐", "⠐", "⠒", "⠓", "⠋", "⠉", "⠈", "⠈"}, 27 | 22: {"⠈", "⠉", "⠋", "⠓", "⠒", "⠐", "⠐", "⠒", "⠖", "⠦", "⠤", "⠠", "⠠", "⠤", "⠦", "⠖", "⠒", "⠐", "⠐", "⠒", "⠓", "⠋", "⠉", "⠈"}, 28 | 23: {"⠁", "⠉", "⠙", "⠚", "⠒", "⠂", "⠂", "⠒", "⠲", "⠴", "⠤", "⠄", "⠄", "⠤", "⠴", "⠲", "⠒", "⠂", "⠂", "⠒", "⠚", "⠙", "⠉", "⠁"}, 29 | 24: {"⠋", "⠙", "⠚", "⠒", "⠂", "⠂", "⠒", "⠲", "⠴", "⠦", "⠖", "⠒", "⠐", "⠐", "⠒", "⠓", "⠋"}, 30 | 25: {"ヲ", "ァ", "ィ", "ゥ", "ェ", "ォ", "ャ", "ュ", "ョ", "ッ", "ア", "イ", "ウ", "エ", "オ", "カ", "キ", "ク", "ケ", "コ", "サ", "シ", "ス", "セ", "ソ", "タ", "チ", "ツ", "テ", "ト", "ナ", "ニ", "ヌ", "ネ", "ノ", "ハ", "ヒ", "フ", "ヘ", "ホ", "マ", "ミ", "ム", "メ", "モ", "ヤ", "ユ", "ヨ", "ラ", "リ", "ル", "レ", "ロ", "ワ", "ン"}, 31 | 26: {".", "..", "..."}, 32 | 27: {"▁", "▂", "▃", "▄", "▅", "▆", "▇", "█", "▉", "▊", "▋", "▌", "▍", "▎", "▏", "▏", "▎", "▍", "▌", "▋", "▊", "▉", "█", "▇", "▆", "▅", "▄", "▃", "▂", "▁"}, 33 | 28: {".", "o", "O", "°", "O", "o", "."}, 34 | 29: {"+", "x"}, 35 | 30: {"v", "<", "^", ">"}, 36 | 31: {">>--->", " >>--->", " >>--->", " >>--->", " >>--->", " <---<<", " <---<<", " <---<<", " <---<<", "<---<<"}, 37 | 32: {"|", "||", "|||", "||||", "|||||", "|||||||", "||||||||", "|||||||", "||||||", "|||||", "||||", "|||", "||", "|"}, 38 | 33: {"[ ]", "[= ]", "[== ]", "[=== ]", "[==== ]", "[===== ]", "[====== ]", "[======= ]", "[======== ]", "[========= ]", "[==========]"}, 39 | 34: {"(*---------)", "(-*--------)", "(--*-------)", "(---*------)", "(----*-----)", "(-----*----)", "(------*---)", "(-------*--)", "(--------*-)", "(---------*)"}, 40 | 35: {"█▒▒▒▒▒▒▒▒▒", "███▒▒▒▒▒▒▒", "█████▒▒▒▒▒", "███████▒▒▒", "██████████"}, 41 | 36: {"[ ]", "[=> ]", "[===> ]", "[=====> ]", "[======> ]", "[========> ]", "[==========> ]", "[============> ]", "[==============> ]", "[================> ]", "[==================> ]", "[===================>]"}, 42 | } 43 | -------------------------------------------------------------------------------- /vendor/github.com/fatih/color/LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Fatih Arslan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /vendor/github.com/fatih/color/README.md: -------------------------------------------------------------------------------- 1 | # Color [![GoDoc](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)](http://godoc.org/github.com/fatih/color) [![Build Status](http://img.shields.io/travis/fatih/color.svg?style=flat-square)](https://travis-ci.org/fatih/color) 2 | 3 | 4 | 5 | Color lets you use colorized outputs in terms of [ANSI Escape 6 | Codes](http://en.wikipedia.org/wiki/ANSI_escape_code#Colors) in Go (Golang). It 7 | has support for Windows too! The API can be used in several ways, pick one that 8 | suits you. 9 | 10 | 11 | 12 | ![Color](http://i.imgur.com/c1JI0lA.png) 13 | 14 | 15 | ## Install 16 | 17 | ```bash 18 | go get github.com/fatih/color 19 | ``` 20 | 21 | ## Examples 22 | 23 | ### Standard colors 24 | 25 | ```go 26 | // Print with default helper functions 27 | color.Cyan("Prints text in cyan.") 28 | 29 | // A newline will be appended automatically 30 | color.Blue("Prints %s in blue.", "text") 31 | 32 | // These are using the default foreground colors 33 | color.Red("We have red") 34 | color.Magenta("And many others ..") 35 | 36 | ``` 37 | 38 | ### Mix and reuse colors 39 | 40 | ```go 41 | // Create a new color object 42 | c := color.New(color.FgCyan).Add(color.Underline) 43 | c.Println("Prints cyan text with an underline.") 44 | 45 | // Or just add them to New() 46 | d := color.New(color.FgCyan, color.Bold) 47 | d.Printf("This prints bold cyan %s\n", "too!.") 48 | 49 | // Mix up foreground and background colors, create new mixes! 50 | red := color.New(color.FgRed) 51 | 52 | boldRed := red.Add(color.Bold) 53 | boldRed.Println("This will print text in bold red.") 54 | 55 | whiteBackground := red.Add(color.BgWhite) 56 | whiteBackground.Println("Red text with white background.") 57 | ``` 58 | 59 | ### Custom print functions (PrintFunc) 60 | 61 | ```go 62 | // Create a custom print function for convenience 63 | red := color.New(color.FgRed).PrintfFunc() 64 | red("Warning") 65 | red("Error: %s", err) 66 | 67 | // Mix up multiple attributes 68 | notice := color.New(color.Bold, color.FgGreen).PrintlnFunc() 69 | notice("Don't forget this...") 70 | ``` 71 | 72 | ### Insert into noncolor strings (SprintFunc) 73 | 74 | ```go 75 | // Create SprintXxx functions to mix strings with other non-colorized strings: 76 | yellow := color.New(color.FgYellow).SprintFunc() 77 | red := color.New(color.FgRed).SprintFunc() 78 | fmt.Printf("This is a %s and this is %s.\n", yellow("warning"), red("error")) 79 | 80 | info := color.New(color.FgWhite, color.BgGreen).SprintFunc() 81 | fmt.Printf("This %s rocks!\n", info("package")) 82 | 83 | // Use helper functions 84 | fmt.Printf("This", color.RedString("warning"), "should be not neglected.") 85 | fmt.Printf(color.GreenString("Info:"), "an important message." ) 86 | 87 | // Windows supported too! Just don't forget to change the output to color.Output 88 | fmt.Fprintf(color.Output, "Windows support: %s", color.GreenString("PASS")) 89 | ``` 90 | 91 | ### Plug into existing code 92 | 93 | ```go 94 | // Use handy standard colors 95 | color.Set(color.FgYellow) 96 | 97 | fmt.Println("Existing text will now be in yellow") 98 | fmt.Printf("This one %s\n", "too") 99 | 100 | color.Unset() // Don't forget to unset 101 | 102 | // You can mix up parameters 103 | color.Set(color.FgMagenta, color.Bold) 104 | defer color.Unset() // Use it in your function 105 | 106 | fmt.Println("All text will now be bold magenta.") 107 | ``` 108 | 109 | ### Disable color 110 | 111 | There might be a case where you want to disable color output (for example to 112 | pipe the standard output of your app to somewhere else). `Color` has support to 113 | disable colors both globally and for single color definition. For example 114 | suppose you have a CLI app and a `--no-color` bool flag. You can easily disable 115 | the color output with: 116 | 117 | ```go 118 | 119 | var flagNoColor = flag.Bool("no-color", false, "Disable color output") 120 | 121 | if *flagNoColor { 122 | color.NoColor = true // disables colorized output 123 | } 124 | ``` 125 | 126 | It also has support for single color definitions (local). You can 127 | disable/enable color output on the fly: 128 | 129 | ```go 130 | c := color.New(color.FgCyan) 131 | c.Println("Prints cyan text") 132 | 133 | c.DisableColor() 134 | c.Println("This is printed without any color") 135 | 136 | c.EnableColor() 137 | c.Println("This prints again cyan...") 138 | ``` 139 | 140 | ## Todo 141 | 142 | * Save/Return previous values 143 | * Evaluate fmt.Formatter interface 144 | 145 | 146 | ## Credits 147 | 148 | * [Fatih Arslan](https://github.com/fatih) 149 | * Windows support via @mattn: [colorable](https://github.com/mattn/go-colorable) 150 | 151 | ## License 152 | 153 | The MIT License (MIT) - see [`LICENSE.md`](https://github.com/fatih/color/blob/master/LICENSE.md) for more details 154 | 155 | -------------------------------------------------------------------------------- /vendor/github.com/fatih/color/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package color is an ANSI color package to output colorized or SGR defined 3 | output to the standard output. The API can be used in several way, pick one 4 | that suits you. 5 | 6 | Use simple and default helper functions with predefined foreground colors: 7 | 8 | color.Cyan("Prints text in cyan.") 9 | 10 | // a newline will be appended automatically 11 | color.Blue("Prints %s in blue.", "text") 12 | 13 | // More default foreground colors.. 14 | color.Red("We have red") 15 | color.Yellow("Yellow color too!") 16 | color.Magenta("And many others ..") 17 | 18 | However there are times where custom color mixes are required. Below are some 19 | examples to create custom color objects and use the print functions of each 20 | separate color object. 21 | 22 | // Create a new color object 23 | c := color.New(color.FgCyan).Add(color.Underline) 24 | c.Println("Prints cyan text with an underline.") 25 | 26 | // Or just add them to New() 27 | d := color.New(color.FgCyan, color.Bold) 28 | d.Printf("This prints bold cyan %s\n", "too!.") 29 | 30 | 31 | // Mix up foreground and background colors, create new mixes! 32 | red := color.New(color.FgRed) 33 | 34 | boldRed := red.Add(color.Bold) 35 | boldRed.Println("This will print text in bold red.") 36 | 37 | whiteBackground := red.Add(color.BgWhite) 38 | whiteBackground.Println("Red text with White background.") 39 | 40 | 41 | You can create PrintXxx functions to simplify even more: 42 | 43 | // Create a custom print function for convenient 44 | red := color.New(color.FgRed).PrintfFunc() 45 | red("warning") 46 | red("error: %s", err) 47 | 48 | // Mix up multiple attributes 49 | notice := color.New(color.Bold, color.FgGreen).PrintlnFunc() 50 | notice("don't forget this...") 51 | 52 | 53 | Or create SprintXxx functions to mix strings with other non-colorized strings: 54 | 55 | yellow := New(FgYellow).SprintFunc() 56 | red := New(FgRed).SprintFunc() 57 | 58 | fmt.Printf("this is a %s and this is %s.\n", yellow("warning"), red("error")) 59 | 60 | info := New(FgWhite, BgGreen).SprintFunc() 61 | fmt.Printf("this %s rocks!\n", info("package")) 62 | 63 | Windows support is enabled by default. All Print functions works as intended. 64 | However only for color.SprintXXX functions, user should use fmt.FprintXXX and 65 | set the output to color.Output: 66 | 67 | fmt.Fprintf(color.Output, "Windows support: %s", color.GreenString("PASS")) 68 | 69 | info := New(FgWhite, BgGreen).SprintFunc() 70 | fmt.Fprintf(color.Output, "this %s rocks!\n", info("package")) 71 | 72 | Using with existing code is possible. Just use the Set() method to set the 73 | standard output to the given parameters. That way a rewrite of an existing 74 | code is not required. 75 | 76 | // Use handy standard colors. 77 | color.Set(color.FgYellow) 78 | 79 | fmt.Println("Existing text will be now in Yellow") 80 | fmt.Printf("This one %s\n", "too") 81 | 82 | color.Unset() // don't forget to unset 83 | 84 | // You can mix up parameters 85 | color.Set(color.FgMagenta, color.Bold) 86 | defer color.Unset() // use it in your function 87 | 88 | fmt.Println("All text will be now bold magenta.") 89 | 90 | There might be a case where you want to disable color output (for example to 91 | pipe the standard output of your app to somewhere else). `Color` has support to 92 | disable colors both globally and for single color definition. For example 93 | suppose you have a CLI app and a `--no-color` bool flag. You can easily disable 94 | the color output with: 95 | 96 | var flagNoColor = flag.Bool("no-color", false, "Disable color output") 97 | 98 | if *flagNoColor { 99 | color.NoColor = true // disables colorized output 100 | } 101 | 102 | It also has support for single color definitions (local). You can 103 | disable/enable color output on the fly: 104 | 105 | c := color.New(color.FgCyan) 106 | c.Println("Prints cyan text") 107 | 108 | c.DisableColor() 109 | c.Println("This is printed without any color") 110 | 111 | c.EnableColor() 112 | c.Println("This prints again cyan...") 113 | */ 114 | package color 115 | -------------------------------------------------------------------------------- /vendor/github.com/howeyc/fsnotify/AUTHORS: -------------------------------------------------------------------------------- 1 | # Names should be added to this file as 2 | # Name or Organization 3 | # The email address is not required for organizations. 4 | 5 | # You can update this list using the following command: 6 | # 7 | # $ git shortlog -se | awk '{print $2 " " $3 " " $4}' 8 | 9 | # Please keep the list sorted. 10 | 11 | Adrien Bustany 12 | Caleb Spare 13 | Case Nelson 14 | Chris Howey 15 | Christoffer Buchholz 16 | Dave Cheney 17 | Francisco Souza 18 | John C Barstow 19 | Kelvin Fo 20 | Nathan Youngman 21 | Paul Hammond 22 | Pursuit92 23 | Rob Figueiredo 24 | Travis Cline 25 | Tudor Golubenco 26 | bronze1man 27 | debrando 28 | henrikedwards 29 | -------------------------------------------------------------------------------- /vendor/github.com/howeyc/fsnotify/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## v0.9.0 / 2014-01-17 4 | 5 | * IsAttrib() for events that only concern a file's metadata [#79][] (thanks @abustany) 6 | * [Fix] kqueue: fix deadlock [#77][] (thanks @cespare) 7 | * [NOTICE] Development has moved to `code.google.com/p/go.exp/fsnotify` in preparation for inclusion in the Go standard library. 8 | 9 | ## v0.8.12 / 2013-11-13 10 | 11 | * [API] Remove FD_SET and friends from Linux adapter 12 | 13 | ## v0.8.11 / 2013-11-02 14 | 15 | * [Doc] Add Changelog [#72][] (thanks @nathany) 16 | * [Doc] Spotlight and double modify events on OS X [#62][] (reported by @paulhammond) 17 | 18 | ## v0.8.10 / 2013-10-19 19 | 20 | * [Fix] kqueue: remove file watches when parent directory is removed [#71][] (reported by @mdwhatcott) 21 | * [Fix] kqueue: race between Close and readEvents [#70][] (reported by @bernerdschaefer) 22 | * [Doc] specify OS-specific limits in README (thanks @debrando) 23 | 24 | ## v0.8.9 / 2013-09-08 25 | 26 | * [Doc] Contributing (thanks @nathany) 27 | * [Doc] update package path in example code [#63][] (thanks @paulhammond) 28 | * [Doc] GoCI badge in README (Linux only) [#60][] 29 | * [Doc] Cross-platform testing with Vagrant [#59][] (thanks @nathany) 30 | 31 | ## v0.8.8 / 2013-06-17 32 | 33 | * [Fix] Windows: handle `ERROR_MORE_DATA` on Windows [#49][] (thanks @jbowtie) 34 | 35 | ## v0.8.7 / 2013-06-03 36 | 37 | * [API] Make syscall flags internal 38 | * [Fix] inotify: ignore event changes 39 | * [Fix] race in symlink test [#45][] (reported by @srid) 40 | * [Fix] tests on Windows 41 | * lower case error messages 42 | 43 | ## v0.8.6 / 2013-05-23 44 | 45 | * kqueue: Use EVT_ONLY flag on Darwin 46 | * [Doc] Update README with full example 47 | 48 | ## v0.8.5 / 2013-05-09 49 | 50 | * [Fix] inotify: allow monitoring of "broken" symlinks (thanks @tsg) 51 | 52 | ## v0.8.4 / 2013-04-07 53 | 54 | * [Fix] kqueue: watch all file events [#40][] (thanks @ChrisBuchholz) 55 | 56 | ## v0.8.3 / 2013-03-13 57 | 58 | * [Fix] inoitfy/kqueue memory leak [#36][] (reported by @nbkolchin) 59 | * [Fix] kqueue: use fsnFlags for watching a directory [#33][] (reported by @nbkolchin) 60 | 61 | ## v0.8.2 / 2013-02-07 62 | 63 | * [Doc] add Authors 64 | * [Fix] fix data races for map access [#29][] (thanks @fsouza) 65 | 66 | ## v0.8.1 / 2013-01-09 67 | 68 | * [Fix] Windows path separators 69 | * [Doc] BSD License 70 | 71 | ## v0.8.0 / 2012-11-09 72 | 73 | * kqueue: directory watching improvements (thanks @vmirage) 74 | * inotify: add `IN_MOVED_TO` [#25][] (requested by @cpisto) 75 | * [Fix] kqueue: deleting watched directory [#24][] (reported by @jakerr) 76 | 77 | ## v0.7.4 / 2012-10-09 78 | 79 | * [Fix] inotify: fixes from https://codereview.appspot.com/5418045/ (ugorji) 80 | * [Fix] kqueue: preserve watch flags when watching for delete [#21][] (reported by @robfig) 81 | * [Fix] kqueue: watch the directory even if it isn't a new watch (thanks @robfig) 82 | * [Fix] kqueue: modify after recreation of file 83 | 84 | ## v0.7.3 / 2012-09-27 85 | 86 | * [Fix] kqueue: watch with an existing folder inside the watched folder (thanks @vmirage) 87 | * [Fix] kqueue: no longer get duplicate CREATE events 88 | 89 | ## v0.7.2 / 2012-09-01 90 | 91 | * kqueue: events for created directories 92 | 93 | ## v0.7.1 / 2012-07-14 94 | 95 | * [Fix] for renaming files 96 | 97 | ## v0.7.0 / 2012-07-02 98 | 99 | * [Feature] FSNotify flags 100 | * [Fix] inotify: Added file name back to event path 101 | 102 | ## v0.6.0 / 2012-06-06 103 | 104 | * kqueue: watch files after directory created (thanks @tmc) 105 | 106 | ## v0.5.1 / 2012-05-22 107 | 108 | * [Fix] inotify: remove all watches before Close() 109 | 110 | ## v0.5.0 / 2012-05-03 111 | 112 | * [API] kqueue: return errors during watch instead of sending over channel 113 | * kqueue: match symlink behavior on Linux 114 | * inotify: add `DELETE_SELF` (requested by @taralx) 115 | * [Fix] kqueue: handle EINTR (reported by @robfig) 116 | * [Doc] Godoc example [#1][] (thanks @davecheney) 117 | 118 | ## v0.4.0 / 2012-03-30 119 | 120 | * Go 1 released: build with go tool 121 | * [Feature] Windows support using winfsnotify 122 | * Windows does not have attribute change notifications 123 | * Roll attribute notifications into IsModify 124 | 125 | ## v0.3.0 / 2012-02-19 126 | 127 | * kqueue: add files when watch directory 128 | 129 | ## v0.2.0 / 2011-12-30 130 | 131 | * update to latest Go weekly code 132 | 133 | ## v0.1.0 / 2011-10-19 134 | 135 | * kqueue: add watch on file creation to match inotify 136 | * kqueue: create file event 137 | * inotify: ignore `IN_IGNORED` events 138 | * event String() 139 | * linux: common FileEvent functions 140 | * initial commit 141 | 142 | [#79]: https://github.com/howeyc/fsnotify/pull/79 143 | [#77]: https://github.com/howeyc/fsnotify/pull/77 144 | [#72]: https://github.com/howeyc/fsnotify/issues/72 145 | [#71]: https://github.com/howeyc/fsnotify/issues/71 146 | [#70]: https://github.com/howeyc/fsnotify/issues/70 147 | [#63]: https://github.com/howeyc/fsnotify/issues/63 148 | [#62]: https://github.com/howeyc/fsnotify/issues/62 149 | [#60]: https://github.com/howeyc/fsnotify/issues/60 150 | [#59]: https://github.com/howeyc/fsnotify/issues/59 151 | [#49]: https://github.com/howeyc/fsnotify/issues/49 152 | [#45]: https://github.com/howeyc/fsnotify/issues/45 153 | [#40]: https://github.com/howeyc/fsnotify/issues/40 154 | [#36]: https://github.com/howeyc/fsnotify/issues/36 155 | [#33]: https://github.com/howeyc/fsnotify/issues/33 156 | [#29]: https://github.com/howeyc/fsnotify/issues/29 157 | [#25]: https://github.com/howeyc/fsnotify/issues/25 158 | [#24]: https://github.com/howeyc/fsnotify/issues/24 159 | [#21]: https://github.com/howeyc/fsnotify/issues/21 160 | [#1]: https://github.com/howeyc/fsnotify/issues/1 161 | -------------------------------------------------------------------------------- /vendor/github.com/howeyc/fsnotify/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | ## Moving Notice 4 | 5 | There is a fork being actively developed with a new API in preparation for the Go Standard Library: 6 | [github.com/go-fsnotify/fsnotify](https://github.com/go-fsnotify/fsnotify) 7 | 8 | -------------------------------------------------------------------------------- /vendor/github.com/howeyc/fsnotify/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 The Go Authors. All rights reserved. 2 | Copyright (c) 2012 fsnotify Authors. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above 11 | copyright notice, this list of conditions and the following disclaimer 12 | in the documentation and/or other materials provided with the 13 | distribution. 14 | * Neither the name of Google Inc. nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /vendor/github.com/howeyc/fsnotify/README.md: -------------------------------------------------------------------------------- 1 | # File system notifications for Go 2 | 3 | [![GoDoc](https://godoc.org/github.com/howeyc/fsnotify?status.png)](http://godoc.org/github.com/howeyc/fsnotify) 4 | 5 | Cross platform: Windows, Linux, BSD and OS X. 6 | 7 | ## Moving Notice 8 | 9 | There is a fork being actively developed with a new API in preparation for the Go Standard Library: 10 | [github.com/go-fsnotify/fsnotify](https://github.com/go-fsnotify/fsnotify) 11 | 12 | ## Example: 13 | 14 | ```go 15 | package main 16 | 17 | import ( 18 | "log" 19 | 20 | "github.com/howeyc/fsnotify" 21 | ) 22 | 23 | func main() { 24 | watcher, err := fsnotify.NewWatcher() 25 | if err != nil { 26 | log.Fatal(err) 27 | } 28 | 29 | done := make(chan bool) 30 | 31 | // Process events 32 | go func() { 33 | for { 34 | select { 35 | case ev := <-watcher.Event: 36 | log.Println("event:", ev) 37 | case err := <-watcher.Error: 38 | log.Println("error:", err) 39 | } 40 | } 41 | }() 42 | 43 | err = watcher.Watch("testDir") 44 | if err != nil { 45 | log.Fatal(err) 46 | } 47 | 48 | // Hang so program doesn't exit 49 | <-done 50 | 51 | /* ... do stuff ... */ 52 | watcher.Close() 53 | } 54 | ``` 55 | 56 | For each event: 57 | * Name 58 | * IsCreate() 59 | * IsDelete() 60 | * IsModify() 61 | * IsRename() 62 | 63 | ## FAQ 64 | 65 | **When a file is moved to another directory is it still being watched?** 66 | 67 | No (it shouldn't be, unless you are watching where it was moved to). 68 | 69 | **When I watch a directory, are all subdirectories watched as well?** 70 | 71 | No, you must add watches for any directory you want to watch (a recursive watcher is in the works [#56][]). 72 | 73 | **Do I have to watch the Error and Event channels in a separate goroutine?** 74 | 75 | As of now, yes. Looking into making this single-thread friendly (see [#7][]) 76 | 77 | **Why am I receiving multiple events for the same file on OS X?** 78 | 79 | Spotlight indexing on OS X can result in multiple events (see [#62][]). A temporary workaround is to add your folder(s) to the *Spotlight Privacy settings* until we have a native FSEvents implementation (see [#54][]). 80 | 81 | **How many files can be watched at once?** 82 | 83 | There are OS-specific limits as to how many watches can be created: 84 | * Linux: /proc/sys/fs/inotify/max_user_watches contains the limit, 85 | reaching this limit results in a "no space left on device" error. 86 | * BSD / OSX: sysctl variables "kern.maxfiles" and "kern.maxfilesperproc", reaching these limits results in a "too many open files" error. 87 | 88 | 89 | [#62]: https://github.com/howeyc/fsnotify/issues/62 90 | [#56]: https://github.com/howeyc/fsnotify/issues/56 91 | [#54]: https://github.com/howeyc/fsnotify/issues/54 92 | [#7]: https://github.com/howeyc/fsnotify/issues/7 93 | 94 | -------------------------------------------------------------------------------- /vendor/github.com/howeyc/fsnotify/fsnotify.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Package fsnotify implements file system notification. 6 | package fsnotify 7 | 8 | import "fmt" 9 | 10 | const ( 11 | FSN_CREATE = 1 12 | FSN_MODIFY = 2 13 | FSN_DELETE = 4 14 | FSN_RENAME = 8 15 | 16 | FSN_ALL = FSN_MODIFY | FSN_DELETE | FSN_RENAME | FSN_CREATE 17 | ) 18 | 19 | // Purge events from interal chan to external chan if passes filter 20 | func (w *Watcher) purgeEvents() { 21 | for ev := range w.internalEvent { 22 | sendEvent := false 23 | w.fsnmut.Lock() 24 | fsnFlags := w.fsnFlags[ev.Name] 25 | w.fsnmut.Unlock() 26 | 27 | if (fsnFlags&FSN_CREATE == FSN_CREATE) && ev.IsCreate() { 28 | sendEvent = true 29 | } 30 | 31 | if (fsnFlags&FSN_MODIFY == FSN_MODIFY) && ev.IsModify() { 32 | sendEvent = true 33 | } 34 | 35 | if (fsnFlags&FSN_DELETE == FSN_DELETE) && ev.IsDelete() { 36 | sendEvent = true 37 | } 38 | 39 | if (fsnFlags&FSN_RENAME == FSN_RENAME) && ev.IsRename() { 40 | sendEvent = true 41 | } 42 | 43 | if sendEvent { 44 | w.Event <- ev 45 | } 46 | 47 | // If there's no file, then no more events for user 48 | // BSD must keep watch for internal use (watches DELETEs to keep track 49 | // what files exist for create events) 50 | if ev.IsDelete() { 51 | w.fsnmut.Lock() 52 | delete(w.fsnFlags, ev.Name) 53 | w.fsnmut.Unlock() 54 | } 55 | } 56 | 57 | close(w.Event) 58 | } 59 | 60 | // Watch a given file path 61 | func (w *Watcher) Watch(path string) error { 62 | return w.WatchFlags(path, FSN_ALL) 63 | } 64 | 65 | // Watch a given file path for a particular set of notifications (FSN_MODIFY etc.) 66 | func (w *Watcher) WatchFlags(path string, flags uint32) error { 67 | w.fsnmut.Lock() 68 | w.fsnFlags[path] = flags 69 | w.fsnmut.Unlock() 70 | return w.watch(path) 71 | } 72 | 73 | // Remove a watch on a file 74 | func (w *Watcher) RemoveWatch(path string) error { 75 | w.fsnmut.Lock() 76 | delete(w.fsnFlags, path) 77 | w.fsnmut.Unlock() 78 | return w.removeWatch(path) 79 | } 80 | 81 | // String formats the event e in the form 82 | // "filename: DELETE|MODIFY|..." 83 | func (e *FileEvent) String() string { 84 | var events string = "" 85 | 86 | if e.IsCreate() { 87 | events += "|" + "CREATE" 88 | } 89 | 90 | if e.IsDelete() { 91 | events += "|" + "DELETE" 92 | } 93 | 94 | if e.IsModify() { 95 | events += "|" + "MODIFY" 96 | } 97 | 98 | if e.IsRename() { 99 | events += "|" + "RENAME" 100 | } 101 | 102 | if e.IsAttrib() { 103 | events += "|" + "ATTRIB" 104 | } 105 | 106 | if len(events) > 0 { 107 | events = events[1:] 108 | } 109 | 110 | return fmt.Sprintf("%q: %s", e.Name, events) 111 | } 112 | -------------------------------------------------------------------------------- /vendor/github.com/howeyc/fsnotify/fsnotify_open_bsd.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build freebsd openbsd netbsd dragonfly 6 | 7 | package fsnotify 8 | 9 | import "syscall" 10 | 11 | const open_FLAGS = syscall.O_NONBLOCK | syscall.O_RDONLY 12 | -------------------------------------------------------------------------------- /vendor/github.com/howeyc/fsnotify/fsnotify_open_darwin.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build darwin 6 | 7 | package fsnotify 8 | 9 | import "syscall" 10 | 11 | const open_FLAGS = syscall.O_EVTONLY 12 | -------------------------------------------------------------------------------- /vendor/github.com/kardianos/osext/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 The Go Authors. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google Inc. nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /vendor/github.com/kardianos/osext/README.md: -------------------------------------------------------------------------------- 1 | ### Extensions to the "os" package. 2 | 3 | [![GoDoc](https://godoc.org/github.com/kardianos/osext?status.svg)](https://godoc.org/github.com/kardianos/osext) 4 | 5 | ## Find the current Executable and ExecutableFolder. 6 | 7 | There is sometimes utility in finding the current executable file 8 | that is running. This can be used for upgrading the current executable 9 | or finding resources located relative to the executable file. Both 10 | working directory and the os.Args[0] value are arbitrary and cannot 11 | be relied on; os.Args[0] can be "faked". 12 | 13 | Multi-platform and supports: 14 | * Linux 15 | * OS X 16 | * Windows 17 | * Plan 9 18 | * BSDs. 19 | -------------------------------------------------------------------------------- /vendor/github.com/kardianos/osext/osext.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Extensions to the standard "os" package. 6 | package osext // import "github.com/kardianos/osext" 7 | 8 | import "path/filepath" 9 | 10 | var cx, ce = executableClean() 11 | 12 | func executableClean() (string, error) { 13 | p, err := executable() 14 | return filepath.Clean(p), err 15 | } 16 | 17 | // Executable returns an absolute path that can be used to 18 | // re-invoke the current program. 19 | // It may not be valid after the current program exits. 20 | func Executable() (string, error) { 21 | return cx, ce 22 | } 23 | 24 | // Returns same path as Executable, returns just the folder 25 | // path. Excludes the executable name and any trailing slash. 26 | func ExecutableFolder() (string, error) { 27 | p, err := Executable() 28 | if err != nil { 29 | return "", err 30 | } 31 | 32 | return filepath.Dir(p), nil 33 | } 34 | -------------------------------------------------------------------------------- /vendor/github.com/kardianos/osext/osext_plan9.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package osext 6 | 7 | import ( 8 | "os" 9 | "strconv" 10 | "syscall" 11 | ) 12 | 13 | func executable() (string, error) { 14 | f, err := os.Open("/proc/" + strconv.Itoa(os.Getpid()) + "/text") 15 | if err != nil { 16 | return "", err 17 | } 18 | defer f.Close() 19 | return syscall.Fd2path(int(f.Fd())) 20 | } 21 | -------------------------------------------------------------------------------- /vendor/github.com/kardianos/osext/osext_procfs.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build linux netbsd solaris dragonfly 6 | 7 | package osext 8 | 9 | import ( 10 | "errors" 11 | "fmt" 12 | "os" 13 | "runtime" 14 | "strings" 15 | ) 16 | 17 | func executable() (string, error) { 18 | switch runtime.GOOS { 19 | case "linux": 20 | const deletedTag = " (deleted)" 21 | execpath, err := os.Readlink("/proc/self/exe") 22 | if err != nil { 23 | return execpath, err 24 | } 25 | execpath = strings.TrimSuffix(execpath, deletedTag) 26 | execpath = strings.TrimPrefix(execpath, deletedTag) 27 | return execpath, nil 28 | case "netbsd": 29 | return os.Readlink("/proc/curproc/exe") 30 | case "dragonfly": 31 | return os.Readlink("/proc/curproc/file") 32 | case "solaris": 33 | return os.Readlink(fmt.Sprintf("/proc/%d/path/a.out", os.Getpid())) 34 | } 35 | return "", errors.New("ExecPath not implemented for " + runtime.GOOS) 36 | } 37 | -------------------------------------------------------------------------------- /vendor/github.com/kardianos/osext/osext_sysctl.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build darwin freebsd openbsd 6 | 7 | package osext 8 | 9 | import ( 10 | "os" 11 | "os/exec" 12 | "path/filepath" 13 | "runtime" 14 | "syscall" 15 | "unsafe" 16 | ) 17 | 18 | var initCwd, initCwdErr = os.Getwd() 19 | 20 | func executable() (string, error) { 21 | var mib [4]int32 22 | switch runtime.GOOS { 23 | case "freebsd": 24 | mib = [4]int32{1 /* CTL_KERN */, 14 /* KERN_PROC */, 12 /* KERN_PROC_PATHNAME */, -1} 25 | case "darwin": 26 | mib = [4]int32{1 /* CTL_KERN */, 38 /* KERN_PROCARGS */, int32(os.Getpid()), -1} 27 | case "openbsd": 28 | mib = [4]int32{1 /* CTL_KERN */, 55 /* KERN_PROC_ARGS */, int32(os.Getpid()), 1 /* KERN_PROC_ARGV */} 29 | } 30 | 31 | n := uintptr(0) 32 | // Get length. 33 | _, _, errNum := syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(unsafe.Pointer(&mib[0])), 4, 0, uintptr(unsafe.Pointer(&n)), 0, 0) 34 | if errNum != 0 { 35 | return "", errNum 36 | } 37 | if n == 0 { // This shouldn't happen. 38 | return "", nil 39 | } 40 | buf := make([]byte, n) 41 | _, _, errNum = syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(unsafe.Pointer(&mib[0])), 4, uintptr(unsafe.Pointer(&buf[0])), uintptr(unsafe.Pointer(&n)), 0, 0) 42 | if errNum != 0 { 43 | return "", errNum 44 | } 45 | if n == 0 { // This shouldn't happen. 46 | return "", nil 47 | } 48 | 49 | var execPath string 50 | switch runtime.GOOS { 51 | case "openbsd": 52 | // buf now contains **argv, with pointers to each of the C-style 53 | // NULL terminated arguments. 54 | var args []string 55 | argv := uintptr(unsafe.Pointer(&buf[0])) 56 | Loop: 57 | for { 58 | argp := *(**[1 << 20]byte)(unsafe.Pointer(argv)) 59 | if argp == nil { 60 | break 61 | } 62 | for i := 0; uintptr(i) < n; i++ { 63 | // we don't want the full arguments list 64 | if string(argp[i]) == " " { 65 | break Loop 66 | } 67 | if argp[i] != 0 { 68 | continue 69 | } 70 | args = append(args, string(argp[:i])) 71 | n -= uintptr(i) 72 | break 73 | } 74 | if n < unsafe.Sizeof(argv) { 75 | break 76 | } 77 | argv += unsafe.Sizeof(argv) 78 | n -= unsafe.Sizeof(argv) 79 | } 80 | execPath = args[0] 81 | // There is no canonical way to get an executable path on 82 | // OpenBSD, so check PATH in case we are called directly 83 | if execPath[0] != '/' && execPath[0] != '.' { 84 | execIsInPath, err := exec.LookPath(execPath) 85 | if err == nil { 86 | execPath = execIsInPath 87 | } 88 | } 89 | default: 90 | for i, v := range buf { 91 | if v == 0 { 92 | buf = buf[:i] 93 | break 94 | } 95 | } 96 | execPath = string(buf) 97 | } 98 | 99 | var err error 100 | // execPath will not be empty due to above checks. 101 | // Try to get the absolute path if the execPath is not rooted. 102 | if execPath[0] != '/' { 103 | execPath, err = getAbs(execPath) 104 | if err != nil { 105 | return execPath, err 106 | } 107 | } 108 | // For darwin KERN_PROCARGS may return the path to a symlink rather than the 109 | // actual executable. 110 | if runtime.GOOS == "darwin" { 111 | if execPath, err = filepath.EvalSymlinks(execPath); err != nil { 112 | return execPath, err 113 | } 114 | } 115 | return execPath, nil 116 | } 117 | 118 | func getAbs(execPath string) (string, error) { 119 | if initCwdErr != nil { 120 | return execPath, initCwdErr 121 | } 122 | // The execPath may begin with a "../" or a "./" so clean it first. 123 | // Join the two paths, trailing and starting slashes undetermined, so use 124 | // the generic Join function. 125 | return filepath.Join(initCwd, filepath.Clean(execPath)), nil 126 | } 127 | -------------------------------------------------------------------------------- /vendor/github.com/kardianos/osext/osext_windows.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package osext 6 | 7 | import ( 8 | "syscall" 9 | "unicode/utf16" 10 | "unsafe" 11 | ) 12 | 13 | var ( 14 | kernel = syscall.MustLoadDLL("kernel32.dll") 15 | getModuleFileNameProc = kernel.MustFindProc("GetModuleFileNameW") 16 | ) 17 | 18 | // GetModuleFileName() with hModule = NULL 19 | func executable() (exePath string, err error) { 20 | return getModuleFileName() 21 | } 22 | 23 | func getModuleFileName() (string, error) { 24 | var n uint32 25 | b := make([]uint16, syscall.MAX_PATH) 26 | size := uint32(len(b)) 27 | 28 | r0, _, e1 := getModuleFileNameProc.Call(0, uintptr(unsafe.Pointer(&b[0])), uintptr(size)) 29 | n = uint32(r0) 30 | if n == 0 { 31 | return "", e1 32 | } 33 | return string(utf16.Decode(b[0:n])), nil 34 | } 35 | -------------------------------------------------------------------------------- /vendor/github.com/mattn/go-colorable/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Yasuhiro Matsumoto 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /vendor/github.com/mattn/go-colorable/README.md: -------------------------------------------------------------------------------- 1 | # go-colorable 2 | 3 | Colorable writer for windows. 4 | 5 | For example, most of logger packages doesn't show colors on windows. (I know we can do it with ansicon. But I don't want.) 6 | This package is possible to handle escape sequence for ansi color on windows. 7 | 8 | ## Too Bad! 9 | 10 | ![](https://raw.githubusercontent.com/mattn/go-colorable/gh-pages/bad.png) 11 | 12 | 13 | ## So Good! 14 | 15 | ![](https://raw.githubusercontent.com/mattn/go-colorable/gh-pages/good.png) 16 | 17 | ## Usage 18 | 19 | ```go 20 | logrus.SetFormatter(&logrus.TextFormatter{ForceColors: true}) 21 | logrus.SetOutput(colorable.NewColorableStdout()) 22 | 23 | logrus.Info("succeeded") 24 | logrus.Warn("not correct") 25 | logrus.Error("something error") 26 | logrus.Fatal("panic") 27 | ``` 28 | 29 | You can compile above code on non-windows OSs. 30 | 31 | ## Installation 32 | 33 | ``` 34 | $ go get github.com/mattn/go-colorable 35 | ``` 36 | 37 | # License 38 | 39 | MIT 40 | 41 | # Author 42 | 43 | Yasuhiro Matsumoto (a.k.a mattn) 44 | -------------------------------------------------------------------------------- /vendor/github.com/mattn/go-colorable/colorable_others.go: -------------------------------------------------------------------------------- 1 | // +build !windows 2 | 3 | package colorable 4 | 5 | import ( 6 | "io" 7 | "os" 8 | ) 9 | 10 | func NewColorable(file *os.File) io.Writer { 11 | if file == nil { 12 | panic("nil passed instead of *os.File to NewColorable()") 13 | } 14 | 15 | return file 16 | } 17 | 18 | func NewColorableStdout() io.Writer { 19 | return os.Stdout 20 | } 21 | 22 | func NewColorableStderr() io.Writer { 23 | return os.Stderr 24 | } 25 | -------------------------------------------------------------------------------- /vendor/github.com/mattn/go-colorable/noncolorable.go: -------------------------------------------------------------------------------- 1 | package colorable 2 | 3 | import ( 4 | "bytes" 5 | "io" 6 | ) 7 | 8 | type NonColorable struct { 9 | out io.Writer 10 | lastbuf bytes.Buffer 11 | } 12 | 13 | func NewNonColorable(w io.Writer) io.Writer { 14 | return &NonColorable{out: w} 15 | } 16 | 17 | func (w *NonColorable) Write(data []byte) (n int, err error) { 18 | er := bytes.NewReader(data) 19 | var bw [1]byte 20 | loop: 21 | for { 22 | c1, err := er.ReadByte() 23 | if err != nil { 24 | break loop 25 | } 26 | if c1 != 0x1b { 27 | bw[0] = c1 28 | w.out.Write(bw[:]) 29 | continue 30 | } 31 | c2, err := er.ReadByte() 32 | if err != nil { 33 | w.lastbuf.WriteByte(c1) 34 | break loop 35 | } 36 | if c2 != 0x5b { 37 | w.lastbuf.WriteByte(c1) 38 | w.lastbuf.WriteByte(c2) 39 | continue 40 | } 41 | 42 | var buf bytes.Buffer 43 | for { 44 | c, err := er.ReadByte() 45 | if err != nil { 46 | w.lastbuf.WriteByte(c1) 47 | w.lastbuf.WriteByte(c2) 48 | w.lastbuf.Write(buf.Bytes()) 49 | break loop 50 | } 51 | if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '@' { 52 | break 53 | } 54 | buf.Write([]byte(string(c))) 55 | } 56 | } 57 | return len(data) - w.lastbuf.Len(), nil 58 | } 59 | -------------------------------------------------------------------------------- /vendor/github.com/mattn/go-isatty/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) Yasuhiro MATSUMOTO 2 | 3 | MIT License (Expat) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /vendor/github.com/mattn/go-isatty/README.md: -------------------------------------------------------------------------------- 1 | # go-isatty 2 | 3 | isatty for golang 4 | 5 | ## Usage 6 | 7 | ```go 8 | package main 9 | 10 | import ( 11 | "fmt" 12 | "github.com/mattn/go-isatty" 13 | "os" 14 | ) 15 | 16 | func main() { 17 | if isatty.IsTerminal(os.Stdout.Fd()) { 18 | fmt.Println("Is Terminal") 19 | } else { 20 | fmt.Println("Is Not Terminal") 21 | } 22 | } 23 | ``` 24 | 25 | ## Installation 26 | 27 | ``` 28 | $ go get github.com/mattn/go-isatty 29 | ``` 30 | 31 | # License 32 | 33 | MIT 34 | 35 | # Author 36 | 37 | Yasuhiro Matsumoto (a.k.a mattn) 38 | -------------------------------------------------------------------------------- /vendor/github.com/mattn/go-isatty/doc.go: -------------------------------------------------------------------------------- 1 | // Package isatty implements interface to isatty 2 | package isatty 3 | -------------------------------------------------------------------------------- /vendor/github.com/mattn/go-isatty/isatty_appengine.go: -------------------------------------------------------------------------------- 1 | // +build appengine 2 | 3 | package isatty 4 | 5 | // IsTerminal returns true if the file descriptor is terminal which 6 | // is always false on on appengine classic which is a sandboxed PaaS. 7 | func IsTerminal(fd uintptr) bool { 8 | return false 9 | } 10 | -------------------------------------------------------------------------------- /vendor/github.com/mattn/go-isatty/isatty_bsd.go: -------------------------------------------------------------------------------- 1 | // +build darwin freebsd openbsd netbsd dragonfly 2 | // +build !appengine 3 | 4 | package isatty 5 | 6 | import ( 7 | "syscall" 8 | "unsafe" 9 | ) 10 | 11 | const ioctlReadTermios = syscall.TIOCGETA 12 | 13 | // IsTerminal return true if the file descriptor is terminal. 14 | func IsTerminal(fd uintptr) bool { 15 | var termios syscall.Termios 16 | _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0) 17 | return err == 0 18 | } 19 | -------------------------------------------------------------------------------- /vendor/github.com/mattn/go-isatty/isatty_linux.go: -------------------------------------------------------------------------------- 1 | // +build linux 2 | // +build !appengine 3 | 4 | package isatty 5 | 6 | import ( 7 | "syscall" 8 | "unsafe" 9 | ) 10 | 11 | const ioctlReadTermios = syscall.TCGETS 12 | 13 | // IsTerminal return true if the file descriptor is terminal. 14 | func IsTerminal(fd uintptr) bool { 15 | var termios syscall.Termios 16 | _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0) 17 | return err == 0 18 | } 19 | -------------------------------------------------------------------------------- /vendor/github.com/mattn/go-isatty/isatty_solaris.go: -------------------------------------------------------------------------------- 1 | // +build solaris 2 | // +build !appengine 3 | 4 | package isatty 5 | 6 | import ( 7 | "golang.org/x/sys/unix" 8 | ) 9 | 10 | // IsTerminal returns true if the given file descriptor is a terminal. 11 | // see: http://src.illumos.org/source/xref/illumos-gate/usr/src/lib/libbc/libc/gen/common/isatty.c 12 | func IsTerminal(fd uintptr) bool { 13 | var termio unix.Termio 14 | err := unix.IoctlSetTermio(int(fd), unix.TCGETA, &termio) 15 | return err == nil 16 | } 17 | -------------------------------------------------------------------------------- /vendor/github.com/mattn/go-isatty/isatty_windows.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | // +build !appengine 3 | 4 | package isatty 5 | 6 | import ( 7 | "syscall" 8 | "unsafe" 9 | ) 10 | 11 | var kernel32 = syscall.NewLazyDLL("kernel32.dll") 12 | var procGetConsoleMode = kernel32.NewProc("GetConsoleMode") 13 | 14 | // IsTerminal return true if the file descriptor is terminal. 15 | func IsTerminal(fd uintptr) bool { 16 | var st uint32 17 | r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, fd, uintptr(unsafe.Pointer(&st)), 0) 18 | return r != 0 && e == 0 19 | } 20 | -------------------------------------------------------------------------------- /vendor/github.com/miekg/dns/AUTHORS: -------------------------------------------------------------------------------- 1 | Miek Gieben 2 | -------------------------------------------------------------------------------- /vendor/github.com/miekg/dns/CONTRIBUTORS: -------------------------------------------------------------------------------- 1 | Alex A. Skinner 2 | Andrew Tunnell-Jones 3 | Ask Bjørn Hansen 4 | Dave Cheney 5 | Dusty Wilson 6 | Marek Majkowski 7 | Peter van Dijk 8 | Omri Bahumi 9 | Alex Sergeyev 10 | -------------------------------------------------------------------------------- /vendor/github.com/miekg/dns/COPYRIGHT: -------------------------------------------------------------------------------- 1 | Copyright 2009 The Go Authors. All rights reserved. Use of this source code 2 | is governed by a BSD-style license that can be found in the LICENSE file. 3 | Extensions of the original work are copyright (c) 2011 Miek Gieben 4 | 5 | Copyright 2011 Miek Gieben. All rights reserved. Use of this source code is 6 | governed by a BSD-style license that can be found in the LICENSE file. 7 | 8 | Copyright 2014 CloudFlare. All rights reserved. Use of this source code is 9 | governed by a BSD-style license that can be found in the LICENSE file. 10 | -------------------------------------------------------------------------------- /vendor/github.com/miekg/dns/LICENSE: -------------------------------------------------------------------------------- 1 | Extensions of the original work are copyright (c) 2011 Miek Gieben 2 | 3 | As this is fork of the official Go code the same license applies: 4 | 5 | Copyright (c) 2009 The Go Authors. All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are 9 | met: 10 | 11 | * Redistributions of source code must retain the above copyright 12 | notice, this list of conditions and the following disclaimer. 13 | * Redistributions in binary form must reproduce the above 14 | copyright notice, this list of conditions and the following disclaimer 15 | in the documentation and/or other materials provided with the 16 | distribution. 17 | * Neither the name of Google Inc. nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | 33 | -------------------------------------------------------------------------------- /vendor/github.com/miekg/dns/README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/miekg/dns.svg?branch=master)](https://travis-ci.org/miekg/dns) [![](https://godoc.org/github.com/miekg/dns?status.svg)](https://godoc.org/github.com/miekg/dns) 2 | 3 | # Alternative (more granular) approach to a DNS library 4 | 5 | > Less is more. 6 | 7 | Complete and usable DNS library. All widely used Resource Records are 8 | supported, including the DNSSEC types. It follows a lean and mean philosophy. 9 | If there is stuff you should know as a DNS programmer there isn't a convenience 10 | function for it. Server side and client side programming is supported, i.e. you 11 | can build servers and resolvers with it. 12 | 13 | We try to keep the "master" branch as sane as possible and at the bleeding edge 14 | of standards, avoiding breaking changes wherever reasonable. We support the last 15 | two versions of Go, currently: 1.5 and 1.6. 16 | 17 | # Goals 18 | 19 | * KISS; 20 | * Fast; 21 | * Small API, if its easy to code in Go, don't make a function for it. 22 | 23 | # Users 24 | 25 | A not-so-up-to-date-list-that-may-be-actually-current: 26 | 27 | * https://cloudflare.com 28 | * https://github.com/abh/geodns 29 | * http://www.statdns.com/ 30 | * http://www.dnsinspect.com/ 31 | * https://github.com/chuangbo/jianbing-dictionary-dns 32 | * http://www.dns-lg.com/ 33 | * https://github.com/fcambus/rrda 34 | * https://github.com/kenshinx/godns 35 | * https://github.com/skynetservices/skydns 36 | * https://github.com/hashicorp/consul 37 | * https://github.com/DevelopersPL/godnsagent 38 | * https://github.com/duedil-ltd/discodns 39 | * https://github.com/StalkR/dns-reverse-proxy 40 | * https://github.com/tianon/rawdns 41 | * https://mesosphere.github.io/mesos-dns/ 42 | * https://pulse.turbobytes.com/ 43 | * https://play.google.com/store/apps/details?id=com.turbobytes.dig 44 | * https://github.com/fcambus/statzone 45 | * https://github.com/benschw/dns-clb-go 46 | * https://github.com/corny/dnscheck for http://public-dns.info/ 47 | * https://namesmith.io 48 | * https://github.com/miekg/unbound 49 | * https://github.com/miekg/exdns 50 | * https://dnslookup.org 51 | * https://github.com/looterz/grimd 52 | * https://github.com/phamhongviet/serf-dns 53 | * https://github.com/mehrdadrad/mylg 54 | * https://github.com/bamarni/dockness 55 | * https://github.com/fffaraz/microdns 56 | 57 | Send pull request if you want to be listed here. 58 | 59 | # Features 60 | 61 | * UDP/TCP queries, IPv4 and IPv6; 62 | * RFC 1035 zone file parsing ($INCLUDE, $ORIGIN, $TTL and $GENERATE (for all record types) are supported; 63 | * Fast: 64 | * Reply speed around ~ 80K qps (faster hardware results in more qps); 65 | * Parsing RRs ~ 100K RR/s, that's 5M records in about 50 seconds; 66 | * Server side programming (mimicking the net/http package); 67 | * Client side programming; 68 | * DNSSEC: signing, validating and key generation for DSA, RSA and ECDSA; 69 | * EDNS0, NSID, Cookies; 70 | * AXFR/IXFR; 71 | * TSIG, SIG(0); 72 | * DNS over TLS: optional encrypted connection between client and server; 73 | * DNS name compression; 74 | * Depends only on the standard library. 75 | 76 | Have fun! 77 | 78 | Miek Gieben - 2010-2012 - 79 | 80 | # Building 81 | 82 | Building is done with the `go` tool. If you have setup your GOPATH 83 | correctly, the following should work: 84 | 85 | go get github.com/miekg/dns 86 | go build github.com/miekg/dns 87 | 88 | ## Examples 89 | 90 | A short "how to use the API" is at the beginning of doc.go (this also will show 91 | when you call `godoc github.com/miekg/dns`). 92 | 93 | Example programs can be found in the `github.com/miekg/exdns` repository. 94 | 95 | ## Supported RFCs 96 | 97 | *all of them* 98 | 99 | * 103{4,5} - DNS standard 100 | * 1348 - NSAP record (removed the record) 101 | * 1982 - Serial Arithmetic 102 | * 1876 - LOC record 103 | * 1995 - IXFR 104 | * 1996 - DNS notify 105 | * 2136 - DNS Update (dynamic updates) 106 | * 2181 - RRset definition - there is no RRset type though, just []RR 107 | * 2537 - RSAMD5 DNS keys 108 | * 2065 - DNSSEC (updated in later RFCs) 109 | * 2671 - EDNS record 110 | * 2782 - SRV record 111 | * 2845 - TSIG record 112 | * 2915 - NAPTR record 113 | * 2929 - DNS IANA Considerations 114 | * 3110 - RSASHA1 DNS keys 115 | * 3225 - DO bit (DNSSEC OK) 116 | * 340{1,2,3} - NAPTR record 117 | * 3445 - Limiting the scope of (DNS)KEY 118 | * 3597 - Unknown RRs 119 | * 403{3,4,5} - DNSSEC + validation functions 120 | * 4255 - SSHFP record 121 | * 4343 - Case insensitivity 122 | * 4408 - SPF record 123 | * 4509 - SHA256 Hash in DS 124 | * 4592 - Wildcards in the DNS 125 | * 4635 - HMAC SHA TSIG 126 | * 4701 - DHCID 127 | * 4892 - id.server 128 | * 5001 - NSID 129 | * 5155 - NSEC3 record 130 | * 5205 - HIP record 131 | * 5702 - SHA2 in the DNS 132 | * 5936 - AXFR 133 | * 5966 - TCP implementation recommendations 134 | * 6605 - ECDSA 135 | * 6725 - IANA Registry Update 136 | * 6742 - ILNP DNS 137 | * 6840 - Clarifications and Implementation Notes for DNS Security 138 | * 6844 - CAA record 139 | * 6891 - EDNS0 update 140 | * 6895 - DNS IANA considerations 141 | * 6975 - Algorithm Understanding in DNSSEC 142 | * 7043 - EUI48/EUI64 records 143 | * 7314 - DNS (EDNS) EXPIRE Option 144 | * 7553 - URI record 145 | * 7858 - DNS over TLS: Initiation and Performance Considerations (draft) 146 | * 7873 - Domain Name System (DNS) Cookies (draft-ietf-dnsop-cookies) 147 | * xxxx - EDNS0 DNS Update Lease (draft) 148 | 149 | ## Loosely based upon 150 | 151 | * `ldns` 152 | * `NSD` 153 | * `Net::DNS` 154 | * `GRONG` 155 | -------------------------------------------------------------------------------- /vendor/github.com/miekg/dns/clientconfig.go: -------------------------------------------------------------------------------- 1 | package dns 2 | 3 | import ( 4 | "bufio" 5 | "os" 6 | "strconv" 7 | "strings" 8 | ) 9 | 10 | // ClientConfig wraps the contents of the /etc/resolv.conf file. 11 | type ClientConfig struct { 12 | Servers []string // servers to use 13 | Search []string // suffixes to append to local name 14 | Port string // what port to use 15 | Ndots int // number of dots in name to trigger absolute lookup 16 | Timeout int // seconds before giving up on packet 17 | Attempts int // lost packets before giving up on server, not used in the package dns 18 | } 19 | 20 | // ClientConfigFromFile parses a resolv.conf(5) like file and returns 21 | // a *ClientConfig. 22 | func ClientConfigFromFile(resolvconf string) (*ClientConfig, error) { 23 | file, err := os.Open(resolvconf) 24 | if err != nil { 25 | return nil, err 26 | } 27 | defer file.Close() 28 | c := new(ClientConfig) 29 | scanner := bufio.NewScanner(file) 30 | c.Servers = make([]string, 0) 31 | c.Search = make([]string, 0) 32 | c.Port = "53" 33 | c.Ndots = 1 34 | c.Timeout = 5 35 | c.Attempts = 2 36 | 37 | for scanner.Scan() { 38 | if err := scanner.Err(); err != nil { 39 | return nil, err 40 | } 41 | line := scanner.Text() 42 | f := strings.Fields(line) 43 | if len(f) < 1 { 44 | continue 45 | } 46 | switch f[0] { 47 | case "nameserver": // add one name server 48 | if len(f) > 1 { 49 | // One more check: make sure server name is 50 | // just an IP address. Otherwise we need DNS 51 | // to look it up. 52 | name := f[1] 53 | c.Servers = append(c.Servers, name) 54 | } 55 | 56 | case "domain": // set search path to just this domain 57 | if len(f) > 1 { 58 | c.Search = make([]string, 1) 59 | c.Search[0] = f[1] 60 | } else { 61 | c.Search = make([]string, 0) 62 | } 63 | 64 | case "search": // set search path to given servers 65 | c.Search = make([]string, len(f)-1) 66 | for i := 0; i < len(c.Search); i++ { 67 | c.Search[i] = f[i+1] 68 | } 69 | 70 | case "options": // magic options 71 | for i := 1; i < len(f); i++ { 72 | s := f[i] 73 | switch { 74 | case len(s) >= 6 && s[:6] == "ndots:": 75 | n, _ := strconv.Atoi(s[6:]) 76 | if n < 1 { 77 | n = 1 78 | } 79 | c.Ndots = n 80 | case len(s) >= 8 && s[:8] == "timeout:": 81 | n, _ := strconv.Atoi(s[8:]) 82 | if n < 1 { 83 | n = 1 84 | } 85 | c.Timeout = n 86 | case len(s) >= 8 && s[:9] == "attempts:": 87 | n, _ := strconv.Atoi(s[9:]) 88 | if n < 1 { 89 | n = 1 90 | } 91 | c.Attempts = n 92 | case s == "rotate": 93 | /* not imp */ 94 | } 95 | } 96 | } 97 | } 98 | return c, nil 99 | } 100 | -------------------------------------------------------------------------------- /vendor/github.com/miekg/dns/dane.go: -------------------------------------------------------------------------------- 1 | package dns 2 | 3 | import ( 4 | "crypto/sha256" 5 | "crypto/sha512" 6 | "crypto/x509" 7 | "encoding/hex" 8 | "errors" 9 | "io" 10 | ) 11 | 12 | // CertificateToDANE converts a certificate to a hex string as used in the TLSA or SMIMEA records. 13 | func CertificateToDANE(selector, matchingType uint8, cert *x509.Certificate) (string, error) { 14 | switch matchingType { 15 | case 0: 16 | switch selector { 17 | case 0: 18 | return hex.EncodeToString(cert.Raw), nil 19 | case 1: 20 | return hex.EncodeToString(cert.RawSubjectPublicKeyInfo), nil 21 | } 22 | case 1: 23 | h := sha256.New() 24 | switch selector { 25 | case 0: 26 | io.WriteString(h, string(cert.Raw)) 27 | return hex.EncodeToString(h.Sum(nil)), nil 28 | case 1: 29 | io.WriteString(h, string(cert.RawSubjectPublicKeyInfo)) 30 | return hex.EncodeToString(h.Sum(nil)), nil 31 | } 32 | case 2: 33 | h := sha512.New() 34 | switch selector { 35 | case 0: 36 | io.WriteString(h, string(cert.Raw)) 37 | return hex.EncodeToString(h.Sum(nil)), nil 38 | case 1: 39 | io.WriteString(h, string(cert.RawSubjectPublicKeyInfo)) 40 | return hex.EncodeToString(h.Sum(nil)), nil 41 | } 42 | } 43 | return "", errors.New("dns: bad MatchingType or Selector") 44 | } 45 | -------------------------------------------------------------------------------- /vendor/github.com/miekg/dns/dns.go: -------------------------------------------------------------------------------- 1 | package dns 2 | 3 | import "strconv" 4 | 5 | const ( 6 | year68 = 1 << 31 // For RFC1982 (Serial Arithmetic) calculations in 32 bits. 7 | defaultTtl = 3600 // Default internal TTL. 8 | 9 | DefaultMsgSize = 4096 // DefaultMsgSize is the standard default for messages larger than 512 bytes. 10 | MinMsgSize = 512 // MinMsgSize is the minimal size of a DNS packet. 11 | MaxMsgSize = 65535 // MaxMsgSize is the largest possible DNS packet. 12 | ) 13 | 14 | // Error represents a DNS error. 15 | type Error struct{ err string } 16 | 17 | func (e *Error) Error() string { 18 | if e == nil { 19 | return "dns: " 20 | } 21 | return "dns: " + e.err 22 | } 23 | 24 | // An RR represents a resource record. 25 | type RR interface { 26 | // Header returns the header of an resource record. The header contains 27 | // everything up to the rdata. 28 | Header() *RR_Header 29 | // String returns the text representation of the resource record. 30 | String() string 31 | 32 | // copy returns a copy of the RR 33 | copy() RR 34 | // len returns the length (in octets) of the uncompressed RR in wire format. 35 | len() int 36 | // pack packs an RR into wire format. 37 | pack([]byte, int, map[string]int, bool) (int, error) 38 | } 39 | 40 | // RR_Header is the header all DNS resource records share. 41 | type RR_Header struct { 42 | Name string `dns:"cdomain-name"` 43 | Rrtype uint16 44 | Class uint16 45 | Ttl uint32 46 | Rdlength uint16 // Length of data after header. 47 | } 48 | 49 | // Header returns itself. This is here to make RR_Header implements the RR interface. 50 | func (h *RR_Header) Header() *RR_Header { return h } 51 | 52 | // Just to implement the RR interface. 53 | func (h *RR_Header) copy() RR { return nil } 54 | 55 | func (h *RR_Header) copyHeader() *RR_Header { 56 | r := new(RR_Header) 57 | r.Name = h.Name 58 | r.Rrtype = h.Rrtype 59 | r.Class = h.Class 60 | r.Ttl = h.Ttl 61 | r.Rdlength = h.Rdlength 62 | return r 63 | } 64 | 65 | func (h *RR_Header) String() string { 66 | var s string 67 | 68 | if h.Rrtype == TypeOPT { 69 | s = ";" 70 | // and maybe other things 71 | } 72 | 73 | s += sprintName(h.Name) + "\t" 74 | s += strconv.FormatInt(int64(h.Ttl), 10) + "\t" 75 | s += Class(h.Class).String() + "\t" 76 | s += Type(h.Rrtype).String() + "\t" 77 | return s 78 | } 79 | 80 | func (h *RR_Header) len() int { 81 | l := len(h.Name) + 1 82 | l += 10 // rrtype(2) + class(2) + ttl(4) + rdlength(2) 83 | return l 84 | } 85 | 86 | // ToRFC3597 converts a known RR to the unknown RR representation from RFC 3597. 87 | func (rr *RFC3597) ToRFC3597(r RR) error { 88 | buf := make([]byte, r.len()*2) 89 | off, err := PackRR(r, buf, 0, nil, false) 90 | if err != nil { 91 | return err 92 | } 93 | buf = buf[:off] 94 | if int(r.Header().Rdlength) > off { 95 | return ErrBuf 96 | } 97 | 98 | rfc3597, _, err := unpackRFC3597(*r.Header(), buf, off-int(r.Header().Rdlength)) 99 | if err != nil { 100 | return err 101 | } 102 | *rr = *rfc3597.(*RFC3597) 103 | return nil 104 | } 105 | -------------------------------------------------------------------------------- /vendor/github.com/miekg/dns/dnssec_keygen.go: -------------------------------------------------------------------------------- 1 | package dns 2 | 3 | import ( 4 | "crypto" 5 | "crypto/dsa" 6 | "crypto/ecdsa" 7 | "crypto/elliptic" 8 | "crypto/rand" 9 | "crypto/rsa" 10 | "math/big" 11 | ) 12 | 13 | // Generate generates a DNSKEY of the given bit size. 14 | // The public part is put inside the DNSKEY record. 15 | // The Algorithm in the key must be set as this will define 16 | // what kind of DNSKEY will be generated. 17 | // The ECDSA algorithms imply a fixed keysize, in that case 18 | // bits should be set to the size of the algorithm. 19 | func (k *DNSKEY) Generate(bits int) (crypto.PrivateKey, error) { 20 | switch k.Algorithm { 21 | case DSA, DSANSEC3SHA1: 22 | if bits != 1024 { 23 | return nil, ErrKeySize 24 | } 25 | case RSAMD5, RSASHA1, RSASHA256, RSASHA1NSEC3SHA1: 26 | if bits < 512 || bits > 4096 { 27 | return nil, ErrKeySize 28 | } 29 | case RSASHA512: 30 | if bits < 1024 || bits > 4096 { 31 | return nil, ErrKeySize 32 | } 33 | case ECDSAP256SHA256: 34 | if bits != 256 { 35 | return nil, ErrKeySize 36 | } 37 | case ECDSAP384SHA384: 38 | if bits != 384 { 39 | return nil, ErrKeySize 40 | } 41 | } 42 | 43 | switch k.Algorithm { 44 | case DSA, DSANSEC3SHA1: 45 | params := new(dsa.Parameters) 46 | if err := dsa.GenerateParameters(params, rand.Reader, dsa.L1024N160); err != nil { 47 | return nil, err 48 | } 49 | priv := new(dsa.PrivateKey) 50 | priv.PublicKey.Parameters = *params 51 | err := dsa.GenerateKey(priv, rand.Reader) 52 | if err != nil { 53 | return nil, err 54 | } 55 | k.setPublicKeyDSA(params.Q, params.P, params.G, priv.PublicKey.Y) 56 | return priv, nil 57 | case RSAMD5, RSASHA1, RSASHA256, RSASHA512, RSASHA1NSEC3SHA1: 58 | priv, err := rsa.GenerateKey(rand.Reader, bits) 59 | if err != nil { 60 | return nil, err 61 | } 62 | k.setPublicKeyRSA(priv.PublicKey.E, priv.PublicKey.N) 63 | return priv, nil 64 | case ECDSAP256SHA256, ECDSAP384SHA384: 65 | var c elliptic.Curve 66 | switch k.Algorithm { 67 | case ECDSAP256SHA256: 68 | c = elliptic.P256() 69 | case ECDSAP384SHA384: 70 | c = elliptic.P384() 71 | } 72 | priv, err := ecdsa.GenerateKey(c, rand.Reader) 73 | if err != nil { 74 | return nil, err 75 | } 76 | k.setPublicKeyECDSA(priv.PublicKey.X, priv.PublicKey.Y) 77 | return priv, nil 78 | default: 79 | return nil, ErrAlg 80 | } 81 | } 82 | 83 | // Set the public key (the value E and N) 84 | func (k *DNSKEY) setPublicKeyRSA(_E int, _N *big.Int) bool { 85 | if _E == 0 || _N == nil { 86 | return false 87 | } 88 | buf := exponentToBuf(_E) 89 | buf = append(buf, _N.Bytes()...) 90 | k.PublicKey = toBase64(buf) 91 | return true 92 | } 93 | 94 | // Set the public key for Elliptic Curves 95 | func (k *DNSKEY) setPublicKeyECDSA(_X, _Y *big.Int) bool { 96 | if _X == nil || _Y == nil { 97 | return false 98 | } 99 | var intlen int 100 | switch k.Algorithm { 101 | case ECDSAP256SHA256: 102 | intlen = 32 103 | case ECDSAP384SHA384: 104 | intlen = 48 105 | } 106 | k.PublicKey = toBase64(curveToBuf(_X, _Y, intlen)) 107 | return true 108 | } 109 | 110 | // Set the public key for DSA 111 | func (k *DNSKEY) setPublicKeyDSA(_Q, _P, _G, _Y *big.Int) bool { 112 | if _Q == nil || _P == nil || _G == nil || _Y == nil { 113 | return false 114 | } 115 | buf := dsaToBuf(_Q, _P, _G, _Y) 116 | k.PublicKey = toBase64(buf) 117 | return true 118 | } 119 | 120 | // Set the public key (the values E and N) for RSA 121 | // RFC 3110: Section 2. RSA Public KEY Resource Records 122 | func exponentToBuf(_E int) []byte { 123 | var buf []byte 124 | i := big.NewInt(int64(_E)) 125 | if len(i.Bytes()) < 256 { 126 | buf = make([]byte, 1) 127 | buf[0] = uint8(len(i.Bytes())) 128 | } else { 129 | buf = make([]byte, 3) 130 | buf[0] = 0 131 | buf[1] = uint8(len(i.Bytes()) >> 8) 132 | buf[2] = uint8(len(i.Bytes())) 133 | } 134 | buf = append(buf, i.Bytes()...) 135 | return buf 136 | } 137 | 138 | // Set the public key for X and Y for Curve. The two 139 | // values are just concatenated. 140 | func curveToBuf(_X, _Y *big.Int, intlen int) []byte { 141 | buf := intToBytes(_X, intlen) 142 | buf = append(buf, intToBytes(_Y, intlen)...) 143 | return buf 144 | } 145 | 146 | // Set the public key for X and Y for Curve. The two 147 | // values are just concatenated. 148 | func dsaToBuf(_Q, _P, _G, _Y *big.Int) []byte { 149 | t := divRoundUp(divRoundUp(_G.BitLen(), 8)-64, 8) 150 | buf := []byte{byte(t)} 151 | buf = append(buf, intToBytes(_Q, 20)...) 152 | buf = append(buf, intToBytes(_P, 64+t*8)...) 153 | buf = append(buf, intToBytes(_G, 64+t*8)...) 154 | buf = append(buf, intToBytes(_Y, 64+t*8)...) 155 | return buf 156 | } 157 | -------------------------------------------------------------------------------- /vendor/github.com/miekg/dns/dnssec_privkey.go: -------------------------------------------------------------------------------- 1 | package dns 2 | 3 | import ( 4 | "crypto" 5 | "crypto/dsa" 6 | "crypto/ecdsa" 7 | "crypto/rsa" 8 | "math/big" 9 | "strconv" 10 | ) 11 | 12 | const format = "Private-key-format: v1.3\n" 13 | 14 | // PrivateKeyString converts a PrivateKey to a string. This string has the same 15 | // format as the private-key-file of BIND9 (Private-key-format: v1.3). 16 | // It needs some info from the key (the algorithm), so its a method of the DNSKEY 17 | // It supports rsa.PrivateKey, ecdsa.PrivateKey and dsa.PrivateKey 18 | func (r *DNSKEY) PrivateKeyString(p crypto.PrivateKey) string { 19 | algorithm := strconv.Itoa(int(r.Algorithm)) 20 | algorithm += " (" + AlgorithmToString[r.Algorithm] + ")" 21 | 22 | switch p := p.(type) { 23 | case *rsa.PrivateKey: 24 | modulus := toBase64(p.PublicKey.N.Bytes()) 25 | e := big.NewInt(int64(p.PublicKey.E)) 26 | publicExponent := toBase64(e.Bytes()) 27 | privateExponent := toBase64(p.D.Bytes()) 28 | prime1 := toBase64(p.Primes[0].Bytes()) 29 | prime2 := toBase64(p.Primes[1].Bytes()) 30 | // Calculate Exponent1/2 and Coefficient as per: http://en.wikipedia.org/wiki/RSA#Using_the_Chinese_remainder_algorithm 31 | // and from: http://code.google.com/p/go/issues/detail?id=987 32 | one := big.NewInt(1) 33 | p1 := big.NewInt(0).Sub(p.Primes[0], one) 34 | q1 := big.NewInt(0).Sub(p.Primes[1], one) 35 | exp1 := big.NewInt(0).Mod(p.D, p1) 36 | exp2 := big.NewInt(0).Mod(p.D, q1) 37 | coeff := big.NewInt(0).ModInverse(p.Primes[1], p.Primes[0]) 38 | 39 | exponent1 := toBase64(exp1.Bytes()) 40 | exponent2 := toBase64(exp2.Bytes()) 41 | coefficient := toBase64(coeff.Bytes()) 42 | 43 | return format + 44 | "Algorithm: " + algorithm + "\n" + 45 | "Modulus: " + modulus + "\n" + 46 | "PublicExponent: " + publicExponent + "\n" + 47 | "PrivateExponent: " + privateExponent + "\n" + 48 | "Prime1: " + prime1 + "\n" + 49 | "Prime2: " + prime2 + "\n" + 50 | "Exponent1: " + exponent1 + "\n" + 51 | "Exponent2: " + exponent2 + "\n" + 52 | "Coefficient: " + coefficient + "\n" 53 | 54 | case *ecdsa.PrivateKey: 55 | var intlen int 56 | switch r.Algorithm { 57 | case ECDSAP256SHA256: 58 | intlen = 32 59 | case ECDSAP384SHA384: 60 | intlen = 48 61 | } 62 | private := toBase64(intToBytes(p.D, intlen)) 63 | return format + 64 | "Algorithm: " + algorithm + "\n" + 65 | "PrivateKey: " + private + "\n" 66 | 67 | case *dsa.PrivateKey: 68 | T := divRoundUp(divRoundUp(p.PublicKey.Parameters.G.BitLen(), 8)-64, 8) 69 | prime := toBase64(intToBytes(p.PublicKey.Parameters.P, 64+T*8)) 70 | subprime := toBase64(intToBytes(p.PublicKey.Parameters.Q, 20)) 71 | base := toBase64(intToBytes(p.PublicKey.Parameters.G, 64+T*8)) 72 | priv := toBase64(intToBytes(p.X, 20)) 73 | pub := toBase64(intToBytes(p.PublicKey.Y, 64+T*8)) 74 | return format + 75 | "Algorithm: " + algorithm + "\n" + 76 | "Prime(p): " + prime + "\n" + 77 | "Subprime(q): " + subprime + "\n" + 78 | "Base(g): " + base + "\n" + 79 | "Private_value(x): " + priv + "\n" + 80 | "Public_value(y): " + pub + "\n" 81 | 82 | default: 83 | return "" 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /vendor/github.com/miekg/dns/format.go: -------------------------------------------------------------------------------- 1 | package dns 2 | 3 | import ( 4 | "net" 5 | "reflect" 6 | "strconv" 7 | ) 8 | 9 | // NumField returns the number of rdata fields r has. 10 | func NumField(r RR) int { 11 | return reflect.ValueOf(r).Elem().NumField() - 1 // Remove RR_Header 12 | } 13 | 14 | // Field returns the rdata field i as a string. Fields are indexed starting from 1. 15 | // RR types that holds slice data, for instance the NSEC type bitmap will return a single 16 | // string where the types are concatenated using a space. 17 | // Accessing non existing fields will cause a panic. 18 | func Field(r RR, i int) string { 19 | if i == 0 { 20 | return "" 21 | } 22 | d := reflect.ValueOf(r).Elem().Field(i) 23 | switch k := d.Kind(); k { 24 | case reflect.String: 25 | return d.String() 26 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 27 | return strconv.FormatInt(d.Int(), 10) 28 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 29 | return strconv.FormatUint(d.Uint(), 10) 30 | case reflect.Slice: 31 | switch reflect.ValueOf(r).Elem().Type().Field(i).Tag { 32 | case `dns:"a"`: 33 | // TODO(miek): Hmm store this as 16 bytes 34 | if d.Len() < net.IPv6len { 35 | return net.IPv4(byte(d.Index(0).Uint()), 36 | byte(d.Index(1).Uint()), 37 | byte(d.Index(2).Uint()), 38 | byte(d.Index(3).Uint())).String() 39 | } 40 | return net.IPv4(byte(d.Index(12).Uint()), 41 | byte(d.Index(13).Uint()), 42 | byte(d.Index(14).Uint()), 43 | byte(d.Index(15).Uint())).String() 44 | case `dns:"aaaa"`: 45 | return net.IP{ 46 | byte(d.Index(0).Uint()), 47 | byte(d.Index(1).Uint()), 48 | byte(d.Index(2).Uint()), 49 | byte(d.Index(3).Uint()), 50 | byte(d.Index(4).Uint()), 51 | byte(d.Index(5).Uint()), 52 | byte(d.Index(6).Uint()), 53 | byte(d.Index(7).Uint()), 54 | byte(d.Index(8).Uint()), 55 | byte(d.Index(9).Uint()), 56 | byte(d.Index(10).Uint()), 57 | byte(d.Index(11).Uint()), 58 | byte(d.Index(12).Uint()), 59 | byte(d.Index(13).Uint()), 60 | byte(d.Index(14).Uint()), 61 | byte(d.Index(15).Uint()), 62 | }.String() 63 | case `dns:"nsec"`: 64 | if d.Len() == 0 { 65 | return "" 66 | } 67 | s := Type(d.Index(0).Uint()).String() 68 | for i := 1; i < d.Len(); i++ { 69 | s += " " + Type(d.Index(i).Uint()).String() 70 | } 71 | return s 72 | default: 73 | // if it does not have a tag its a string slice 74 | fallthrough 75 | case `dns:"txt"`: 76 | if d.Len() == 0 { 77 | return "" 78 | } 79 | s := d.Index(0).String() 80 | for i := 1; i < d.Len(); i++ { 81 | s += " " + d.Index(i).String() 82 | } 83 | return s 84 | } 85 | } 86 | return "" 87 | } 88 | -------------------------------------------------------------------------------- /vendor/github.com/miekg/dns/generate.go: -------------------------------------------------------------------------------- 1 | package dns 2 | 3 | import ( 4 | "bytes" 5 | "errors" 6 | "fmt" 7 | "strconv" 8 | "strings" 9 | ) 10 | 11 | // Parse the $GENERATE statement as used in BIND9 zones. 12 | // See http://www.zytrax.com/books/dns/ch8/generate.html for instance. 13 | // We are called after '$GENERATE '. After which we expect: 14 | // * the range (12-24/2) 15 | // * lhs (ownername) 16 | // * [[ttl][class]] 17 | // * type 18 | // * rhs (rdata) 19 | // But we are lazy here, only the range is parsed *all* occurrences 20 | // of $ after that are interpreted. 21 | // Any error are returned as a string value, the empty string signals 22 | // "no error". 23 | func generate(l lex, c chan lex, t chan *Token, o string) string { 24 | step := 1 25 | if i := strings.IndexAny(l.token, "/"); i != -1 { 26 | if i+1 == len(l.token) { 27 | return "bad step in $GENERATE range" 28 | } 29 | if s, err := strconv.Atoi(l.token[i+1:]); err == nil { 30 | if s < 0 { 31 | return "bad step in $GENERATE range" 32 | } 33 | step = s 34 | } else { 35 | return "bad step in $GENERATE range" 36 | } 37 | l.token = l.token[:i] 38 | } 39 | sx := strings.SplitN(l.token, "-", 2) 40 | if len(sx) != 2 { 41 | return "bad start-stop in $GENERATE range" 42 | } 43 | start, err := strconv.Atoi(sx[0]) 44 | if err != nil { 45 | return "bad start in $GENERATE range" 46 | } 47 | end, err := strconv.Atoi(sx[1]) 48 | if err != nil { 49 | return "bad stop in $GENERATE range" 50 | } 51 | if end < 0 || start < 0 || end < start { 52 | return "bad range in $GENERATE range" 53 | } 54 | 55 | <-c // _BLANK 56 | // Create a complete new string, which we then parse again. 57 | s := "" 58 | BuildRR: 59 | l = <-c 60 | if l.value != zNewline && l.value != zEOF { 61 | s += l.token 62 | goto BuildRR 63 | } 64 | for i := start; i <= end; i += step { 65 | var ( 66 | escape bool 67 | dom bytes.Buffer 68 | mod string 69 | err error 70 | offset int 71 | ) 72 | 73 | for j := 0; j < len(s); j++ { // No 'range' because we need to jump around 74 | switch s[j] { 75 | case '\\': 76 | if escape { 77 | dom.WriteByte('\\') 78 | escape = false 79 | continue 80 | } 81 | escape = true 82 | case '$': 83 | mod = "%d" 84 | offset = 0 85 | if escape { 86 | dom.WriteByte('$') 87 | escape = false 88 | continue 89 | } 90 | escape = false 91 | if j+1 >= len(s) { // End of the string 92 | dom.WriteString(fmt.Sprintf(mod, i+offset)) 93 | continue 94 | } else { 95 | if s[j+1] == '$' { 96 | dom.WriteByte('$') 97 | j++ 98 | continue 99 | } 100 | } 101 | // Search for { and } 102 | if s[j+1] == '{' { // Modifier block 103 | sep := strings.Index(s[j+2:], "}") 104 | if sep == -1 { 105 | return "bad modifier in $GENERATE" 106 | } 107 | mod, offset, err = modToPrintf(s[j+2 : j+2+sep]) 108 | if err != nil { 109 | return err.Error() 110 | } 111 | j += 2 + sep // Jump to it 112 | } 113 | dom.WriteString(fmt.Sprintf(mod, i+offset)) 114 | default: 115 | if escape { // Pretty useless here 116 | escape = false 117 | continue 118 | } 119 | dom.WriteByte(s[j]) 120 | } 121 | } 122 | // Re-parse the RR and send it on the current channel t 123 | rx, err := NewRR("$ORIGIN " + o + "\n" + dom.String()) 124 | if err != nil { 125 | return err.Error() 126 | } 127 | t <- &Token{RR: rx} 128 | // Its more efficient to first built the rrlist and then parse it in 129 | // one go! But is this a problem? 130 | } 131 | return "" 132 | } 133 | 134 | // Convert a $GENERATE modifier 0,0,d to something Printf can deal with. 135 | func modToPrintf(s string) (string, int, error) { 136 | xs := strings.SplitN(s, ",", 3) 137 | if len(xs) != 3 { 138 | return "", 0, errors.New("bad modifier in $GENERATE") 139 | } 140 | // xs[0] is offset, xs[1] is width, xs[2] is base 141 | if xs[2] != "o" && xs[2] != "d" && xs[2] != "x" && xs[2] != "X" { 142 | return "", 0, errors.New("bad base in $GENERATE") 143 | } 144 | offset, err := strconv.Atoi(xs[0]) 145 | if err != nil || offset > 255 { 146 | return "", 0, errors.New("bad offset in $GENERATE") 147 | } 148 | width, err := strconv.Atoi(xs[1]) 149 | if err != nil || width > 255 { 150 | return "", offset, errors.New("bad width in $GENERATE") 151 | } 152 | switch { 153 | case width < 0: 154 | return "", offset, errors.New("bad width in $GENERATE") 155 | case width == 0: 156 | return "%" + xs[1] + xs[2], offset, nil 157 | } 158 | return "%0" + xs[1] + xs[2], offset, nil 159 | } 160 | -------------------------------------------------------------------------------- /vendor/github.com/miekg/dns/labels.go: -------------------------------------------------------------------------------- 1 | package dns 2 | 3 | // Holds a bunch of helper functions for dealing with labels. 4 | 5 | // SplitDomainName splits a name string into it's labels. 6 | // www.miek.nl. returns []string{"www", "miek", "nl"} 7 | // .www.miek.nl. returns []string{"", "www", "miek", "nl"}, 8 | // The root label (.) returns nil. Note that using 9 | // strings.Split(s) will work in most cases, but does not handle 10 | // escaped dots (\.) for instance. 11 | // s must be a syntactically valid domain name, see IsDomainName. 12 | func SplitDomainName(s string) (labels []string) { 13 | if len(s) == 0 { 14 | return nil 15 | } 16 | fqdnEnd := 0 // offset of the final '.' or the length of the name 17 | idx := Split(s) 18 | begin := 0 19 | if s[len(s)-1] == '.' { 20 | fqdnEnd = len(s) - 1 21 | } else { 22 | fqdnEnd = len(s) 23 | } 24 | 25 | switch len(idx) { 26 | case 0: 27 | return nil 28 | case 1: 29 | // no-op 30 | default: 31 | end := 0 32 | for i := 1; i < len(idx); i++ { 33 | end = idx[i] 34 | labels = append(labels, s[begin:end-1]) 35 | begin = end 36 | } 37 | } 38 | 39 | labels = append(labels, s[begin:fqdnEnd]) 40 | return labels 41 | } 42 | 43 | // CompareDomainName compares the names s1 and s2 and 44 | // returns how many labels they have in common starting from the *right*. 45 | // The comparison stops at the first inequality. The names are not downcased 46 | // before the comparison. 47 | // 48 | // www.miek.nl. and miek.nl. have two labels in common: miek and nl 49 | // www.miek.nl. and www.bla.nl. have one label in common: nl 50 | // 51 | // s1 and s2 must be syntactically valid domain names. 52 | func CompareDomainName(s1, s2 string) (n int) { 53 | s1 = Fqdn(s1) 54 | s2 = Fqdn(s2) 55 | l1 := Split(s1) 56 | l2 := Split(s2) 57 | 58 | // the first check: root label 59 | if l1 == nil || l2 == nil { 60 | return 61 | } 62 | 63 | j1 := len(l1) - 1 // end 64 | i1 := len(l1) - 2 // start 65 | j2 := len(l2) - 1 66 | i2 := len(l2) - 2 67 | // the second check can be done here: last/only label 68 | // before we fall through into the for-loop below 69 | if s1[l1[j1]:] == s2[l2[j2]:] { 70 | n++ 71 | } else { 72 | return 73 | } 74 | for { 75 | if i1 < 0 || i2 < 0 { 76 | break 77 | } 78 | if s1[l1[i1]:l1[j1]] == s2[l2[i2]:l2[j2]] { 79 | n++ 80 | } else { 81 | break 82 | } 83 | j1-- 84 | i1-- 85 | j2-- 86 | i2-- 87 | } 88 | return 89 | } 90 | 91 | // CountLabel counts the the number of labels in the string s. 92 | // s must be a syntactically valid domain name. 93 | func CountLabel(s string) (labels int) { 94 | if s == "." { 95 | return 96 | } 97 | off := 0 98 | end := false 99 | for { 100 | off, end = NextLabel(s, off) 101 | labels++ 102 | if end { 103 | return 104 | } 105 | } 106 | } 107 | 108 | // Split splits a name s into its label indexes. 109 | // www.miek.nl. returns []int{0, 4, 9}, www.miek.nl also returns []int{0, 4, 9}. 110 | // The root name (.) returns nil. Also see SplitDomainName. 111 | // s must be a syntactically valid domain name. 112 | func Split(s string) []int { 113 | if s == "." { 114 | return nil 115 | } 116 | idx := make([]int, 1, 3) 117 | off := 0 118 | end := false 119 | 120 | for { 121 | off, end = NextLabel(s, off) 122 | if end { 123 | return idx 124 | } 125 | idx = append(idx, off) 126 | } 127 | } 128 | 129 | // NextLabel returns the index of the start of the next label in the 130 | // string s starting at offset. 131 | // The bool end is true when the end of the string has been reached. 132 | // Also see PrevLabel. 133 | func NextLabel(s string, offset int) (i int, end bool) { 134 | quote := false 135 | for i = offset; i < len(s)-1; i++ { 136 | switch s[i] { 137 | case '\\': 138 | quote = !quote 139 | default: 140 | quote = false 141 | case '.': 142 | if quote { 143 | quote = !quote 144 | continue 145 | } 146 | return i + 1, false 147 | } 148 | } 149 | return i + 1, true 150 | } 151 | 152 | // PrevLabel returns the index of the label when starting from the right and 153 | // jumping n labels to the left. 154 | // The bool start is true when the start of the string has been overshot. 155 | // Also see NextLabel. 156 | func PrevLabel(s string, n int) (i int, start bool) { 157 | if n == 0 { 158 | return len(s), false 159 | } 160 | lab := Split(s) 161 | if lab == nil { 162 | return 0, true 163 | } 164 | if n > len(lab) { 165 | return 0, true 166 | } 167 | return lab[len(lab)-n], false 168 | } 169 | -------------------------------------------------------------------------------- /vendor/github.com/miekg/dns/nsecx.go: -------------------------------------------------------------------------------- 1 | package dns 2 | 3 | import ( 4 | "crypto/sha1" 5 | "hash" 6 | "io" 7 | "strings" 8 | ) 9 | 10 | type saltWireFmt struct { 11 | Salt string `dns:"size-hex"` 12 | } 13 | 14 | // HashName hashes a string (label) according to RFC 5155. It returns the hashed string in uppercase. 15 | func HashName(label string, ha uint8, iter uint16, salt string) string { 16 | saltwire := new(saltWireFmt) 17 | saltwire.Salt = salt 18 | wire := make([]byte, DefaultMsgSize) 19 | n, err := packSaltWire(saltwire, wire) 20 | if err != nil { 21 | return "" 22 | } 23 | wire = wire[:n] 24 | name := make([]byte, 255) 25 | off, err := PackDomainName(strings.ToLower(label), name, 0, nil, false) 26 | if err != nil { 27 | return "" 28 | } 29 | name = name[:off] 30 | var s hash.Hash 31 | switch ha { 32 | case SHA1: 33 | s = sha1.New() 34 | default: 35 | return "" 36 | } 37 | 38 | // k = 0 39 | name = append(name, wire...) 40 | io.WriteString(s, string(name)) 41 | nsec3 := s.Sum(nil) 42 | // k > 0 43 | for k := uint16(0); k < iter; k++ { 44 | s.Reset() 45 | nsec3 = append(nsec3, wire...) 46 | io.WriteString(s, string(nsec3)) 47 | nsec3 = s.Sum(nil) 48 | } 49 | return toBase32(nsec3) 50 | } 51 | 52 | // Denialer is an interface that should be implemented by types that are used to denial 53 | // answers in DNSSEC. 54 | type Denialer interface { 55 | // Cover will check if the (unhashed) name is being covered by this NSEC or NSEC3. 56 | Cover(name string) bool 57 | // Match will check if the ownername matches the (unhashed) name for this NSEC3 or NSEC3. 58 | Match(name string) bool 59 | } 60 | 61 | // Cover implements the Denialer interface. 62 | func (rr *NSEC) Cover(name string) bool { 63 | return true 64 | } 65 | 66 | // Match implements the Denialer interface. 67 | func (rr *NSEC) Match(name string) bool { 68 | return true 69 | } 70 | 71 | // Cover implements the Denialer interface. 72 | func (rr *NSEC3) Cover(name string) bool { 73 | // FIXME(miek): check if the zones match 74 | // FIXME(miek): check if we're not dealing with parent nsec3 75 | hname := HashName(name, rr.Hash, rr.Iterations, rr.Salt) 76 | labels := Split(rr.Hdr.Name) 77 | if len(labels) < 2 { 78 | return false 79 | } 80 | hash := strings.ToUpper(rr.Hdr.Name[labels[0] : labels[1]-1]) // -1 to remove the dot 81 | if hash == rr.NextDomain { 82 | return false // empty interval 83 | } 84 | if hash > rr.NextDomain { // last name, points to apex 85 | // hname > hash 86 | // hname > rr.NextDomain 87 | // TODO(miek) 88 | } 89 | if hname <= hash { 90 | return false 91 | } 92 | if hname >= rr.NextDomain { 93 | return false 94 | } 95 | return true 96 | } 97 | 98 | // Match implements the Denialer interface. 99 | func (rr *NSEC3) Match(name string) bool { 100 | // FIXME(miek): Check if we are in the same zone 101 | hname := HashName(name, rr.Hash, rr.Iterations, rr.Salt) 102 | labels := Split(rr.Hdr.Name) 103 | if len(labels) < 2 { 104 | return false 105 | } 106 | hash := strings.ToUpper(rr.Hdr.Name[labels[0] : labels[1]-1]) // -1 to remove the . 107 | if hash == hname { 108 | return true 109 | } 110 | return false 111 | } 112 | 113 | func packSaltWire(sw *saltWireFmt, msg []byte) (int, error) { 114 | off, err := packStringHex(sw.Salt, msg, 0) 115 | if err != nil { 116 | return off, err 117 | } 118 | return off, nil 119 | } 120 | -------------------------------------------------------------------------------- /vendor/github.com/miekg/dns/privaterr.go: -------------------------------------------------------------------------------- 1 | package dns 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | ) 7 | 8 | // PrivateRdata is an interface used for implementing "Private Use" RR types, see 9 | // RFC 6895. This allows one to experiment with new RR types, without requesting an 10 | // official type code. Also see dns.PrivateHandle and dns.PrivateHandleRemove. 11 | type PrivateRdata interface { 12 | // String returns the text presentaton of the Rdata of the Private RR. 13 | String() string 14 | // Parse parses the Rdata of the private RR. 15 | Parse([]string) error 16 | // Pack is used when packing a private RR into a buffer. 17 | Pack([]byte) (int, error) 18 | // Unpack is used when unpacking a private RR from a buffer. 19 | // TODO(miek): diff. signature than Pack, see edns0.go for instance. 20 | Unpack([]byte) (int, error) 21 | // Copy copies the Rdata. 22 | Copy(PrivateRdata) error 23 | // Len returns the length in octets of the Rdata. 24 | Len() int 25 | } 26 | 27 | // PrivateRR represents an RR that uses a PrivateRdata user-defined type. 28 | // It mocks normal RRs and implements dns.RR interface. 29 | type PrivateRR struct { 30 | Hdr RR_Header 31 | Data PrivateRdata 32 | } 33 | 34 | func mkPrivateRR(rrtype uint16) *PrivateRR { 35 | // Panics if RR is not an instance of PrivateRR. 36 | rrfunc, ok := TypeToRR[rrtype] 37 | if !ok { 38 | panic(fmt.Sprintf("dns: invalid operation with Private RR type %d", rrtype)) 39 | } 40 | 41 | anyrr := rrfunc() 42 | switch rr := anyrr.(type) { 43 | case *PrivateRR: 44 | return rr 45 | } 46 | panic(fmt.Sprintf("dns: RR is not a PrivateRR, TypeToRR[%d] generator returned %T", rrtype, anyrr)) 47 | } 48 | 49 | // Header return the RR header of r. 50 | func (r *PrivateRR) Header() *RR_Header { return &r.Hdr } 51 | 52 | func (r *PrivateRR) String() string { return r.Hdr.String() + r.Data.String() } 53 | 54 | // Private len and copy parts to satisfy RR interface. 55 | func (r *PrivateRR) len() int { return r.Hdr.len() + r.Data.Len() } 56 | func (r *PrivateRR) copy() RR { 57 | // make new RR like this: 58 | rr := mkPrivateRR(r.Hdr.Rrtype) 59 | newh := r.Hdr.copyHeader() 60 | rr.Hdr = *newh 61 | 62 | err := r.Data.Copy(rr.Data) 63 | if err != nil { 64 | panic("dns: got value that could not be used to copy Private rdata") 65 | } 66 | return rr 67 | } 68 | func (r *PrivateRR) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) { 69 | off, err := r.Hdr.pack(msg, off, compression, compress) 70 | if err != nil { 71 | return off, err 72 | } 73 | headerEnd := off 74 | n, err := r.Data.Pack(msg[off:]) 75 | if err != nil { 76 | return len(msg), err 77 | } 78 | off += n 79 | r.Header().Rdlength = uint16(off - headerEnd) 80 | return off, nil 81 | } 82 | 83 | // PrivateHandle registers a private resource record type. It requires 84 | // string and numeric representation of private RR type and generator function as argument. 85 | func PrivateHandle(rtypestr string, rtype uint16, generator func() PrivateRdata) { 86 | rtypestr = strings.ToUpper(rtypestr) 87 | 88 | TypeToRR[rtype] = func() RR { return &PrivateRR{RR_Header{}, generator()} } 89 | TypeToString[rtype] = rtypestr 90 | StringToType[rtypestr] = rtype 91 | 92 | typeToUnpack[rtype] = func(h RR_Header, msg []byte, off int) (RR, int, error) { 93 | if noRdata(h) { 94 | return &h, off, nil 95 | } 96 | var err error 97 | 98 | rr := mkPrivateRR(h.Rrtype) 99 | rr.Hdr = h 100 | 101 | off1, err := rr.Data.Unpack(msg[off:]) 102 | off += off1 103 | if err != nil { 104 | return rr, off, err 105 | } 106 | return rr, off, err 107 | } 108 | 109 | setPrivateRR := func(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { 110 | rr := mkPrivateRR(h.Rrtype) 111 | rr.Hdr = h 112 | 113 | var l lex 114 | text := make([]string, 0, 2) // could be 0..N elements, median is probably 1 115 | Fetch: 116 | for { 117 | // TODO(miek): we could also be returning _QUOTE, this might or might not 118 | // be an issue (basically parsing TXT becomes hard) 119 | switch l = <-c; l.value { 120 | case zNewline, zEOF: 121 | break Fetch 122 | case zString: 123 | text = append(text, l.token) 124 | } 125 | } 126 | 127 | err := rr.Data.Parse(text) 128 | if err != nil { 129 | return nil, &ParseError{f, err.Error(), l}, "" 130 | } 131 | 132 | return rr, nil, "" 133 | } 134 | 135 | typeToparserFunc[rtype] = parserFunc{setPrivateRR, true} 136 | } 137 | 138 | // PrivateHandleRemove removes defenitions required to support private RR type. 139 | func PrivateHandleRemove(rtype uint16) { 140 | rtypestr, ok := TypeToString[rtype] 141 | if ok { 142 | delete(TypeToRR, rtype) 143 | delete(TypeToString, rtype) 144 | delete(typeToparserFunc, rtype) 145 | delete(StringToType, rtypestr) 146 | delete(typeToUnpack, rtype) 147 | } 148 | return 149 | } 150 | -------------------------------------------------------------------------------- /vendor/github.com/miekg/dns/rawmsg.go: -------------------------------------------------------------------------------- 1 | package dns 2 | 3 | import "encoding/binary" 4 | 5 | // rawSetRdlength sets the rdlength in the header of 6 | // the RR. The offset 'off' must be positioned at the 7 | // start of the header of the RR, 'end' must be the 8 | // end of the RR. 9 | func rawSetRdlength(msg []byte, off, end int) bool { 10 | l := len(msg) 11 | Loop: 12 | for { 13 | if off+1 > l { 14 | return false 15 | } 16 | c := int(msg[off]) 17 | off++ 18 | switch c & 0xC0 { 19 | case 0x00: 20 | if c == 0x00 { 21 | // End of the domainname 22 | break Loop 23 | } 24 | if off+c > l { 25 | return false 26 | } 27 | off += c 28 | 29 | case 0xC0: 30 | // pointer, next byte included, ends domainname 31 | off++ 32 | break Loop 33 | } 34 | } 35 | // The domainname has been seen, we at the start of the fixed part in the header. 36 | // Type is 2 bytes, class is 2 bytes, ttl 4 and then 2 bytes for the length. 37 | off += 2 + 2 + 4 38 | if off+2 > l { 39 | return false 40 | } 41 | //off+1 is the end of the header, 'end' is the end of the rr 42 | //so 'end' - 'off+2' is the length of the rdata 43 | rdatalen := end - (off + 2) 44 | if rdatalen > 0xFFFF { 45 | return false 46 | } 47 | binary.BigEndian.PutUint16(msg[off:], uint16(rdatalen)) 48 | return true 49 | } 50 | -------------------------------------------------------------------------------- /vendor/github.com/miekg/dns/reverse.go: -------------------------------------------------------------------------------- 1 | package dns 2 | 3 | // StringToType is the reverse of TypeToString, needed for string parsing. 4 | var StringToType = reverseInt16(TypeToString) 5 | 6 | // StringToClass is the reverse of ClassToString, needed for string parsing. 7 | var StringToClass = reverseInt16(ClassToString) 8 | 9 | // Map of opcodes strings. 10 | var StringToOpcode = reverseInt(OpcodeToString) 11 | 12 | // Map of rcodes strings. 13 | var StringToRcode = reverseInt(RcodeToString) 14 | 15 | // Reverse a map 16 | func reverseInt8(m map[uint8]string) map[string]uint8 { 17 | n := make(map[string]uint8, len(m)) 18 | for u, s := range m { 19 | n[s] = u 20 | } 21 | return n 22 | } 23 | 24 | func reverseInt16(m map[uint16]string) map[string]uint16 { 25 | n := make(map[string]uint16, len(m)) 26 | for u, s := range m { 27 | n[s] = u 28 | } 29 | return n 30 | } 31 | 32 | func reverseInt(m map[int]string) map[string]int { 33 | n := make(map[string]int, len(m)) 34 | for u, s := range m { 35 | n[s] = u 36 | } 37 | return n 38 | } 39 | -------------------------------------------------------------------------------- /vendor/github.com/miekg/dns/sanitize.go: -------------------------------------------------------------------------------- 1 | package dns 2 | 3 | // Dedup removes identical RRs from rrs. It preserves the original ordering. 4 | // The lowest TTL of any duplicates is used in the remaining one. Dedup modifies 5 | // rrs. 6 | // m is used to store the RRs temporay. If it is nil a new map will be allocated. 7 | func Dedup(rrs []RR, m map[string]RR) []RR { 8 | if m == nil { 9 | m = make(map[string]RR) 10 | } 11 | // Save the keys, so we don't have to call normalizedString twice. 12 | keys := make([]*string, 0, len(rrs)) 13 | 14 | for _, r := range rrs { 15 | key := normalizedString(r) 16 | keys = append(keys, &key) 17 | if _, ok := m[key]; ok { 18 | // Shortest TTL wins. 19 | if m[key].Header().Ttl > r.Header().Ttl { 20 | m[key].Header().Ttl = r.Header().Ttl 21 | } 22 | continue 23 | } 24 | 25 | m[key] = r 26 | } 27 | // If the length of the result map equals the amount of RRs we got, 28 | // it means they were all different. We can then just return the original rrset. 29 | if len(m) == len(rrs) { 30 | return rrs 31 | } 32 | 33 | j := 0 34 | for i, r := range rrs { 35 | // If keys[i] lives in the map, we should copy and remove it. 36 | if _, ok := m[*keys[i]]; ok { 37 | delete(m, *keys[i]) 38 | rrs[j] = r 39 | j++ 40 | } 41 | 42 | if len(m) == 0 { 43 | break 44 | } 45 | } 46 | 47 | return rrs[:j] 48 | } 49 | 50 | // normalizedString returns a normalized string from r. The TTL 51 | // is removed and the domain name is lowercased. We go from this: 52 | // DomainNameTTLCLASSTYPERDATA to: 53 | // lowercasenameCLASSTYPE... 54 | func normalizedString(r RR) string { 55 | // A string Go DNS makes has: domainnameTTL... 56 | b := []byte(r.String()) 57 | 58 | // find the first non-escaped tab, then another, so we capture where the TTL lives. 59 | esc := false 60 | ttlStart, ttlEnd := 0, 0 61 | for i := 0; i < len(b) && ttlEnd == 0; i++ { 62 | switch { 63 | case b[i] == '\\': 64 | esc = !esc 65 | case b[i] == '\t' && !esc: 66 | if ttlStart == 0 { 67 | ttlStart = i 68 | continue 69 | } 70 | if ttlEnd == 0 { 71 | ttlEnd = i 72 | } 73 | case b[i] >= 'A' && b[i] <= 'Z' && !esc: 74 | b[i] += 32 75 | default: 76 | esc = false 77 | } 78 | } 79 | 80 | // remove TTL. 81 | copy(b[ttlStart:], b[ttlEnd:]) 82 | cut := ttlEnd - ttlStart 83 | return string(b[:len(b)-cut]) 84 | } 85 | -------------------------------------------------------------------------------- /vendor/github.com/miekg/dns/scanner.go: -------------------------------------------------------------------------------- 1 | package dns 2 | 3 | // Implement a simple scanner, return a byte stream from an io reader. 4 | 5 | import ( 6 | "bufio" 7 | "io" 8 | "text/scanner" 9 | ) 10 | 11 | type scan struct { 12 | src *bufio.Reader 13 | position scanner.Position 14 | eof bool // Have we just seen a eof 15 | } 16 | 17 | func scanInit(r io.Reader) *scan { 18 | s := new(scan) 19 | s.src = bufio.NewReader(r) 20 | s.position.Line = 1 21 | return s 22 | } 23 | 24 | // tokenText returns the next byte from the input 25 | func (s *scan) tokenText() (byte, error) { 26 | c, err := s.src.ReadByte() 27 | if err != nil { 28 | return c, err 29 | } 30 | // delay the newline handling until the next token is delivered, 31 | // fixes off-by-one errors when reporting a parse error. 32 | if s.eof == true { 33 | s.position.Line++ 34 | s.position.Column = 0 35 | s.eof = false 36 | } 37 | if c == '\n' { 38 | s.eof = true 39 | return c, nil 40 | } 41 | s.position.Column++ 42 | return c, nil 43 | } 44 | -------------------------------------------------------------------------------- /vendor/github.com/miekg/dns/singleinflight.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Adapted for dns package usage by Miek Gieben. 6 | 7 | package dns 8 | 9 | import "sync" 10 | import "time" 11 | 12 | // call is an in-flight or completed singleflight.Do call 13 | type call struct { 14 | wg sync.WaitGroup 15 | val *Msg 16 | rtt time.Duration 17 | err error 18 | dups int 19 | } 20 | 21 | // singleflight represents a class of work and forms a namespace in 22 | // which units of work can be executed with duplicate suppression. 23 | type singleflight struct { 24 | sync.Mutex // protects m 25 | m map[string]*call // lazily initialized 26 | } 27 | 28 | // Do executes and returns the results of the given function, making 29 | // sure that only one execution is in-flight for a given key at a 30 | // time. If a duplicate comes in, the duplicate caller waits for the 31 | // original to complete and receives the same results. 32 | // The return value shared indicates whether v was given to multiple callers. 33 | func (g *singleflight) Do(key string, fn func() (*Msg, time.Duration, error)) (v *Msg, rtt time.Duration, err error, shared bool) { 34 | g.Lock() 35 | if g.m == nil { 36 | g.m = make(map[string]*call) 37 | } 38 | if c, ok := g.m[key]; ok { 39 | c.dups++ 40 | g.Unlock() 41 | c.wg.Wait() 42 | return c.val, c.rtt, c.err, true 43 | } 44 | c := new(call) 45 | c.wg.Add(1) 46 | g.m[key] = c 47 | g.Unlock() 48 | 49 | c.val, c.rtt, c.err = fn() 50 | c.wg.Done() 51 | 52 | g.Lock() 53 | delete(g.m, key) 54 | g.Unlock() 55 | 56 | return c.val, c.rtt, c.err, c.dups > 0 57 | } 58 | -------------------------------------------------------------------------------- /vendor/github.com/miekg/dns/smimea.go: -------------------------------------------------------------------------------- 1 | package dns 2 | 3 | import ( 4 | "crypto/sha256" 5 | "crypto/x509" 6 | "encoding/hex" 7 | ) 8 | 9 | // Sign creates a SMIMEA record from an SSL certificate. 10 | func (r *SMIMEA) Sign(usage, selector, matchingType int, cert *x509.Certificate) (err error) { 11 | r.Hdr.Rrtype = TypeSMIMEA 12 | r.Usage = uint8(usage) 13 | r.Selector = uint8(selector) 14 | r.MatchingType = uint8(matchingType) 15 | 16 | r.Certificate, err = CertificateToDANE(r.Selector, r.MatchingType, cert) 17 | if err != nil { 18 | return err 19 | } 20 | return nil 21 | } 22 | 23 | // Verify verifies a SMIMEA record against an SSL certificate. If it is OK 24 | // a nil error is returned. 25 | func (r *SMIMEA) Verify(cert *x509.Certificate) error { 26 | c, err := CertificateToDANE(r.Selector, r.MatchingType, cert) 27 | if err != nil { 28 | return err // Not also ErrSig? 29 | } 30 | if r.Certificate == c { 31 | return nil 32 | } 33 | return ErrSig // ErrSig, really? 34 | } 35 | 36 | // SIMEAName returns the ownername of a SMIMEA resource record as per the 37 | // format specified in RFC 'draft-ietf-dane-smime-12' Section 2 and 3 38 | func SMIMEAName(email_address string, domain_name string) (string, error) { 39 | hasher := sha256.New() 40 | hasher.Write([]byte(email_address)) 41 | 42 | // RFC Section 3: "The local-part is hashed using the SHA2-256 43 | // algorithm with the hash truncated to 28 octets and 44 | // represented in its hexadecimal representation to become the 45 | // left-most label in the prepared domain name" 46 | return hex.EncodeToString(hasher.Sum(nil)[:28]) + "." + "_smimecert." + domain_name, nil 47 | } 48 | -------------------------------------------------------------------------------- /vendor/github.com/miekg/dns/tlsa.go: -------------------------------------------------------------------------------- 1 | package dns 2 | 3 | import ( 4 | "crypto/x509" 5 | "net" 6 | "strconv" 7 | ) 8 | 9 | // Sign creates a TLSA record from an SSL certificate. 10 | func (r *TLSA) Sign(usage, selector, matchingType int, cert *x509.Certificate) (err error) { 11 | r.Hdr.Rrtype = TypeTLSA 12 | r.Usage = uint8(usage) 13 | r.Selector = uint8(selector) 14 | r.MatchingType = uint8(matchingType) 15 | 16 | r.Certificate, err = CertificateToDANE(r.Selector, r.MatchingType, cert) 17 | if err != nil { 18 | return err 19 | } 20 | return nil 21 | } 22 | 23 | // Verify verifies a TLSA record against an SSL certificate. If it is OK 24 | // a nil error is returned. 25 | func (r *TLSA) Verify(cert *x509.Certificate) error { 26 | c, err := CertificateToDANE(r.Selector, r.MatchingType, cert) 27 | if err != nil { 28 | return err // Not also ErrSig? 29 | } 30 | if r.Certificate == c { 31 | return nil 32 | } 33 | return ErrSig // ErrSig, really? 34 | } 35 | 36 | // TLSAName returns the ownername of a TLSA resource record as per the 37 | // rules specified in RFC 6698, Section 3. 38 | func TLSAName(name, service, network string) (string, error) { 39 | if !IsFqdn(name) { 40 | return "", ErrFqdn 41 | } 42 | p, err := net.LookupPort(network, service) 43 | if err != nil { 44 | return "", err 45 | } 46 | return "_" + strconv.Itoa(p) + "._" + network + "." + name, nil 47 | } 48 | -------------------------------------------------------------------------------- /vendor/github.com/miekg/dns/udp.go: -------------------------------------------------------------------------------- 1 | // +build !windows,!plan9 2 | 3 | package dns 4 | 5 | import ( 6 | "net" 7 | "syscall" 8 | ) 9 | 10 | // SessionUDP holds the remote address and the associated 11 | // out-of-band data. 12 | type SessionUDP struct { 13 | raddr *net.UDPAddr 14 | context []byte 15 | } 16 | 17 | // RemoteAddr returns the remote network address. 18 | func (s *SessionUDP) RemoteAddr() net.Addr { return s.raddr } 19 | 20 | // setUDPSocketOptions sets the UDP socket options. 21 | // This function is implemented on a per platform basis. See udp_*.go for more details 22 | func setUDPSocketOptions(conn *net.UDPConn) error { 23 | sa, err := getUDPSocketName(conn) 24 | if err != nil { 25 | return err 26 | } 27 | switch sa.(type) { 28 | case *syscall.SockaddrInet6: 29 | v6only, err := getUDPSocketOptions6Only(conn) 30 | if err != nil { 31 | return err 32 | } 33 | setUDPSocketOptions6(conn) 34 | if !v6only { 35 | setUDPSocketOptions4(conn) 36 | } 37 | case *syscall.SockaddrInet4: 38 | setUDPSocketOptions4(conn) 39 | } 40 | return nil 41 | } 42 | 43 | // ReadFromSessionUDP acts just like net.UDPConn.ReadFrom(), but returns a session object instead of a 44 | // net.UDPAddr. 45 | func ReadFromSessionUDP(conn *net.UDPConn, b []byte) (int, *SessionUDP, error) { 46 | oob := make([]byte, 40) 47 | n, oobn, _, raddr, err := conn.ReadMsgUDP(b, oob) 48 | if err != nil { 49 | return n, nil, err 50 | } 51 | return n, &SessionUDP{raddr, oob[:oobn]}, err 52 | } 53 | 54 | // WriteToSessionUDP acts just like net.UDPConn.WritetTo(), but uses a *SessionUDP instead of a net.Addr. 55 | func WriteToSessionUDP(conn *net.UDPConn, b []byte, session *SessionUDP) (int, error) { 56 | n, _, err := conn.WriteMsgUDP(b, session.context, session.raddr) 57 | return n, err 58 | } 59 | -------------------------------------------------------------------------------- /vendor/github.com/miekg/dns/udp_linux.go: -------------------------------------------------------------------------------- 1 | // +build linux 2 | 3 | package dns 4 | 5 | // See: 6 | // * http://stackoverflow.com/questions/3062205/setting-the-source-ip-for-a-udp-socket and 7 | // * http://blog.powerdns.com/2012/10/08/on-binding-datagram-udp-sockets-to-the-any-addresses/ 8 | // 9 | // Why do we need this: When listening on 0.0.0.0 with UDP so kernel decides what is the outgoing 10 | // interface, this might not always be the correct one. This code will make sure the egress 11 | // packet's interface matched the ingress' one. 12 | 13 | import ( 14 | "net" 15 | "syscall" 16 | ) 17 | 18 | // setUDPSocketOptions4 prepares the v4 socket for sessions. 19 | func setUDPSocketOptions4(conn *net.UDPConn) error { 20 | file, err := conn.File() 21 | if err != nil { 22 | return err 23 | } 24 | if err := syscall.SetsockoptInt(int(file.Fd()), syscall.IPPROTO_IP, syscall.IP_PKTINFO, 1); err != nil { 25 | return err 26 | } 27 | // Calling File() above results in the connection becoming blocking, we must fix that. 28 | // See https://github.com/miekg/dns/issues/279 29 | err = syscall.SetNonblock(int(file.Fd()), true) 30 | if err != nil { 31 | return err 32 | } 33 | return nil 34 | } 35 | 36 | // setUDPSocketOptions6 prepares the v6 socket for sessions. 37 | func setUDPSocketOptions6(conn *net.UDPConn) error { 38 | file, err := conn.File() 39 | if err != nil { 40 | return err 41 | } 42 | if err := syscall.SetsockoptInt(int(file.Fd()), syscall.IPPROTO_IPV6, syscall.IPV6_RECVPKTINFO, 1); err != nil { 43 | return err 44 | } 45 | err = syscall.SetNonblock(int(file.Fd()), true) 46 | if err != nil { 47 | return err 48 | } 49 | return nil 50 | } 51 | 52 | // getUDPSocketOption6Only return true if the socket is v6 only and false when it is v4/v6 combined 53 | // (dualstack). 54 | func getUDPSocketOptions6Only(conn *net.UDPConn) (bool, error) { 55 | file, err := conn.File() 56 | if err != nil { 57 | return false, err 58 | } 59 | // dual stack. See http://stackoverflow.com/questions/1618240/how-to-support-both-ipv4-and-ipv6-connections 60 | v6only, err := syscall.GetsockoptInt(int(file.Fd()), syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY) 61 | if err != nil { 62 | return false, err 63 | } 64 | return v6only == 1, nil 65 | } 66 | 67 | func getUDPSocketName(conn *net.UDPConn) (syscall.Sockaddr, error) { 68 | file, err := conn.File() 69 | if err != nil { 70 | return nil, err 71 | } 72 | return syscall.Getsockname(int(file.Fd())) 73 | } 74 | -------------------------------------------------------------------------------- /vendor/github.com/miekg/dns/udp_other.go: -------------------------------------------------------------------------------- 1 | // +build !linux,!plan9 2 | 3 | package dns 4 | 5 | import ( 6 | "net" 7 | "syscall" 8 | ) 9 | 10 | // These do nothing. See udp_linux.go for an example of how to implement this. 11 | 12 | // We tried to adhire to some kind of naming scheme. 13 | 14 | func setUDPSocketOptions4(conn *net.UDPConn) error { return nil } 15 | func setUDPSocketOptions6(conn *net.UDPConn) error { return nil } 16 | func getUDPSocketOptions6Only(conn *net.UDPConn) (bool, error) { return false, nil } 17 | func getUDPSocketName(conn *net.UDPConn) (syscall.Sockaddr, error) { return nil, nil } 18 | -------------------------------------------------------------------------------- /vendor/github.com/miekg/dns/udp_plan9.go: -------------------------------------------------------------------------------- 1 | package dns 2 | 3 | import ( 4 | "net" 5 | ) 6 | 7 | func setUDPSocketOptions(conn *net.UDPConn) error { return nil } 8 | 9 | // SessionUDP holds the remote address and the associated 10 | // out-of-band data. 11 | type SessionUDP struct { 12 | raddr *net.UDPAddr 13 | context []byte 14 | } 15 | 16 | // RemoteAddr returns the remote network address. 17 | func (s *SessionUDP) RemoteAddr() net.Addr { return s.raddr } 18 | 19 | // ReadFromSessionUDP acts just like net.UDPConn.ReadFrom(), but returns a session object instead of a 20 | // net.UDPAddr. 21 | func ReadFromSessionUDP(conn *net.UDPConn, b []byte) (int, *SessionUDP, error) { 22 | oob := make([]byte, 40) 23 | n, oobn, _, raddr, err := conn.ReadMsgUDP(b, oob) 24 | if err != nil { 25 | return n, nil, err 26 | } 27 | return n, &SessionUDP{raddr, oob[:oobn]}, err 28 | } 29 | 30 | // WriteToSessionUDP acts just like net.UDPConn.WritetTo(), but uses a *SessionUDP instead of a net.Addr. 31 | func WriteToSessionUDP(conn *net.UDPConn, b []byte, session *SessionUDP) (int, error) { 32 | n, _, err := conn.WriteMsgUDP(b, session.context, session.raddr) 33 | return n, err 34 | } 35 | -------------------------------------------------------------------------------- /vendor/github.com/miekg/dns/udp_windows.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | 3 | package dns 4 | 5 | import "net" 6 | 7 | type SessionUDP struct { 8 | raddr *net.UDPAddr 9 | } 10 | 11 | // ReadFromSessionUDP acts just like net.UDPConn.ReadFrom(), but returns a session object instead of a 12 | // net.UDPAddr. 13 | func ReadFromSessionUDP(conn *net.UDPConn, b []byte) (int, *SessionUDP, error) { 14 | n, raddr, err := conn.ReadFrom(b) 15 | if err != nil { 16 | return n, nil, err 17 | } 18 | session := &SessionUDP{raddr.(*net.UDPAddr)} 19 | return n, session, err 20 | } 21 | 22 | // WriteToSessionUDP acts just like net.UDPConn.WritetTo(), but uses a *SessionUDP instead of a net.Addr. 23 | func WriteToSessionUDP(conn *net.UDPConn, b []byte, session *SessionUDP) (int, error) { 24 | n, err := conn.WriteTo(b, session.raddr) 25 | return n, err 26 | } 27 | 28 | func (s *SessionUDP) RemoteAddr() net.Addr { return s.raddr } 29 | 30 | // setUDPSocketOptions sets the UDP socket options. 31 | // This function is implemented on a per platform basis. See udp_*.go for more details 32 | func setUDPSocketOptions(conn *net.UDPConn) error { 33 | return nil 34 | } 35 | -------------------------------------------------------------------------------- /vendor/github.com/miekg/dns/update.go: -------------------------------------------------------------------------------- 1 | package dns 2 | 3 | // NameUsed sets the RRs in the prereq section to 4 | // "Name is in use" RRs. RFC 2136 section 2.4.4. 5 | func (u *Msg) NameUsed(rr []RR) { 6 | if u.Answer == nil { 7 | u.Answer = make([]RR, 0, len(rr)) 8 | } 9 | for _, r := range rr { 10 | u.Answer = append(u.Answer, &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: TypeANY, Class: ClassANY}}) 11 | } 12 | } 13 | 14 | // NameNotUsed sets the RRs in the prereq section to 15 | // "Name is in not use" RRs. RFC 2136 section 2.4.5. 16 | func (u *Msg) NameNotUsed(rr []RR) { 17 | if u.Answer == nil { 18 | u.Answer = make([]RR, 0, len(rr)) 19 | } 20 | for _, r := range rr { 21 | u.Answer = append(u.Answer, &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: TypeANY, Class: ClassNONE}}) 22 | } 23 | } 24 | 25 | // Used sets the RRs in the prereq section to 26 | // "RRset exists (value dependent -- with rdata)" RRs. RFC 2136 section 2.4.2. 27 | func (u *Msg) Used(rr []RR) { 28 | if len(u.Question) == 0 { 29 | panic("dns: empty question section") 30 | } 31 | if u.Answer == nil { 32 | u.Answer = make([]RR, 0, len(rr)) 33 | } 34 | for _, r := range rr { 35 | r.Header().Class = u.Question[0].Qclass 36 | u.Answer = append(u.Answer, r) 37 | } 38 | } 39 | 40 | // RRsetUsed sets the RRs in the prereq section to 41 | // "RRset exists (value independent -- no rdata)" RRs. RFC 2136 section 2.4.1. 42 | func (u *Msg) RRsetUsed(rr []RR) { 43 | if u.Answer == nil { 44 | u.Answer = make([]RR, 0, len(rr)) 45 | } 46 | for _, r := range rr { 47 | u.Answer = append(u.Answer, &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: r.Header().Rrtype, Class: ClassANY}}) 48 | } 49 | } 50 | 51 | // RRsetNotUsed sets the RRs in the prereq section to 52 | // "RRset does not exist" RRs. RFC 2136 section 2.4.3. 53 | func (u *Msg) RRsetNotUsed(rr []RR) { 54 | if u.Answer == nil { 55 | u.Answer = make([]RR, 0, len(rr)) 56 | } 57 | for _, r := range rr { 58 | u.Answer = append(u.Answer, &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: r.Header().Rrtype, Class: ClassNONE}}) 59 | } 60 | } 61 | 62 | // Insert creates a dynamic update packet that adds an complete RRset, see RFC 2136 section 2.5.1. 63 | func (u *Msg) Insert(rr []RR) { 64 | if len(u.Question) == 0 { 65 | panic("dns: empty question section") 66 | } 67 | if u.Ns == nil { 68 | u.Ns = make([]RR, 0, len(rr)) 69 | } 70 | for _, r := range rr { 71 | r.Header().Class = u.Question[0].Qclass 72 | u.Ns = append(u.Ns, r) 73 | } 74 | } 75 | 76 | // RemoveRRset creates a dynamic update packet that deletes an RRset, see RFC 2136 section 2.5.2. 77 | func (u *Msg) RemoveRRset(rr []RR) { 78 | if u.Ns == nil { 79 | u.Ns = make([]RR, 0, len(rr)) 80 | } 81 | for _, r := range rr { 82 | u.Ns = append(u.Ns, &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: r.Header().Rrtype, Class: ClassANY}}) 83 | } 84 | } 85 | 86 | // RemoveName creates a dynamic update packet that deletes all RRsets of a name, see RFC 2136 section 2.5.3 87 | func (u *Msg) RemoveName(rr []RR) { 88 | if u.Ns == nil { 89 | u.Ns = make([]RR, 0, len(rr)) 90 | } 91 | for _, r := range rr { 92 | u.Ns = append(u.Ns, &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: TypeANY, Class: ClassANY}}) 93 | } 94 | } 95 | 96 | // Remove creates a dynamic update packet deletes RR from a RRSset, see RFC 2136 section 2.5.4 97 | func (u *Msg) Remove(rr []RR) { 98 | if u.Ns == nil { 99 | u.Ns = make([]RR, 0, len(rr)) 100 | } 101 | for _, r := range rr { 102 | r.Header().Class = ClassNONE 103 | r.Header().Ttl = 0 104 | u.Ns = append(u.Ns, r) 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /vendor/github.com/satori/go.uuid/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2013-2016 by Maxim Bublis 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /vendor/github.com/satori/go.uuid/README.md: -------------------------------------------------------------------------------- 1 | # UUID package for Go language 2 | 3 | [![Build Status](https://travis-ci.org/satori/go.uuid.png?branch=master)](https://travis-ci.org/satori/go.uuid) 4 | [![Coverage Status](https://coveralls.io/repos/github/satori/go.uuid/badge.svg?branch=master)](https://coveralls.io/github/satori/go.uuid) 5 | [![GoDoc](http://godoc.org/github.com/satori/go.uuid?status.png)](http://godoc.org/github.com/satori/go.uuid) 6 | 7 | This package provides pure Go implementation of Universally Unique Identifier (UUID). Supported both creation and parsing of UUIDs. 8 | 9 | With 100% test coverage and benchmarks out of box. 10 | 11 | Supported versions: 12 | * Version 1, based on timestamp and MAC address (RFC 4122) 13 | * Version 2, based on timestamp, MAC address and POSIX UID/GID (DCE 1.1) 14 | * Version 3, based on MD5 hashing (RFC 4122) 15 | * Version 4, based on random numbers (RFC 4122) 16 | * Version 5, based on SHA-1 hashing (RFC 4122) 17 | 18 | ## Installation 19 | 20 | Use the `go` command: 21 | 22 | $ go get github.com/satori/go.uuid 23 | 24 | ## Requirements 25 | 26 | UUID package requires Go >= 1.2. 27 | 28 | ## Example 29 | 30 | ```go 31 | package main 32 | 33 | import ( 34 | "fmt" 35 | "github.com/satori/go.uuid" 36 | ) 37 | 38 | func main() { 39 | // Creating UUID Version 4 40 | u1 := uuid.NewV4() 41 | fmt.Printf("UUIDv4: %s\n", u1) 42 | 43 | // Parsing UUID from string input 44 | u2, err := uuid.FromString("6ba7b810-9dad-11d1-80b4-00c04fd430c8") 45 | if err != nil { 46 | fmt.Printf("Something gone wrong: %s", err) 47 | } 48 | fmt.Printf("Successfully parsed: %s", u2) 49 | } 50 | ``` 51 | 52 | ## Documentation 53 | 54 | [Documentation](http://godoc.org/github.com/satori/go.uuid) is hosted at GoDoc project. 55 | 56 | ## Links 57 | * [RFC 4122](http://tools.ietf.org/html/rfc4122) 58 | * [DCE 1.1: Authentication and Security Services](http://pubs.opengroup.org/onlinepubs/9696989899/chap5.htm#tagcjh_08_02_01_01) 59 | 60 | ## Copyright 61 | 62 | Copyright (C) 2013-2016 by Maxim Bublis . 63 | 64 | UUID package released under MIT License. 65 | See [LICENSE](https://github.com/satori/go.uuid/blob/master/LICENSE) for details. 66 | -------------------------------------------------------------------------------- /vendor/github.com/tsuru/config/CONTRIBUTORS: -------------------------------------------------------------------------------- 1 | # This is the list of people who have contributed code to config. 2 | 3 | Andrews Medina 4 | Cezar Sa Espinola 5 | Flavia Missi 6 | Francisco Souza 7 | Marc Abramowitz 8 | Mauricio Souza Lima 9 | Tarsis Azevedo 10 | -------------------------------------------------------------------------------- /vendor/github.com/tsuru/config/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Globo.com 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, 9 | this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation and/or 12 | other materials provided with the distribution. 13 | * Neither the name of Globo.com nor the names of its contributors may be used 14 | to endorse or promote products derived from this software without specific 15 | prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 18 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 19 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20 | PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 21 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 22 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 23 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 24 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 25 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 26 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /vendor/github.com/tsuru/config/README.markdown: -------------------------------------------------------------------------------- 1 | #Config 2 | 3 | [![Build Status](https://secure.travis-ci.org/tsuru/config.png)](http://travis-ci.org/tsuru/config) 4 | 5 | [![GoDoc](http://godoc.org/github.com/tsuru/config?status.png)](http://godoc.org/github.com/tsuru/config) 6 | 7 | Config is a Go package to manage yaml configuration files. 8 | 9 | For usage information, read our package documentation: 10 | . 11 | -------------------------------------------------------------------------------- /vendor/github.com/tsuru/config/checker.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Globo.com. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package config 6 | 7 | import ( 8 | "fmt" 9 | "io" 10 | ) 11 | 12 | type Checker func() error 13 | 14 | type warningErr struct{ msg string } 15 | 16 | func (e *warningErr) Error() string { 17 | return e.msg 18 | } 19 | 20 | func NewWarning(msg string) error { 21 | return &warningErr{msg: msg} 22 | } 23 | 24 | // Check a parsed config file and consider warnings as errors. 25 | func Check(checkers []Checker) error { 26 | return CheckWithWarnings(checkers, nil) 27 | } 28 | 29 | // Check a parsed config file and writes warnings to received writer. 30 | func CheckWithWarnings(checkers []Checker, warningWriter io.Writer) error { 31 | for _, check := range checkers { 32 | err := check() 33 | if _, isWarn := err.(*warningErr); warningWriter != nil && isWarn { 34 | fmt.Fprintf(warningWriter, "WARNING: %s\n", err) 35 | continue 36 | } 37 | if err != nil { 38 | return err 39 | } 40 | } 41 | return nil 42 | } 43 | -------------------------------------------------------------------------------- /vendor/github.com/urfave/cli/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Jeremy Saenz & Contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /vendor/github.com/urfave/cli/appveyor.yml: -------------------------------------------------------------------------------- 1 | version: "{build}" 2 | 3 | os: Windows Server 2012 R2 4 | 5 | clone_folder: c:\gopath\src\github.com\urfave\cli 6 | 7 | environment: 8 | GOPATH: C:\gopath 9 | GOVERSION: 1.6 10 | PYTHON: C:\Python27-x64 11 | PYTHON_VERSION: 2.7.x 12 | PYTHON_ARCH: 64 13 | 14 | install: 15 | - set PATH=%GOPATH%\bin;C:\go\bin;%PATH% 16 | - go version 17 | - go env 18 | - go get github.com/urfave/gfmrun/... 19 | - go get -v -t ./... 20 | 21 | build_script: 22 | - python runtests vet 23 | - python runtests test 24 | - python runtests gfmrun 25 | -------------------------------------------------------------------------------- /vendor/github.com/urfave/cli/category.go: -------------------------------------------------------------------------------- 1 | package cli 2 | 3 | // CommandCategories is a slice of *CommandCategory. 4 | type CommandCategories []*CommandCategory 5 | 6 | // CommandCategory is a category containing commands. 7 | type CommandCategory struct { 8 | Name string 9 | Commands Commands 10 | } 11 | 12 | func (c CommandCategories) Less(i, j int) bool { 13 | return c[i].Name < c[j].Name 14 | } 15 | 16 | func (c CommandCategories) Len() int { 17 | return len(c) 18 | } 19 | 20 | func (c CommandCategories) Swap(i, j int) { 21 | c[i], c[j] = c[j], c[i] 22 | } 23 | 24 | // AddCommand adds a command to a category. 25 | func (c CommandCategories) AddCommand(category string, command Command) CommandCategories { 26 | for _, commandCategory := range c { 27 | if commandCategory.Name == category { 28 | commandCategory.Commands = append(commandCategory.Commands, command) 29 | return c 30 | } 31 | } 32 | return append(c, &CommandCategory{Name: category, Commands: []Command{command}}) 33 | } 34 | 35 | // VisibleCommands returns a slice of the Commands with Hidden=false 36 | func (c *CommandCategory) VisibleCommands() []Command { 37 | ret := []Command{} 38 | for _, command := range c.Commands { 39 | if !command.Hidden { 40 | ret = append(ret, command) 41 | } 42 | } 43 | return ret 44 | } 45 | -------------------------------------------------------------------------------- /vendor/github.com/urfave/cli/cli.go: -------------------------------------------------------------------------------- 1 | // Package cli provides a minimal framework for creating and organizing command line 2 | // Go applications. cli is designed to be easy to understand and write, the most simple 3 | // cli application can be written as follows: 4 | // func main() { 5 | // cli.NewApp().Run(os.Args) 6 | // } 7 | // 8 | // Of course this application does not do much, so let's make this an actual application: 9 | // func main() { 10 | // app := cli.NewApp() 11 | // app.Name = "greet" 12 | // app.Usage = "say a greeting" 13 | // app.Action = func(c *cli.Context) error { 14 | // println("Greetings") 15 | // } 16 | // 17 | // app.Run(os.Args) 18 | // } 19 | package cli 20 | 21 | //go:generate python ./generate-flag-types cli -i flag-types.json -o flag_generated.go 22 | -------------------------------------------------------------------------------- /vendor/github.com/urfave/cli/errors.go: -------------------------------------------------------------------------------- 1 | package cli 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "os" 7 | "strings" 8 | ) 9 | 10 | // OsExiter is the function used when the app exits. If not set defaults to os.Exit. 11 | var OsExiter = os.Exit 12 | 13 | // ErrWriter is used to write errors to the user. This can be anything 14 | // implementing the io.Writer interface and defaults to os.Stderr. 15 | var ErrWriter io.Writer = os.Stderr 16 | 17 | // MultiError is an error that wraps multiple errors. 18 | type MultiError struct { 19 | Errors []error 20 | } 21 | 22 | // NewMultiError creates a new MultiError. Pass in one or more errors. 23 | func NewMultiError(err ...error) MultiError { 24 | return MultiError{Errors: err} 25 | } 26 | 27 | // Error implements the error interface. 28 | func (m MultiError) Error() string { 29 | errs := make([]string, len(m.Errors)) 30 | for i, err := range m.Errors { 31 | errs[i] = err.Error() 32 | } 33 | 34 | return strings.Join(errs, "\n") 35 | } 36 | 37 | // ExitCoder is the interface checked by `App` and `Command` for a custom exit 38 | // code 39 | type ExitCoder interface { 40 | error 41 | ExitCode() int 42 | } 43 | 44 | // ExitError fulfills both the builtin `error` interface and `ExitCoder` 45 | type ExitError struct { 46 | exitCode int 47 | message string 48 | } 49 | 50 | // NewExitError makes a new *ExitError 51 | func NewExitError(message string, exitCode int) *ExitError { 52 | return &ExitError{ 53 | exitCode: exitCode, 54 | message: message, 55 | } 56 | } 57 | 58 | // Error returns the string message, fulfilling the interface required by 59 | // `error` 60 | func (ee *ExitError) Error() string { 61 | return ee.message 62 | } 63 | 64 | // ExitCode returns the exit code, fulfilling the interface required by 65 | // `ExitCoder` 66 | func (ee *ExitError) ExitCode() int { 67 | return ee.exitCode 68 | } 69 | 70 | // HandleExitCoder checks if the error fulfills the ExitCoder interface, and if 71 | // so prints the error to stderr (if it is non-empty) and calls OsExiter with the 72 | // given exit code. If the given error is a MultiError, then this func is 73 | // called on all members of the Errors slice. 74 | func HandleExitCoder(err error) { 75 | if err == nil { 76 | return 77 | } 78 | 79 | if exitErr, ok := err.(ExitCoder); ok { 80 | if err.Error() != "" { 81 | fmt.Fprintln(ErrWriter, err) 82 | } 83 | OsExiter(exitErr.ExitCode()) 84 | return 85 | } 86 | 87 | if multiErr, ok := err.(MultiError); ok { 88 | for _, merr := range multiErr.Errors { 89 | HandleExitCoder(merr) 90 | } 91 | return 92 | } 93 | 94 | if err.Error() != "" { 95 | fmt.Fprintln(ErrWriter, err) 96 | } 97 | OsExiter(1) 98 | } 99 | -------------------------------------------------------------------------------- /vendor/github.com/urfave/cli/flag-types.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Bool", 4 | "type": "bool", 5 | "value": false, 6 | "context_default": "false", 7 | "parser": "strconv.ParseBool(f.Value.String())" 8 | }, 9 | { 10 | "name": "BoolT", 11 | "type": "bool", 12 | "value": false, 13 | "doctail": " that is true by default", 14 | "context_default": "false", 15 | "parser": "strconv.ParseBool(f.Value.String())" 16 | }, 17 | { 18 | "name": "Duration", 19 | "type": "time.Duration", 20 | "doctail": " (see https://golang.org/pkg/time/#ParseDuration)", 21 | "context_default": "0", 22 | "parser": "time.ParseDuration(f.Value.String())" 23 | }, 24 | { 25 | "name": "Float64", 26 | "type": "float64", 27 | "context_default": "0", 28 | "parser": "strconv.ParseFloat(f.Value.String(), 64)" 29 | }, 30 | { 31 | "name": "Generic", 32 | "type": "Generic", 33 | "dest": false, 34 | "context_default": "nil", 35 | "context_type": "interface{}" 36 | }, 37 | { 38 | "name": "Int64", 39 | "type": "int64", 40 | "context_default": "0", 41 | "parser": "strconv.ParseInt(f.Value.String(), 0, 64)" 42 | }, 43 | { 44 | "name": "Int", 45 | "type": "int", 46 | "context_default": "0", 47 | "parser": "strconv.ParseInt(f.Value.String(), 0, 64)", 48 | "parser_cast": "int(parsed)" 49 | }, 50 | { 51 | "name": "IntSlice", 52 | "type": "*IntSlice", 53 | "dest": false, 54 | "context_default": "nil", 55 | "context_type": "[]int", 56 | "parser": "(f.Value.(*IntSlice)).Value(), error(nil)" 57 | }, 58 | { 59 | "name": "Int64Slice", 60 | "type": "*Int64Slice", 61 | "dest": false, 62 | "context_default": "nil", 63 | "context_type": "[]int64", 64 | "parser": "(f.Value.(*Int64Slice)).Value(), error(nil)" 65 | }, 66 | { 67 | "name": "String", 68 | "type": "string", 69 | "context_default": "\"\"", 70 | "parser": "f.Value.String(), error(nil)" 71 | }, 72 | { 73 | "name": "StringSlice", 74 | "type": "*StringSlice", 75 | "dest": false, 76 | "context_default": "nil", 77 | "context_type": "[]string", 78 | "parser": "(f.Value.(*StringSlice)).Value(), error(nil)" 79 | }, 80 | { 81 | "name": "Uint64", 82 | "type": "uint64", 83 | "context_default": "0", 84 | "parser": "strconv.ParseUint(f.Value.String(), 0, 64)" 85 | }, 86 | { 87 | "name": "Uint", 88 | "type": "uint", 89 | "context_default": "0", 90 | "parser": "strconv.ParseUint(f.Value.String(), 0, 64)", 91 | "parser_cast": "uint(parsed)" 92 | } 93 | ] 94 | -------------------------------------------------------------------------------- /vendor/github.com/urfave/cli/funcs.go: -------------------------------------------------------------------------------- 1 | package cli 2 | 3 | // BashCompleteFunc is an action to execute when the bash-completion flag is set 4 | type BashCompleteFunc func(*Context) 5 | 6 | // BeforeFunc is an action to execute before any subcommands are run, but after 7 | // the context is ready if a non-nil error is returned, no subcommands are run 8 | type BeforeFunc func(*Context) error 9 | 10 | // AfterFunc is an action to execute after any subcommands are run, but after the 11 | // subcommand has finished it is run even if Action() panics 12 | type AfterFunc func(*Context) error 13 | 14 | // ActionFunc is the action to execute when no subcommands are specified 15 | type ActionFunc func(*Context) error 16 | 17 | // CommandNotFoundFunc is executed if the proper command cannot be found 18 | type CommandNotFoundFunc func(*Context, string) 19 | 20 | // OnUsageErrorFunc is executed if an usage error occurs. This is useful for displaying 21 | // customized usage error messages. This function is able to replace the 22 | // original error messages. If this function is not set, the "Incorrect usage" 23 | // is displayed and the execution is interrupted. 24 | type OnUsageErrorFunc func(context *Context, err error, isSubcommand bool) error 25 | 26 | // FlagStringFunc is used by the help generation to display a flag, which is 27 | // expected to be a single line. 28 | type FlagStringFunc func(Flag) string 29 | -------------------------------------------------------------------------------- /vendor/github.com/urfave/cli/runtests: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from __future__ import print_function 3 | 4 | import argparse 5 | import os 6 | import sys 7 | import tempfile 8 | 9 | from subprocess import check_call, check_output 10 | 11 | 12 | PACKAGE_NAME = os.environ.get( 13 | 'CLI_PACKAGE_NAME', 'github.com/urfave/cli' 14 | ) 15 | 16 | 17 | def main(sysargs=sys.argv[:]): 18 | targets = { 19 | 'vet': _vet, 20 | 'test': _test, 21 | 'gfmrun': _gfmrun, 22 | 'toc': _toc, 23 | 'gen': _gen, 24 | } 25 | 26 | parser = argparse.ArgumentParser() 27 | parser.add_argument( 28 | 'target', nargs='?', choices=tuple(targets.keys()), default='test' 29 | ) 30 | args = parser.parse_args(sysargs[1:]) 31 | 32 | targets[args.target]() 33 | return 0 34 | 35 | 36 | def _test(): 37 | if check_output('go version'.split()).split()[2] < 'go1.2': 38 | _run('go test -v .') 39 | return 40 | 41 | coverprofiles = [] 42 | for subpackage in ['', 'altsrc']: 43 | coverprofile = 'cli.coverprofile' 44 | if subpackage != '': 45 | coverprofile = '{}.coverprofile'.format(subpackage) 46 | 47 | coverprofiles.append(coverprofile) 48 | 49 | _run('go test -v'.split() + [ 50 | '-coverprofile={}'.format(coverprofile), 51 | ('{}/{}'.format(PACKAGE_NAME, subpackage)).rstrip('/') 52 | ]) 53 | 54 | combined_name = _combine_coverprofiles(coverprofiles) 55 | _run('go tool cover -func={}'.format(combined_name)) 56 | os.remove(combined_name) 57 | 58 | 59 | def _gfmrun(): 60 | go_version = check_output('go version'.split()).split()[2] 61 | if go_version < 'go1.3': 62 | print('runtests: skip on {}'.format(go_version), file=sys.stderr) 63 | return 64 | _run(['gfmrun', '-c', str(_gfmrun_count()), '-s', 'README.md']) 65 | 66 | 67 | def _vet(): 68 | _run('go vet ./...') 69 | 70 | 71 | def _toc(): 72 | _run('node_modules/.bin/markdown-toc -i README.md') 73 | _run('git diff --exit-code') 74 | 75 | 76 | def _gen(): 77 | go_version = check_output('go version'.split()).split()[2] 78 | if go_version < 'go1.5': 79 | print('runtests: skip on {}'.format(go_version), file=sys.stderr) 80 | return 81 | 82 | _run('go generate ./...') 83 | _run('git diff --exit-code') 84 | 85 | 86 | def _run(command): 87 | if hasattr(command, 'split'): 88 | command = command.split() 89 | print('runtests: {}'.format(' '.join(command)), file=sys.stderr) 90 | check_call(command) 91 | 92 | 93 | def _gfmrun_count(): 94 | with open('README.md') as infile: 95 | lines = infile.read().splitlines() 96 | return len(filter(_is_go_runnable, lines)) 97 | 98 | 99 | def _is_go_runnable(line): 100 | return line.startswith('package main') 101 | 102 | 103 | def _combine_coverprofiles(coverprofiles): 104 | combined = tempfile.NamedTemporaryFile( 105 | suffix='.coverprofile', delete=False 106 | ) 107 | combined.write('mode: set\n') 108 | 109 | for coverprofile in coverprofiles: 110 | with open(coverprofile, 'r') as infile: 111 | for line in infile.readlines(): 112 | if not line.startswith('mode: '): 113 | combined.write(line) 114 | 115 | combined.flush() 116 | name = combined.name 117 | combined.close() 118 | return name 119 | 120 | 121 | if __name__ == '__main__': 122 | sys.exit(main()) 123 | -------------------------------------------------------------------------------- /vendor/gopkg.in/yaml.v1/LICENSE.libyaml: -------------------------------------------------------------------------------- 1 | The following files were ported to Go from C files of libyaml, and thus 2 | are still covered by their original copyright and license: 3 | 4 | apic.go 5 | emitterc.go 6 | parserc.go 7 | readerc.go 8 | scannerc.go 9 | writerc.go 10 | yamlh.go 11 | yamlprivateh.go 12 | 13 | Copyright (c) 2006 Kirill Simonov 14 | 15 | Permission is hereby granted, free of charge, to any person obtaining a copy of 16 | this software and associated documentation files (the "Software"), to deal in 17 | the Software without restriction, including without limitation the rights to 18 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 19 | of the Software, and to permit persons to whom the Software is furnished to do 20 | so, subject to the following conditions: 21 | 22 | The above copyright notice and this permission notice shall be included in all 23 | copies or substantial portions of the Software. 24 | 25 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 26 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 27 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 28 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 29 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 30 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31 | SOFTWARE. 32 | -------------------------------------------------------------------------------- /vendor/gopkg.in/yaml.v1/README.md: -------------------------------------------------------------------------------- 1 | # YAML support for the Go language 2 | 3 | Introduction 4 | ------------ 5 | 6 | The yaml package enables Go programs to comfortably encode and decode YAML 7 | values. It was developed within [Canonical](https://www.canonical.com) as 8 | part of the [juju](https://juju.ubuntu.com) project, and is based on a 9 | pure Go port of the well-known [libyaml](http://pyyaml.org/wiki/LibYAML) 10 | C library to parse and generate YAML data quickly and reliably. 11 | 12 | Compatibility 13 | ------------- 14 | 15 | The yaml package supports most of YAML 1.1 and 1.2, including support for 16 | anchors, tags, map merging, etc. Multi-document unmarshalling is not yet 17 | implemented, and base-60 floats from YAML 1.1 are purposefully not 18 | supported since they're a poor design and are gone in YAML 1.2. 19 | 20 | Installation and usage 21 | ---------------------- 22 | 23 | The import path for the package is *gopkg.in/yaml.v1*. 24 | 25 | To install it, run: 26 | 27 | go get gopkg.in/yaml.v1 28 | 29 | API documentation 30 | ----------------- 31 | 32 | If opened in a browser, the import path itself leads to the API documentation: 33 | 34 | * [https://gopkg.in/yaml.v1](https://gopkg.in/yaml.v1) 35 | 36 | API stability 37 | ------------- 38 | 39 | The package API for yaml v1 will remain stable as described in [gopkg.in](https://gopkg.in). 40 | 41 | 42 | License 43 | ------- 44 | 45 | The yaml package is licensed under the LGPL with an exception that allows it to be linked statically. Please see the LICENSE file for details. 46 | 47 | 48 | Example 49 | ------- 50 | 51 | ```Go 52 | package main 53 | 54 | import ( 55 | "fmt" 56 | "log" 57 | 58 | "gopkg.in/yaml.v1" 59 | ) 60 | 61 | var data = ` 62 | a: Easy! 63 | b: 64 | c: 2 65 | d: [3, 4] 66 | ` 67 | 68 | type T struct { 69 | A string 70 | B struct{C int; D []int ",flow"} 71 | } 72 | 73 | func main() { 74 | t := T{} 75 | 76 | err := yaml.Unmarshal([]byte(data), &t) 77 | if err != nil { 78 | log.Fatalf("error: %v", err) 79 | } 80 | fmt.Printf("--- t:\n%v\n\n", t) 81 | 82 | d, err := yaml.Marshal(&t) 83 | if err != nil { 84 | log.Fatalf("error: %v", err) 85 | } 86 | fmt.Printf("--- t dump:\n%s\n\n", string(d)) 87 | 88 | m := make(map[interface{}]interface{}) 89 | 90 | err = yaml.Unmarshal([]byte(data), &m) 91 | if err != nil { 92 | log.Fatalf("error: %v", err) 93 | } 94 | fmt.Printf("--- m:\n%v\n\n", m) 95 | 96 | d, err = yaml.Marshal(&m) 97 | if err != nil { 98 | log.Fatalf("error: %v", err) 99 | } 100 | fmt.Printf("--- m dump:\n%s\n\n", string(d)) 101 | } 102 | ``` 103 | 104 | This example will generate the following output: 105 | 106 | ``` 107 | --- t: 108 | {Easy! {2 [3 4]}} 109 | 110 | --- t dump: 111 | a: Easy! 112 | b: 113 | c: 2 114 | d: [3, 4] 115 | 116 | 117 | --- m: 118 | map[a:Easy! b:map[c:2 d:[3 4]]] 119 | 120 | --- m dump: 121 | a: Easy! 122 | b: 123 | c: 2 124 | d: 125 | - 3 126 | - 4 127 | ``` 128 | 129 | -------------------------------------------------------------------------------- /vendor/gopkg.in/yaml.v1/resolve.go: -------------------------------------------------------------------------------- 1 | package yaml 2 | 3 | import ( 4 | "encoding/base64" 5 | "fmt" 6 | "math" 7 | "strconv" 8 | "strings" 9 | "unicode/utf8" 10 | ) 11 | 12 | // TODO: merge, timestamps, base 60 floats, omap. 13 | 14 | type resolveMapItem struct { 15 | value interface{} 16 | tag string 17 | } 18 | 19 | var resolveTable = make([]byte, 256) 20 | var resolveMap = make(map[string]resolveMapItem) 21 | 22 | func init() { 23 | t := resolveTable 24 | t[int('+')] = 'S' // Sign 25 | t[int('-')] = 'S' 26 | for _, c := range "0123456789" { 27 | t[int(c)] = 'D' // Digit 28 | } 29 | for _, c := range "yYnNtTfFoO~" { 30 | t[int(c)] = 'M' // In map 31 | } 32 | t[int('.')] = '.' // Float (potentially in map) 33 | 34 | var resolveMapList = []struct { 35 | v interface{} 36 | tag string 37 | l []string 38 | }{ 39 | {true, yaml_BOOL_TAG, []string{"y", "Y", "yes", "Yes", "YES"}}, 40 | {true, yaml_BOOL_TAG, []string{"true", "True", "TRUE"}}, 41 | {true, yaml_BOOL_TAG, []string{"on", "On", "ON"}}, 42 | {false, yaml_BOOL_TAG, []string{"n", "N", "no", "No", "NO"}}, 43 | {false, yaml_BOOL_TAG, []string{"false", "False", "FALSE"}}, 44 | {false, yaml_BOOL_TAG, []string{"off", "Off", "OFF"}}, 45 | {nil, yaml_NULL_TAG, []string{"", "~", "null", "Null", "NULL"}}, 46 | {math.NaN(), yaml_FLOAT_TAG, []string{".nan", ".NaN", ".NAN"}}, 47 | {math.Inf(+1), yaml_FLOAT_TAG, []string{".inf", ".Inf", ".INF"}}, 48 | {math.Inf(+1), yaml_FLOAT_TAG, []string{"+.inf", "+.Inf", "+.INF"}}, 49 | {math.Inf(-1), yaml_FLOAT_TAG, []string{"-.inf", "-.Inf", "-.INF"}}, 50 | {"<<", yaml_MERGE_TAG, []string{"<<"}}, 51 | } 52 | 53 | m := resolveMap 54 | for _, item := range resolveMapList { 55 | for _, s := range item.l { 56 | m[s] = resolveMapItem{item.v, item.tag} 57 | } 58 | } 59 | } 60 | 61 | const longTagPrefix = "tag:yaml.org,2002:" 62 | 63 | func shortTag(tag string) string { 64 | // TODO This can easily be made faster and produce less garbage. 65 | if strings.HasPrefix(tag, longTagPrefix) { 66 | return "!!" + tag[len(longTagPrefix):] 67 | } 68 | return tag 69 | } 70 | 71 | func longTag(tag string) string { 72 | if strings.HasPrefix(tag, "!!") { 73 | return longTagPrefix + tag[2:] 74 | } 75 | return tag 76 | } 77 | 78 | func resolvableTag(tag string) bool { 79 | switch tag { 80 | case "", yaml_STR_TAG, yaml_BOOL_TAG, yaml_INT_TAG, yaml_FLOAT_TAG, yaml_NULL_TAG: 81 | return true 82 | } 83 | return false 84 | } 85 | 86 | func resolve(tag string, in string) (rtag string, out interface{}) { 87 | if !resolvableTag(tag) { 88 | return tag, in 89 | } 90 | 91 | defer func() { 92 | switch tag { 93 | case "", rtag, yaml_STR_TAG, yaml_BINARY_TAG: 94 | return 95 | } 96 | fail(fmt.Sprintf("cannot decode %s `%s` as a %s", shortTag(rtag), in, shortTag(tag))) 97 | }() 98 | 99 | // Any data is accepted as a !!str or !!binary. 100 | // Otherwise, the prefix is enough of a hint about what it might be. 101 | hint := byte('N') 102 | if in != "" { 103 | hint = resolveTable[in[0]] 104 | } 105 | if hint != 0 && tag != yaml_STR_TAG && tag != yaml_BINARY_TAG { 106 | // Handle things we can lookup in a map. 107 | if item, ok := resolveMap[in]; ok { 108 | return item.tag, item.value 109 | } 110 | 111 | // Base 60 floats are a bad idea, were dropped in YAML 1.2, and 112 | // are purposefully unsupported here. They're still quoted on 113 | // the way out for compatibility with other parser, though. 114 | 115 | switch hint { 116 | case 'M': 117 | // We've already checked the map above. 118 | 119 | case '.': 120 | // Not in the map, so maybe a normal float. 121 | floatv, err := strconv.ParseFloat(in, 64) 122 | if err == nil { 123 | return yaml_FLOAT_TAG, floatv 124 | } 125 | 126 | case 'D', 'S': 127 | // Int, float, or timestamp. 128 | plain := strings.Replace(in, "_", "", -1) 129 | intv, err := strconv.ParseInt(plain, 0, 64) 130 | if err == nil { 131 | if intv == int64(int(intv)) { 132 | return yaml_INT_TAG, int(intv) 133 | } else { 134 | return yaml_INT_TAG, intv 135 | } 136 | } 137 | floatv, err := strconv.ParseFloat(plain, 64) 138 | if err == nil { 139 | return yaml_FLOAT_TAG, floatv 140 | } 141 | if strings.HasPrefix(plain, "0b") { 142 | intv, err := strconv.ParseInt(plain[2:], 2, 64) 143 | if err == nil { 144 | return yaml_INT_TAG, int(intv) 145 | } 146 | } else if strings.HasPrefix(plain, "-0b") { 147 | intv, err := strconv.ParseInt(plain[3:], 2, 64) 148 | if err == nil { 149 | return yaml_INT_TAG, -int(intv) 150 | } 151 | } 152 | // XXX Handle timestamps here. 153 | 154 | default: 155 | panic("resolveTable item not yet handled: " + string(rune(hint)) + " (with " + in + ")") 156 | } 157 | } 158 | if tag == yaml_BINARY_TAG { 159 | return yaml_BINARY_TAG, in 160 | } 161 | if utf8.ValidString(in) { 162 | return yaml_STR_TAG, in 163 | } 164 | return yaml_BINARY_TAG, encodeBase64(in) 165 | } 166 | 167 | // encodeBase64 encodes s as base64 that is broken up into multiple lines 168 | // as appropriate for the resulting length. 169 | func encodeBase64(s string) string { 170 | const lineLen = 70 171 | encLen := base64.StdEncoding.EncodedLen(len(s)) 172 | lines := encLen/lineLen + 1 173 | buf := make([]byte, encLen*2+lines) 174 | in := buf[0:encLen] 175 | out := buf[encLen:] 176 | base64.StdEncoding.Encode(in, []byte(s)) 177 | k := 0 178 | for i := 0; i < len(in); i += lineLen { 179 | j := i + lineLen 180 | if j > len(in) { 181 | j = len(in) 182 | } 183 | k += copy(out[k:], in[i:j]) 184 | if lines > 1 { 185 | out[k] = '\n' 186 | k++ 187 | } 188 | } 189 | return string(out[:k]) 190 | } 191 | -------------------------------------------------------------------------------- /vendor/gopkg.in/yaml.v1/sorter.go: -------------------------------------------------------------------------------- 1 | package yaml 2 | 3 | import ( 4 | "reflect" 5 | "unicode" 6 | ) 7 | 8 | type keyList []reflect.Value 9 | 10 | func (l keyList) Len() int { return len(l) } 11 | func (l keyList) Swap(i, j int) { l[i], l[j] = l[j], l[i] } 12 | func (l keyList) Less(i, j int) bool { 13 | a := l[i] 14 | b := l[j] 15 | ak := a.Kind() 16 | bk := b.Kind() 17 | for (ak == reflect.Interface || ak == reflect.Ptr) && !a.IsNil() { 18 | a = a.Elem() 19 | ak = a.Kind() 20 | } 21 | for (bk == reflect.Interface || bk == reflect.Ptr) && !b.IsNil() { 22 | b = b.Elem() 23 | bk = b.Kind() 24 | } 25 | af, aok := keyFloat(a) 26 | bf, bok := keyFloat(b) 27 | if aok && bok { 28 | if af != bf { 29 | return af < bf 30 | } 31 | if ak != bk { 32 | return ak < bk 33 | } 34 | return numLess(a, b) 35 | } 36 | if ak != reflect.String || bk != reflect.String { 37 | return ak < bk 38 | } 39 | ar, br := []rune(a.String()), []rune(b.String()) 40 | for i := 0; i < len(ar) && i < len(br); i++ { 41 | if ar[i] == br[i] { 42 | continue 43 | } 44 | al := unicode.IsLetter(ar[i]) 45 | bl := unicode.IsLetter(br[i]) 46 | if al && bl { 47 | return ar[i] < br[i] 48 | } 49 | if al || bl { 50 | return bl 51 | } 52 | var ai, bi int 53 | var an, bn int64 54 | for ai = i; ai < len(ar) && unicode.IsDigit(ar[ai]); ai++ { 55 | an = an*10 + int64(ar[ai]-'0') 56 | } 57 | for bi = i; bi < len(br) && unicode.IsDigit(br[bi]); bi++ { 58 | bn = bn*10 + int64(br[bi]-'0') 59 | } 60 | if an != bn { 61 | return an < bn 62 | } 63 | if ai != bi { 64 | return ai < bi 65 | } 66 | return ar[i] < br[i] 67 | } 68 | return len(ar) < len(br) 69 | } 70 | 71 | // keyFloat returns a float value for v if it is a number/bool 72 | // and whether it is a number/bool or not. 73 | func keyFloat(v reflect.Value) (f float64, ok bool) { 74 | switch v.Kind() { 75 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 76 | return float64(v.Int()), true 77 | case reflect.Float32, reflect.Float64: 78 | return v.Float(), true 79 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 80 | return float64(v.Uint()), true 81 | case reflect.Bool: 82 | if v.Bool() { 83 | return 1, true 84 | } 85 | return 0, true 86 | } 87 | return 0, false 88 | } 89 | 90 | // numLess returns whether a < b. 91 | // a and b must necessarily have the same kind. 92 | func numLess(a, b reflect.Value) bool { 93 | switch a.Kind() { 94 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 95 | return a.Int() < b.Int() 96 | case reflect.Float32, reflect.Float64: 97 | return a.Float() < b.Float() 98 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 99 | return a.Uint() < b.Uint() 100 | case reflect.Bool: 101 | return !a.Bool() && b.Bool() 102 | } 103 | panic("not a number") 104 | } 105 | -------------------------------------------------------------------------------- /vendor/gopkg.in/yaml.v1/writerc.go: -------------------------------------------------------------------------------- 1 | package yaml 2 | 3 | // Set the writer error and return false. 4 | func yaml_emitter_set_writer_error(emitter *yaml_emitter_t, problem string) bool { 5 | emitter.error = yaml_WRITER_ERROR 6 | emitter.problem = problem 7 | return false 8 | } 9 | 10 | // Flush the output buffer. 11 | func yaml_emitter_flush(emitter *yaml_emitter_t) bool { 12 | if emitter.write_handler == nil { 13 | panic("write handler not set") 14 | } 15 | 16 | // Check if the buffer is empty. 17 | if emitter.buffer_pos == 0 { 18 | return true 19 | } 20 | 21 | // If the output encoding is UTF-8, we don't need to recode the buffer. 22 | if emitter.encoding == yaml_UTF8_ENCODING { 23 | if err := emitter.write_handler(emitter, emitter.buffer[:emitter.buffer_pos]); err != nil { 24 | return yaml_emitter_set_writer_error(emitter, "write error: "+err.Error()) 25 | } 26 | emitter.buffer_pos = 0 27 | return true 28 | } 29 | 30 | // Recode the buffer into the raw buffer. 31 | var low, high int 32 | if emitter.encoding == yaml_UTF16LE_ENCODING { 33 | low, high = 0, 1 34 | } else { 35 | high, low = 1, 0 36 | } 37 | 38 | pos := 0 39 | for pos < emitter.buffer_pos { 40 | // See the "reader.c" code for more details on UTF-8 encoding. Note 41 | // that we assume that the buffer contains a valid UTF-8 sequence. 42 | 43 | // Read the next UTF-8 character. 44 | octet := emitter.buffer[pos] 45 | 46 | var w int 47 | var value rune 48 | switch { 49 | case octet&0x80 == 0x00: 50 | w, value = 1, rune(octet&0x7F) 51 | case octet&0xE0 == 0xC0: 52 | w, value = 2, rune(octet&0x1F) 53 | case octet&0xF0 == 0xE0: 54 | w, value = 3, rune(octet&0x0F) 55 | case octet&0xF8 == 0xF0: 56 | w, value = 4, rune(octet&0x07) 57 | } 58 | for k := 1; k < w; k++ { 59 | octet = emitter.buffer[pos+k] 60 | value = (value << 6) + (rune(octet) & 0x3F) 61 | } 62 | pos += w 63 | 64 | // Write the character. 65 | if value < 0x10000 { 66 | var b [2]byte 67 | b[high] = byte(value >> 8) 68 | b[low] = byte(value & 0xFF) 69 | emitter.raw_buffer = append(emitter.raw_buffer, b[0], b[1]) 70 | } else { 71 | // Write the character using a surrogate pair (check "reader.c"). 72 | var b [4]byte 73 | value -= 0x10000 74 | b[high] = byte(0xD8 + (value >> 18)) 75 | b[low] = byte((value >> 10) & 0xFF) 76 | b[high+2] = byte(0xDC + ((value >> 8) & 0xFF)) 77 | b[low+2] = byte(value & 0xFF) 78 | emitter.raw_buffer = append(emitter.raw_buffer, b[0], b[1], b[2], b[3]) 79 | } 80 | } 81 | 82 | // Write the raw buffer. 83 | if err := emitter.write_handler(emitter, emitter.raw_buffer); err != nil { 84 | return yaml_emitter_set_writer_error(emitter, "write error: "+err.Error()) 85 | } 86 | emitter.buffer_pos = 0 87 | emitter.raw_buffer = emitter.raw_buffer[:0] 88 | return true 89 | } 90 | -------------------------------------------------------------------------------- /vendor/gopkg.in/yaml.v1/yamlprivateh.go: -------------------------------------------------------------------------------- 1 | package yaml 2 | 3 | const ( 4 | // The size of the input raw buffer. 5 | input_raw_buffer_size = 512 6 | 7 | // The size of the input buffer. 8 | // It should be possible to decode the whole raw buffer. 9 | input_buffer_size = input_raw_buffer_size * 3 10 | 11 | // The size of the output buffer. 12 | output_buffer_size = 128 13 | 14 | // The size of the output raw buffer. 15 | // It should be possible to encode the whole output buffer. 16 | output_raw_buffer_size = (output_buffer_size*2 + 2) 17 | 18 | // The size of other stacks and queues. 19 | initial_stack_size = 16 20 | initial_queue_size = 16 21 | initial_string_size = 16 22 | ) 23 | 24 | // Check if the character at the specified position is an alphabetical 25 | // character, a digit, '_', or '-'. 26 | func is_alpha(b []byte, i int) bool { 27 | return b[i] >= '0' && b[i] <= '9' || b[i] >= 'A' && b[i] <= 'Z' || b[i] >= 'a' && b[i] <= 'z' || b[i] == '_' || b[i] == '-' 28 | } 29 | 30 | // Check if the character at the specified position is a digit. 31 | func is_digit(b []byte, i int) bool { 32 | return b[i] >= '0' && b[i] <= '9' 33 | } 34 | 35 | // Get the value of a digit. 36 | func as_digit(b []byte, i int) int { 37 | return int(b[i]) - '0' 38 | } 39 | 40 | // Check if the character at the specified position is a hex-digit. 41 | func is_hex(b []byte, i int) bool { 42 | return b[i] >= '0' && b[i] <= '9' || b[i] >= 'A' && b[i] <= 'F' || b[i] >= 'a' && b[i] <= 'f' 43 | } 44 | 45 | // Get the value of a hex-digit. 46 | func as_hex(b []byte, i int) int { 47 | bi := b[i] 48 | if bi >= 'A' && bi <= 'F' { 49 | return int(bi) - 'A' + 10 50 | } 51 | if bi >= 'a' && bi <= 'f' { 52 | return int(bi) - 'a' + 10 53 | } 54 | return int(bi) - '0' 55 | } 56 | 57 | // Check if the character is ASCII. 58 | func is_ascii(b []byte, i int) bool { 59 | return b[i] <= 0x7F 60 | } 61 | 62 | // Check if the character at the start of the buffer can be printed unescaped. 63 | func is_printable(b []byte, i int) bool { 64 | return ((b[i] == 0x0A) || // . == #x0A 65 | (b[i] >= 0x20 && b[i] <= 0x7E) || // #x20 <= . <= #x7E 66 | (b[i] == 0xC2 && b[i+1] >= 0xA0) || // #0xA0 <= . <= #xD7FF 67 | (b[i] > 0xC2 && b[i] < 0xED) || 68 | (b[i] == 0xED && b[i+1] < 0xA0) || 69 | (b[i] == 0xEE) || 70 | (b[i] == 0xEF && // #xE000 <= . <= #xFFFD 71 | !(b[i+1] == 0xBB && b[i+2] == 0xBF) && // && . != #xFEFF 72 | !(b[i+1] == 0xBF && (b[i+2] == 0xBE || b[i+2] == 0xBF)))) 73 | } 74 | 75 | // Check if the character at the specified position is NUL. 76 | func is_z(b []byte, i int) bool { 77 | return b[i] == 0x00 78 | } 79 | 80 | // Check if the beginning of the buffer is a BOM. 81 | func is_bom(b []byte, i int) bool { 82 | return b[0] == 0xEF && b[1] == 0xBB && b[2] == 0xBF 83 | } 84 | 85 | // Check if the character at the specified position is space. 86 | func is_space(b []byte, i int) bool { 87 | return b[i] == ' ' 88 | } 89 | 90 | // Check if the character at the specified position is tab. 91 | func is_tab(b []byte, i int) bool { 92 | return b[i] == '\t' 93 | } 94 | 95 | // Check if the character at the specified position is blank (space or tab). 96 | func is_blank(b []byte, i int) bool { 97 | //return is_space(b, i) || is_tab(b, i) 98 | return b[i] == ' ' || b[i] == '\t' 99 | } 100 | 101 | // Check if the character at the specified position is a line break. 102 | func is_break(b []byte, i int) bool { 103 | return (b[i] == '\r' || // CR (#xD) 104 | b[i] == '\n' || // LF (#xA) 105 | b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85) 106 | b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028) 107 | b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9) // PS (#x2029) 108 | } 109 | 110 | func is_crlf(b []byte, i int) bool { 111 | return b[i] == '\r' && b[i+1] == '\n' 112 | } 113 | 114 | // Check if the character is a line break or NUL. 115 | func is_breakz(b []byte, i int) bool { 116 | //return is_break(b, i) || is_z(b, i) 117 | return ( // is_break: 118 | b[i] == '\r' || // CR (#xD) 119 | b[i] == '\n' || // LF (#xA) 120 | b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85) 121 | b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028) 122 | b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029) 123 | // is_z: 124 | b[i] == 0) 125 | } 126 | 127 | // Check if the character is a line break, space, or NUL. 128 | func is_spacez(b []byte, i int) bool { 129 | //return is_space(b, i) || is_breakz(b, i) 130 | return ( // is_space: 131 | b[i] == ' ' || 132 | // is_breakz: 133 | b[i] == '\r' || // CR (#xD) 134 | b[i] == '\n' || // LF (#xA) 135 | b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85) 136 | b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028) 137 | b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029) 138 | b[i] == 0) 139 | } 140 | 141 | // Check if the character is a line break, space, tab, or NUL. 142 | func is_blankz(b []byte, i int) bool { 143 | //return is_blank(b, i) || is_breakz(b, i) 144 | return ( // is_blank: 145 | b[i] == ' ' || b[i] == '\t' || 146 | // is_breakz: 147 | b[i] == '\r' || // CR (#xD) 148 | b[i] == '\n' || // LF (#xA) 149 | b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85) 150 | b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028) 151 | b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029) 152 | b[i] == 0) 153 | } 154 | 155 | // Determine the width of the character. 156 | func width(b byte) int { 157 | // Don't replace these by a switch without first 158 | // confirming that it is being inlined. 159 | if b&0x80 == 0x00 { 160 | return 1 161 | } 162 | if b&0xE0 == 0xC0 { 163 | return 2 164 | } 165 | if b&0xF0 == 0xE0 { 166 | return 3 167 | } 168 | if b&0xF8 == 0xF0 { 169 | return 4 170 | } 171 | return 0 172 | 173 | } 174 | -------------------------------------------------------------------------------- /vendor/vendor.json: -------------------------------------------------------------------------------- 1 | { 2 | "comment": "", 3 | "ignore": "test", 4 | "package": [ 5 | { 6 | "checksumSHA1": "Oae/AzW8+W/lPdL6smTcgyhncrc=", 7 | "path": "github.com/blang/semver", 8 | "revision": "60ec3488bfea7cca02b021d106d9911120d25fe9", 9 | "revisionTime": "2016-07-01T05:46:53Z" 10 | }, 11 | { 12 | "checksumSHA1": "SIt1nDmxTb831cdF+UKseuS4AK4=", 13 | "path": "github.com/briandowns/spinner", 14 | "revision": "a00ac22c746220ee70a0891a0ec4aa6c56c6bb6a", 15 | "revisionTime": "2016-07-18T20:30:27Z" 16 | }, 17 | { 18 | "checksumSHA1": "G0Jclpec4uGGO1B/N+s9OjUjx5w=", 19 | "path": "github.com/fatih/color", 20 | "revision": "0016e2689083bc05a71fc0bdcd75f4947f6a5182", 21 | "revisionTime": "2016-09-27T15:48:50Z" 22 | }, 23 | { 24 | "checksumSHA1": "ZxzYc1JwJ3U6kZbw/KGuPko5lSY=", 25 | "path": "github.com/howeyc/fsnotify", 26 | "revision": "f0c08ee9c60704c1879025f2ae0ff3e000082c13", 27 | "revisionTime": "2015-10-03T19:46:02Z" 28 | }, 29 | { 30 | "checksumSHA1": "g+afVQQVopBLiLB5pFZp/8s6aBs=", 31 | "path": "github.com/kardianos/osext", 32 | "revision": "c2c54e542fb797ad986b31721e1baedf214ca413", 33 | "revisionTime": "2016-08-11T00:15:26Z" 34 | }, 35 | { 36 | "checksumSHA1": "ugnSryGF6VPBb5s87QgoRH6730g=", 37 | "path": "github.com/mattn/go-colorable", 38 | "revision": "6c903ff4aa50920ca86087a280590b36b3152b9c", 39 | "revisionTime": "2016-09-30T08:41:57Z" 40 | }, 41 | { 42 | "checksumSHA1": "xZuhljnmBysJPta/lMyYmJdujCg=", 43 | "path": "github.com/mattn/go-isatty", 44 | "revision": "66b8e73f3f5cda9f96b69efd03dd3d7fc4a5cdb8", 45 | "revisionTime": "2016-08-06T12:27:52Z" 46 | }, 47 | { 48 | "checksumSHA1": "Wahi4g/9XiHhSLAJ+8jskg71PCU=", 49 | "path": "github.com/miekg/dns", 50 | "revision": "58f52c57ce9df13460ac68200cef30a008b9c468", 51 | "revisionTime": "2016-10-18T06:08:08Z" 52 | }, 53 | { 54 | "checksumSHA1": "zmC8/3V4ls53DJlNTKDZwPSC/dA=", 55 | "path": "github.com/satori/go.uuid", 56 | "revision": "0aa62d5ddceb50dbcb909d790b5345affd3669b6", 57 | "revisionTime": "2016-07-13T18:03:06Z" 58 | }, 59 | { 60 | "checksumSHA1": "ND36F6pc3iBYhsU4xw7vsX/sBQM=", 61 | "path": "github.com/tsuru/config", 62 | "revision": "66463741517827f979a47fbfc05299199c0ced13", 63 | "revisionTime": "2016-09-09T01:02:41Z" 64 | }, 65 | { 66 | "checksumSHA1": "VzCBWaUbB+sJ7NvGf1TMPoxcqSE=", 67 | "path": "github.com/urfave/cli", 68 | "revision": "6f2647a880e25bd7178ab4bbf1f4045ac256cc57", 69 | "revisionTime": "2016-10-22T17:29:59Z" 70 | }, 71 | { 72 | "checksumSHA1": "MGk7cSnHqiL5soaovzgcJaNH3fc=", 73 | "path": "gopkg.in/yaml.v1", 74 | "revision": "9f9df34309c04878acc86042b16630b0f696e1de", 75 | "revisionTime": "2014-09-24T16:16:07Z" 76 | } 77 | ], 78 | "rootPath": "github.com/nlf/dlite" 79 | } 80 | --------------------------------------------------------------------------------