<commit_before>//
// Copyright 2015 The rkt Authors
// Copyright (c) 2016 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

package virtcontainers

import (
	"fmt"
	"os"
	"path/filepath"
	"syscall"
)

const mountPerm = os.FileMode(0755)

// bindMount bind mounts a source in to a destination. This will
// do some bookkeeping:
// * evaluate all symlinks
// * ensure the source exists
// * recursively create the destination
func bindMount(source, destination string) error {
	absSource, err := filepath.EvalSymlinks(source)
	if err != nil {
		return fmt.Errorf("Could not resolve symlink for source %v", source)
	}

	if err := ensureDestinationExists(absSource, destination); err != nil {
		return fmt.Errorf("Could not create destination mount point: %v", destination)
	} else if err := syscall.Mount(absSource, destination, "bind", syscall.MS_BIND, ""); err != nil {
		return fmt.Errorf("Could not bind mount %v to %v", absSource, destination)
	}

	return nil
}

// ensureDestinationExists will recursively create a given mountpoint. If directories
// are created, their permissions are initialized to mountPerm
func ensureDestinationExists(source, destination string) error {
	fileInfo, err := os.Stat(source)
	if err != nil {
		return fmt.Errorf("could not stat source location: %v", source)
	}

	targetPathParent, _ := filepath.Split(destination)
	if err := os.MkdirAll(targetPathParent, mountPerm); err != nil {
		return fmt.Errorf("could not create parent directory: %v", targetPathParent)
	}

	if fileInfo.IsDir() {
		if err := os.Mkdir(destination, mountPerm); !os.IsExist(err) {
			return err
		}
	} else {
		file, err := os.OpenFile(destination, os.O_CREATE, mountPerm)
		if err != nil {
			return err
		}

		file.Close()
	}
	return nil
}
<commit_msg>syscall: Return full error details.<commit_after>//
// Copyright 2015 The rkt Authors
// Copyright (c) 2016 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

package virtcontainers

import (
	"fmt"
	"os"
	"path/filepath"
	"syscall"
)

const mountPerm = os.FileMode(0755)

// bindMount bind mounts a source in to a destination. This will
// do some bookkeeping:
// * evaluate all symlinks
// * ensure the source exists
// * recursively create the destination
func bindMount(source, destination string) error {
	absSource, err := filepath.EvalSymlinks(source)
	if err != nil {
		return fmt.Errorf("Could not resolve symlink for source %v", source)
	}

	if err := ensureDestinationExists(absSource, destination); err != nil {
		return fmt.Errorf("Could not create destination mount point %v: %v", destination, err)
	} else if err := syscall.Mount(absSource, destination, "bind", syscall.MS_BIND, ""); err != nil {
		return fmt.Errorf("Could not bind mount %v to %v: %v", absSource, destination, err)
	}

	return nil
}

// ensureDestinationExists will recursively create a given mountpoint. If directories
// are created, their permissions are initialized to mountPerm
func ensureDestinationExists(source, destination string) error {
	fileInfo, err := os.Stat(source)
	if err != nil {
		return fmt.Errorf("could not stat source location %v: %v", source, err)
	}

	targetPathParent, _ := filepath.Split(destination)
	if err := os.MkdirAll(targetPathParent, mountPerm); err != nil {
		return fmt.Errorf("could not create parent directory %v: %v", targetPathParent, err)
	}

	if fileInfo.IsDir() {
		if err := os.Mkdir(destination, mountPerm); !os.IsExist(err) {
			return err
		}
	} else {
		file, err := os.OpenFile(destination, os.O_CREATE, mountPerm)
		if err != nil {
			return err
		}

		file.Close()
	}
	return nil
}
<|endoftext|>


<commit_before>package main

// lingua evalia
//
// try it with `curl -i localhost:8000/run --data-binary @hello-world.go`

import (
	"fmt"
	"html/template"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
)

type Language interface {
	RunFile(f *os.File) (result []byte, err error)
	Name() string
	Extension() string
}

type LanguageGeneral struct {
	name    string
	ext     string
	command string
	args    []string
}

func (l LanguageGeneral) RunFile(f *os.File) ([]byte, error) {
	args := append(l.args, f.Name())
	cmd := exec.Command(l.command, args...)
	return cmd.CombinedOutput()
}

func (l LanguageGeneral) Name() string { return l.name }

func (l LanguageGeneral) Extension() string { return l.ext }

var Go = LanguageGeneral{"Go", "go", "go", []string{"run"}}
var Python = LanguageGeneral{"Python", "py", "python", []string{}}
var Ruby = LanguageGeneral{"Ruby", "rb", "ruby", []string{}}
var JavaScript = LanguageGeneral{"JavaScript", "js", "node", []string{}}
var Haskell = LanguageGeneral{"Haskell", "hs", "runhaskell", []string{}}
var Rust = LanguageGeneral{"Rust", "rs", "./bin/run-rust", []string{}}

var languageMappings = map[string]Language{
	"go":         Go,
	"python":     Python,
	"ruby":       Ruby,
	"javascript": JavaScript,
	"haskell":    Haskell,
	"rust":       Rust,
}

func writeCode(code string, extension string) (*os.File, error) {
	// create tmp file
	f, err := os.Create(fmt.Sprintf("/tmp/linguaevalia-%s.%s", extension, extension)) // FIXME: actually create a tmpfile
	if err != nil {
		return f, err
	}
	// write code to it
	_, err = f.Write([]byte(code))
	if err != nil {
		return f, err
	}
	return f, nil
}

func Eval(lang Language, code string) ([]byte, error) {
	// write code to temp file
	f, err := writeCode(code, lang.Extension())
	defer f.Close()
	if err != nil {
		return nil, err
	}
	// `go run` it
	res, err := lang.RunFile(f)
	if err != nil {
		return res, err
	}
	// remove the file
	os.Remove(f.Name())
	// return output
	return res, nil
}

func runCodeHandler(w http.ResponseWriter, r *http.Request) {
	code, err := ioutil.ReadAll(r.Body)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	lang := getLanguage(r)
	res, err := Eval(lang, string(code))
	if err != nil {
		http.Error(w, string(res), http.StatusNotAcceptable)
		return
	}
	w.Write(res)
}

func getLanguage(r *http.Request) Language {
	langName := r.URL.Query().Get("language")
	if langName != "" {
		lang, ok := languageMappings[langName]
		if ok {
			return lang
		}
	}
	return Go
}

func homePageHandler(w http.ResponseWriter, r *http.Request) {
	bindings := map[string]interface{}{
		"languages": languageMappings,
	}
	homePageTemplate.Execute(w, bindings)
}

var homePageTemplate = template.Must(template.New("homepage").Parse(homePageTemplateStr))

func main() {
	addr, port := "localhost", 8000
	fmt.Printf("running on %s:%d\n", addr, port)

	http.HandleFunc("/run", runCodeHandler)
	http.HandleFunc("/", homePageHandler)

	err := http.ListenAndServe(fmt.Sprintf("%s:%d", addr, port), nil)
	if err != nil {
		log.Fatal(err)
	}
}

const homePageTemplateStr = `
<!doctype html>

    <title>lingua evalia</title>
    <meta charset="utf-8" />

      <textarea id="code" autofocus rows="20" cols="80">package main

import (
	"fmt"
)

func main() {
	fmt.Println("Hello, World!")
}
</textarea>
      <select id="language">
        {{ range $short, $name := .languages }}
        <option value="{{ $short }}">{{ $name.Name }}</option>
        {{ end }}
      </select>

`
<commit_msg>julia<commit_after>package main

// lingua evalia
//
// try it with `curl -i localhost:8000/run --data-binary @hello-world.go`

import (
	"fmt"
	"html/template"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
)

type Language interface {
	RunFile(f *os.File) (result []byte, err error)
	Name() string
	Extension() string
}

type LanguageGeneral struct {
	name    string
	ext     string
	command string
	args    []string
}

func (l LanguageGeneral) RunFile(f *os.File) ([]byte, error) {
	args := append(l.args, f.Name())
	cmd := exec.Command(l.command, args...)
	return cmd.CombinedOutput()
}

func (l LanguageGeneral) Name() string { return l.name }

func (l LanguageGeneral) Extension() string { return l.ext }

var Go = LanguageGeneral{"Go", "go", "go", []string{"run"}}
var Python = LanguageGeneral{"Python", "py", "python", []string{}}
var Ruby = LanguageGeneral{"Ruby", "rb", "ruby", []string{}}
var JavaScript = LanguageGeneral{"JavaScript", "js", "node", []string{}}
var Haskell = LanguageGeneral{"Haskell", "hs", "runhaskell", []string{}}
var Rust = LanguageGeneral{"Rust", "rs", "./bin/run-rust", []string{}}
var Julia = LanguageGeneral{"Julia", "jl", "julia", []string{}}

var languageMappings = map[string]Language{
	"go":         Go,
	"python":     Python,
	"ruby":       Ruby,
	"javascript": JavaScript,
	"haskell":    Haskell,
	"rust":       Rust,
	"julia":      Julia,
}

func writeCode(code string, extension string) (*os.File, error) {
	// create tmp file
	f, err := os.Create(fmt.Sprintf("/tmp/linguaevalia-%s.%s", extension, extension)) // FIXME: actually create a tmpfile
	if err != nil {
		return f, err
	}
	// write code to it
	_, err = f.Write([]byte(code))
	if err != nil {
		return f, err
	}
	return f, nil
}

func Eval(lang Language, code string) ([]byte, error) {
	// write code to temp file
	f, err := writeCode(code, lang.Extension())
	defer f.Close()
	if err != nil {
		return nil, err
	}
	// `go run` it
	res, err := lang.RunFile(f)
	if err != nil {
		return res, err
	}
	// remove the file
	os.Remove(f.Name())
	// return output
	return res, nil
}

func runCodeHandler(w http.ResponseWriter, r *http.Request) {
	code, err := ioutil.ReadAll(r.Body)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	lang := getLanguage(r)
	res, err := Eval(lang, string(code))
	if err != nil {
		http.Error(w, string(res), http.StatusNotAcceptable)
		return
	}
	w.Write(res)
}

func getLanguage(r *http.Request) Language {
	langName := r.URL.Query().Get("language")
	if langName != "" {
		lang, ok := languageMappings[langName]
		if ok {
			return lang
		}
	}
	return Go
}

func homePageHandler(w http.ResponseWriter, r *http.Request) {
	bindings := map[string]interface{}{
		"languages": languageMappings,
	}
	homePageTemplate.Execute(w, bindings)
}

var homePageTemplate = template.Must(template.New("homepage").Parse(homePageTemplateStr))

func main() {
	addr, port := "localhost", 8000
	fmt.Printf("running on %s:%d\n", addr, port)

	http.HandleFunc("/run", runCodeHandler)
	http.HandleFunc("/", homePageHandler)

	err := http.ListenAndServe(fmt.Sprintf("%s:%d", addr, port), nil)
	if err != nil {
		log.Fatal(err)
	}
}

const homePageTemplateStr = `
<!doctype html>

    <title>lingua evalia</title>
    <meta charset="utf-8" />

      <textarea id="code" autofocus rows="20" cols="80">package main

import (
	"fmt"
)

func main() {
	fmt.Println("Hello, World!")
}
</textarea>
      <select id="language">
        {{ range $short, $name := .languages }}
        <option value="{{ $short }}">{{ $name.Name }}</option>
        {{ end }}
      </select>

`
<|endoftext|>


<commit_before>package api

import (
	"bytes"
	"html/template"
	"net/http"
	"strings"
	"time"

	"github.com/go-pkgz/lcw"

	"github.com/go-chi/chi"
	"github.com/go-chi/render"
	"github.com/go-pkgz/rest"

	"github.com/umputun/feed-master/app/feed"
)

var templates = template.Must(template.ParseGlob("webapp/templates/*"))

// GET /feed/{name} - renders page with list of items
func (s *Server) getFeedPageCtrl(w http.ResponseWriter, r *http.Request) {
	feedName := chi.URLParam(r, "name")

	data, err := s.cache.Get(feedName, func() (lcw.Value, error) {
		items, err := s.Store.Load(feedName, s.Conf.System.MaxTotal)
		if err != nil {
			return nil, err
		}
		tmplData := struct {
			Items       []feed.Item
			Name        string
			Description string
			Link        string
			LastUpdate  time.Time
			Feeds       int
			Version     string
		}{
			Items:       items,
			Name:        s.Conf.Feeds[feedName].Title,
			Description: s.Conf.Feeds[feedName].Description,
			Link:        s.Conf.Feeds[feedName].Link,
			LastUpdate:  items[0].DT,
			Feeds:       len(s.Conf.Feeds),
			Version:     s.Version,
		}

		res := bytes.NewBuffer(nil)
		err = templates.ExecuteTemplate(res, "feed.tmpl", &tmplData)
		return res.Bytes(), err
	})

	if err != nil {
		s.renderErrorPage(w, r, err, 400)
		return
	}

	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	w.WriteHeader(http.StatusOK)
	w.Write(data.([]byte)) //nolint
}

func (s *Server) renderErrorPage(w http.ResponseWriter, r *http.Request, err error, errCode int) {

	tmplData := struct {
		Status int
		Error  string
	}{Status: errCode, Error: err.Error()}

	if err := templates.ExecuteTemplate(w, "error.tmpl", &tmplData); err != nil {
		render.Status(r, http.StatusInternalServerError)
		render.JSON(w, r, rest.JSON{"error": err.Error()})
		return
	}
}

// serves static files from /web
func (s *Server) addFileServer(r chi.Router, path string, root http.FileSystem) {
	fs := http.StripPrefix(path, http.FileServer(root))

	if path != "/" && path[len(path)-1] != '/' {
		r.Get(path, http.RedirectHandler(path+"/", 301).ServeHTTP)
		path += "/"
	}
	path += "*"

	r.Get(path, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// don't show dirs, just serve files
		if strings.HasSuffix(r.URL.Path, "/") {
			http.NotFound(w, r)
			return
		}
		fs.ServeHTTP(w, r)
	}))
}
<commit_msg>fix feeds count<commit_after>package api

import (
	"bytes"
	"html/template"
	"net/http"
	"strings"
	"time"

	"github.com/go-pkgz/lcw"

	"github.com/go-chi/chi"
	"github.com/go-chi/render"
	"github.com/go-pkgz/rest"

	"github.com/umputun/feed-master/app/feed"
)

var templates = template.Must(template.ParseGlob("webapp/templates/*"))

// GET /feed/{name} - renders page with list of items
func (s *Server) getFeedPageCtrl(w http.ResponseWriter, r *http.Request) {
	feedName := chi.URLParam(r, "name")

	data, err := s.cache.Get(feedName, func() (lcw.Value, error) {
		items, err := s.Store.Load(feedName, s.Conf.System.MaxTotal)
		if err != nil {
			return nil, err
		}
		tmplData := struct {
			Items       []feed.Item
			Name        string
			Description string
			Link        string
			LastUpdate  time.Time
			Feeds       int
			Version     string
		}{
			Items:       items,
			Name:        s.Conf.Feeds[feedName].Title,
			Description: s.Conf.Feeds[feedName].Description,
			Link:        s.Conf.Feeds[feedName].Link,
			LastUpdate:  items[0].DT,
			Feeds:       len(s.Conf.Feeds[feedName].Sources),
			Version:     s.Version,
		}

		res := bytes.NewBuffer(nil)
		err = templates.ExecuteTemplate(res, "feed.tmpl", &tmplData)
		return res.Bytes(), err
	})

	if err != nil {
		s.renderErrorPage(w, r, err, 400)
		return
	}

	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	w.WriteHeader(http.StatusOK)
	_, _ = w.Write(data.([]byte)) //nolint
}

func (s *Server) renderErrorPage(w http.ResponseWriter, r *http.Request, err error, errCode int) {

	tmplData := struct {
		Status int
		Error  string
	}{Status: errCode, Error: err.Error()}

	if err := templates.ExecuteTemplate(w, "error.tmpl", &tmplData); err != nil {
		render.Status(r, http.StatusInternalServerError)
		render.JSON(w, r, rest.JSON{"error": err.Error()})
		return
	}
}

// serves static files from /web
func (s *Server) addFileServer(r chi.Router, path string, root http.FileSystem) {
	fs := http.StripPrefix(path, http.FileServer(root))

	if path != "/" && path[len(path)-1] != '/' {
		r.Get(path, http.RedirectHandler(path+"/", 301).ServeHTTP)
		path += "/"
	}
	path += "*"

	r.Get(path, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// don't show dirs, just serve files
		if strings.HasSuffix(r.URL.Path, "/") {
			http.NotFound(w, r)
			return
		}
		fs.ServeHTTP(w, r)
	}))
}
<|endoftext|>


<commit_before>package glob

import (
	"fmt"
	"log"
	"os"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
)

type includeMap map[string]bool

// SpecialRunes identifies the runes that have special meaning in patterns accepted by Glob.
var SpecialRunes = []rune("*?")

// Match returns true if name matches the provided pattern.
// The pattern syntax is identical to that of path.Match, except as follows:
//	'*' does not match dotfiles unless explicitly preceded by a dot.
//	'**/' (globstar) matches 0 or more directories (not including dot directories).
// globstar only has a special meaning if it is the only pattern in its containing element
// (that is, it is either preceded by the beginning of the string or a filepath separator).
// Otherwise, it is treated simply as two sequential globs (which will then be condensed to a single glob).
func Match(pattern, name string) (bool, error) {
	re, err := makeRegexp(pattern)
	if err != nil {
		return false, err
	}
	abs, err := filepath.Abs(name)
	if err != nil {
		return false, err
	}
	return re.MatchString(filepath.ToSlash(abs)), nil
}

// Glob returns the list of filenames which match the provided pattern.
// The syntax is the same as for Match.
func Glob(pattern string) ([]string, error) {
	// Lacking a globstar, use filepath.Glob with tedious dotfile filtering
	if strings.Index(pattern, "**") == -1 {
		patterns := negateDotfiles(pattern)
		m, err := include(filepath.Glob, patterns...)
		return m.list(), err
	}
	return globstar(pattern)
}

// negateDotfiles appends a filter for each glob in pattern that does not explicitly follow a dot character.
// Each filter will be identical to pattern except for an explicit dot before one of the globs.
func negateDotfiles(pattern string) []string {
	patterns := []string{pattern}
	pieces := strings.Split(pattern, "*")
	l := len(pieces)
	for i := 0; i < l-1; i++ {
		p := pieces[i]
		if n := len(p); n != 0 && p[n-1] == '.' {
			continue
		}
		ps := make([]string, l)
		copy(ps, pieces)
		ps[i] += "."
		ps[0] = "!" + ps[0]
		patterns = append(patterns, strings.Join(ps, "*"))
	}
	return patterns
}

// globstar does a filesystem walk rooted at the longest definite prefix of pattern.
// It returns the list of filenames that match the pattern as dictated by the syntax of Match.
func globstar(pattern string) ([]string, error) {
	var s []string
	re, err := makeRegexp(pattern)
	if err != nil {
		return s, err
	}
	filepath.Walk(Prefix(pattern, SpecialRunes), func(path string, info os.FileInfo, _ error) error {
		if info == nil {
			log.Println("Malformed directory", path)
			return filepath.SkipDir
		}
		path, err = filepath.Abs(path)
		if err != nil {
			return nil
		}
		if re.MatchString(filepath.ToSlash(path)) {
			s = append(s, path)
		}
		return nil
	})
	return s, nil
}

// makeRegexp compiles a regular expression that will match a filepath containing a globstar.
// The resulting regex expects matches to have passed through filepath.ToSlash.
func makeRegexp(p string) (*regexp.Regexp, error) {
	fmt.Println(p)
	p, err := filepath.Abs(p)
	if err != nil {
		return nil, err
	}
	p = filepath.ToSlash(p)
	p = regexify(p)
	p = "^" + p + "$"
	return regexp.Compile(p)
}

// regexify converts a pattern string fit for filepath.Match into a pattern for regexp.MatchString.
// The resulting regexp should have the same results as filepath.Match
// (with the differences mentioned in the documentation for Match).
func regexify(p string) string {
	// The worst case pattern is a cycle of globs followed by a file separator.
	// This will replace every 2 characters with 16 characters, so 8*len(p) will suffice.
	s := make([]byte, 8*len(p))
	j := 0
	onseparator := true
	inrange := false
	l := len(p)
	for i := 0; i < l; i++ {
		for inrange && i < l {
			switch p[i] {
			case '\\':
				s[j] = p[i]
				i++
				j++
			case ']':
				inrange = false
			}
			s[j] = p[i]
			i++
			j++
		}
		keepchar := true
		switch p[i] {
		case '\\':
			s[j] = p[i]
			i++
			j++
		case '.':
			s[j] = '\\'
			j++
			if l > i+1 && p[i+1] == '*' {
				s[j] = '.'
				i++
				j++
				goto Suffix
			}
		case '*':
			if !onseparator {
				goto Suffix
			}
			if l > i+3 && p[i:i+3] == "**/" {
				_ = append(s[0:j], []byte("(?:[^./][^/]*/)*")...)
				i += 2
				// Condense sequential globstars
				for l > i+3 && p[i+1:i+4] == "**/" {
					i += 3
				}
				j += 16
			} else {
				_ = append(s[0:j], []byte("(?:[^./][^/]*)?")...)
				// Condense sequential globs
				// (?s cannot easily combine with dotfile-excluding globs)
				for l > i+1 && p[i+1] == '*' {
					i++
				}
				j += 15
			}
			keepchar = false
		case '?':
			goto Suffix
		case '[':
			inrange = true
		case '+', '(', ')', '|', '{', '}', '^', '$':
			s[j] = '\\'
			j++
		}
		if keepchar {
			s[j] = p[i]
			j++
		}
	Separator:
		onseparator = p[i] == '/'
		continue
	Suffix:
		// Condense sequential *s and ?s into a single regex
		n, suffix := wildcardSuffix(p[i:])
		_ = append(s[0:j], []byte("[^/]"+suffix)...)
		i += n - 1
		j += 4 + len(suffix)
		goto Separator
	}
	return string(s[0:j])
}

// wildcardSuffix returns the number of sequential wildcards and an appropriate regexp suffix for their characteristics.
func wildcardSuffix(p string) (skip int, suffix string) {
	var req int
	var star bool
	for _, b := range p {
		switch b {
		case '?':
			req++
			skip++
		case '*':
			star = true
			skip++
		default:
			break
		}
	}
	if req > 1 {
		var comma string
		if star {
			comma = ","
		}
		suffix = "{" + strconv.Itoa(req) + comma + "}"
	} else if req == 1 && star {
		suffix = "+"
	} else if star {
		suffix = "*"
	}
	return
}
<commit_msg>Remove fmt dependency from gulf/glob<commit_after>package glob

import (
	"log"
	"os"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
)

type includeMap map[string]bool

// SpecialRunes identifies the runes that have special meaning in patterns accepted by Glob.
var SpecialRunes = []rune("*?")

// Match returns true if name matches the provided pattern.
// The pattern syntax is identical to that of path.Match, except as follows:
//	'*' does not match dotfiles unless explicitly preceded by a dot.
//	'**/' (globstar) matches 0 or more directories (not including dot directories).
// globstar only has a special meaning if it is the only pattern in its containing element
// (that is, it is either preceded by the beginning of the string or a filepath separator).
// Otherwise, it is treated simply as two sequential globs (which will then be condensed to a single glob).
func Match(pattern, name string) (bool, error) {
	re, err := makeRegexp(pattern)
	if err != nil {
		return false, err
	}
	abs, err := filepath.Abs(name)
	if err != nil {
		return false, err
	}
	return re.MatchString(filepath.ToSlash(abs)), nil
}

// Glob returns the list of filenames which match the provided pattern.
// The syntax is the same as for Match.
func Glob(pattern string) ([]string, error) {
	// Lacking a globstar, use filepath.Glob with tedious dotfile filtering
	if strings.Index(pattern, "**") == -1 {
		patterns := negateDotfiles(pattern)
		m, err := include(filepath.Glob, patterns...)
		return m.list(), err
	}
	return globstar(pattern)
}

// negateDotfiles appends a filter for each glob in pattern that does not explicitly follow a dot character.
// Each filter will be identical to pattern except for an explicit dot before one of the globs.
func negateDotfiles(pattern string) []string {
	patterns := []string{pattern}
	pieces := strings.Split(pattern, "*")
	l := len(pieces)
	for i := 0; i < l-1; i++ {
		p := pieces[i]
		if n := len(p); n != 0 && p[n-1] == '.' {
			continue
		}
		ps := make([]string, l)
		copy(ps, pieces)
		ps[i] += "."
		ps[0] = "!" + ps[0]
		patterns = append(patterns, strings.Join(ps, "*"))
	}
	return patterns
}

// globstar does a filesystem walk rooted at the longest definite prefix of pattern.
// It returns the list of filenames that match the pattern as dictated by the syntax of Match.
func globstar(pattern string) ([]string, error) {
	var s []string
	re, err := makeRegexp(pattern)
	if err != nil {
		return s, err
	}
	filepath.Walk(Prefix(pattern, SpecialRunes), func(path string, info os.FileInfo, _ error) error {
		if info == nil {
			log.Println("Malformed directory", path)
			return filepath.SkipDir
		}
		path, err = filepath.Abs(path)
		if err != nil {
			return nil
		}
		if re.MatchString(filepath.ToSlash(path)) {
			s = append(s, path)
		}
		return nil
	})
	return s, nil
}

// makeRegexp compiles a regular expression that will match a filepath containing a globstar.
// The resulting regex expects matches to have passed through filepath.ToSlash.
func makeRegexp(p string) (*regexp.Regexp, error) {
	p, err := filepath.Abs(p)
	if err != nil {
		return nil, err
	}
	p = filepath.ToSlash(p)
	p = regexify(p)
	p = "^" + p + "$"
	return regexp.Compile(p)
}

// regexify converts a pattern string fit for filepath.Match into a pattern for regexp.MatchString.
// The resulting regexp should have the same results as filepath.Match
// (with the differences mentioned in the documentation for Match).
func regexify(p string) string {
	// The worst case pattern is a cycle of globs followed by a file separator.
	// This will replace every 2 characters with 16 characters, so 8*len(p) will suffice.
	s := make([]byte, 8*len(p))
	j := 0
	onseparator := true
	inrange := false
	l := len(p)
	for i := 0; i < l; i++ {
		for inrange && i < l {
			switch p[i] {
			case '\\':
				s[j] = p[i]
				i++
				j++
			case ']':
				inrange = false
			}
			s[j] = p[i]
			i++
			j++
		}
		keepchar := true
		switch p[i] {
		case '\\':
			s[j] = p[i]
			i++
			j++
		case '.':
			s[j] = '\\'
			j++
			if l > i+1 && p[i+1] == '*' {
				s[j] = '.'
				i++
				j++
				goto Suffix
			}
		case '*':
			if !onseparator {
				goto Suffix
			}
			if l > i+3 && p[i:i+3] == "**/" {
				_ = append(s[0:j], []byte("(?:[^./][^/]*/)*")...)
				i += 2
				// Condense sequential globstars
				for l > i+3 && p[i+1:i+4] == "**/" {
					i += 3
				}
				j += 16
			} else {
				_ = append(s[0:j], []byte("(?:[^./][^/]*)?")...)
				// Condense sequential globs
				// (?s cannot easily combine with dotfile-excluding globs)
				for l > i+1 && p[i+1] == '*' {
					i++
				}
				j += 15
			}
			keepchar = false
		case '?':
			goto Suffix
		case '[':
			inrange = true
		case '+', '(', ')', '|', '{', '}', '^', '$':
			s[j] = '\\'
			j++
		}
		if keepchar {
			s[j] = p[i]
			j++
		}
	Separator:
		onseparator = p[i] == '/'
		continue
	Suffix:
		// Condense sequential *s and ?s into a single regex
		n, suffix := wildcardSuffix(p[i:])
		_ = append(s[0:j], []byte("[^/]"+suffix)...)
		i += n - 1
		j += 4 + len(suffix)
		goto Separator
	}
	return string(s[0:j])
}

// wildcardSuffix returns the number of sequential wildcards and an appropriate regexp suffix for their characteristics.
func wildcardSuffix(p string) (skip int, suffix string) {
	var req int
	var star bool
	for _, b := range p {
		switch b {
		case '?':
			req++
			skip++
		case '*':
			star = true
			skip++
		default:
			break
		}
	}
	if req > 1 {
		var comma string
		if star {
			comma = ","
		}
		suffix = "{" + strconv.Itoa(req) + comma + "}"
	} else if req == 1 && star {
		suffix = "+"
	} else if star {
		suffix = "*"
	}
	return
}
<|endoftext|>


<commit_before>package mpb_test

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"strings"
	"sync/atomic"
	"testing"
	"time"
	"unicode/utf8"

	"github.com/vbauerster/mpb/v7"
	"github.com/vbauerster/mpb/v7/decor"
)

func TestBarCompleted(t *testing.T) {
	p := mpb.New(mpb.WithWidth(80), mpb.WithOutput(ioutil.Discard))
	total := 80
	bar := p.AddBar(int64(total))

	if bar.Completed() {
		t.Error("bar is completed before increment")
	}

	for i := 0; i < total; i++ {
		bar.Increment()
	}

	if !bar.Completed() {
		t.Error("bar isn't completed after increment")
	}

	p.Wait()
}

func TestBarID(t *testing.T) {
	p := mpb.New(mpb.WithWidth(80), mpb.WithOutput(ioutil.Discard))
	total := 100
	wantID := 11
	bar := p.AddBar(int64(total), mpb.BarID(wantID))

	gotID := bar.ID()
	if gotID != wantID {
		t.Errorf("Expected bar id: %d, got %d\n", wantID, gotID)
	}

	bar.Abort(true)
	p.Wait()
}

func TestBarSetRefill(t *testing.T) {
	var buf bytes.Buffer

	p := mpb.New(mpb.WithOutput(&buf), mpb.WithWidth(100))

	total := 100
	till := 30
	refiller := "+"

	bar := p.New(int64(total), mpb.BarStyle().Refiller(refiller), mpb.BarFillerTrim())

	bar.SetRefill(int64(till))
	bar.IncrBy(till)

	for i := 0; i < total-till; i++ {
		bar.Increment()
		time.Sleep(10 * time.Millisecond)
	}

	p.Wait()

	wantBar := fmt.Sprintf("[%s%s]",
		strings.Repeat(refiller, till-1),
		strings.Repeat("=", total-till-1),
	)

	got := string(getLastLine(buf.Bytes()))

	if !strings.Contains(got, wantBar) {
		t.Errorf("Want bar: %q, got bar: %q\n", wantBar, got)
	}
}

func TestBarHas100PercentWithBarRemoveOnComplete(t *testing.T) {
	var buf bytes.Buffer

	p := mpb.New(mpb.WithWidth(80), mpb.WithOutput(&buf))

	total := 50

	bar := p.AddBar(int64(total),
		mpb.BarRemoveOnComplete(),
		mpb.AppendDecorators(decor.Percentage()),
	)

	for i := 0; i < total; i++ {
		bar.Increment()
		time.Sleep(10 * time.Millisecond)
	}

	p.Wait()

	hundred := "100 %"
	if !bytes.Contains(buf.Bytes(), []byte(hundred)) {
		t.Errorf("Bar's buffer does not contain: %q\n", hundred)
	}
}

func TestBarStyle(t *testing.T) {
	var buf bytes.Buffer
	customFormat := "╢▌▌░╟"
	runes := []rune(customFormat)
	total := 80
	p := mpb.New(mpb.WithWidth(total), mpb.WithOutput(&buf))
	bs := mpb.BarStyle()
	bs.Lbound(string(runes[0]))
	bs.Filler(string(runes[1]))
	bs.Tip(string(runes[2]))
	bs.Padding(string(runes[3]))
	bs.Rbound(string(runes[4]))
	bar := p.New(int64(total), bs, mpb.BarFillerTrim())

	for i := 0; i < total; i++ {
		bar.Increment()
		time.Sleep(10 * time.Millisecond)
	}

	p.Wait()

	wantBar := fmt.Sprintf("%s%s%s%s",
		string(runes[0]),
		strings.Repeat(string(runes[1]), total-3),
		string(runes[2]),
		string(runes[4]),
	)
	got := string(getLastLine(buf.Bytes()))

	if !strings.Contains(got, wantBar) {
		t.Errorf("Want bar: %q:%d, got bar: %q:%d\n", wantBar, utf8.RuneCountInString(wantBar), got, utf8.RuneCountInString(got))
	}
}

func TestBarPanicBeforeComplete(t *testing.T) {
	var buf bytes.Buffer
	p := mpb.New(
		mpb.WithWidth(80),
		mpb.WithDebugOutput(&buf),
		mpb.WithOutput(ioutil.Discard),
	)

	total := 100
	panicMsg := "Upps!!!"
	var pCount uint32
	bar := p.AddBar(int64(total),
		mpb.PrependDecorators(panicDecorator(panicMsg,
			func(st decor.Statistics) bool {
				if st.Current >= 42 {
					atomic.AddUint32(&pCount, 1)
					return true
				}
				return false
			},
		)),
	)

	for i := 0; i < total; i++ {
		time.Sleep(10 * time.Millisecond)
		bar.Increment()
	}

	p.Wait()

	if pCount != 1 {
		t.Errorf("Decor called after panic %d times\n", pCount-1)
	}

	barStr := buf.String()
	if !strings.Contains(barStr, panicMsg) {
		t.Errorf("%q doesn't contain %q\n", barStr, panicMsg)
	}
}

func TestBarPanicAfterComplete(t *testing.T) {
	var buf bytes.Buffer
	p := mpb.New(
		mpb.WithWidth(80),
		mpb.WithDebugOutput(&buf),
		mpb.WithOutput(ioutil.Discard),
	)

	total := 100
	panicMsg := "Upps!!!"
	var pCount uint32
	bar := p.AddBar(int64(total),
		mpb.PrependDecorators(panicDecorator(panicMsg,
			func(st decor.Statistics) bool {
				if st.Completed {
					atomic.AddUint32(&pCount, 1)
					return true
				}
				return false
			},
		)),
	)

	for i := 0; i < total; i++ {
		time.Sleep(10 * time.Millisecond)
		bar.Increment()
	}

	p.Wait()

	if pCount > 2 {
		t.Error("Decor called after panic more than 2 times\n")
	}

	barStr := buf.String()
	if !strings.Contains(barStr, panicMsg) {
		t.Errorf("%q doesn't contain %q\n", barStr, panicMsg)
	}
}

func TestDecorStatisticsAvailableWidth(t *testing.T) {
	total := 100
	down := make(chan struct{})
	checkDone := make(chan struct{})
	td1 := func(s decor.Statistics) string {
		if s.AvailableWidth != 80 {
			t.Errorf("expected AvailableWidth %d got %d\n", 80, s.AvailableWidth)
		}
		return fmt.Sprintf("\x1b[31;1;4m%s\x1b[0m", strings.Repeat("0", 20))
	}
	td2 := func(s decor.Statistics) string {
		defer func() {
			select {
			case checkDone <- struct{}{}:
			default:
			}
		}()
		if s.AvailableWidth != 40 {
			t.Errorf("expected AvailableWidth %d got %d\n", 40, s.AvailableWidth)
		}
		return ""
	}
	p := mpb.New(
		mpb.WithWidth(100),
		mpb.WithShutdownNotifier(down),
		mpb.WithOutput(ioutil.Discard),
	)
	bar := p.AddBar(int64(total),
		mpb.BarFillerTrim(),
		mpb.PrependDecorators(
			decor.Name(strings.Repeat("0", 20)),
			decor.Any(td1),
		),
		mpb.AppendDecorators(
			decor.Name(strings.Repeat("0", 20)),
			decor.Any(td2),
		),
	)
	go func() {
		for {
			select {
			case <-checkDone:
				bar.Abort(true)
			case <-down:
				return
			}
		}
	}()
	for !bar.Completed() {
		bar.Increment()
	}
	p.Wait()
}

func panicDecorator(panicMsg string, cond func(decor.Statistics) bool) decor.Decorator {
	return decor.Any(func(st decor.Statistics) string {
		if cond(st) {
			panic(panicMsg)
		}
		return ""
	})
}

func getLastLine(bb []byte) []byte {
	split := bytes.Split(bb, []byte("\n"))
	return split[len(split)-2]
}
<commit_msg>add TestBarAborted<commit_after>package mpb_test

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"strings"
	"sync/atomic"
	"testing"
	"time"
	"unicode/utf8"

	"github.com/vbauerster/mpb/v7"
	"github.com/vbauerster/mpb/v7/decor"
)

func TestBarCompleted(t *testing.T) {
	p := mpb.New(mpb.WithWidth(80), mpb.WithOutput(ioutil.Discard))
	total := 80
	bar := p.AddBar(int64(total))

	if bar.Completed() {
		t.Error("bar is completed before increment")
	}

	for i := 0; i < total; i++ {
		bar.Increment()
	}

	if !bar.Completed() {
		t.Error("bar isn't completed after increment")
	}

	p.Wait()
}

func TestBarAborted(t *testing.T) {
	p := mpb.New(mpb.WithWidth(80), mpb.WithOutput(ioutil.Discard))
	total := 80
	bar := p.AddBar(int64(total))

	if bar.Aborted() {
		t.Fail()
	}

	bar.Abort(false)

	if !bar.Aborted() {
		t.Error("bar isn't aborted after abort call")
	}

	p.Wait()
}

func TestBarID(t *testing.T) {
	p := mpb.New(mpb.WithWidth(80), mpb.WithOutput(ioutil.Discard))
	total := 100
	wantID := 11
	bar := p.AddBar(int64(total), mpb.BarID(wantID))

	gotID := bar.ID()
	if gotID != wantID {
		t.Errorf("Expected bar id: %d, got %d\n", wantID, gotID)
	}

	bar.Abort(true)
	p.Wait()
}

func TestBarSetRefill(t *testing.T) {
	var buf bytes.Buffer

	p := mpb.New(mpb.WithOutput(&buf), mpb.WithWidth(100))

	total := 100
	till := 30
	refiller := "+"

	bar := p.New(int64(total), mpb.BarStyle().Refiller(refiller), mpb.BarFillerTrim())

	bar.SetRefill(int64(till))
	bar.IncrBy(till)

	for i := 0; i < total-till; i++ {
		bar.Increment()
		time.Sleep(10 * time.Millisecond)
	}

	p.Wait()

	wantBar := fmt.Sprintf("[%s%s]",
		strings.Repeat(refiller, till-1),
		strings.Repeat("=", total-till-1),
	)

	got := string(getLastLine(buf.Bytes()))

	if !strings.Contains(got, wantBar) {
		t.Errorf("Want bar: %q, got bar: %q\n", wantBar, got)
	}
}

func TestBarHas100PercentWithBarRemoveOnComplete(t *testing.T) {
	var buf bytes.Buffer

	p := mpb.New(mpb.WithWidth(80), mpb.WithOutput(&buf))

	total := 50

	bar := p.AddBar(int64(total),
		mpb.BarRemoveOnComplete(),
		mpb.AppendDecorators(decor.Percentage()),
	)

	for i := 0; i < total; i++ {
		bar.Increment()
		time.Sleep(10 * time.Millisecond)
	}

	p.Wait()

	hundred := "100 %"
	if !bytes.Contains(buf.Bytes(), []byte(hundred)) {
		t.Errorf("Bar's buffer does not contain: %q\n", hundred)
	}
}

func TestBarStyle(t *testing.T) {
	var buf bytes.Buffer
	customFormat := "╢▌▌░╟"
	runes := []rune(customFormat)
	total := 80
	p := mpb.New(mpb.WithWidth(total), mpb.WithOutput(&buf))
	bs := mpb.BarStyle()
	bs.Lbound(string(runes[0]))
	bs.Filler(string(runes[1]))
	bs.Tip(string(runes[2]))
	bs.Padding(string(runes[3]))
	bs.Rbound(string(runes[4]))
	bar := p.New(int64(total), bs, mpb.BarFillerTrim())

	for i := 0; i < total; i++ {
		bar.Increment()
		time.Sleep(10 * time.Millisecond)
	}

	p.Wait()

	wantBar := fmt.Sprintf("%s%s%s%s",
		string(runes[0]),
		strings.Repeat(string(runes[1]), total-3),
		string(runes[2]),
		string(runes[4]),
	)
	got := string(getLastLine(buf.Bytes()))

	if !strings.Contains(got, wantBar) {
		t.Errorf("Want bar: %q:%d, got bar: %q:%d\n", wantBar, utf8.RuneCountInString(wantBar), got, utf8.RuneCountInString(got))
	}
}

func TestBarPanicBeforeComplete(t *testing.T) {
	var buf bytes.Buffer
	p := mpb.New(
		mpb.WithWidth(80),
		mpb.WithDebugOutput(&buf),
		mpb.WithOutput(ioutil.Discard),
	)

	total := 100
	panicMsg := "Upps!!!"
	var pCount uint32
	bar := p.AddBar(int64(total),
		mpb.PrependDecorators(panicDecorator(panicMsg,
			func(st decor.Statistics) bool {
				if st.Current >= 42 {
					atomic.AddUint32(&pCount, 1)
					return true
				}
				return false
			},
		)),
	)

	for i := 0; i < total; i++ {
		time.Sleep(10 * time.Millisecond)
		bar.Increment()
	}

	p.Wait()

	if pCount != 1 {
		t.Errorf("Decor called after panic %d times\n", pCount-1)
	}

	barStr := buf.String()
	if !strings.Contains(barStr, panicMsg) {
		t.Errorf("%q doesn't contain %q\n", barStr, panicMsg)
	}
}

func TestBarPanicAfterComplete(t *testing.T) {
	var buf bytes.Buffer
	p := mpb.New(
		mpb.WithWidth(80),
		mpb.WithDebugOutput(&buf),
		mpb.WithOutput(ioutil.Discard),
	)

	total := 100
	panicMsg := "Upps!!!"
	var pCount uint32
	bar := p.AddBar(int64(total),
		mpb.PrependDecorators(panicDecorator(panicMsg,
			func(st decor.Statistics) bool {
				if st.Completed {
					atomic.AddUint32(&pCount, 1)
					return true
				}
				return false
			},
		)),
	)

	for i := 0; i < total; i++ {
		time.Sleep(10 * time.Millisecond)
		bar.Increment()
	}

	p.Wait()

	if pCount > 2 {
		t.Error("Decor called after panic more than 2 times\n")
	}

	barStr := buf.String()
	if !strings.Contains(barStr, panicMsg) {
		t.Errorf("%q doesn't contain %q\n", barStr, panicMsg)
	}
}

func TestDecorStatisticsAvailableWidth(t *testing.T) {
	total := 100
	down := make(chan struct{})
	checkDone := make(chan struct{})
	td1 := func(s decor.Statistics) string {
		if s.AvailableWidth != 80 {
			t.Errorf("expected AvailableWidth %d got %d\n", 80, s.AvailableWidth)
		}
		return fmt.Sprintf("\x1b[31;1;4m%s\x1b[0m", strings.Repeat("0", 20))
	}
	td2 := func(s decor.Statistics) string {
		defer func() {
			select {
			case checkDone <- struct{}{}:
			default:
			}
		}()
		if s.AvailableWidth != 40 {
			t.Errorf("expected AvailableWidth %d got %d\n", 40, s.AvailableWidth)
		}
		return ""
	}
	p := mpb.New(
		mpb.WithWidth(100),
		mpb.WithShutdownNotifier(down),
		mpb.WithOutput(ioutil.Discard),
	)
	bar := p.AddBar(int64(total),
		mpb.BarFillerTrim(),
		mpb.PrependDecorators(
			decor.Name(strings.Repeat("0", 20)),
			decor.Any(td1),
		),
		mpb.AppendDecorators(
			decor.Name(strings.Repeat("0", 20)),
			decor.Any(td2),
		),
	)
	go func() {
		for {
			select {
			case <-checkDone:
				bar.Abort(true)
			case <-down:
				return
			}
		}
	}()
	for !bar.Completed() {
		bar.Increment()
	}
	p.Wait()
}

func panicDecorator(panicMsg string, cond func(decor.Statistics) bool) decor.Decorator {
	return decor.Any(func(st decor.Statistics) string {
		if cond(st) {
			panic(panicMsg)
		}
		return ""
	})
}

func getLastLine(bb []byte) []byte {
	split := bytes.Split(bb, []byte("\n"))
	return split[len(split)-2]
}
<|endoftext|>


<commit_before>// Copyright 2013 Alexandre Fiori
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Diameter AVP.  Part of go-diameter.
// http://tools.ietf.org/html/rfc6733#section-4

package base

// AVP represents an AVP header and data.
type AVP struct {
	Code     uint32
	Flags    uint8
	Length   uint32
	VendorId uint32
	Data     Codec
	Message  *Message // Link to parent Message
}

// Data is an interface for AVP Data types.
// These are the supported types and their equivalent native types:
//
// Diameter             Go
// --------             --
// OctetString          string
// DiameterIdentity     string
// Integer32            int32
// Integer64            int64
// Unsigned32           uint32
// Unsigned64           uint64
// Enumerated           []EnumItem
// Grouped              []*AVP
type Data interface{}

// Codec provides an interface for converting Data from network bytes to
// native and vice-versa.
type Codec interface {
	// Write binary data from the network to this AVP Data.
	Put(Data)

	// Encode this AVP Data into binary data.
	Bytes() []byte

	// Returns its internal Data.
	Data() Data

	// Length without padding. Might be diffent from len(Bytes()).
	Length() uint32

	// String represents the AVP data in human readable format.
	String() string
}
<commit_msg>Updated docs<commit_after>// Copyright 2013 Alexandre Fiori
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Diameter AVP.  Part of go-diameter.
// http://tools.ietf.org/html/rfc6733#section-4

package base

// AVP represents an AVP header and data.
type AVP struct {
	Code     uint32
	Flags    uint8
	Length   uint32
	VendorId uint32
	Data     Codec
	Message  *Message // Link to parent Message
}

// Data is an interface for AVP Data types.
type Data interface{}

// Codec provides an interface for converting Data from network bytes to
// native and vice-versa.
type Codec interface {
	// Write binary data from the network to this AVP Data.
	Put(Data)

	// Encode this AVP Data into binary data.
	Bytes() []byte

	// Returns its internal Data.
	Data() Data

	// Length without padding. Might be diffent from len(Bytes()).
	Length() uint32

	// String represents the AVP data in human readable format.
	String() string
}
<|endoftext|>


<commit_before>package terraform

import (
	"bytes"
	"errors"
	"fmt"

	"github.com/hashicorp/terraform/plugin/discovery"
)

// ResourceProvider is an interface that must be implemented by any
// resource provider: the thing that creates and manages the resources in
// a Terraform configuration.
//
// Important implementation note: All returned pointers, such as
// *ResourceConfig, *InstanceState, *InstanceDiff, etc. must not point to
// shared data. Terraform is highly parallel and assumes that this data is safe
// to read/write in parallel so it must be unique references. Note that it is
// safe to return arguments as results, however.
type ResourceProvider interface {
	/*********************************************************************
	* Functions related to the provider
	*********************************************************************/

	// Input is called to ask the provider to ask the user for input
	// for completing the configuration if necesarry.
	//
	// This may or may not be called, so resource provider writers shouldn't
	// rely on this being available to set some default values for validate
	// later. Example of a situation where this wouldn't be called is if
	// the user is not using a TTY.
	Input(UIInput, *ResourceConfig) (*ResourceConfig, error)

	// Validate is called once at the beginning with the raw configuration
	// (no interpolation done) and can return a list of warnings and/or
	// errors.
	//
	// This is called once with the provider configuration only. It may not
	// be called at all if no provider configuration is given.
	//
	// This should not assume that any values of the configurations are valid.
	// The primary use case of this call is to check that required keys are
	// set.
	Validate(*ResourceConfig) ([]string, []error)

	// Configure configures the provider itself with the configuration
	// given. This is useful for setting things like access keys.
	//
	// This won't be called at all if no provider configuration is given.
	//
	// Configure returns an error if it occurred.
	Configure(*ResourceConfig) error

	// Resources returns all the available resource types that this provider
	// knows how to manage.
	Resources() []ResourceType

	// Stop is called when the provider should halt any in-flight actions.
	//
	// This can be used to make a nicer Ctrl-C experience for Terraform.
	// Even if this isn't implemented to do anything (just returns nil),
	// Terraform will still cleanly stop after the currently executing
	// graph node is complete. However, this API can be used to make more
	// efficient halts.
	//
	// Stop doesn't have to and shouldn't block waiting for in-flight actions
	// to complete. It should take any action it wants and return immediately
	// acknowledging it has received the stop request. Terraform core will
	// automatically not make any further API calls to the provider soon
	// after Stop is called (technically exactly once the currently executing
	// graph nodes are complete).
	//
	// The error returned, if non-nil, is assumed to mean that signaling the
	// stop somehow failed and that the user should expect potentially waiting
	// a longer period of time.
	Stop() error

	/*********************************************************************
	* Functions related to individual resources
	*********************************************************************/

	// ValidateResource is called once at the beginning with the raw
	// configuration (no interpolation done) and can return a list of warnings
	// and/or errors.
	//
	// This is called once per resource.
	//
	// This should not assume any of the values in the resource configuration
	// are valid since it is possible they have to be interpolated still.
	// The primary use case of this call is to check that the required keys
	// are set and that the general structure is correct.
	ValidateResource(string, *ResourceConfig) ([]string, []error)

	// Apply applies a diff to a specific resource and returns the new
	// resource state along with an error.
	//
	// If the resource state given has an empty ID, then a new resource
	// is expected to be created.
	Apply(
		*InstanceInfo,
		*InstanceState,
		*InstanceDiff) (*InstanceState, error)

	// Diff diffs a resource versus a desired state and returns
	// a diff.
	Diff(
		*InstanceInfo,
		*InstanceState,
		*ResourceConfig) (*InstanceDiff, error)

	// Refresh refreshes a resource and updates all of its attributes
	// with the latest information.
	Refresh(*InstanceInfo, *InstanceState) (*InstanceState, error)

	/*********************************************************************
	* Functions related to importing
	*********************************************************************/

	// ImportState requests that the given resource be imported.
	//
	// The returned InstanceState only requires ID be set. Importing
	// will always call Refresh after the state to complete it.
	//
	// IMPORTANT: InstanceState doesn't have the resource type attached
	// to it. A type must be specified on the state via the Ephemeral
	// field on the state.
	//
	// This function can return multiple states. Normally, an import
	// will map 1:1 to a physical resource. However, some resources map
	// to multiple. For example, an AWS security group may contain many rules.
	// Each rule is represented by a separate resource in Terraform,
	// therefore multiple states are returned.
	ImportState(*InstanceInfo, string) ([]*InstanceState, error)

	/*********************************************************************
	* Functions related to data resources
	*********************************************************************/

	// ValidateDataSource is called once at the beginning with the raw
	// configuration (no interpolation done) and can return a list of warnings
	// and/or errors.
	//
	// This is called once per data source instance.
	//
	// This should not assume any of the values in the resource configuration
	// are valid since it is possible they have to be interpolated still.
	// The primary use case of this call is to check that the required keys
	// are set and that the general structure is correct.
	ValidateDataSource(string, *ResourceConfig) ([]string, []error)

	// DataSources returns all of the available data sources that this
	// provider implements.
	DataSources() []DataSource

	// ReadDataDiff produces a diff that represents the state that will
	// be produced when the given data source is read using a later call
	// to ReadDataApply.
	ReadDataDiff(*InstanceInfo, *ResourceConfig) (*InstanceDiff, error)

	// ReadDataApply initializes a data instance using the configuration
	// in a diff produced by ReadDataDiff.
	ReadDataApply(*InstanceInfo, *InstanceDiff) (*InstanceState, error)
}

// ResourceProviderCloser is an interface that providers that can close
// connections that aren't needed anymore must implement.
type ResourceProviderCloser interface {
	Close() error
}

// ResourceType is a type of resource that a resource provider can manage.
type ResourceType struct {
	Name       string // Name of the resource, example "instance" (no provider prefix)
	Importable bool   // Whether this resource supports importing
}

// DataSource is a data source that a resource provider implements.
type DataSource struct {
	Name string
}

// ResourceProviderResolver is an interface implemented by objects that are
// able to resolve a given set of resource provider version constraints
// into ResourceProviderFactory callbacks.
type ResourceProviderResolver interface {
	// Given a constraint map, return a ResourceProviderFactory for each
	// requested provider. If some or all of the constraints cannot be
	// satisfied, return a non-nil slice of errors describing the problems.
	ResolveProviders(reqd discovery.PluginRequirements) (map[string]ResourceProviderFactory, []error)
}

// ResourceProviderResolverFunc wraps a callback function and turns it into
// a ResourceProviderResolver implementation, for convenience in situations
// where a function and its associated closure are sufficient as a resolver
// implementation.
type ResourceProviderResolverFunc func(reqd discovery.PluginRequirements) (map[string]ResourceProviderFactory, []error)

// ResolveProviders implements ResourceProviderResolver by calling the
// wrapped function.
func (f ResourceProviderResolverFunc) ResolveProviders(reqd discovery.PluginRequirements) (map[string]ResourceProviderFactory, []error) {
	return f(reqd)
}

// ResourceProviderResolverFixed returns a ResourceProviderResolver that
// has a fixed set of provider factories provided by the caller. The returned
// resolver ignores version constraints entirely and just returns the given
// factory for each requested provider name.
//
// This function is primarily used in tests, to provide mock providers or
// in-process providers under test.
func ResourceProviderResolverFixed(factories map[string]ResourceProviderFactory) ResourceProviderResolver {
	return ResourceProviderResolverFunc(func(reqd discovery.PluginRequirements) (map[string]ResourceProviderFactory, []error) {
		ret := make(map[string]ResourceProviderFactory, len(reqd))
		var errs []error
		for name := range reqd {
			if factory, exists := factories[name]; exists {
				ret[name] = factory
			} else {
				errs = append(errs, fmt.Errorf("provider %q is not available", name))
			}
		}
		return ret, errs
	})
}

// ResourceProviderFactory is a function type that creates a new instance
// of a resource provider.
type ResourceProviderFactory func() (ResourceProvider, error)

// ResourceProviderFactoryFixed is a helper that creates a
// ResourceProviderFactory that just returns some fixed provider.
func ResourceProviderFactoryFixed(p ResourceProvider) ResourceProviderFactory {
	return func() (ResourceProvider, error) {
		return p, nil
	}
}

func ProviderHasResource(p ResourceProvider, n string) bool {
	for _, rt := range p.Resources() {
		if rt.Name == n {
			return true
		}
	}

	return false
}

func ProviderHasDataSource(p ResourceProvider, n string) bool {
	for _, rt := range p.DataSources() {
		if rt.Name == n {
			return true
		}
	}

	return false
}

// resourceProviderFactories matches available plugins to the given version
// requirements to produce a map of compatible provider plugins if possible,
// or an error if the currently-available plugins are insufficient.
//
// This should be called only with configurations that have passed calls
// to config.Validate(), which ensures that all of the given version
// constraints are valid. It will panic if any invalid constraints are present.
func resourceProviderFactories(resolver ResourceProviderResolver, reqd discovery.PluginRequirements) (map[string]ResourceProviderFactory, error) {
	ret, errs := resolver.ResolveProviders(reqd)
	if errs != nil {
		errBuf := &bytes.Buffer{}
		errBuf.WriteString("Can't satisfy provider requirements with currently-installed plugins:\n\n")
		for _, err := range errs {
			fmt.Fprintf(errBuf, "* %s\n", err)
		}
		errBuf.WriteString("\nRun 'terraform init' to install the necessary provider plugins.\n")
		return nil, errors.New(errBuf.String())
	}

	return ret, nil
}
<commit_msg>have the local backend provide a plugin init msg<commit_after>package terraform

import (
	"fmt"

	multierror "github.com/hashicorp/go-multierror"
	"github.com/hashicorp/terraform/plugin/discovery"
)

// ResourceProvider is an interface that must be implemented by any
// resource provider: the thing that creates and manages the resources in
// a Terraform configuration.
//
// Important implementation note: All returned pointers, such as
// *ResourceConfig, *InstanceState, *InstanceDiff, etc. must not point to
// shared data. Terraform is highly parallel and assumes that this data is safe
// to read/write in parallel so it must be unique references. Note that it is
// safe to return arguments as results, however.
type ResourceProvider interface {
	/*********************************************************************
	* Functions related to the provider
	*********************************************************************/

	// Input is called to ask the provider to ask the user for input
	// for completing the configuration if necesarry.
	//
	// This may or may not be called, so resource provider writers shouldn't
	// rely on this being available to set some default values for validate
	// later. Example of a situation where this wouldn't be called is if
	// the user is not using a TTY.
	Input(UIInput, *ResourceConfig) (*ResourceConfig, error)

	// Validate is called once at the beginning with the raw configuration
	// (no interpolation done) and can return a list of warnings and/or
	// errors.
	//
	// This is called once with the provider configuration only. It may not
	// be called at all if no provider configuration is given.
	//
	// This should not assume that any values of the configurations are valid.
	// The primary use case of this call is to check that required keys are
	// set.
	Validate(*ResourceConfig) ([]string, []error)

	// Configure configures the provider itself with the configuration
	// given. This is useful for setting things like access keys.
	//
	// This won't be called at all if no provider configuration is given.
	//
	// Configure returns an error if it occurred.
	Configure(*ResourceConfig) error

	// Resources returns all the available resource types that this provider
	// knows how to manage.
	Resources() []ResourceType

	// Stop is called when the provider should halt any in-flight actions.
	//
	// This can be used to make a nicer Ctrl-C experience for Terraform.
	// Even if this isn't implemented to do anything (just returns nil),
	// Terraform will still cleanly stop after the currently executing
	// graph node is complete. However, this API can be used to make more
	// efficient halts.
	//
	// Stop doesn't have to and shouldn't block waiting for in-flight actions
	// to complete. It should take any action it wants and return immediately
	// acknowledging it has received the stop request. Terraform core will
	// automatically not make any further API calls to the provider soon
	// after Stop is called (technically exactly once the currently executing
	// graph nodes are complete).
	//
	// The error returned, if non-nil, is assumed to mean that signaling the
	// stop somehow failed and that the user should expect potentially waiting
	// a longer period of time.
	Stop() error

	/*********************************************************************
	* Functions related to individual resources
	*********************************************************************/

	// ValidateResource is called once at the beginning with the raw
	// configuration (no interpolation done) and can return a list of warnings
	// and/or errors.
	//
	// This is called once per resource.
	//
	// This should not assume any of the values in the resource configuration
	// are valid since it is possible they have to be interpolated still.
	// The primary use case of this call is to check that the required keys
	// are set and that the general structure is correct.
	ValidateResource(string, *ResourceConfig) ([]string, []error)

	// Apply applies a diff to a specific resource and returns the new
	// resource state along with an error.
	//
	// If the resource state given has an empty ID, then a new resource
	// is expected to be created.
	Apply(
		*InstanceInfo,
		*InstanceState,
		*InstanceDiff) (*InstanceState, error)

	// Diff diffs a resource versus a desired state and returns
	// a diff.
	Diff(
		*InstanceInfo,
		*InstanceState,
		*ResourceConfig) (*InstanceDiff, error)

	// Refresh refreshes a resource and updates all of its attributes
	// with the latest information.
	Refresh(*InstanceInfo, *InstanceState) (*InstanceState, error)

	/*********************************************************************
	* Functions related to importing
	*********************************************************************/

	// ImportState requests that the given resource be imported.
	//
	// The returned InstanceState only requires ID be set. Importing
	// will always call Refresh after the state to complete it.
	//
	// IMPORTANT: InstanceState doesn't have the resource type attached
	// to it. A type must be specified on the state via the Ephemeral
	// field on the state.
	//
	// This function can return multiple states. Normally, an import
	// will map 1:1 to a physical resource. However, some resources map
	// to multiple. For example, an AWS security group may contain many rules.
	// Each rule is represented by a separate resource in Terraform,
	// therefore multiple states are returned.
	ImportState(*InstanceInfo, string) ([]*InstanceState, error)

	/*********************************************************************
	* Functions related to data resources
	*********************************************************************/

	// ValidateDataSource is called once at the beginning with the raw
	// configuration (no interpolation done) and can return a list of warnings
	// and/or errors.
	//
	// This is called once per data source instance.
	//
	// This should not assume any of the values in the resource configuration
	// are valid since it is possible they have to be interpolated still.
	// The primary use case of this call is to check that the required keys
	// are set and that the general structure is correct.
	ValidateDataSource(string, *ResourceConfig) ([]string, []error)

	// DataSources returns all of the available data sources that this
	// provider implements.
	DataSources() []DataSource

	// ReadDataDiff produces a diff that represents the state that will
	// be produced when the given data source is read using a later call
	// to ReadDataApply.
	ReadDataDiff(*InstanceInfo, *ResourceConfig) (*InstanceDiff, error)

	// ReadDataApply initializes a data instance using the configuration
	// in a diff produced by ReadDataDiff.
	ReadDataApply(*InstanceInfo, *InstanceDiff) (*InstanceState, error)
}

// ResourceProviderError may be returned when creating a Context if the
// required providers cannot be satisfied. This error can then be used to
// format a more useful message for the user.
type ResourceProviderError struct {
	Errors []error
}

func (e *ResourceProviderError) Error() string {
	// use multierror to format the default output
	return multierror.Append(nil, e.Errors...).Error()
}

// ResourceProviderCloser is an interface that providers that can close
// connections that aren't needed anymore must implement.
type ResourceProviderCloser interface {
	Close() error
}

// ResourceType is a type of resource that a resource provider can manage.
type ResourceType struct {
	Name       string // Name of the resource, example "instance" (no provider prefix)
	Importable bool   // Whether this resource supports importing
}

// DataSource is a data source that a resource provider implements.
type DataSource struct {
	Name string
}

// ResourceProviderResolver is an interface implemented by objects that are
// able to resolve a given set of resource provider version constraints
// into ResourceProviderFactory callbacks.
type ResourceProviderResolver interface {
	// Given a constraint map, return a ResourceProviderFactory for each
	// requested provider. If some or all of the constraints cannot be
	// satisfied, return a non-nil slice of errors describing the problems.
	ResolveProviders(reqd discovery.PluginRequirements) (map[string]ResourceProviderFactory, []error)
}

// ResourceProviderResolverFunc wraps a callback function and turns it into
// a ResourceProviderResolver implementation, for convenience in situations
// where a function and its associated closure are sufficient as a resolver
// implementation.
type ResourceProviderResolverFunc func(reqd discovery.PluginRequirements) (map[string]ResourceProviderFactory, []error)

// ResolveProviders implements ResourceProviderResolver by calling the
// wrapped function.
func (f ResourceProviderResolverFunc) ResolveProviders(reqd discovery.PluginRequirements) (map[string]ResourceProviderFactory, []error) {
	return f(reqd)
}

// ResourceProviderResolverFixed returns a ResourceProviderResolver that
// has a fixed set of provider factories provided by the caller. The returned
// resolver ignores version constraints entirely and just returns the given
// factory for each requested provider name.
//
// This function is primarily used in tests, to provide mock providers or
// in-process providers under test.
func ResourceProviderResolverFixed(factories map[string]ResourceProviderFactory) ResourceProviderResolver {
	return ResourceProviderResolverFunc(func(reqd discovery.PluginRequirements) (map[string]ResourceProviderFactory, []error) {
		ret := make(map[string]ResourceProviderFactory, len(reqd))
		var errs []error
		for name := range reqd {
			if factory, exists := factories[name]; exists {
				ret[name] = factory
			} else {
				errs = append(errs, fmt.Errorf("provider %q is not available", name))
			}
		}
		return ret, errs
	})
}

// ResourceProviderFactory is a function type that creates a new instance
// of a resource provider.
type ResourceProviderFactory func() (ResourceProvider, error)

// ResourceProviderFactoryFixed is a helper that creates a
// ResourceProviderFactory that just returns some fixed provider.
func ResourceProviderFactoryFixed(p ResourceProvider) ResourceProviderFactory {
	return func() (ResourceProvider, error) {
		return p, nil
	}
}

func ProviderHasResource(p ResourceProvider, n string) bool {
	for _, rt := range p.Resources() {
		if rt.Name == n {
			return true
		}
	}

	return false
}

func ProviderHasDataSource(p ResourceProvider, n string) bool {
	for _, rt := range p.DataSources() {
		if rt.Name == n {
			return true
		}
	}

	return false
}

// resourceProviderFactories matches available plugins to the given version
// requirements to produce a map of compatible provider plugins if possible,
// or an error if the currently-available plugins are insufficient.
//
// This should be called only with configurations that have passed calls
// to config.Validate(), which ensures that all of the given version
// constraints are valid. It will panic if any invalid constraints are present.
func resourceProviderFactories(resolver ResourceProviderResolver, reqd discovery.PluginRequirements) (map[string]ResourceProviderFactory, error) {
	ret, errs := resolver.ResolveProviders(reqd)
	if errs != nil {
		return nil, &ResourceProviderError{
			Errors: errs,
		}
	}

	return ret, nil
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"go/token"
	"go/types"
	"log"
	"os"
	"sort"
	"strings"

	"github.com/kisielk/gotool"
	"golang.org/x/tools/go/loader"
)

var exitCode int

var (
	fConstants bool
	fFunctions bool
	fTypes     bool
	fVariables bool
)

func init() {
	flag.BoolVar(&fConstants, "c", true, "Report unused constants")
	flag.BoolVar(&fFunctions, "f", true, "Report unused functions and methods")
	flag.BoolVar(&fTypes, "t", true, "Report unused types")
	flag.BoolVar(&fVariables, "v", true, "Report unused variables")
}

func main() {
	flag.Parse()
	// FIXME check flag.NArgs
	paths := gotool.ImportPaths([]string{flag.Arg(0)})
	conf := loader.Config{AllowErrors: true}
	for _, path := range paths {
		conf.ImportWithTests(path)
	}
	lprog, err := conf.Load()
	if err != nil {
		log.Fatal(err)
	}

	defs := map[types.Object]bool{}
	var interfaces []*types.Interface
	for _, path := range paths {
		pkg := lprog.Package(path)
		if pkg == nil {
			log.Println("Couldn't load package", path)
			continue
		}
		for _, obj := range pkg.Defs {
			if obj == nil {
				continue
			}
			if obj, ok := obj.(*types.Var); ok {
				if typ, ok := obj.Type().(*types.Interface); ok {
					interfaces = append(interfaces, typ)
				}
			}
			if obj, ok := obj.(*types.TypeName); ok {
				if typ, ok := obj.Type().Underlying().(*types.Interface); ok {
					interfaces = append(interfaces, typ)
				}
			}
			if isVariable(obj) && !isPkgScope(obj) && !isField(obj) {
				// Skip variables that aren't package variables or struct fields
				continue
			}
			if _, ok := obj.(*types.PkgName); ok {
				continue
			}
			defs[obj] = false
		}
		for _, obj := range pkg.Uses {
			defs[obj] = true
		}
	}
	var reports Reports
	for obj, used := range defs {
		f := lprog.Fset.Position(obj.Pos()).Filename
		if strings.HasSuffix(f, "_test.go") {
			continue
		}
		if obj.Pkg() == nil {
			continue
		}
		// TODO methods + reflection
		if !checkFlags(obj) {
			continue
		}
		if used {
			continue
		}
		if obj.Name() == "_" {
			continue
		}
		if obj.Exported() && (isPkgScope(obj) || isMethod(obj) || isField(obj)) {
			f := lprog.Fset.Position(obj.Pos()).Filename
			if !strings.HasSuffix(f, "_test.go") || strings.HasPrefix(obj.Name(), "Test") || strings.HasPrefix(obj.Name(), "Benchmark") {
				continue
			}
		}
		if isMain(obj) {
			continue
		}
		if isFunction(obj) && !isMethod(obj) && obj.Name() == "init" {
			continue
		}
		if isMethod(obj) && implements(obj, interfaces) {
			continue
		}
		reports = append(reports, Report{obj.Pos(), obj.Name()})
	}
	sort.Sort(reports)
	for _, report := range reports {
		fmt.Printf("%s: %s is unused\n", lprog.Fset.Position(report.pos), report.name)
	}

	os.Exit(exitCode)
}

func implements(obj types.Object, ifaces []*types.Interface) bool {
	recvType := obj.(*types.Func).Type().(*types.Signature).Recv().Type()
	for _, iface := range ifaces {
		if !types.Implements(recvType, iface) {
			continue
		}
		n := iface.NumMethods()
		for i := 0; i < n; i++ {
			if iface.Method(i).Name() == obj.Name() {
				return true
			}
		}
	}
	return false
}

func isPkgScope(obj types.Object) bool {
	return obj.Parent() == obj.Pkg().Scope()
}

func isMain(obj types.Object) bool {
	if obj.Pkg().Name() != "main" {
		return false
	}
	if obj.Name() != "main" {
		return false
	}
	if !isPkgScope(obj) {
		return false
	}
	if !isFunction(obj) {
		return false
	}
	if isMethod(obj) {
		return false
	}
	return true
}

func isFunction(obj types.Object) bool {
	_, ok := obj.(*types.Func)
	return ok
}

func isMethod(obj types.Object) bool {
	if !isFunction(obj) {
		return false
	}
	return obj.(*types.Func).Type().(*types.Signature).Recv() != nil
}

func isVariable(obj types.Object) bool {
	_, ok := obj.(*types.Var)
	return ok
}

func isConstant(obj types.Object) bool {
	_, ok := obj.(*types.Const)
	return ok
}

func isType(obj types.Object) bool {
	_, ok := obj.(*types.TypeName)
	return ok
}

func isField(obj types.Object) bool {
	if obj, ok := obj.(*types.Var); ok && obj.IsField() {
		return true
	}
	return false
}

func checkFlags(obj types.Object) bool {
	if isFunction(obj) && !fFunctions {
		return false
	}
	if isVariable(obj) && !fVariables {
		return false
	}
	if isConstant(obj) && !fConstants {
		return false
	}
	if isType(obj) && !fTypes {
		return false
	}
	return true
}

type Report struct {
	pos  token.Pos
	name string
}
type Reports []Report

func (l Reports) Len() int           { return len(l) }
func (l Reports) Less(i, j int) bool { return l[i].pos < l[j].pos }
func (l Reports) Swap(i, j int)      { l[i], l[j] = l[j], l[i] }
<commit_msg>Don't allow errors<commit_after>package main

import (
	"flag"
	"fmt"
	"go/token"
	"go/types"
	"log"
	"os"
	"sort"
	"strings"

	"github.com/kisielk/gotool"
	"golang.org/x/tools/go/loader"
)

var exitCode int

var (
	fConstants bool
	fFunctions bool
	fTypes     bool
	fVariables bool
)

func init() {
	flag.BoolVar(&fConstants, "c", true, "Report unused constants")
	flag.BoolVar(&fFunctions, "f", true, "Report unused functions and methods")
	flag.BoolVar(&fTypes, "t", true, "Report unused types")
	flag.BoolVar(&fVariables, "v", true, "Report unused variables")
}

func main() {
	flag.Parse()
	// FIXME check flag.NArgs
	paths := gotool.ImportPaths([]string{flag.Arg(0)})
	conf := loader.Config{}
	for _, path := range paths {
		conf.ImportWithTests(path)
	}
	lprog, err := conf.Load()
	if err != nil {
		log.Fatal(err)
	}

	defs := map[types.Object]bool{}
	var interfaces []*types.Interface
	for _, path := range paths {
		pkg := lprog.Package(path)
		if pkg == nil {
			log.Println("Couldn't load package", path)
			continue
		}
		for _, obj := range pkg.Defs {
			if obj == nil {
				continue
			}
			if obj, ok := obj.(*types.Var); ok {
				if typ, ok := obj.Type().(*types.Interface); ok {
					interfaces = append(interfaces, typ)
				}
			}
			if obj, ok := obj.(*types.TypeName); ok {
				if typ, ok := obj.Type().Underlying().(*types.Interface); ok {
					interfaces = append(interfaces, typ)
				}
			}
			if isVariable(obj) && !isPkgScope(obj) && !isField(obj) {
				// Skip variables that aren't package variables or struct fields
				continue
			}
			if _, ok := obj.(*types.PkgName); ok {
				continue
			}
			defs[obj] = false
		}
		for _, obj := range pkg.Uses {
			defs[obj] = true
		}
	}
	var reports Reports
	for obj, used := range defs {
		f := lprog.Fset.Position(obj.Pos()).Filename
		if strings.HasSuffix(f, "_test.go") {
			continue
		}
		if obj.Pkg() == nil {
			continue
		}
		// TODO methods + reflection
		if !checkFlags(obj) {
			continue
		}
		if used {
			continue
		}
		if obj.Name() == "_" {
			continue
		}
		if obj.Exported() && (isPkgScope(obj) || isMethod(obj) || isField(obj)) {
			f := lprog.Fset.Position(obj.Pos()).Filename
			if !strings.HasSuffix(f, "_test.go") || strings.HasPrefix(obj.Name(), "Test") || strings.HasPrefix(obj.Name(), "Benchmark") {
				continue
			}
		}
		if isMain(obj) {
			continue
		}
		if isFunction(obj) && !isMethod(obj) && obj.Name() == "init" {
			continue
		}
		if isMethod(obj) && implements(obj, interfaces) {
			continue
		}
		reports = append(reports, Report{obj.Pos(), obj.Name()})
	}
	sort.Sort(reports)
	for _, report := range reports {
		fmt.Printf("%s: %s is unused\n", lprog.Fset.Position(report.pos), report.name)
	}

	os.Exit(exitCode)
}

func implements(obj types.Object, ifaces []*types.Interface) bool {
	recvType := obj.(*types.Func).Type().(*types.Signature).Recv().Type()
	for _, iface := range ifaces {
		if !types.Implements(recvType, iface) {
			continue
		}
		n := iface.NumMethods()
		for i := 0; i < n; i++ {
			if iface.Method(i).Name() == obj.Name() {
				return true
			}
		}
	}
	return false
}

func isPkgScope(obj types.Object) bool {
	return obj.Parent() == obj.Pkg().Scope()
}

func isMain(obj types.Object) bool {
	if obj.Pkg().Name() != "main" {
		return false
	}
	if obj.Name() != "main" {
		return false
	}
	if !isPkgScope(obj) {
		return false
	}
	if !isFunction(obj) {
		return false
	}
	if isMethod(obj) {
		return false
	}
	return true
}

func isFunction(obj types.Object) bool {
	_, ok := obj.(*types.Func)
	return ok
}

func isMethod(obj types.Object) bool {
	if !isFunction(obj) {
		return false
	}
	return obj.(*types.Func).Type().(*types.Signature).Recv() != nil
}

func isVariable(obj types.Object) bool {
	_, ok := obj.(*types.Var)
	return ok
}

func isConstant(obj types.Object) bool {
	_, ok := obj.(*types.Const)
	return ok
}

func isType(obj types.Object) bool {
	_, ok := obj.(*types.TypeName)
	return ok
}

func isField(obj types.Object) bool {
	if obj, ok := obj.(*types.Var); ok && obj.IsField() {
		return true
	}
	return false
}

func checkFlags(obj types.Object) bool {
	if isFunction(obj) && !fFunctions {
		return false
	}
	if isVariable(obj) && !fVariables {
		return false
	}
	if isConstant(obj) && !fConstants {
		return false
	}
	if isType(obj) && !fTypes {
		return false
	}
	return true
}

type Report struct {
	pos  token.Pos
	name string
}
type Reports []Report

func (l Reports) Len() int           { return len(l) }
func (l Reports) Less(i, j int) bool { return l[i].pos < l[j].pos }
func (l Reports) Swap(i, j int)      { l[i], l[j] = l[j], l[i] }
<|endoftext|>


<commit_before>// Copyright 2009 The Ninep Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package nullfs

import (
	"io"
	"net"
	"os"
	"testing"

	"github.com/lionkov/ninep"
	"github.com/lionkov/ninep/clnt"
)

// It's recommended not to have a helper. But this is so much boiler plate.
func setup(failf func(...interface{})) (*clnt.Clnt, *clnt.Fid) {
	f := new(NullFS)
	f.Dotu = false
	f.Id = "ufs"
	f.Debuglevel = 0
	if !f.Start(f) {
		failf("Can't happen: Starting the server failed")
	}

	l, err := net.Listen("unix", "")
	if err != nil {
		failf("net.Listen: want nil, got %v", err)
	}

	go func() {
		if err = f.StartListener(l); err != nil {
			failf("Can not start listener: %v", err)
		}
	}()

	var conn net.Conn
	if conn, err = net.Dial("unix", l.Addr().String()); err != nil {
		failf("%v", err)
	}

	user := ninep.OsUsers.Uid2User(os.Geteuid())
	clnt := clnt.NewClnt(conn, 8192, false)

	rootfid, err := clnt.Attach(nil, user, "/")
	if err != nil {
		failf("Attach: %v", err)
	}

	return clnt, rootfid
}

func TestAttach(t *testing.T) {
	setup(t.Fatal)
}
func TestAttachOpenReaddir(t *testing.T) {
	var err error
	clnt, rootfid := setup(t.Fatal)

	dirfid := clnt.FidAlloc()
	if _, err = clnt.Walk(rootfid, dirfid, []string{}); err != nil {
		t.Fatalf("%v", err)
	}

	if err = clnt.Open(dirfid, 0); err != nil {
		t.Fatalf("%v", err)
	}
	var b []byte
	if b, err = clnt.Read(dirfid, 0, 64*1024); err != nil {
		t.Fatalf("%v", err)
	}
	var i, amt int
	var offset uint64
	err = nil
	for err == nil {
		if b, err = clnt.Read(dirfid, offset, 64*1024); err != nil {
			t.Fatalf("%v", err)
		}

		if len(b) == 0 {
			break
		}
		for b != nil && len(b) > 0 {
			if _, b, amt, err = ninep.UnpackDir(b, true); err != nil {
				t.Errorf("UnpackDir returns %v", err)
				break
			} else {
				i++
				offset += uint64(amt)
			}
		}
	}
	if i != len(dirQids) {
		t.Fatalf("Reading: got %d entries, wanted %d, err %v", i, len(dirQids), err)
	}

	t.Logf("-----------------------------> Alternate form, using readdir and File")
	// Alternate form, using readdir and File
	dirfile, err := clnt.FOpen(".", ninep.OREAD)
	if err != nil {
		t.Fatalf("%v", err)
	}
	i, amt, offset = 0, 0, 0
	err = nil

	for err == nil {
		d, err := dirfile.Readdir(64)
		if err != nil && err != io.EOF {
			t.Errorf("%v", err)
		}

		if len(d) == 0 {
			break
		}
		i += len(d)
		if i >= len(dirQids) {
			break
		}
	}
	if i != len(dirQids)-1 {
		t.Fatalf("Readdir: got %d entries, wanted %d", i, len(dirQids)-1)
	}
}

func TestNull(t *testing.T) {
	var err error
	clnt, rootfid := setup(t.Fatal)

	d := clnt.FidAlloc()
	if _, err = clnt.Walk(rootfid, d, []string{"null"}); err != nil {
		t.Fatalf("%v", err)
	}

	if err = clnt.Open(d, 0); err != nil {
		t.Fatalf("%v", err)
	}

	var b []byte
	if b, err = clnt.Read(d, 0, 64*1024); err != nil {
		t.Fatalf("%v", err)
	}
	if len(b) > 0 {
		t.Fatalf("Read of null: want 0, got %d bytes", len(b))
	}

	st, err := clnt.Stat(d)
	if err != nil {
		t.Fatalf("%v", err)
	}

	if st.Name != "null" {
		t.Fatalf("Stat: want 'null', got %v", st.Name)
	}
	if st.Mode != 0666 {
		t.Fatalf("Stat: want 0777, got %o", st.Mode)
	}

}

func TestZero(t *testing.T) {
	var err error
	clnt, rootfid := setup(t.Fatal)

	d := clnt.FidAlloc()
	if _, err = clnt.Walk(rootfid, d, []string{"zero"}); err != nil {
		t.Fatalf("%v", err)
	}

	if err = clnt.Open(d, 0); err != nil {
		t.Fatalf("%v", err)
	}

	var b []byte
	if b, err = clnt.Read(d, 0, 64*1024); err != nil {
		t.Fatalf("%v", err)
	}
	if len(b) == 0 {
		t.Fatalf("Read of null: want > 0, got %d bytes", len(b))
	}

}

func BenchmarkNull(b *testing.B) {
	clnt, rootfid := setup(b.Fatal)
	d := clnt.FidAlloc()
	if _, err := clnt.Walk(rootfid, d, []string{"null"}); err != nil {
		b.Fatalf("%v", err)
	}

	if err := clnt.Open(d, 0); err != nil {
		b.Fatalf("%v", err)
	}

	for i := 0; i < b.N; i++ {
		if _, err := clnt.Read(d, 0, 64*1024); err != nil {
			b.Fatalf("%v", err)
		}
	}

}

func BenchmarkZero4k(b *testing.B) {
	clnt, rootfid := setup(b.Fatal)
	d := clnt.FidAlloc()
	if _, err := clnt.Walk(rootfid, d, []string{"zero"}); err != nil {
		b.Fatalf("%v", err)
	}

	if err := clnt.Open(d, 0); err != nil {
		b.Fatalf("%v", err)
	}

	for i := 0; i < b.N; i++ {
		if _, err := clnt.Read(d, 0, 4*1024); err != nil {
			b.Fatalf("%v", err)
		}
	}

}

/*
func BenchmarkRootWalk(b *testing.B) {
	nullfs := new(nullfs.Nullfs)
	nullfs.Dotu = false
	nullfs.Id = "nullfs"
	nullfs.Debuglevel = *debug
	nullfs.Msize = 8192
	nullfs.Start(nullfs)

	l, err := net.Listen("unix", "")
	if err != nil {
		b.Fatalf("Can not start listener: %v", err)
	}
	srvAddr := l.Addr().String()
	go func() {
		if err = nullfs.StartListener(l); err != nil {
			b.Fatalf("Can not start listener: %v", err)
		}
		b.Fatalf("Listener returned")
	}()
	var conn net.Conn
	if conn, err = net.Dial("unix", srvAddr); err != nil {
		b.Fatalf("%v", err)
	}

	user := ninep.OsUsers.Uid2User(os.Geteuid())
	clnt := NewClnt(conn, 8192, false)
	rootfid, err := clnt.Attach(nil, user, "/")
	if err != nil {
		b.Fatalf("%v", err)
	}

	for i := 0; i < b.N; i++ {
		f := clnt.FidAlloc()
		if _, err = clnt.Walk(rootfid, f, []string{"bin"}); err != nil {
			b.Fatalf("%v", err)
		}
	}
}
func BenchmarkRootWalkBadFid(b *testing.B) {
	nullfs := new(nullfs.Nullfs)
	nullfs.Dotu = false
	nullfs.Id = "nullfs"
	nullfs.Debuglevel = *debug
	nullfs.Msize = 8192
	nullfs.Start(nullfs)

	l, err := net.Listen("unix", "")
	if err != nil {
		b.Fatalf("Can not start listener: %v", err)
	}
	srvAddr := l.Addr().String()
	go func() {
		if err = nullfs.StartListener(l); err != nil {
			b.Fatalf("Can not start listener: %v", err)
		}
		b.Fatalf("Listener returned")
	}()
	var conn net.Conn
	if conn, err = net.Dial("unix", srvAddr); err != nil {
		b.Fatalf("%v", err)
	}

	user := ninep.OsUsers.Uid2User(os.Geteuid())
	clnt := NewClnt(conn, 8192, false)
	rootfid, err := clnt.Attach(nil, user, "/")
	if err != nil {
		b.Fatalf("%v", err)
	}

	rootfid.Fid++
	for i := 0; i < b.N; i++ {
		if _, err = clnt.Walk(rootfid, rootfid, []string{"bin"}); err == nil {
			b.Fatalf("Did not get an expected error on walking a bad fid!")
		}
	}
}
*/
<commit_msg>Add a test that shows really bad problems ...<commit_after>// Copyright 2009 The Ninep Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package nullfs

import (
	"io"
	"net"
	"os"
	"testing"

	"github.com/lionkov/ninep"
	"github.com/lionkov/ninep/clnt"
)

// It's recommended not to have a helper. But this is so much boiler plate.
func setup(msize uint32, failf func(...interface{})) (*clnt.Clnt, *clnt.Fid) {
	f := new(NullFS)
	f.Dotu = false
	f.Id = "ufs"
	f.Debuglevel = 0
	if !f.Start(f) {
		failf("Can't happen: Starting the server failed")
	}

	l, err := net.Listen("unix", "")
	if err != nil {
		failf("net.Listen: want nil, got %v", err)
	}

	go func() {
		if err = f.StartListener(l); err != nil {
			failf("Can not start listener: %v", err)
		}
	}()

	var conn net.Conn
	if conn, err = net.Dial("unix", l.Addr().String()); err != nil {
		failf("%v", err)
	}

	user := ninep.OsUsers.Uid2User(os.Geteuid())
	clnt := clnt.NewClnt(conn, msize, false)

	rootfid, err := clnt.Attach(nil, user, "/")
	if err != nil {
		failf("Attach: %v", err)
	}

	return clnt, rootfid
}

func TestAttach(t *testing.T) {
	setup(9000, t.Fatal)
}
func TestAttachOpenReaddir(t *testing.T) {
	var err error
	clnt, rootfid := setup(9000, t.Fatal)

	dirfid := clnt.FidAlloc()
	if _, err = clnt.Walk(rootfid, dirfid, []string{}); err != nil {
		t.Fatalf("%v", err)
	}

	if err = clnt.Open(dirfid, 0); err != nil {
		t.Fatalf("%v", err)
	}
	var b []byte
	if b, err = clnt.Read(dirfid, 0, 64*1024); err != nil {
		t.Fatalf("%v", err)
	}
	var i, amt int
	var offset uint64
	err = nil
	for err == nil {
		if b, err = clnt.Read(dirfid, offset, 64*1024); err != nil {
			t.Fatalf("%v", err)
		}

		if len(b) == 0 {
			break
		}
		for b != nil && len(b) > 0 {
			if _, b, amt, err = ninep.UnpackDir(b, true); err != nil {
				t.Errorf("UnpackDir returns %v", err)
				break
			} else {
				i++
				offset += uint64(amt)
			}
		}
	}
	if i != len(dirQids) {
		t.Fatalf("Reading: got %d entries, wanted %d, err %v", i, len(dirQids), err)
	}

	t.Logf("-----------------------------> Alternate form, using readdir and File")
	// Alternate form, using readdir and File
	dirfile, err := clnt.FOpen(".", ninep.OREAD)
	if err != nil {
		t.Fatalf("%v", err)
	}
	i, amt, offset = 0, 0, 0
	err = nil

	for err == nil {
		d, err := dirfile.Readdir(64)
		if err != nil && err != io.EOF {
			t.Errorf("%v", err)
		}

		if len(d) == 0 {
			break
		}
		i += len(d)
		if i >= len(dirQids) {
			break
		}
	}
	if i != len(dirQids)-1 {
		t.Fatalf("Readdir: got %d entries, wanted %d", i, len(dirQids)-1)
	}
}

func TestNull(t *testing.T) {
	var err error
	clnt, rootfid := setup(9000, t.Fatal)

	d := clnt.FidAlloc()
	if _, err = clnt.Walk(rootfid, d, []string{"null"}); err != nil {
		t.Fatalf("%v", err)
	}

	if err = clnt.Open(d, 0); err != nil {
		t.Fatalf("%v", err)
	}

	var b []byte
	if b, err = clnt.Read(d, 0, 64*1024); err != nil {
		t.Fatalf("%v", err)
	}
	if len(b) > 0 {
		t.Fatalf("Read of null: want 0, got %d bytes", len(b))
	}

	st, err := clnt.Stat(d)
	if err != nil {
		t.Fatalf("%v", err)
	}

	if st.Name != "null" {
		t.Fatalf("Stat: want 'null', got %v", st.Name)
	}
	if st.Mode != 0666 {
		t.Fatalf("Stat: want 0777, got %o", st.Mode)
	}

}

func TestZero(t *testing.T) {
	var err error
	clnt, rootfid := setup(9000, t.Fatal)

	d := clnt.FidAlloc()
	if _, err = clnt.Walk(rootfid, d, []string{"zero"}); err != nil {
		t.Fatalf("%v", err)
	}

	if err = clnt.Open(d, 0); err != nil {
		t.Fatalf("%v", err)
	}

	var b []byte
	if b, err = clnt.Read(d, 0, 64*1024); err != nil {
		t.Fatalf("%v", err)
	}
	if len(b) == 0 {
		t.Fatalf("Read of null: want > 0, got %d bytes", len(b))
	}

}

func BenchmarkNull(b *testing.B) {
	clnt, rootfid := setup(9000, b.Fatal)
	d := clnt.FidAlloc()
	if _, err := clnt.Walk(rootfid, d, []string{"null"}); err != nil {
		b.Fatalf("%v", err)
	}

	if err := clnt.Open(d, 0); err != nil {
		b.Fatalf("%v", err)
	}

	for i := 0; i < b.N; i++ {
		if _, err := clnt.Read(d, 0, 64*1024); err != nil {
			b.Fatalf("%v", err)
		}
	}

}

func BenchmarkZero4k(b *testing.B) {
	clnt, rootfid := setup(9000, b.Fatal)
	d := clnt.FidAlloc()
	if _, err := clnt.Walk(rootfid, d, []string{"zero"}); err != nil {
		b.Fatalf("%v", err)
	}

	if err := clnt.Open(d, 0); err != nil {
		b.Fatalf("%v", err)
	}

	for i := 0; i < b.N; i++ {
		if n, err := clnt.Read(d, 0, 4*1024); err != nil || len(n) != 4096 {
			b.Fatalf("%v", err)
		}
	}

}

func BenchmarkZero1m(b *testing.B) {
	clnt, rootfid := setup(1<<20 + 64, b.Fatal)
	d := clnt.FidAlloc()
	if _, err := clnt.Walk(rootfid, d, []string{"zero"}); err != nil {
		b.Fatalf("%v", err)
	}

	if err := clnt.Open(d, 0); err != nil {
		b.Fatalf("%v", err)
	}

	for i := 0; i < b.N; i++ {
		if n, err := clnt.Read(d, 0, 1<<20); err != nil || len(n) != 1<<20{
			b.Fatalf("%v: only got %d of %d bytes", err, len(n), 1<<20)
		}
	}

}

/*
func BenchmarkRootWalk(b *testing.B) {
	nullfs := new(nullfs.Nullfs)
	nullfs.Dotu = false
	nullfs.Id = "nullfs"
	nullfs.Debuglevel = *debug
	nullfs.Msize = 8192
	nullfs.Start(nullfs)

	l, err := net.Listen("unix", "")
	if err != nil {
		b.Fatalf("Can not start listener: %v", err)
	}
	srvAddr := l.Addr().String()
	go func() {
		if err = nullfs.StartListener(l); err != nil {
			b.Fatalf("Can not start listener: %v", err)
		}
		b.Fatalf("Listener returned")
	}()
	var conn net.Conn
	if conn, err = net.Dial("unix", srvAddr); err != nil {
		b.Fatalf("%v", err)
	}

	user := ninep.OsUsers.Uid2User(os.Geteuid())
	clnt := NewClnt(conn, 8192, false)
	rootfid, err := clnt.Attach(nil, user, "/")
	if err != nil {
		b.Fatalf("%v", err)
	}

	for i := 0; i < b.N; i++ {
		f := clnt.FidAlloc()
		if _, err = clnt.Walk(rootfid, f, []string{"bin"}); err != nil {
			b.Fatalf("%v", err)
		}
	}
}
func BenchmarkRootWalkBadFid(b *testing.B) {
	nullfs := new(nullfs.Nullfs)
	nullfs.Dotu = false
	nullfs.Id = "nullfs"
	nullfs.Debuglevel = *debug
	nullfs.Msize = 8192
	nullfs.Start(nullfs)

	l, err := net.Listen("unix", "")
	if err != nil {
		b.Fatalf("Can not start listener: %v", err)
	}
	srvAddr := l.Addr().String()
	go func() {
		if err = nullfs.StartListener(l); err != nil {
			b.Fatalf("Can not start listener: %v", err)
		}
		b.Fatalf("Listener returned")
	}()
	var conn net.Conn
	if conn, err = net.Dial("unix", srvAddr); err != nil {
		b.Fatalf("%v", err)
	}

	user := ninep.OsUsers.Uid2User(os.Geteuid())
	clnt := NewClnt(conn, 8192, false)
	rootfid, err := clnt.Attach(nil, user, "/")
	if err != nil {
		b.Fatalf("%v", err)
	}

	rootfid.Fid++
	for i := 0; i < b.N; i++ {
		if _, err = clnt.Walk(rootfid, rootfid, []string{"bin"}); err == nil {
			b.Fatalf("Did not get an expected error on walking a bad fid!")
		}
	}
}
*/
<|endoftext|>