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

// for www.gravatar.com image cache

/*
It is recommend to use this way

	cacheDir := "./cache"
	defaultImg := "./default.jpg"
	http.Handle("/avatar/", avatar.CacheServer(cacheDir, defaultImg))
*/
package avatar

import (
	"crypto/md5"
	"encoding/hex"
	"errors"
	"fmt"
	"image"
	"image/jpeg"
	"image/png"
	"io"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"strings"
	"sync"
	"time"

	"github.com/nfnt/resize"

	"github.com/gogits/gogs/modules/log"
	"github.com/gogits/gogs/modules/setting"
)

var gravatarSource string

func init() {
	gravatarSource = setting.GravatarSource
	if !strings.HasPrefix(gravatarSource, "http:") {
		gravatarSource = "http:" + gravatarSource
	}
}

// hash email to md5 string
// keep this func in order to make this package independent
func HashEmail(email string) string {
	// https://en.gravatar.com/site/implement/hash/
	email = strings.TrimSpace(email)
	email = strings.ToLower(email)

	h := md5.New()
	h.Write([]byte(email))
	return hex.EncodeToString(h.Sum(nil))
}

// Avatar represents the avatar object.
type Avatar struct {
	Hash           string
	AlterImage     string // image path
	cacheDir       string // image save dir
	reqParams      string
	imagePath      string
	expireDuration time.Duration
}

func New(hash string, cacheDir string) *Avatar {
	return &Avatar{
		Hash:           hash,
		cacheDir:       cacheDir,
		expireDuration: time.Minute * 10,
		reqParams: url.Values{
			"d":    {"retro"},
			"size": {"200"},
			"r":    {"pg"}}.Encode(),
		imagePath: filepath.Join(cacheDir, hash+".image"), //maybe png or jpeg
	}
}

func (this *Avatar) HasCache() bool {
	fileInfo, err := os.Stat(this.imagePath)
	return err == nil && fileInfo.Mode().IsRegular()
}

func (this *Avatar) Modtime() (modtime time.Time, err error) {
	fileInfo, err := os.Stat(this.imagePath)
	if err != nil {
		return
	}
	return fileInfo.ModTime(), nil
}

func (this *Avatar) Expired() bool {
	modtime, err := this.Modtime()
	return err != nil || time.Since(modtime) > this.expireDuration
}

// default image format: jpeg
func (this *Avatar) Encode(wr io.Writer, size int) (err error) {
	var img image.Image
	decodeImageFile := func(file string) (img image.Image, err error) {
		fd, err := os.Open(file)
		if err != nil {
			return
		}
		defer fd.Close()

		if img, err = jpeg.Decode(fd); err != nil {
			fd.Seek(0, os.SEEK_SET)
			img, err = png.Decode(fd)
		}
		return
	}
	imgPath := this.imagePath
	if !this.HasCache() {
		if this.AlterImage == "" {
			return errors.New("request image failed, and no alt image offered")
		}
		imgPath = this.AlterImage
	}

	if img, err = decodeImageFile(imgPath); err != nil {
		return
	}
	m := resize.Resize(uint(size), 0, img, resize.NearestNeighbor)
	return jpeg.Encode(wr, m, nil)
}

// get image from gravatar.com
func (this *Avatar) Update() {
	thunder.Fetch(gravatarSource+this.Hash+"?"+this.reqParams,
		this.imagePath)
}

func (this *Avatar) UpdateTimeout(timeout time.Duration) (err error) {
	select {
	case <-time.After(timeout):
		err = fmt.Errorf("get gravatar image %s timeout", this.Hash)
	case err = <-thunder.GoFetch(gravatarSource+this.Hash+"?"+this.reqParams,
		this.imagePath):
	}
	return err
}

type service struct {
	cacheDir string
	altImage string
}

func (this *service) mustInt(r *http.Request, defaultValue int, keys ...string) (v int) {
	for _, k := range keys {
		if _, err := fmt.Sscanf(r.FormValue(k), "%d", &v); err == nil {
			defaultValue = v
		}
	}
	return defaultValue
}

func (this *service) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	urlPath := r.URL.Path
	hash := urlPath[strings.LastIndex(urlPath, "/")+1:]
	size := this.mustInt(r, 80, "s", "size") // default size = 80*80

	avatar := New(hash, this.cacheDir)
	avatar.AlterImage = this.altImage
	if avatar.Expired() {
		if err := avatar.UpdateTimeout(time.Millisecond * 1000); err != nil {
			log.Trace("avatar update error: %v", err)
			return
		}
	}
	if modtime, err := avatar.Modtime(); err == nil {
		etag := fmt.Sprintf("size(%d)", size)
		if t, err := time.Parse(http.TimeFormat, r.Header.Get("If-Modified-Since")); err == nil && modtime.Before(t.Add(1*time.Second)) && etag == r.Header.Get("If-None-Match") {
			h := w.Header()
			delete(h, "Content-Type")
			delete(h, "Content-Length")
			w.WriteHeader(http.StatusNotModified)
			return
		}
		w.Header().Set("Last-Modified", modtime.UTC().Format(http.TimeFormat))
		w.Header().Set("ETag", etag)
	}
	w.Header().Set("Content-Type", "image/jpeg")

	if err := avatar.Encode(w, size); err != nil {
		log.Warn("avatar encode error: %v", err)
		w.WriteHeader(500)
	}
}

// http.Handle("/avatar/", avatar.CacheServer("./cache"))
func CacheServer(cacheDir string, defaultImgPath string) http.Handler {
	return &service{
		cacheDir: cacheDir,
		altImage: defaultImgPath,
	}
}

// thunder downloader
var thunder = &Thunder{QueueSize: 10}

type Thunder struct {
	QueueSize int // download queue size
	q         chan *thunderTask
	once      sync.Once
}

func (t *Thunder) init() {
	if t.QueueSize < 1 {
		t.QueueSize = 1
	}
	t.q = make(chan *thunderTask, t.QueueSize)
	for i := 0; i < t.QueueSize; i++ {
		go func() {
			for {
				task := <-t.q
				task.Fetch()
			}
		}()
	}
}

func (t *Thunder) Fetch(url string, saveFile string) error {
	t.once.Do(t.init)
	task := &thunderTask{
		Url:      url,
		SaveFile: saveFile,
	}
	task.Add(1)
	t.q <- task
	task.Wait()
	return task.err
}

func (t *Thunder) GoFetch(url, saveFile string) chan error {
	c := make(chan error)
	go func() {
		c <- t.Fetch(url, saveFile)
	}()
	return c
}

// thunder download
type thunderTask struct {
	Url      string
	SaveFile string
	sync.WaitGroup
	err error
}

func (this *thunderTask) Fetch() {
	this.err = this.fetch()
	this.Done()
}

var client = &http.Client{}

func (this *thunderTask) fetch() error {
	log.Debug("avatar.fetch(fetch new avatar): %s", this.Url)
	req, _ := http.NewRequest("GET", this.Url, nil)
	req.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/jpeg,image/png,*/*;q=0.8")
	req.Header.Set("Accept-Encoding", "deflate,sdch")
	req.Header.Set("Accept-Language", "zh-CN,zh;q=0.8")
	req.Header.Set("Cache-Control", "no-cache")
	req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.154 Safari/537.36")
	resp, err := client.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	if resp.StatusCode != 200 {
		return fmt.Errorf("status code: %d", resp.StatusCode)
	}

	/*
		log.Println("headers:", resp.Header)
		switch resp.Header.Get("Content-Type") {
		case "image/jpeg":
			this.SaveFile += ".jpeg"
		case "image/png":
			this.SaveFile += ".png"
		}
	*/
	/*
		imgType := resp.Header.Get("Content-Type")
		if imgType != "image/jpeg" && imgType != "image/png" {
			return errors.New("not png or jpeg")
		}
	*/

	tmpFile := this.SaveFile + ".part" // mv to destination when finished
	fd, err := os.Create(tmpFile)
	if err != nil {
		return err
	}
	_, err = io.Copy(fd, resp.Body)
	fd.Close()
	if err != nil {
		os.Remove(tmpFile)
		return err
	}
	return os.Rename(tmpFile, this.SaveFile)
}
<commit_msg>fix if service.ENABLE_CACHE_AVATAR is true<commit_after>// Copyright 2014 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

// for www.gravatar.com image cache

/*
It is recommend to use this way

	cacheDir := "./cache"
	defaultImg := "./default.jpg"
	http.Handle("/avatar/", avatar.CacheServer(cacheDir, defaultImg))
*/
package avatar

import (
	"crypto/md5"
	"encoding/hex"
	"errors"
	"fmt"
	"image"
	"image/jpeg"
	"image/png"
	"io"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"strings"
	"sync"
	"time"

	"github.com/nfnt/resize"

	"github.com/gogits/gogs/modules/log"
	"github.com/gogits/gogs/modules/setting"
)

var gravatarSource string

func UpdateGravatarSource() {
	gravatarSource = setting.GravatarSource
	log.Debug("avatar.UpdateGravatarSource(gavatar source): %s", gravatarSource)
	if !strings.HasPrefix(gravatarSource, "http:") {
		gravatarSource = "http:" + gravatarSource
		log.Debug("avatar.UpdateGravatarSource(update gavatar source): %s", gravatarSource)
	}
}

// hash email to md5 string
// keep this func in order to make this package independent
func HashEmail(email string) string {
	// https://en.gravatar.com/site/implement/hash/
	email = strings.TrimSpace(email)
	email = strings.ToLower(email)

	h := md5.New()
	h.Write([]byte(email))
	return hex.EncodeToString(h.Sum(nil))
}

// Avatar represents the avatar object.
type Avatar struct {
	Hash           string
	AlterImage     string // image path
	cacheDir       string // image save dir
	reqParams      string
	imagePath      string
	expireDuration time.Duration
}

func New(hash string, cacheDir string) *Avatar {
	return &Avatar{
		Hash:           hash,
		cacheDir:       cacheDir,
		expireDuration: time.Minute * 10,
		reqParams: url.Values{
			"d":    {"retro"},
			"size": {"200"},
			"r":    {"pg"}}.Encode(),
		imagePath: filepath.Join(cacheDir, hash+".image"), //maybe png or jpeg
	}
}

func (this *Avatar) HasCache() bool {
	fileInfo, err := os.Stat(this.imagePath)
	return err == nil && fileInfo.Mode().IsRegular()
}

func (this *Avatar) Modtime() (modtime time.Time, err error) {
	fileInfo, err := os.Stat(this.imagePath)
	if err != nil {
		return
	}
	return fileInfo.ModTime(), nil
}

func (this *Avatar) Expired() bool {
	modtime, err := this.Modtime()
	return err != nil || time.Since(modtime) > this.expireDuration
}

// default image format: jpeg
func (this *Avatar) Encode(wr io.Writer, size int) (err error) {
	var img image.Image
	decodeImageFile := func(file string) (img image.Image, err error) {
		fd, err := os.Open(file)
		if err != nil {
			return
		}
		defer fd.Close()

		if img, err = jpeg.Decode(fd); err != nil {
			fd.Seek(0, os.SEEK_SET)
			img, err = png.Decode(fd)
		}
		return
	}
	imgPath := this.imagePath
	if !this.HasCache() {
		if this.AlterImage == "" {
			return errors.New("request image failed, and no alt image offered")
		}
		imgPath = this.AlterImage
	}

	if img, err = decodeImageFile(imgPath); err != nil {
		return
	}
	m := resize.Resize(uint(size), 0, img, resize.NearestNeighbor)
	return jpeg.Encode(wr, m, nil)
}

// get image from gravatar.com
func (this *Avatar) Update() {
	UpdateGravatarSource()
	thunder.Fetch(gravatarSource+this.Hash+"?"+this.reqParams,
		this.imagePath)
}

func (this *Avatar) UpdateTimeout(timeout time.Duration) (err error) {
	UpdateGravatarSource()
	select {
	case <-time.After(timeout):
		err = fmt.Errorf("get gravatar image %s timeout", this.Hash)
	case err = <-thunder.GoFetch(gravatarSource+this.Hash+"?"+this.reqParams,
		this.imagePath):
	}
	return err
}

type service struct {
	cacheDir string
	altImage string
}

func (this *service) mustInt(r *http.Request, defaultValue int, keys ...string) (v int) {
	for _, k := range keys {
		if _, err := fmt.Sscanf(r.FormValue(k), "%d", &v); err == nil {
			defaultValue = v
		}
	}
	return defaultValue
}

func (this *service) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	urlPath := r.URL.Path
	hash := urlPath[strings.LastIndex(urlPath, "/")+1:]
	size := this.mustInt(r, 80, "s", "size") // default size = 80*80

	avatar := New(hash, this.cacheDir)
	avatar.AlterImage = this.altImage
	if avatar.Expired() {
		if err := avatar.UpdateTimeout(time.Millisecond * 1000); err != nil {
			log.Trace("avatar update error: %v", err)
			return
		}
	}
	if modtime, err := avatar.Modtime(); err == nil {
		etag := fmt.Sprintf("size(%d)", size)
		if t, err := time.Parse(http.TimeFormat, r.Header.Get("If-Modified-Since")); err == nil && modtime.Before(t.Add(1*time.Second)) && etag == r.Header.Get("If-None-Match") {
			h := w.Header()
			delete(h, "Content-Type")
			delete(h, "Content-Length")
			w.WriteHeader(http.StatusNotModified)
			return
		}
		w.Header().Set("Last-Modified", modtime.UTC().Format(http.TimeFormat))
		w.Header().Set("ETag", etag)
	}
	w.Header().Set("Content-Type", "image/jpeg")

	if err := avatar.Encode(w, size); err != nil {
		log.Warn("avatar encode error: %v", err)
		w.WriteHeader(500)
	}
}

// http.Handle("/avatar/", avatar.CacheServer("./cache"))
func CacheServer(cacheDir string, defaultImgPath string) http.Handler {
	return &service{
		cacheDir: cacheDir,
		altImage: defaultImgPath,
	}
}

// thunder downloader
var thunder = &Thunder{QueueSize: 10}

type Thunder struct {
	QueueSize int // download queue size
	q         chan *thunderTask
	once      sync.Once
}

func (t *Thunder) init() {
	if t.QueueSize < 1 {
		t.QueueSize = 1
	}
	t.q = make(chan *thunderTask, t.QueueSize)
	for i := 0; i < t.QueueSize; i++ {
		go func() {
			for {
				task := <-t.q
				task.Fetch()
			}
		}()
	}
}

func (t *Thunder) Fetch(url string, saveFile string) error {
	t.once.Do(t.init)
	task := &thunderTask{
		Url:      url,
		SaveFile: saveFile,
	}
	task.Add(1)
	t.q <- task
	task.Wait()
	return task.err
}

func (t *Thunder) GoFetch(url, saveFile string) chan error {
	c := make(chan error)
	go func() {
		c <- t.Fetch(url, saveFile)
	}()
	return c
}

// thunder download
type thunderTask struct {
	Url      string
	SaveFile string
	sync.WaitGroup
	err error
}

func (this *thunderTask) Fetch() {
	this.err = this.fetch()
	this.Done()
}

var client = &http.Client{}

func (this *thunderTask) fetch() error {
	log.Debug("avatar.fetch(fetch new avatar): %s", this.Url)
	req, _ := http.NewRequest("GET", this.Url, nil)
	req.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/jpeg,image/png,*/*;q=0.8")
	req.Header.Set("Accept-Encoding", "deflate,sdch")
	req.Header.Set("Accept-Language", "zh-CN,zh;q=0.8")
	req.Header.Set("Cache-Control", "no-cache")
	req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.154 Safari/537.36")
	resp, err := client.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	if resp.StatusCode != 200 {
		return fmt.Errorf("status code: %d", resp.StatusCode)
	}

	/*
		log.Println("headers:", resp.Header)
		switch resp.Header.Get("Content-Type") {
		case "image/jpeg":
			this.SaveFile += ".jpeg"
		case "image/png":
			this.SaveFile += ".png"
		}
	*/
	/*
		imgType := resp.Header.Get("Content-Type")
		if imgType != "image/jpeg" && imgType != "image/png" {
			return errors.New("not png or jpeg")
		}
	*/

	tmpFile := this.SaveFile + ".part" // mv to destination when finished
	fd, err := os.Create(tmpFile)
	if err != nil {
		return err
	}
	_, err = io.Copy(fd, resp.Body)
	fd.Close()
	if err != nil {
		os.Remove(tmpFile)
		return err
	}
	return os.Rename(tmpFile, this.SaveFile)
}
<|endoftext|>


<commit_before>package man

import (
	"bytes"
	"fmt"
	"io"
	"strings"
	"time"

	"github.com/cpuguy83/go-md2man/md2man"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
)

// Options specify the common properties of the man page.
type Options struct {
	Header  Header   // General data.
	Origin  Origin   // Data representing the origin of this man page.
	SeeAlso []string // Links to other man pages, e.g. "ps(1)"
}

// Origin conveys data of the man page origin.
type Origin struct {
	Source string    // Origin of the man page.
	Date   time.Time // The Date when the man page was written.
}

// Header conveys general data of the man page.
type Header struct {
	// Man page title.
	Title string
	// Man page section.
	// Use "1" for General commands.
	// Use "2" for System calls.
	// Use "3" for Library functions, covering in particular the C standard library.
	// Use "4" for Special files (usually devices, those found in /dev) and drivers.
	// Use "5" for File formats and conventions. Use "6" for Games and screensavers.
	// Use "7" for Miscellanea.
	// Use "8" for System administration commands and daemons.
	Section string
	// Manual title.
	Manual string
}

type mdBuffer struct {
	*bytes.Buffer
}

func (buf *mdBuffer) printfln(format string, a ...interface{}) (int, error) {
	return buf.WriteString(fmt.Sprintf(format+"\n", a...))
}

func (buf *mdBuffer) printline(s string) (int, error) {
	return buf.WriteString(s + "\n")
}

func (buf *mdBuffer) boldln(s string) (int, error) {
	return buf.printfln("**%s**", s)
}

func (buf *mdBuffer) header(title string) (int, error) {
	return buf.printfln("# %s", title)
}

func (buf *mdBuffer) code(s string) (int, error) {
	return buf.printfln("```\n%s\n```", s)
}

func newMdBuffer() *mdBuffer {
	buf := new(mdBuffer)
	buf.Buffer = new(bytes.Buffer)
	return buf
}

// GenerateManPage writes the man page, taking the given command as root, to a writer.
func GenerateManPage(cmd *cobra.Command, options *Options, w io.Writer) error {
	buf := newMdBuffer()
	writeToBuf(buf, options, cmd)
	return writeAsMan(buf, w)
}

func writeToBuf(buf *mdBuffer, options *Options, cmd *cobra.Command) {
	writeMetadata(options, buf)
	writeName(cmd.Name(), cmd.Short, buf)
	writeSynopsis(cmd.UseLine(), buf)
	writeDescription(cmd.Long, buf)
	writeOptions(cmd.Flags(), buf)
	writeCommands(cmd, buf)
	writeExamples(cmd, buf)
	writeExitStatus(buf)
	writeSeeAlso(options.SeeAlso, buf)
}

func writeMetadata(options *Options, buf *mdBuffer) {
	buf.printfln("%% %s(%s)%s", options.Header.Title, options.Header.Section, options.Origin.Date.Format("Jan 2006"))
	buf.printfln("%% %s", options.Origin.Source)
	buf.printfln("%% %s", options.Header.Manual)
}

func writeName(name, short string, buf *mdBuffer) {
	buf.header("NAME")
	buf.printfln("%s \\- %s", name, short)
}

func writeSynopsis(use string, buf *mdBuffer) {
	buf.header("SYNOPSIS")
	buf.boldln(use)
}

func writeDescription(description string, buf *mdBuffer) {
	buf.header("DESCRIPTION")
	buf.printline(description)
}

func writeOptions(flags *pflag.FlagSet, buf *mdBuffer) {
	buf.header("OPTIONS")
	flags.VisitAll(func(flag *pflag.Flag) {
		writeOption(flag, buf)
	})
}

func writeOption(flag *pflag.Flag, buf *mdBuffer) {
	buf.printfln("**--%s**=%q\n\t%s\n", flag.Name, flag.DefValue, flag.Usage)
}

func writeCommands(cmd *cobra.Command, buf *mdBuffer) {
	buf.header("COMMANDS")
	buf.printline("The following commands are understood:\n")
	writeCommandRecursive(cmd, buf)
}

func writeCommandRecursive(cmd *cobra.Command, buf *mdBuffer) {
	if cmd.RunE != nil || cmd.Run != nil {
		buf.printfln("**%s** - %s\n", cmd.CommandPath(), cmd.Short)
		buf.printfln("\t\t%s\n", cmd.Long)
	}
	for _, sub := range cmd.Commands() {
		writeCommandRecursive(sub, buf)
	}
}

func writeExamples(cmd *cobra.Command, buf *mdBuffer) {
	buf.header("EXAMPLES")
	writeExampleRecursive(cmd, buf)
}

func writeExampleRecursive(cmd *cobra.Command, buf *mdBuffer) {
	if cmd.Example != "" {
		buf.boldln(cmd.Short)
		buf.code(cmd.Example)
	}
	for _, sub := range cmd.Commands() {
		writeExampleRecursive(sub, buf)
	}
}

func writeExitStatus(buf *mdBuffer) {
	buf.header("EXIT STATUS")
	buf.printline("On success, 0 is returned, a non-zero failure code otherwise. " +
		"If the return code is non-zero, look at the output to get a hint on what went wrong.")
}

func writeSeeAlso(sa []string, buf *mdBuffer) {
	buf.header("SEE ALSO")
	buf.boldln(strings.Join(sa, ", "))
}

func writeAsMan(buf *mdBuffer, w io.Writer) error {
	bytesMarkdown := buf.Bytes()
	bytesMan := md2man.Render(bytesMarkdown)
	_, err := w.Write(bytesMan)
	return err
}
<commit_msg>newline between docs for man section<commit_after>package man

import (
	"bytes"
	"fmt"
	"io"
	"strings"
	"time"

	"github.com/cpuguy83/go-md2man/md2man"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
)

// Options specify the common properties of the man page.
type Options struct {
	Header  Header   // General data.
	Origin  Origin   // Data representing the origin of this man page.
	SeeAlso []string // Links to other man pages, e.g. "ps(1)"
}

// Origin conveys data of the man page origin.
type Origin struct {
	Source string    // Origin of the man page.
	Date   time.Time // The Date when the man page was written.
}

// Header conveys general data of the man page.
type Header struct {
	// Man page title.
	Title string
	// Man page section.
	// Use "1" for General commands.
	// Use "2" for System calls.
	// Use "3" for Library functions, covering in particular the C standard library.
	// Use "4" for Special files (usually devices, those found in /dev) and drivers.
	// Use "5" for File formats and conventions.
	// Use "6" for Games and screensavers.
	// Use "7" for Miscellanea.
	// Use "8" for System administration commands and daemons.
	Section string
	// Manual title.
	Manual string
}

type mdBuffer struct {
	*bytes.Buffer
}

func (buf *mdBuffer) printfln(format string, a ...interface{}) (int, error) {
	return buf.WriteString(fmt.Sprintf(format+"\n", a...))
}

func (buf *mdBuffer) printline(s string) (int, error) {
	return buf.WriteString(s + "\n")
}

func (buf *mdBuffer) boldln(s string) (int, error) {
	return buf.printfln("**%s**", s)
}

func (buf *mdBuffer) header(title string) (int, error) {
	return buf.printfln("# %s", title)
}

func (buf *mdBuffer) code(s string) (int, error) {
	return buf.printfln("```\n%s\n```", s)
}

func newMdBuffer() *mdBuffer {
	buf := new(mdBuffer)
	buf.Buffer = new(bytes.Buffer)
	return buf
}

// GenerateManPage writes the man page, taking the given command as root, to a writer.
func GenerateManPage(cmd *cobra.Command, options *Options, w io.Writer) error {
	buf := newMdBuffer()
	writeToBuf(buf, options, cmd)
	return writeAsMan(buf, w)
}

func writeToBuf(buf *mdBuffer, options *Options, cmd *cobra.Command) {
	writeMetadata(options, buf)
	writeName(cmd.Name(), cmd.Short, buf)
	writeSynopsis(cmd.UseLine(), buf)
	writeDescription(cmd.Long, buf)
	writeOptions(cmd.Flags(), buf)
	writeCommands(cmd, buf)
	writeExamples(cmd, buf)
	writeExitStatus(buf)
	writeSeeAlso(options.SeeAlso, buf)
}

func writeMetadata(options *Options, buf *mdBuffer) {
	buf.printfln("%% %s(%s)%s", options.Header.Title, options.Header.Section, options.Origin.Date.Format("Jan 2006"))
	buf.printfln("%% %s", options.Origin.Source)
	buf.printfln("%% %s", options.Header.Manual)
}

func writeName(name, short string, buf *mdBuffer) {
	buf.header("NAME")
	buf.printfln("%s \\- %s", name, short)
}

func writeSynopsis(use string, buf *mdBuffer) {
	buf.header("SYNOPSIS")
	buf.boldln(use)
}

func writeDescription(description string, buf *mdBuffer) {
	buf.header("DESCRIPTION")
	buf.printline(description)
}

func writeOptions(flags *pflag.FlagSet, buf *mdBuffer) {
	buf.header("OPTIONS")
	flags.VisitAll(func(flag *pflag.Flag) {
		writeOption(flag, buf)
	})
}

func writeOption(flag *pflag.Flag, buf *mdBuffer) {
	buf.printfln("**--%s**=%q\n\t%s\n", flag.Name, flag.DefValue, flag.Usage)
}

func writeCommands(cmd *cobra.Command, buf *mdBuffer) {
	buf.header("COMMANDS")
	buf.printline("The following commands are understood:\n")
	writeCommandRecursive(cmd, buf)
}

func writeCommandRecursive(cmd *cobra.Command, buf *mdBuffer) {
	if cmd.RunE != nil || cmd.Run != nil {
		buf.printfln("**%s** - %s\n", cmd.CommandPath(), cmd.Short)
		buf.printfln("\t\t%s\n", cmd.Long)
	}
	for _, sub := range cmd.Commands() {
		writeCommandRecursive(sub, buf)
	}
}

func writeExamples(cmd *cobra.Command, buf *mdBuffer) {
	buf.header("EXAMPLES")
	writeExampleRecursive(cmd, buf)
}

func writeExampleRecursive(cmd *cobra.Command, buf *mdBuffer) {
	if cmd.Example != "" {
		buf.boldln(cmd.Short)
		buf.code(cmd.Example)
	}
	for _, sub := range cmd.Commands() {
		writeExampleRecursive(sub, buf)
	}
}

func writeExitStatus(buf *mdBuffer) {
	buf.header("EXIT STATUS")
	buf.printline("On success, 0 is returned, a non-zero failure code otherwise. " +
		"If the return code is non-zero, look at the output to get a hint on what went wrong.")
}

func writeSeeAlso(sa []string, buf *mdBuffer) {
	buf.header("SEE ALSO")
	buf.boldln(strings.Join(sa, ", "))
}

func writeAsMan(buf *mdBuffer, w io.Writer) error {
	bytesMarkdown := buf.Bytes()
	bytesMan := md2man.Render(bytesMarkdown)
	_, err := w.Write(bytesMan)
	return err
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package main

import (
	"bytes"
	"crypto/tls"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"os"
	"runtime"
	"strings"

	"github.com/fatih/color"
)

// Manager manages all api communications
type Manager struct {
	URL string `json:"url"`
}

// Token holds the JWT token that is received when authenticating
type Token struct {
	Token string `json:"token"`
}

// Service ...
type Service struct {
	ID         string `json:"service_id"`
	Name       string `json:"service_name"`
	Datacenter string `json:"datacenter_id"`
	Version    string `json:"service_version"`
	Status     string `json:"service_status"`
	Definition string `json:"service_definition"`
	Result     string `json:"service_result"`
	Endpoint   string `json:"service_endpoint"`
}

// Datacenter ...
type Datacenter struct {
	ID   string `json:"datacenter_id"`
	Name string `json:"datacenter_name"`
}

// User ...
type User struct {
	ID       int    `json:"id"`
	Username string `json:"username"`
	Email    string `json:"email"`
	GroupID  int    `json:"group_id"`
	IsAdmin  bool   `json:"admin"`
}

// Group ...
type Group struct {
	ID   int    `json:"id"`
	Name string `json:"name"`
}

// Session ...
type Session struct {
	UserID    string `json:"user_id"`
	ClientID  string `json:"client_id"`
	UserName  string `json:"user_name"`
	UserEmail string `json:"user_email"`
}

func (m *Manager) client() *http.Client {
	tr := &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}
	client := &http.Client{Transport: tr}

	return client
}

func (m *Manager) doRequest(url, method string, payload []byte, token string, contentType string) (string, *http.Response, error) {
	url = m.URL + url
	req, err := http.NewRequest(method, url, bytes.NewBuffer(payload))
	if token != "" {
		req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", token))
	}
	if contentType != "" {
		req.Header.Set("Content-Type", contentType)
	}
	resp, err := m.client().Do(req)

	if err != nil {
		return err.Error(), resp, err
	}
	defer resp.Body.Close()
	responseBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		color.Red(err.Error())
	}
	body := string(responseBody)

	if resp.StatusCode != 200 {
		return string(body), resp, errors.New(resp.Status)
	}
	return string(body), resp, nil
}

func (m *Manager) createClient(token string, name string) (string, error) {
	payload := []byte(`{"name":"` + name + `"}`)
	body, _, err := m.doRequest("/groups", "POST", payload, token, "")
	if err != nil {
		fmt.Println(err.Error())
		return body, err
	}

	color.Green("SUCCESS: Group " + name + " created")

	var client struct {
		ID string `json:"client_id"`
	}
	err = json.Unmarshal([]byte(body), &client)
	if err != nil {
		return "", errors.New("ERROR: Couldn't read response from server")
	}
	return client.ID, nil
}

func (m *Manager) createUser(token string, client string, user string, password string, email string) error {
	payload := []byte(`{"client_id": "` + client + `", "user_name":"` + user + `", "user_email": "` + email + `", "user_password": "` + password + `"}`)
	_, _, err := m.doRequest("/users/", "POST", payload, token, "")
	if err != nil {
		return err
	}
	color.Green("SUCCESS: User " + user + " created")
	return nil
}

func (m *Manager) getUser(token string, userid string) (user User, err error) {
	res, _, err := m.doRequest("/users/"+userid, "GET", nil, token, "application/yaml")
	json.Unmarshal([]byte(res), &user)
	return user, err
}

func (m *Manager) deleteUser(token string, user string) error {
	_, _, err := m.doRequest("/users/"+user, "DELETE", nil, token, "application/yaml")
	return err
}

func (m *Manager) getSession(token string) (session Session, err error) {
	res, _, err := m.doRequest("/session/", "GET", nil, token, "application/yaml")
	json.Unmarshal([]byte(res), &session)
	return session, err
}

// ********************* Login *******************

// Login does a login action against the api
func (m *Manager) Login(username string, password string) (token string, err error) {
	var t Token

	f := url.Values{}
	f.Add("username", username)
	f.Add("password", password)

	url := m.URL + "/auth"
	req, err := http.NewRequest("POST", url, strings.NewReader(f.Encode()))
	req.Form = f
	req.PostForm = f
	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")

	resp, err := m.client().Do(req)
	if err != nil {
		return "", err
	}

	if resp.StatusCode != 200 {
		return "", errors.New("Unauthorized")
	}
	defer resp.Body.Close()

	responseBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		color.Red(err.Error())
	}

	err = json.Unmarshal(responseBody, &t)
	if err != nil {
		color.Red(err.Error())
	}

	token = t.Token

	return token, nil
}

// ********************* Update *******************

// ChangePassword ...
func (m *Manager) ChangePassword(token string, userid int, oldpassword string, newpassword string) error {
	payload := []byte(`{"old_password":"` + oldpassword + `", "new_password": "` + newpassword + `"}`)
	_, _, err := m.doRequest("/users/"+string(userid), "PUT", payload, token, "application/yaml")
	if err != nil {
		return err
	}
	return nil
}

// ChangePasswordByAdmin ...
func (m *Manager) ChangePasswordByAdmin(token string, userid int, newpassword string) error {
	payload := []byte(`{"new_password": "` + newpassword + `"}`)
	_, _, err := m.doRequest("/users/"+string(userid), "PUT", payload, token, "application/yaml")
	if err != nil {
		return err
	}
	return nil
}

// ********************* Create *******************

// CreateDatacenter ...
func (m *Manager) CreateDatacenter(token string, name string, user string, password string, url string, network string, vseURL string) (string, error) {
	payload := []byte(`{"datacenter_name": "` + name + `", "datacenter_type": "vcloud", "datacenter_region": "LON-001", "datacenter_username":"` + user + `", "datacenter_password":"` + password + `", "external_network":"` + network + `", "vcloud_url":"` + url + `", "vse_url":"` + vseURL + `"}`)
	body, _, err := m.doRequest("/datacenters/", "POST", payload, token, "")
	if err != nil {
		return body, err
	}
	color.Green("SUCCESS: Datacenter " + name + " created")
	return body, err
}

// CreateUser ...
func (m *Manager) CreateUser(name string, email string, user string, password string, adminuser string, adminpassword string) error {
	token, err := m.Login(adminuser, adminpassword)
	if err != nil {
		color.Red(err.Error())
		os.Exit(1)
	}
	c, err := m.createClient(token, name)
	if err != nil {
		color.Red(err.Error() + ": Group " + name + " already exists")
		os.Exit(1)
	}
	res := m.createUser(token, c, user, password, email)
	return res
}

// ********************* Get *******************

// GetUser ...
func (m *Manager) GetUser(token string, userid string) (user User, err error) {
	res, _, err := m.doRequest("/users/"+userid, "GET", nil, token, "application/yaml")
	json.Unmarshal([]byte(res), &user)
	return user, err
}

// GetUUID ...
func (m *Manager) GetUUID(token string, payload []byte) string {
	id, err := buildServiceUUID(payload)
	if err != nil {
		log.Fatal(err)
	}
	body, _, _ := m.doRequest("/services/uuid/", "POST", []byte(`{"id":"`+id+`"}`), token, "")
	var dat map[string]interface{}
	json.Unmarshal([]byte(body), &dat)

	if str, ok := dat["uuid"].(string); ok {
		return str
	}
	return ""
}

// ********************* Apply *******************

// Apply ...
func (m *Manager) Apply(token string, path string, monit bool) (string, error) {
	payload, err := ioutil.ReadFile(path)
	if err != nil {
		color.Red(err.Error())
		return "", nil
	}

	color.Green("Environment creation requested")
	println("Ernest will show you all output from your requested service creation")
	println("You can cancel at any moment with Ctrl+C, even the service is still being created, you won't have any output")

	streamID := m.GetUUID(token, payload)
	if streamID == "" {
		color.Red("Please log in")
		return "", nil
	}

	if monit == true {
		go Monitorize(m.URL, token, streamID)
	} else {
		println("Additionally you can trace your service on ernest monitor tool with id: " + streamID)
	}

	if body, _, err := m.doRequest("/services/", "POST", payload, token, "application/yaml"); err != nil {
		return "", errors.New(body)
	}
	if monit == true {
		runtime.Goexit()
	}
	return streamID, nil
}

// ********************* Destroy *******************

// Destroy ...
func (m *Manager) Destroy(token string, name string, monit bool) error {
	body, _, err := m.doRequest("/services/"+name, "DELETE", nil, token, "application/yaml")
	if err != nil {
		return err
	}

	var res map[string]interface{}
	json.Unmarshal([]byte(body), &res)

	if monit == true {
		if str, ok := res["stream_id"].(string); ok {
			Monitorize(m.URL, token, str)
			runtime.Goexit()
		}
	}

	return err
}

// ********************* Reset *******************

// ResetService ...
func (m *Manager) ResetService(name string, token string) error {
	_, _, err := m.doRequest("/services/"+name+"/reset/", "POST", nil, token, "application/yaml")
	return err
}

// ********************* Status *******************

// ServiceStatus ...
func (m *Manager) ServiceStatus(token string, serviceName string) (service Service, err error) {
	body, _, err := m.doRequest("/services/"+serviceName, "GET", []byte(""), token, "")
	if err != nil {
		return service, err
	}
	json.Unmarshal([]byte(body), &service)
	return service, err
}

// ServiceBuildStatus ...
func (m *Manager) ServiceBuildStatus(token string, serviceName string, serviceID string) (service Service, err error) {
	body, _, err := m.doRequest("/services/"+serviceName+"/builds/"+serviceID, "GET", []byte(""), token, "")
	if err != nil {
		return service, err
	}
	json.Unmarshal([]byte(body), &service)
	return service, err
}

// ********************* List *********************

// ListDatacenters ...
func (m *Manager) ListDatacenters(token string) (datacenters []Datacenter, err error) {
	body, _, err := m.doRequest("/datacenters/", "GET", []byte(""), token, "")
	if err != nil {
		return nil, err
	}
	json.Unmarshal([]byte(body), &datacenters)
	return datacenters, err
}

// ListServices ...
func (m *Manager) ListServices(token string) (services []Service, err error) {
	body, _, err := m.doRequest("/services/", "GET", []byte(""), token, "")
	if err != nil {
		return nil, err
	}
	json.Unmarshal([]byte(body), &services)
	return services, err
}

// ListBuilds ...
func (m *Manager) ListBuilds(name string, token string) (builds []Service, err error) {
	body, _, err := m.doRequest("/services/"+name+"/builds/", "GET", []byte(""), token, "")
	if err != nil {
		return nil, err
	}
	json.Unmarshal([]byte(body), &builds)
	return builds, err
}

// ListUsers ...
func (m *Manager) ListUsers(token string) (users []User, err error) {
	body, _, err := m.doRequest("/api/users/", "GET", []byte(""), token, "")
	if err != nil {
		return nil, err
	}
	json.Unmarshal([]byte(body), &users)
	return users, err
}

// ListGroups ...
func (m *Manager) ListGroups(token string) (groups []Group, err error) {
	body, _, err := m.doRequest("/api/groups/", "GET", []byte(""), token, "")
	if err != nil {
		return nil, err
	}
	json.Unmarshal([]byte(body), &groups)
	return groups, err
}
<commit_msg>Added prefix /api/ on all the calls<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package main

import (
	"bytes"
	"crypto/tls"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"os"
	"runtime"
	"strings"

	"github.com/fatih/color"
)

// Manager manages all api communications
type Manager struct {
	URL string `json:"url"`
}

// Token holds the JWT token that is received when authenticating
type Token struct {
	Token string `json:"token"`
}

// Service ...
type Service struct {
	ID         string `json:"service_id"`
	Name       string `json:"service_name"`
	Datacenter string `json:"datacenter_id"`
	Version    string `json:"service_version"`
	Status     string `json:"service_status"`
	Definition string `json:"service_definition"`
	Result     string `json:"service_result"`
	Endpoint   string `json:"service_endpoint"`
}

// Datacenter ...
type Datacenter struct {
	ID   string `json:"datacenter_id"`
	Name string `json:"datacenter_name"`
}

// User ...
type User struct {
	ID       int    `json:"id"`
	Username string `json:"username"`
	Email    string `json:"email"`
	GroupID  int    `json:"group_id"`
	IsAdmin  bool   `json:"admin"`
}

// Group ...
type Group struct {
	ID   int    `json:"id"`
	Name string `json:"name"`
}

// Session ...
type Session struct {
	UserID    string `json:"user_id"`
	ClientID  string `json:"client_id"`
	UserName  string `json:"user_name"`
	UserEmail string `json:"user_email"`
}

func (m *Manager) client() *http.Client {
	tr := &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}
	client := &http.Client{Transport: tr}

	return client
}

func (m *Manager) doRequest(url, method string, payload []byte, token string, contentType string) (string, *http.Response, error) {
	url = m.URL + url
	req, err := http.NewRequest(method, url, bytes.NewBuffer(payload))
	if token != "" {
		req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", token))
	}
	if contentType != "" {
		req.Header.Set("Content-Type", contentType)
	}
	resp, err := m.client().Do(req)

	if err != nil {
		return err.Error(), resp, err
	}
	defer resp.Body.Close()
	responseBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		color.Red(err.Error())
	}
	body := string(responseBody)

	if resp.StatusCode != 200 {
		return string(body), resp, errors.New(resp.Status)
	}
	return string(body), resp, nil
}

func (m *Manager) createClient(token string, name string) (string, error) {
	payload := []byte(`{"name":"` + name + `"}`)
	body, _, err := m.doRequest("/api/groups", "POST", payload, token, "")
	if err != nil {
		fmt.Println(err.Error())
		return body, err
	}

	color.Green("SUCCESS: Group " + name + " created")

	var client struct {
		ID string `json:"client_id"`
	}
	err = json.Unmarshal([]byte(body), &client)
	if err != nil {
		return "", errors.New("ERROR: Couldn't read response from server")
	}
	return client.ID, nil
}

func (m *Manager) createUser(token string, client string, user string, password string, email string) error {
	payload := []byte(`{"client_id": "` + client + `", "user_name":"` + user + `", "user_email": "` + email + `", "user_password": "` + password + `"}`)
	_, _, err := m.doRequest("/api/users/", "POST", payload, token, "")
	if err != nil {
		return err
	}
	color.Green("SUCCESS: User " + user + " created")
	return nil
}

func (m *Manager) getUser(token string, userid string) (user User, err error) {
	res, _, err := m.doRequest("/api/users/"+userid, "GET", nil, token, "application/yaml")
	json.Unmarshal([]byte(res), &user)
	return user, err
}

func (m *Manager) deleteUser(token string, user string) error {
	_, _, err := m.doRequest("/api/users/"+user, "DELETE", nil, token, "application/yaml")
	return err
}

func (m *Manager) getSession(token string) (session Session, err error) {
	res, _, err := m.doRequest("/api/session/", "GET", nil, token, "application/yaml")
	json.Unmarshal([]byte(res), &session)
	return session, err
}

// ********************* Login *******************

// Login does a login action against the api
func (m *Manager) Login(username string, password string) (token string, err error) {
	var t Token

	f := url.Values{}
	f.Add("username", username)
	f.Add("password", password)

	url := m.URL + "/auth"
	req, err := http.NewRequest("POST", url, strings.NewReader(f.Encode()))
	req.Form = f
	req.PostForm = f
	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")

	resp, err := m.client().Do(req)
	if err != nil {
		return "", err
	}

	if resp.StatusCode != 200 {
		return "", errors.New("Unauthorized")
	}
	defer resp.Body.Close()

	responseBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		color.Red(err.Error())
	}

	err = json.Unmarshal(responseBody, &t)
	if err != nil {
		color.Red(err.Error())
	}

	token = t.Token

	return token, nil
}

// ********************* Update *******************

// ChangePassword ...
func (m *Manager) ChangePassword(token string, userid int, oldpassword string, newpassword string) error {
	payload := []byte(`{"old_password":"` + oldpassword + `", "new_password": "` + newpassword + `"}`)
	_, _, err := m.doRequest("/api/users/"+string(userid), "PUT", payload, token, "application/yaml")
	if err != nil {
		return err
	}
	return nil
}

// ChangePasswordByAdmin ...
func (m *Manager) ChangePasswordByAdmin(token string, userid int, newpassword string) error {
	payload := []byte(`{"new_password": "` + newpassword + `"}`)
	_, _, err := m.doRequest("/api/users/"+string(userid), "PUT", payload, token, "application/yaml")
	if err != nil {
		return err
	}
	return nil
}

// ********************* Create *******************

// CreateDatacenter ...
func (m *Manager) CreateDatacenter(token string, name string, user string, password string, url string, network string, vseURL string) (string, error) {
	payload := []byte(`{"datacenter_name": "` + name + `", "datacenter_type": "vcloud", "datacenter_region": "LON-001", "datacenter_username":"` + user + `", "datacenter_password":"` + password + `", "external_network":"` + network + `", "vcloud_url":"` + url + `", "vse_url":"` + vseURL + `"}`)
	body, _, err := m.doRequest("/api/datacenters/", "POST", payload, token, "")
	if err != nil {
		return body, err
	}
	color.Green("SUCCESS: Datacenter " + name + " created")
	return body, err
}

// CreateUser ...
func (m *Manager) CreateUser(name string, email string, user string, password string, adminuser string, adminpassword string) error {
	token, err := m.Login(adminuser, adminpassword)
	if err != nil {
		color.Red(err.Error())
		os.Exit(1)
	}
	c, err := m.createClient(token, name)
	if err != nil {
		color.Red(err.Error() + ": Group " + name + " already exists")
		os.Exit(1)
	}
	res := m.createUser(token, c, user, password, email)
	return res
}

// ********************* Get *******************

// GetUser ...
func (m *Manager) GetUser(token string, userid string) (user User, err error) {
	res, _, err := m.doRequest("/api/users/"+userid, "GET", nil, token, "application/yaml")
	json.Unmarshal([]byte(res), &user)
	return user, err
}

// GetUUID ...
func (m *Manager) GetUUID(token string, payload []byte) string {
	id, err := buildServiceUUID(payload)
	if err != nil {
		log.Fatal(err)
	}
	body, _, _ := m.doRequest("/api/services/uuid/", "POST", []byte(`{"id":"`+id+`"}`), token, "")
	var dat map[string]interface{}
	json.Unmarshal([]byte(body), &dat)

	if str, ok := dat["uuid"].(string); ok {
		return str
	}
	return ""
}

// ********************* Apply *******************

// Apply ...
func (m *Manager) Apply(token string, path string, monit bool) (string, error) {
	payload, err := ioutil.ReadFile(path)
	if err != nil {
		color.Red(err.Error())
		return "", nil
	}

	color.Green("Environment creation requested")
	println("Ernest will show you all output from your requested service creation")
	println("You can cancel at any moment with Ctrl+C, even the service is still being created, you won't have any output")

	streamID := m.GetUUID(token, payload)
	if streamID == "" {
		color.Red("Please log in")
		return "", nil
	}

	if monit == true {
		go Monitorize(m.URL, token, streamID)
	} else {
		println("Additionally you can trace your service on ernest monitor tool with id: " + streamID)
	}

	if body, _, err := m.doRequest("/api/services/", "POST", payload, token, "application/yaml"); err != nil {
		return "", errors.New(body)
	}
	if monit == true {
		runtime.Goexit()
	}
	return streamID, nil
}

// ********************* Destroy *******************

// Destroy ...
func (m *Manager) Destroy(token string, name string, monit bool) error {
	body, _, err := m.doRequest("/api/services/"+name, "DELETE", nil, token, "application/yaml")
	if err != nil {
		return err
	}

	var res map[string]interface{}
	json.Unmarshal([]byte(body), &res)

	if monit == true {
		if str, ok := res["stream_id"].(string); ok {
			Monitorize(m.URL, token, str)
			runtime.Goexit()
		}
	}

	return err
}

// ********************* Reset *******************

// ResetService ...
func (m *Manager) ResetService(name string, token string) error {
	_, _, err := m.doRequest("/api/services/"+name+"/reset/", "POST", nil, token, "application/yaml")
	return err
}

// ********************* Status *******************

// ServiceStatus ...
func (m *Manager) ServiceStatus(token string, serviceName string) (service Service, err error) {
	body, _, err := m.doRequest("/api/services/"+serviceName, "GET", []byte(""), token, "")
	if err != nil {
		return service, err
	}
	json.Unmarshal([]byte(body), &service)
	return service, err
}

// ServiceBuildStatus ...
func (m *Manager) ServiceBuildStatus(token string, serviceName string, serviceID string) (service Service, err error) {
	body, _, err := m.doRequest("/api/services/"+serviceName+"/builds/"+serviceID, "GET", []byte(""), token, "")
	if err != nil {
		return service, err
	}
	json.Unmarshal([]byte(body), &service)
	return service, err
}

// ********************* List *********************

// ListDatacenters ...
func (m *Manager) ListDatacenters(token string) (datacenters []Datacenter, err error) {
	body, _, err := m.doRequest("/api/datacenters/", "GET", []byte(""), token, "")
	if err != nil {
		return nil, err
	}
	json.Unmarshal([]byte(body), &datacenters)
	return datacenters, err
}

// ListServices ...
func (m *Manager) ListServices(token string) (services []Service, err error) {
	body, _, err := m.doRequest("/api/services/", "GET", []byte(""), token, "")
	if err != nil {
		return nil, err
	}
	json.Unmarshal([]byte(body), &services)
	return services, err
}

// ListBuilds ...
func (m *Manager) ListBuilds(name string, token string) (builds []Service, err error) {
	body, _, err := m.doRequest("/api/services/"+name+"/builds/", "GET", []byte(""), token, "")
	if err != nil {
		return nil, err
	}
	json.Unmarshal([]byte(body), &builds)
	return builds, err
}

// ListUsers ...
func (m *Manager) ListUsers(token string) (users []User, err error) {
	body, _, err := m.doRequest("/api/users/", "GET", []byte(""), token, "")
	if err != nil {
		return nil, err
	}
	json.Unmarshal([]byte(body), &users)
	return users, err
}

// ListGroups ...
func (m *Manager) ListGroups(token string) (groups []Group, err error) {
	body, _, err := m.doRequest("/api/groups/", "GET", []byte(""), token, "")
	if err != nil {
		return nil, err
	}
	json.Unmarshal([]byte(body), &groups)
	return groups, err
}
<|endoftext|>


<commit_before>package manners

import (
	"net"
	"net/http"
	"os"
	"os/signal"
	"sync"
)

var (
	ShutdownChannel chan os.Signal
	shutdownHandler func()
	waitGroup       = sync.WaitGroup{}
)

func ListenAndServe(addr string, handler http.Handler) error {
	oldListener, err := net.Listen("tcp", addr)
	if err != nil {
		return err
	}
	listener := NewListener(oldListener)
	err = Serve(listener, handler)
	return err
}

func Serve(listener *GracefulListener, handler http.Handler) error {
	listener.CloseOnShutdown()
	go WaitForShutdown()
	server := http.Server{Handler: handler}
	err := server.Serve(listener)
	if err == nil {
		return nil
	} else if _, ok := err.(mannersError); ok {
		return nil
	}
	return err
}

func StartRoutine() {
	waitGroup.Add(1)
}

func FinishRoutine() {
	waitGroup.Done()
}

func WaitForShutdown() {
	signal.Notify(ShutdownChannel)
	<-ShutdownChannel
	shutdownHandler()
}

func NewListener(oldListener net.Listener) *GracefulListener {
	listener := GracefulListener{oldListener, true}
	return &listener
}

type GracefulListener struct {
	net.Listener
	open bool
}

func (this *GracefulListener) Accept() (net.Conn, error) {
	conn, err := this.Listener.Accept()
	if err != nil {
		if !this.open {
			waitGroup.Wait()
			err = mannersError{err}
		}
		return nil, err
	}
	StartRoutine()
	return GracefulConnection{conn}, nil
}

func (this *GracefulListener) Close() error {
	if !this.open {
		return nil
	}
	this.open = false
	err := this.Listener.Close()
	return err
}

func (this *GracefulListener) CloseOnShutdown() {
	shutdownHandler = func() { this.Close() }
}

type GracefulConnection struct {
	net.Conn
}

func (this GracefulConnection) Close() error {
	err := this.Conn.Close()
	FinishRoutine()
	return err
}

type mannersError struct {
	error
}
<commit_msg>Added a wrapper for routines<commit_after>package manners

import (
	"net"
	"net/http"
	"os"
	"os/signal"
	"sync"
)

var (
	ShutdownChannel chan os.Signal
	shutdownHandler func()
	waitGroup       = sync.WaitGroup{}
)

func ListenAndServe(addr string, handler http.Handler) error {
	oldListener, err := net.Listen("tcp", addr)
	if err != nil {
		return err
	}
	listener := NewListener(oldListener)
	err = Serve(listener, handler)
	return err
}

func Serve(listener *GracefulListener, handler http.Handler) error {
	listener.CloseOnShutdown()
	go WaitForShutdown()
	server := http.Server{Handler: handler}
	err := server.Serve(listener)
	if err == nil {
		return nil
	} else if _, ok := err.(mannersError); ok {
		return nil
	}
	return err
}

func RunRoutine(f func()) {
  StartRoutine()
  go func() {
    defer FinishRoutine()
    f()
  }()
}

func StartRoutine() {
	waitGroup.Add(1)
}

func FinishRoutine() {
	waitGroup.Done()
}

func WaitForShutdown() {
	signal.Notify(ShutdownChannel)
	<-ShutdownChannel
	shutdownHandler()
}

func NewListener(oldListener net.Listener) *GracefulListener {
	listener := GracefulListener{oldListener, true}
	return &listener
}

type GracefulListener struct {
	net.Listener
	open bool
}

func (this *GracefulListener) Accept() (net.Conn, error) {
	conn, err := this.Listener.Accept()
	if err != nil {
		if !this.open {
			waitGroup.Wait()
			err = mannersError{err}
		}
		return nil, err
	}
	StartRoutine()
	return GracefulConnection{conn}, nil
}

func (this *GracefulListener) Close() error {
	if !this.open {
		return nil
	}
	this.open = false
	err := this.Listener.Close()
	return err
}

func (this *GracefulListener) CloseOnShutdown() {
	shutdownHandler = func() { this.Close() }
}

type GracefulConnection struct {
	net.Conn
}

func (this GracefulConnection) Close() error {
	err := this.Conn.Close()
	FinishRoutine()
	return err
}

type mannersError struct {
	error
}
<|endoftext|>


<commit_before><commit_msg>terraform: add variables to Interpolator value<commit_after><|endoftext|>


<commit_before>package green_extension_uploader

import (
	"fmt"
	"github.com/aliyun/alibaba-cloud-sdk-go/services/green"
	"github.com/aliyun/aliyun-oss-go-sdk/oss"
	"github.com/satori/go.uuid"
	"os"
	"bytes"
	"time"
	"encoding/json"
)

type uploadCredentials struct {
	AccessKeyId string `json:"accessKeyId"`
	AccessKeySecret string `json:"accessKeySecret"`
	SecurityToken string `json:"securityToken"`
	ExpiredTime int64 `json:"expiredTime"`
	OssEndpoint string `json:"ossEndpoint"`
	UploadBucket string `json:"uploadBucket"`
	UploadFolder string `json:"uploadFolder"`
}

type ClientUploader struct {
	GreenClient *green.Client
	UploadCredentials *uploadCredentials
	Headers map[string]string
	Prefix string
}

func GetImageUploaderClient(client *green.Client)(clientUploader *ClientUploader)  {
	clientUploader = &ClientUploader{client, nil, make(map[string]string), "images"}
	return
}

func GetVideoUploaderClient(client *green.Client)(clientUploader *ClientUploader)  {
	clientUploader = &ClientUploader{client, nil, make(map[string]string), "videos"}
	return
}

func GetVoiceUploaderClient(client *green.Client)(clientUploader *ClientUploader)  {
	clientUploader = &ClientUploader{client, nil, make(map[string]string), "voices"}
	return
}

func GetFileUploaderClient(client *green.Client)(clientUploader *ClientUploader)  {
	clientUploader = &ClientUploader{client, nil, make(map[string]string), "files"}
	return
}

func (clientUploader *ClientUploader)UploadFile(filepath string)(*string, error)  {
	uploadCredentials, err := clientUploader.getUploadCredentials()
	fmt.Println(uploadCredentials.OssEndpoint)
	if uploadCredentials == nil {
		return nil, err
	}

	client, err := oss.New(uploadCredentials.OssEndpoint, uploadCredentials.AccessKeyId, uploadCredentials.AccessKeySecret, oss.SecurityToken(uploadCredentials.SecurityToken))
	if err != nil {
		fmt.Println("Error:", err)
		return nil, err
	}
	// 获取存储空间。
	bucket, err := client.Bucket(uploadCredentials.UploadBucket)
	if err != nil {
		fmt.Println("Error:", err)
		return nil, err
	}

	// 读取本地文件。
	fd, err := os.Open(filepath)
	if err != nil {
		fmt.Println("Error:", err)
		return nil, err
	}
	defer fd.Close()

	uuid := uuid.NewV4()
	object := uploadCredentials.UploadFolder + "/" + clientUploader.Prefix + "/" + uuid.String()
	// 上传文件流。
	err = bucket.PutObject(object, fd)
	if err != nil {
		fmt.Println("Error:", err)
		return nil, err
	}

	uploadedUrl :="oss://" + uploadCredentials.UploadBucket + "/" + object
	return &uploadedUrl, nil
}

func (clientUploader *ClientUploader)UploadBytes(dataBytes []byte)(*string, error)  {
	uploadCredentials, err := clientUploader.getUploadCredentials()

	if uploadCredentials == nil {
		return nil, err
	}

	client, err := oss.New(uploadCredentials.OssEndpoint, uploadCredentials.AccessKeyId, uploadCredentials.AccessKeySecret, oss.SecurityToken(uploadCredentials.SecurityToken))
	if err != nil {
		fmt.Println("Error:", err)
		return nil, err
	}
	// 获取存储空间。
	bucket, err := client.Bucket(uploadCredentials.UploadBucket)
	if err != nil {
		fmt.Println("Error:", err)
		return nil, err
	}

	uuid := uuid.NewV4()
	object := uploadCredentials.UploadFolder + "/" + clientUploader.Prefix + "/" + uuid.String()
	// 上传文件流。
	err = bucket.PutObject(object, bytes.NewReader(dataBytes))
	if err != nil {
		fmt.Println("Error:", err)
		return nil, err
	}

	uploadedUrl :="oss://" + uploadCredentials.UploadBucket + "/" + object
	return &uploadedUrl, nil
}

func (clientUploader *ClientUploader)getUploadCredentials()(*uploadCredentials,  error)  {
	if clientUploader.UploadCredentials == nil || clientUploader.UploadCredentials.ExpiredTime < (time.Now().UnixNano() / 1e6) {
		 uploadCredentials, err := clientUploader.getUploadCredentialsFromServer()
         if err == nil {
			 clientUploader.UploadCredentials = uploadCredentials
		 }

		 return clientUploader.UploadCredentials, err
	}

	return clientUploader.UploadCredentials, nil
}

type uploadCredentialsResponse struct {
	Code int16 `json:"code"`
	Data uploadCredentials `json:"data"`
	Msg string `json:"msg"`
	RequestId string `json:"requestId"`

}

func (clientUploader *ClientUploader)getUploadCredentialsFromServer()(*uploadCredentials, error)  {
	uploadCredentialsRequest := green.CreateUploadCredentialsRequest();
	dataJson, _:= json.Marshal(make(map[string]string))
	uploadCredentialsRequest.SetContent(dataJson)
	var uploadCredentials *uploadCredentials
	// 发起请求并处理异常
	response, err := clientUploader.GreenClient.UploadCredentials(uploadCredentialsRequest)
	if err != nil {
		// 异常处理
		return uploadCredentials, err
	}

	uploadCredentialsResponse := uploadCredentialsResponse{}
	err = json.Unmarshal([]byte(response.GetHttpContentString()), &uploadCredentialsResponse)
	if err == nil {
		uploadCredentials = &uploadCredentialsResponse.Data
	}

	return  uploadCredentials, err
}

<commit_msg>Delete client_uploader.go<commit_after><|endoftext|>


<commit_before>package gateway

import (
	"errors"
	"math/rand"
	"net"
	"sync"
	"time"

	"github.com/NebulousLabs/Sia/build"
	"github.com/NebulousLabs/Sia/encoding"
	"github.com/NebulousLabs/Sia/modules"

	"github.com/inconshreveable/muxado"
)

const (
	dialTimeout = 10 * time.Second
	// the gateway will not make outbound connections above this threshold
	wellConnectedThreshold = 8
	// the gateway will not accept inbound connections above this threshold
	fullyConnectedThreshold = 128
)

type peer struct {
	addr    modules.NetAddress
	sess    muxado.Session
	inbound bool
}

func (p *peer) open() (modules.PeerConn, error) {
	conn, err := p.sess.Open()
	if err != nil {
		return nil, err
	}
	return &peerConn{conn}, nil
}

func (p *peer) accept() (modules.PeerConn, error) {
	conn, err := p.sess.Accept()
	if err != nil {
		return nil, err
	}
	return &peerConn{conn}, nil
}

// addPeer adds a peer to the Gateway's peer list and spawns a listener thread
// to handle its requests.
func (g *Gateway) addPeer(p *peer) {
	g.peers[p.addr] = p
	go g.listenPeer(p)
}

// randomInboundPeer returns a random peer that initiated its connection.
func (g *Gateway) randomInboundPeer() modules.NetAddress {
	if len(g.peers) > 0 {
		r := rand.Intn(len(g.peers))
		for addr, peer := range g.peers {
			// only select inbound peers
			if !peer.inbound {
				continue
			}
			if r == 0 {
				return addr
			}
			r--
		}
	}

	return ""
}

// listen handles incoming connection requests. If the connection is accepted,
// the peer will be added to the Gateway's peer list.
func (g *Gateway) listen() {
	for {
		conn, err := g.listener.Accept()
		if err != nil {
			return
		}

		go g.acceptConn(conn)
	}
}

// acceptConn adds a connecting node as a peer.
func (g *Gateway) acceptConn(conn net.Conn) {
	addr := modules.NetAddress(conn.RemoteAddr().String())
	g.log.Printf("INFO: %v wants to connect", addr)

	// don't connect to an IP address more than once
	if build.Release != "testing" {
		id := g.mu.RLock()
		for p := range g.peers {
			if p.Host() == addr.Host() {
				g.mu.RUnlock(id)
				conn.Close()
				g.log.Printf("INFO: rejected connection from %v: already connected", addr)
				return
			}
		}
		g.mu.RUnlock(id)
	}

	// read version
	var remoteVersion string
	if err := encoding.ReadObject(conn, &remoteVersion, maxAddrLength); err != nil {
		conn.Close()
		g.log.Printf("INFO: %v wanted to connect, but we could not read their version: %v", addr, err)
		return
	}

	// decide whether to accept
	// NOTE: this version must be bumped whenever the gateway or consensus
	// breaks compatibility.
	if build.VersionCmp(remoteVersion, "0.3.3") < 0 {
		encoding.WriteObject(conn, "reject")
		conn.Close()
		g.log.Printf("INFO: %v wanted to connect, but their version (%v) was unacceptable", addr, remoteVersion)
		return
	}

	// respond with our version
	if err := encoding.WriteObject(conn, "0.3.3"); err != nil {
		conn.Close()
		g.log.Printf("INFO: could not write version ack to %v: %v", addr, err)
		return
	}

	// If we are already fully connected, kick out an old inbound peer to make
	// room for the new one. Among other things, this ensures that bootstrap
	// nodes will always be connectible. Worst case, you'll connect, receive a
	// node list, and immediately get booted. But once you have the node list
	// you should be able to connect to less full peers.
	id := g.mu.Lock()
	if len(g.peers) >= fullyConnectedThreshold {
		oldPeer := g.randomInboundPeer()
		g.peers[oldPeer].sess.Close()
		delete(g.peers, oldPeer)
		g.log.Printf("INFO: disconnected from %v to make room for %v", oldPeer, addr)
	}
	// add the peer
	g.addPeer(&peer{addr: addr, sess: muxado.Server(conn), inbound: true})
	g.mu.Unlock(id)

	g.log.Printf("INFO: accepted connection from new peer %v (v%v)", addr, remoteVersion)
}

// Connect establishes a persistent connection to a peer, and adds it to the
// Gateway's peer list.
func (g *Gateway) Connect(addr modules.NetAddress) error {
	if addr == g.Address() {
		return errors.New("can't connect to our own address")
	}

	id := g.mu.RLock()
	_, exists := g.peers[addr]
	g.mu.RUnlock(id)
	if exists {
		return errors.New("peer already added")
	}

	conn, err := net.DialTimeout("tcp", string(addr), dialTimeout)
	if err != nil {
		return err
	}
	// send our version
	if err := encoding.WriteObject(conn, "0.3.3"); err != nil {
		return err
	}
	// read version ack
	var remoteVersion string
	if err := encoding.ReadObject(conn, &remoteVersion, maxAddrLength); err != nil {
		return err
	} else if remoteVersion == "reject" {
		return errors.New("peer rejected connection")
	}
	// decide whether to accept this version
	if build.VersionCmp(remoteVersion, "0.3.3") < 0 {
		conn.Close()
		return errors.New("unacceptable version: " + remoteVersion)
	}

	g.log.Println("INFO: connected to new peer", addr)

	id = g.mu.Lock()
	g.addPeer(&peer{addr: addr, sess: muxado.Client(conn), inbound: false})
	g.mu.Unlock(id)

	// call initRPCs
	id = g.mu.RLock()
	var wg sync.WaitGroup
	wg.Add(len(g.initRPCs))
	for name, fn := range g.initRPCs {
		go func(name string, fn modules.RPCFunc) {
			// errors here are non-fatal
			g.RPC(addr, name, fn)
			wg.Done()
		}(name, fn)
	}
	g.mu.RUnlock(id)
	wg.Wait()

	return nil
}

// Disconnect terminates a connection to a peer and removes it from the
// Gateway's peer list. The peer's address remains in the node list.
func (g *Gateway) Disconnect(addr modules.NetAddress) error {
	id := g.mu.RLock()
	p, exists := g.peers[addr]
	g.mu.RUnlock(id)
	if !exists {
		return errors.New("not connected to that node")
	}
	p.sess.Close()
	id = g.mu.Lock()
	delete(g.peers, addr)
	g.mu.Unlock(id)

	g.log.Println("INFO: disconnected from peer", addr)
	return nil
}

// makeOutboundConnections tries to keep the Gateway well-connected. As long
// as the Gateway is not well-connected, it tries to add random nodes as
// peers. It sleeps when the Gateway becomes well-connected, or it has tried
// more than 100 nodes.
func (g *Gateway) makeOutboundConnections() {
	for {
		for i := 0; i < 100; i++ {
			id := g.mu.RLock()
			numPeers := len(g.peers)
			addr, err := g.randomNode()
			g.mu.RUnlock(id)
			if err != nil || numPeers >= wellConnectedThreshold {
				break
			}
			err = g.Connect(addr)
			// aggressively remove unresponsive nodes
			if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
				id = g.mu.Lock()
				g.removeNode(addr)
				g.mu.Unlock(id)
			}
		}
		time.Sleep(5 * time.Second)
	}
}

func (g *Gateway) Peers() []modules.NetAddress {
	id := g.mu.RLock()
	defer g.mu.RUnlock(id)
	var peers []modules.NetAddress
	for addr := range g.peers {
		peers = append(peers, addr)
	}
	return peers
}
<commit_msg>ask for more nodes while we have <100<commit_after>package gateway

import (
	"errors"
	"math/rand"
	"net"
	"sync"
	"time"

	"github.com/NebulousLabs/Sia/build"
	"github.com/NebulousLabs/Sia/encoding"
	"github.com/NebulousLabs/Sia/modules"

	"github.com/inconshreveable/muxado"
)

const (
	dialTimeout = 10 * time.Second
	// the gateway will not make outbound connections above this threshold
	wellConnectedThreshold = 8
	// the gateway will not accept inbound connections above this threshold
	fullyConnectedThreshold = 128
	// the gateway will ask for more addresses below this threshold
	minNodeListLen = 100
)

type peer struct {
	addr    modules.NetAddress
	sess    muxado.Session
	inbound bool
}

func (p *peer) open() (modules.PeerConn, error) {
	conn, err := p.sess.Open()
	if err != nil {
		return nil, err
	}
	return &peerConn{conn}, nil
}

func (p *peer) accept() (modules.PeerConn, error) {
	conn, err := p.sess.Accept()
	if err != nil {
		return nil, err
	}
	return &peerConn{conn}, nil
}

// addPeer adds a peer to the Gateway's peer list and spawns a listener thread
// to handle its requests.
func (g *Gateway) addPeer(p *peer) {
	g.peers[p.addr] = p
	go g.listenPeer(p)
}

// randomPeer returns a random peer from the gateway's peer list.
func (g *Gateway) randomPeer() (modules.NetAddress, error) {
	if len(g.peers) > 0 {
		r := rand.Intn(len(g.peers))
		for addr := range g.peers {
			if r == 0 {
				return addr, nil
			}
			r--
		}
	}

	return "", errNoPeers
}

// randomInboundPeer returns a random peer that initiated its connection.
func (g *Gateway) randomInboundPeer() (modules.NetAddress, error) {
	if len(g.peers) > 0 {
		r := rand.Intn(len(g.peers))
		for addr, peer := range g.peers {
			// only select inbound peers
			if !peer.inbound {
				continue
			}
			if r == 0 {
				return addr, nil
			}
			r--
		}
	}

	return "", errNoPeers
}

// listen handles incoming connection requests. If the connection is accepted,
// the peer will be added to the Gateway's peer list.
func (g *Gateway) listen() {
	for {
		conn, err := g.listener.Accept()
		if err != nil {
			return
		}

		go g.acceptConn(conn)
	}
}

// acceptConn adds a connecting node as a peer.
func (g *Gateway) acceptConn(conn net.Conn) {
	addr := modules.NetAddress(conn.RemoteAddr().String())
	g.log.Printf("INFO: %v wants to connect", addr)

	// don't connect to an IP address more than once
	if build.Release != "testing" {
		id := g.mu.RLock()
		for p := range g.peers {
			if p.Host() == addr.Host() {
				g.mu.RUnlock(id)
				conn.Close()
				g.log.Printf("INFO: rejected connection from %v: already connected", addr)
				return
			}
		}
		g.mu.RUnlock(id)
	}

	// read version
	var remoteVersion string
	if err := encoding.ReadObject(conn, &remoteVersion, maxAddrLength); err != nil {
		conn.Close()
		g.log.Printf("INFO: %v wanted to connect, but we could not read their version: %v", addr, err)
		return
	}

	// decide whether to accept
	// NOTE: this version must be bumped whenever the gateway or consensus
	// breaks compatibility.
	if build.VersionCmp(remoteVersion, "0.3.3") < 0 {
		encoding.WriteObject(conn, "reject")
		conn.Close()
		g.log.Printf("INFO: %v wanted to connect, but their version (%v) was unacceptable", addr, remoteVersion)
		return
	}

	// respond with our version
	if err := encoding.WriteObject(conn, "0.3.3"); err != nil {
		conn.Close()
		g.log.Printf("INFO: could not write version ack to %v: %v", addr, err)
		return
	}

	// If we are already fully connected, kick out an old inbound peer to make
	// room for the new one. Among other things, this ensures that bootstrap
	// nodes will always be connectible. Worst case, you'll connect, receive a
	// node list, and immediately get booted. But once you have the node list
	// you should be able to connect to less full peers.
	id := g.mu.Lock()
	if len(g.peers) >= fullyConnectedThreshold {
		oldPeer, err := g.randomInboundPeer()
		if err == nil {
			g.peers[oldPeer].sess.Close()
			delete(g.peers, oldPeer)
			g.log.Printf("INFO: disconnected from %v to make room for %v", oldPeer, addr)
		}
	}
	// add the peer
	g.addPeer(&peer{addr: addr, sess: muxado.Server(conn), inbound: true})
	g.mu.Unlock(id)

	g.log.Printf("INFO: accepted connection from new peer %v (v%v)", addr, remoteVersion)
}

// Connect establishes a persistent connection to a peer, and adds it to the
// Gateway's peer list.
func (g *Gateway) Connect(addr modules.NetAddress) error {
	if addr == g.Address() {
		return errors.New("can't connect to our own address")
	}

	id := g.mu.RLock()
	_, exists := g.peers[addr]
	g.mu.RUnlock(id)
	if exists {
		return errors.New("peer already added")
	}

	conn, err := net.DialTimeout("tcp", string(addr), dialTimeout)
	if err != nil {
		return err
	}
	// send our version
	if err := encoding.WriteObject(conn, "0.3.3"); err != nil {
		return err
	}
	// read version ack
	var remoteVersion string
	if err := encoding.ReadObject(conn, &remoteVersion, maxAddrLength); err != nil {
		return err
	} else if remoteVersion == "reject" {
		return errors.New("peer rejected connection")
	}
	// decide whether to accept this version
	if build.VersionCmp(remoteVersion, "0.3.3") < 0 {
		conn.Close()
		return errors.New("unacceptable version: " + remoteVersion)
	}

	g.log.Println("INFO: connected to new peer", addr)

	id = g.mu.Lock()
	g.addPeer(&peer{addr: addr, sess: muxado.Client(conn), inbound: false})
	g.mu.Unlock(id)

	// call initRPCs
	id = g.mu.RLock()
	var wg sync.WaitGroup
	wg.Add(len(g.initRPCs))
	for name, fn := range g.initRPCs {
		go func(name string, fn modules.RPCFunc) {
			// errors here are non-fatal
			g.RPC(addr, name, fn)
			wg.Done()
		}(name, fn)
	}
	g.mu.RUnlock(id)
	wg.Wait()

	return nil
}

// Disconnect terminates a connection to a peer and removes it from the
// Gateway's peer list. The peer's address remains in the node list.
func (g *Gateway) Disconnect(addr modules.NetAddress) error {
	id := g.mu.RLock()
	p, exists := g.peers[addr]
	g.mu.RUnlock(id)
	if !exists {
		return errors.New("not connected to that node")
	}
	p.sess.Close()
	id = g.mu.Lock()
	delete(g.peers, addr)
	g.mu.Unlock(id)

	g.log.Println("INFO: disconnected from peer", addr)
	return nil
}

// makeOutboundConnections tries to keep the Gateway well-connected. As long
// as the Gateway is not well-connected, it tries to add random nodes as
// peers. It sleeps when the Gateway becomes well-connected, or it has tried
// more than 100 nodes.
func (g *Gateway) makeOutboundConnections() {
	for {
		for i := 0; i < 100; i++ {
			id := g.mu.RLock()
			numPeers := len(g.peers)
			addr, err := g.randomNode()
			g.mu.RUnlock(id)
			if err != nil || numPeers >= wellConnectedThreshold {
				break
			}
			err = g.Connect(addr)
			// aggressively remove unresponsive nodes
			if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
				id = g.mu.Lock()
				g.removeNode(addr)
				g.mu.Unlock(id)
			}
		}
		// request more nodes if necessary
		id := g.mu.RLock()
		numNodes := len(g.nodes)
		addr, err := g.randomPeer()
		g.mu.RUnlock(id)
		if build.Release != "testing" && err == nil && numNodes < minNodeListLen {
			g.RPC(addr, "ShareNodes", g.requestNodes)
		}
		time.Sleep(5 * time.Second)
	}
}

func (g *Gateway) Peers() []modules.NetAddress {
	id := g.mu.RLock()
	defer g.mu.RUnlock(id)
	var peers []modules.NetAddress
	for addr := range g.peers {
		peers = append(peers, addr)
	}
	return peers
}
<|endoftext|>


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

// Cgo; see gmp.go for an overview.

// TODO(rsc):
//	Emit correct line number annotations.
//	Make 6g understand the annotations.

package main

import (
	"fmt";
	"go/ast";
	"os";
)

func usage()	{ fmt.Fprint(os.Stderr, "usage: cgo [compiler options] file.go\n") }

var ptrSizeMap = map[string]int64{
	"386": 4,
	"amd64": 8,
	"arm": 4,
}

var expandName = map[string]string{
	"schar": "signed char",
	"uchar": "unsigned char",
	"ushort": "unsigned short",
	"uint": "unsigned int",
	"ulong": "unsigned long",
	"longlong": "long long",
	"ulonglong": "unsigned long long",
}

func main() {
	args := os.Args;
	if len(args) < 2 {
		usage();
		os.Exit(2);
	}
	gccOptions := args[1 : len(args)-1];
	input := args[len(args)-1];

	arch := os.Getenv("GOARCH");
	if arch == "" {
		fatal("$GOARCH is not set")
	}
	ptrSize, ok := ptrSizeMap[arch];
	if !ok {
		fatal("unknown architecture %s", arch)
	}

	p := openProg(input);
	for _, cref := range p.Crefs {
		// Convert C.ulong to C.unsigned long, etc.
		if expand, ok := expandName[cref.Name]; ok {
			cref.Name = expand
		}
	}

	p.PtrSize = ptrSize;
	p.Preamble = p.Preamble + "\n" + builtinProlog;
	p.GccOptions = gccOptions;
	p.loadDebugInfo();
	p.Vardef = make(map[string]*Type);
	p.Funcdef = make(map[string]*FuncType);

	for _, cref := range p.Crefs {
		switch cref.Context {
		case "call":
			if !cref.TypeName {
				// Is an actual function call.
				*cref.Expr = &ast.Ident{Value: "_C_" + cref.Name};
				p.Funcdef[cref.Name] = cref.FuncType;
				break;
			}
			*cref.Expr = cref.Type.Go;
		case "expr":
			if cref.TypeName {
				error((*cref.Expr).Pos(), "type C.%s used as expression", cref.Name)
			}
			// Reference to C variable.
			// We declare a pointer and arrange to have it filled in.
			*cref.Expr = &ast.StarExpr{X: &ast.Ident{Value: "_C_" + cref.Name}};
			p.Vardef[cref.Name] = cref.Type;
		case "type":
			if !cref.TypeName {
				error((*cref.Expr).Pos(), "expression C.%s used as type", cref.Name)
			}
			*cref.Expr = cref.Type.Go;
		}
	}
	if nerrors > 0 {
		os.Exit(2)
	}

	p.PackagePath = p.Package;
	p.writeOutput(input);
}
<commit_msg>cgo: arrange for English error messages<commit_after>// Copyright 2009 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Cgo; see gmp.go for an overview.

// TODO(rsc):
//	Emit correct line number annotations.
//	Make 6g understand the annotations.

package main

import (
	"fmt";
	"go/ast";
	"os";
)

func usage()	{ fmt.Fprint(os.Stderr, "usage: cgo [compiler options] file.go\n") }

var ptrSizeMap = map[string]int64{
	"386": 4,
	"amd64": 8,
	"arm": 4,
}

var expandName = map[string]string{
	"schar": "signed char",
	"uchar": "unsigned char",
	"ushort": "unsigned short",
	"uint": "unsigned int",
	"ulong": "unsigned long",
	"longlong": "long long",
	"ulonglong": "unsigned long long",
}

func main() {
	args := os.Args;
	if len(args) < 2 {
		usage();
		os.Exit(2);
	}
	gccOptions := args[1 : len(args)-1];
	input := args[len(args)-1];

	arch := os.Getenv("GOARCH");
	if arch == "" {
		fatal("$GOARCH is not set")
	}
	ptrSize, ok := ptrSizeMap[arch];
	if !ok {
		fatal("unknown architecture %s", arch)
	}

	// Clear locale variables so gcc emits English errors [sic].
	os.Setenv("LANG", "en_US.UTF-8");
	os.Setenv("LC_ALL", "C");
	os.Setenv("LC_CTYPE", "C");

	p := openProg(input);
	for _, cref := range p.Crefs {
		// Convert C.ulong to C.unsigned long, etc.
		if expand, ok := expandName[cref.Name]; ok {
			cref.Name = expand
		}
	}

	p.PtrSize = ptrSize;
	p.Preamble = p.Preamble + "\n" + builtinProlog;
	p.GccOptions = gccOptions;
	p.loadDebugInfo();
	p.Vardef = make(map[string]*Type);
	p.Funcdef = make(map[string]*FuncType);

	for _, cref := range p.Crefs {
		switch cref.Context {
		case "call":
			if !cref.TypeName {
				// Is an actual function call.
				*cref.Expr = &ast.Ident{Value: "_C_" + cref.Name};
				p.Funcdef[cref.Name] = cref.FuncType;
				break;
			}
			*cref.Expr = cref.Type.Go;
		case "expr":
			if cref.TypeName {
				error((*cref.Expr).Pos(), "type C.%s used as expression", cref.Name)
			}
			// Reference to C variable.
			// We declare a pointer and arrange to have it filled in.
			*cref.Expr = &ast.StarExpr{X: &ast.Ident{Value: "_C_" + cref.Name}};
			p.Vardef[cref.Name] = cref.Type;
		case "type":
			if !cref.TypeName {
				error((*cref.Expr).Pos(), "expression C.%s used as type", cref.Name)
			}
			*cref.Expr = cref.Type.Go;
		}
	}
	if nerrors > 0 {
		os.Exit(2)
	}

	p.PackagePath = p.Package;
	p.writeOutput(input);
}
<|endoftext|>


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

// Vet is a simple checker for static errors in Go source code.
// See doc.go for more information.
package main

import (
	"bytes"
	"flag"
	"fmt"
	"go/ast"
	"go/build"
	"go/parser"
	"go/printer"
	"go/token"
	"go/types"
	"io/ioutil"
	"os"
	"path/filepath"
	"strconv"
	"strings"
)

var verbose = flag.Bool("v", false, "verbose")
var exitCode = 0

// Flags to control which checks to perform. "all" is set to true here, and disabled later if
// a flag is set explicitly.
var report = map[string]*bool{
	"all":        flag.Bool("all", true, "check everything; disabled if any explicit check is requested"),
	"atomic":     flag.Bool("atomic", false, "check for common mistaken usages of the sync/atomic package"),
	"buildtags":  flag.Bool("buildtags", false, "check that +build tags are valid"),
	"composites": flag.Bool("composites", false, "check that composite literals used type-tagged elements"),
	"methods":    flag.Bool("methods", false, "check that canonically named methods are canonically defined"),
	"printf":     flag.Bool("printf", false, "check printf-like invocations"),
	"structtags": flag.Bool("structtags", false, "check that struct field tags have canonical format"),
	"rangeloops": flag.Bool("rangeloops", false, "check that range loop variables are used correctly"),
}

// vet tells whether to report errors for the named check, a flag name.
func vet(name string) bool {
	return *report["all"] || *report[name]
}

// setExit sets the value for os.Exit when it is called, later.  It
// remembers the highest value.
func setExit(err int) {
	if err > exitCode {
		exitCode = err
	}
}

// Usage is a replacement usage function for the flags package.
func Usage() {
	fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
	fmt.Fprintf(os.Stderr, "\tvet [flags] directory...\n")
	fmt.Fprintf(os.Stderr, "\tvet [flags] files... # Must be a single package\n")
	flag.PrintDefaults()
	os.Exit(2)
}

// File is a wrapper for the state of a file used in the parser.
// The parse tree walkers are all methods of this type.
type File struct {
	pkg  *Package
	fset *token.FileSet
	name string
	file *ast.File
	b    bytes.Buffer // for use by methods
}

func main() {
	flag.Usage = Usage
	flag.Parse()

	// If a check is named explicitly, turn off the 'all' flag.
	for name, ptr := range report {
		if name != "all" && *ptr {
			*report["all"] = false
			break
		}
	}

	if *printfuncs != "" {
		for _, name := range strings.Split(*printfuncs, ",") {
			if len(name) == 0 {
				flag.Usage()
			}
			skip := 0
			if colon := strings.LastIndex(name, ":"); colon > 0 {
				var err error
				skip, err = strconv.Atoi(name[colon+1:])
				if err != nil {
					errorf(`illegal format for "Func:N" argument %q; %s`, name, err)
				}
				name = name[:colon]
			}
			name = strings.ToLower(name)
			if name[len(name)-1] == 'f' {
				printfList[name] = skip
			} else {
				printList[name] = skip
			}
		}
	}

	if flag.NArg() == 0 {
		Usage()
	}
	dirs := false
	files := false
	for _, name := range flag.Args() {
		// Is it a directory?
		fi, err := os.Stat(name)
		if err != nil {
			warnf("error walking tree: %s", err)
			continue
		}
		if fi.IsDir() {
			dirs = true
		} else {
			files = true
		}
	}
	if dirs && files {
		Usage()
	}
	if dirs {
		for _, name := range flag.Args() {
			walkDir(name)
		}
		return
	}
	doPackage(flag.Args())
	os.Exit(exitCode)
}

// doPackageDir analyzes the single package found in the directory, if there is one.
func doPackageDir(directory string) {
	pkg, err := build.Default.ImportDir(directory, 0)
	if err != nil {
		// If it's just that there are no go source files, that's fine.
		if _, nogo := err.(*build.NoGoError); nogo {
			return
		}
		// Non-fatal: we are doing a recursive walk and there may be other directories.
		warnf("cannot process directory %s: %s", directory, err)
		return
	}
	names := append(pkg.GoFiles, pkg.CgoFiles...)
	// Prefix file names with directory names.
	if directory != "." {
		for i, name := range names {
			names[i] = filepath.Join(directory, name)
		}
	}
	doPackage(names)
}

type Package struct {
	types  map[ast.Expr]types.Type
	values map[ast.Expr]interface{}
}

// doPackage analyzes the single package constructed from the named files.
func doPackage(names []string) {
	var files []*File
	var astFiles []*ast.File
	fs := token.NewFileSet()
	for _, name := range names {
		f, err := os.Open(name)
		if err != nil {
			errorf("%s: %s", name, err)
		}
		defer f.Close()
		data, err := ioutil.ReadAll(f)
		if err != nil {
			errorf("%s: %s", name, err)
		}
		checkBuildTag(name, data)
		parsedFile, err := parser.ParseFile(fs, name, bytes.NewReader(data), 0)
		if err != nil {
			errorf("%s: %s", name, err)
		}
		files = append(files, &File{fset: fs, name: name, file: parsedFile})
		astFiles = append(astFiles, parsedFile)
	}
	pkg := new(Package)
	pkg.types = make(map[ast.Expr]types.Type)
	pkg.values = make(map[ast.Expr]interface{})
	exprFn := func(x ast.Expr, typ types.Type, val interface{}) {
		pkg.types[x] = typ
		if val != nil {
			pkg.values[x] = val
		}
	}
	context := types.Context{
		Expr: exprFn,
	}
	// Type check the package.
	_, err := context.Check(fs, astFiles)
	if err != nil {
		warnf("%s", err)
	}
	for _, file := range files {
		file.pkg = pkg
		file.walkFile(file.name, file.file)
	}
}

func visit(path string, f os.FileInfo, err error) error {
	if err != nil {
		errorf("walk error: %s", err)
	}
	// One package per directory. Ignore the files themselves.
	if !f.IsDir() {
		return nil
	}
	doPackageDir(path)
	return nil
}

// walkDir recursively walks the tree looking for .go files.
func walkDir(root string) {
	filepath.Walk(root, visit)
}

// errorf formats the error to standard error, adding program
// identification and a newline, and exits.
func errorf(format string, args ...interface{}) {
	fmt.Fprintf(os.Stderr, "vet: "+format+"\n", args...)
	os.Exit(2)
}

// warnf formats the error to standard error, adding program
// identification and a newline, but does not exit.
func warnf(format string, args ...interface{}) {
	fmt.Fprintf(os.Stderr, "vet: "+format+"\n", args...)
	setExit(1)
}

// Println is fmt.Println guarded by -v.
func Println(args ...interface{}) {
	if !*verbose {
		return
	}
	fmt.Println(args...)
}

// Printf is fmt.Printf guarded by -v.
func Printf(format string, args ...interface{}) {
	if !*verbose {
		return
	}
	fmt.Printf(format+"\n", args...)
}

// Bad reports an error and sets the exit code..
func (f *File) Bad(pos token.Pos, args ...interface{}) {
	f.Warn(pos, args...)
	setExit(1)
}

// Badf reports a formatted error and sets the exit code.
func (f *File) Badf(pos token.Pos, format string, args ...interface{}) {
	f.Warnf(pos, format, args...)
	setExit(1)
}

func (f *File) loc(pos token.Pos) string {
	// Do not print columns. Because the pos often points to the start of an
	// expression instead of the inner part with the actual error, the
	// precision can mislead.
	posn := f.fset.Position(pos)
	return fmt.Sprintf("%s:%d: ", posn.Filename, posn.Line)
}

// Warn reports an error but does not set the exit code.
func (f *File) Warn(pos token.Pos, args ...interface{}) {
	fmt.Fprint(os.Stderr, f.loc(pos)+fmt.Sprintln(args...))
}

// Warnf reports a formatted error but does not set the exit code.
func (f *File) Warnf(pos token.Pos, format string, args ...interface{}) {
	fmt.Fprintf(os.Stderr, f.loc(pos)+format+"\n", args...)
}

// walkFile walks the file's tree.
func (f *File) walkFile(name string, file *ast.File) {
	Println("Checking file", name)
	ast.Walk(f, file)
}

// Visit implements the ast.Visitor interface.
func (f *File) Visit(node ast.Node) ast.Visitor {
	switch n := node.(type) {
	case *ast.AssignStmt:
		f.walkAssignStmt(n)
	case *ast.CallExpr:
		f.walkCallExpr(n)
	case *ast.CompositeLit:
		f.walkCompositeLit(n)
	case *ast.Field:
		f.walkFieldTag(n)
	case *ast.FuncDecl:
		f.walkMethodDecl(n)
	case *ast.InterfaceType:
		f.walkInterfaceType(n)
	case *ast.RangeStmt:
		f.walkRangeStmt(n)
	}
	return f
}

// walkAssignStmt walks an assignment statement
func (f *File) walkAssignStmt(stmt *ast.AssignStmt) {
	f.checkAtomicAssignment(stmt)
}

// walkCall walks a call expression.
func (f *File) walkCall(call *ast.CallExpr, name string) {
	f.checkFmtPrintfCall(call, name)
}

// walkCallExpr walks a call expression.
func (f *File) walkCallExpr(call *ast.CallExpr) {
	switch x := call.Fun.(type) {
	case *ast.Ident:
		f.walkCall(call, x.Name)
	case *ast.SelectorExpr:
		f.walkCall(call, x.Sel.Name)
	}
}

// walkCompositeLit walks a composite literal.
func (f *File) walkCompositeLit(c *ast.CompositeLit) {
	f.checkUntaggedLiteral(c)
}

// walkFieldTag walks a struct field tag.
func (f *File) walkFieldTag(field *ast.Field) {
	if field.Tag == nil {
		return
	}
	f.checkCanonicalFieldTag(field)
}

// walkMethodDecl walks the method's signature.
func (f *File) walkMethod(id *ast.Ident, t *ast.FuncType) {
	f.checkCanonicalMethod(id, t)
}

// walkMethodDecl walks the method signature in the declaration.
func (f *File) walkMethodDecl(d *ast.FuncDecl) {
	if d.Recv == nil {
		// not a method
		return
	}
	f.walkMethod(d.Name, d.Type)
}

// walkInterfaceType walks the method signatures of an interface.
func (f *File) walkInterfaceType(t *ast.InterfaceType) {
	for _, field := range t.Methods.List {
		for _, id := range field.Names {
			f.walkMethod(id, field.Type.(*ast.FuncType))
		}
	}
}

// walkRangeStmt walks a range statement.
func (f *File) walkRangeStmt(n *ast.RangeStmt) {
	checkRangeLoop(f, n)
}

// goFmt returns a string representation of the expression
func (f *File) gofmt(x ast.Expr) string {
	f.b.Reset()
	printer.Fprint(&f.b, f.fset, x)
	return f.b.String()
}
<commit_msg>cmd/vet: silence error from type checker unless verbose is set. Also restores the checking of _test.go files, which disappeared as a result of the package-at-a-time change. Fixes issue 4895.<commit_after>// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Vet is a simple checker for static errors in Go source code.
// See doc.go for more information.
package main

import (
	"bytes"
	"flag"
	"fmt"
	"go/ast"
	"go/build"
	"go/parser"
	"go/printer"
	"go/token"
	"go/types"
	"io/ioutil"
	"os"
	"path/filepath"
	"strconv"
	"strings"
)

var verbose = flag.Bool("v", false, "verbose")
var exitCode = 0

// Flags to control which checks to perform. "all" is set to true here, and disabled later if
// a flag is set explicitly.
var report = map[string]*bool{
	"all":        flag.Bool("all", true, "check everything; disabled if any explicit check is requested"),
	"atomic":     flag.Bool("atomic", false, "check for common mistaken usages of the sync/atomic package"),
	"buildtags":  flag.Bool("buildtags", false, "check that +build tags are valid"),
	"composites": flag.Bool("composites", false, "check that composite literals used type-tagged elements"),
	"methods":    flag.Bool("methods", false, "check that canonically named methods are canonically defined"),
	"printf":     flag.Bool("printf", false, "check printf-like invocations"),
	"structtags": flag.Bool("structtags", false, "check that struct field tags have canonical format"),
	"rangeloops": flag.Bool("rangeloops", false, "check that range loop variables are used correctly"),
}

// vet tells whether to report errors for the named check, a flag name.
func vet(name string) bool {
	return *report["all"] || *report[name]
}

// setExit sets the value for os.Exit when it is called, later.  It
// remembers the highest value.
func setExit(err int) {
	if err > exitCode {
		exitCode = err
	}
}

// Usage is a replacement usage function for the flags package.
func Usage() {
	fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
	fmt.Fprintf(os.Stderr, "\tvet [flags] directory...\n")
	fmt.Fprintf(os.Stderr, "\tvet [flags] files... # Must be a single package\n")
	flag.PrintDefaults()
	os.Exit(2)
}

// File is a wrapper for the state of a file used in the parser.
// The parse tree walkers are all methods of this type.
type File struct {
	pkg  *Package
	fset *token.FileSet
	name string
	file *ast.File
	b    bytes.Buffer // for use by methods
}

func main() {
	flag.Usage = Usage
	flag.Parse()

	// If a check is named explicitly, turn off the 'all' flag.
	for name, ptr := range report {
		if name != "all" && *ptr {
			*report["all"] = false
			break
		}
	}

	if *printfuncs != "" {
		for _, name := range strings.Split(*printfuncs, ",") {
			if len(name) == 0 {
				flag.Usage()
			}
			skip := 0
			if colon := strings.LastIndex(name, ":"); colon > 0 {
				var err error
				skip, err = strconv.Atoi(name[colon+1:])
				if err != nil {
					errorf(`illegal format for "Func:N" argument %q; %s`, name, err)
				}
				name = name[:colon]
			}
			name = strings.ToLower(name)
			if name[len(name)-1] == 'f' {
				printfList[name] = skip
			} else {
				printList[name] = skip
			}
		}
	}

	if flag.NArg() == 0 {
		Usage()
	}
	dirs := false
	files := false
	for _, name := range flag.Args() {
		// Is it a directory?
		fi, err := os.Stat(name)
		if err != nil {
			warnf("error walking tree: %s", err)
			continue
		}
		if fi.IsDir() {
			dirs = true
		} else {
			files = true
		}
	}
	if dirs && files {
		Usage()
	}
	if dirs {
		for _, name := range flag.Args() {
			walkDir(name)
		}
		return
	}
	doPackage(flag.Args())
	os.Exit(exitCode)
}

// prefixDirectory places the directory name on the beginning of each name in the list.
func prefixDirectory(directory string, names []string) {
	if directory != "." {
		for i, name := range names {
			names[i] = filepath.Join(directory, name)
		}
	}
}

// doPackageDir analyzes the single package found in the directory, if there is one,
// plus a test package, if there is one.
func doPackageDir(directory string) {
	pkg, err := build.Default.ImportDir(directory, 0)
	if err != nil {
		// If it's just that there are no go source files, that's fine.
		if _, nogo := err.(*build.NoGoError); nogo {
			return
		}
		// Non-fatal: we are doing a recursive walk and there may be other directories.
		warnf("cannot process directory %s: %s", directory, err)
		return
	}
	var names []string
	names = append(names, pkg.CgoFiles...)
	names = append(names, pkg.TestGoFiles...) // These are also in the "foo" package.
	prefixDirectory(directory, names)
	doPackage(names)
	// Is there also a "foo_test" package? If so, do that one as well.
	if len(pkg.XTestGoFiles) > 0 {
		names = pkg.XTestGoFiles
		prefixDirectory(directory, names)
		doPackage(names)
	}
}

type Package struct {
	types  map[ast.Expr]types.Type
	values map[ast.Expr]interface{}
}

// doPackage analyzes the single package constructed from the named files.
func doPackage(names []string) {
	var files []*File
	var astFiles []*ast.File
	fs := token.NewFileSet()
	for _, name := range names {
		f, err := os.Open(name)
		if err != nil {
			errorf("%s: %s", name, err)
		}
		defer f.Close()
		data, err := ioutil.ReadAll(f)
		if err != nil {
			errorf("%s: %s", name, err)
		}
		checkBuildTag(name, data)
		parsedFile, err := parser.ParseFile(fs, name, bytes.NewReader(data), 0)
		if err != nil {
			errorf("%s: %s", name, err)
		}
		files = append(files, &File{fset: fs, name: name, file: parsedFile})
		astFiles = append(astFiles, parsedFile)
	}
	pkg := new(Package)
	pkg.types = make(map[ast.Expr]types.Type)
	pkg.values = make(map[ast.Expr]interface{})
	exprFn := func(x ast.Expr, typ types.Type, val interface{}) {
		pkg.types[x] = typ
		if val != nil {
			pkg.values[x] = val
		}
	}
	context := types.Context{
		Expr: exprFn,
	}
	// Type check the package.
	_, err := context.Check(fs, astFiles)
	if err != nil && *verbose {
		warnf("%s", err)
	}
	for _, file := range files {
		file.pkg = pkg
		file.walkFile(file.name, file.file)
	}
}

func visit(path string, f os.FileInfo, err error) error {
	if err != nil {
		errorf("walk error: %s", err)
	}
	// One package per directory. Ignore the files themselves.
	if !f.IsDir() {
		return nil
	}
	doPackageDir(path)
	return nil
}

// walkDir recursively walks the tree looking for .go files.
func walkDir(root string) {
	filepath.Walk(root, visit)
}

// errorf formats the error to standard error, adding program
// identification and a newline, and exits.
func errorf(format string, args ...interface{}) {
	fmt.Fprintf(os.Stderr, "vet: "+format+"\n", args...)
	os.Exit(2)
}

// warnf formats the error to standard error, adding program
// identification and a newline, but does not exit.
func warnf(format string, args ...interface{}) {
	fmt.Fprintf(os.Stderr, "vet: "+format+"\n", args...)
	setExit(1)
}

// Println is fmt.Println guarded by -v.
func Println(args ...interface{}) {
	if !*verbose {
		return
	}
	fmt.Println(args...)
}

// Printf is fmt.Printf guarded by -v.
func Printf(format string, args ...interface{}) {
	if !*verbose {
		return
	}
	fmt.Printf(format+"\n", args...)
}

// Bad reports an error and sets the exit code..
func (f *File) Bad(pos token.Pos, args ...interface{}) {
	f.Warn(pos, args...)
	setExit(1)
}

// Badf reports a formatted error and sets the exit code.
func (f *File) Badf(pos token.Pos, format string, args ...interface{}) {
	f.Warnf(pos, format, args...)
	setExit(1)
}

func (f *File) loc(pos token.Pos) string {
	// Do not print columns. Because the pos often points to the start of an
	// expression instead of the inner part with the actual error, the
	// precision can mislead.
	posn := f.fset.Position(pos)
	return fmt.Sprintf("%s:%d: ", posn.Filename, posn.Line)
}

// Warn reports an error but does not set the exit code.
func (f *File) Warn(pos token.Pos, args ...interface{}) {
	fmt.Fprint(os.Stderr, f.loc(pos)+fmt.Sprintln(args...))
}

// Warnf reports a formatted error but does not set the exit code.
func (f *File) Warnf(pos token.Pos, format string, args ...interface{}) {
	fmt.Fprintf(os.Stderr, f.loc(pos)+format+"\n", args...)
}

// walkFile walks the file's tree.
func (f *File) walkFile(name string, file *ast.File) {
	Println("Checking file", name)
	ast.Walk(f, file)
}

// Visit implements the ast.Visitor interface.
func (f *File) Visit(node ast.Node) ast.Visitor {
	switch n := node.(type) {
	case *ast.AssignStmt:
		f.walkAssignStmt(n)
	case *ast.CallExpr:
		f.walkCallExpr(n)
	case *ast.CompositeLit:
		f.walkCompositeLit(n)
	case *ast.Field:
		f.walkFieldTag(n)
	case *ast.FuncDecl:
		f.walkMethodDecl(n)
	case *ast.InterfaceType:
		f.walkInterfaceType(n)
	case *ast.RangeStmt:
		f.walkRangeStmt(n)
	}
	return f
}

// walkAssignStmt walks an assignment statement
func (f *File) walkAssignStmt(stmt *ast.AssignStmt) {
	f.checkAtomicAssignment(stmt)
}

// walkCall walks a call expression.
func (f *File) walkCall(call *ast.CallExpr, name string) {
	f.checkFmtPrintfCall(call, name)
}

// walkCallExpr walks a call expression.
func (f *File) walkCallExpr(call *ast.CallExpr) {
	switch x := call.Fun.(type) {
	case *ast.Ident:
		f.walkCall(call, x.Name)
	case *ast.SelectorExpr:
		f.walkCall(call, x.Sel.Name)
	}
}

// walkCompositeLit walks a composite literal.
func (f *File) walkCompositeLit(c *ast.CompositeLit) {
	f.checkUntaggedLiteral(c)
}

// walkFieldTag walks a struct field tag.
func (f *File) walkFieldTag(field *ast.Field) {
	if field.Tag == nil {
		return
	}
	f.checkCanonicalFieldTag(field)
}

// walkMethodDecl walks the method's signature.
func (f *File) walkMethod(id *ast.Ident, t *ast.FuncType) {
	f.checkCanonicalMethod(id, t)
}

// walkMethodDecl walks the method signature in the declaration.
func (f *File) walkMethodDecl(d *ast.FuncDecl) {
	if d.Recv == nil {
		// not a method
		return
	}
	f.walkMethod(d.Name, d.Type)
}

// walkInterfaceType walks the method signatures of an interface.
func (f *File) walkInterfaceType(t *ast.InterfaceType) {
	for _, field := range t.Methods.List {
		for _, id := range field.Names {
			f.walkMethod(id, field.Type.(*ast.FuncType))
		}
	}
}

// walkRangeStmt walks a range statement.
func (f *File) walkRangeStmt(n *ast.RangeStmt) {
	checkRangeLoop(f, n)
}

// goFmt returns a string representation of the expression
func (f *File) gofmt(x ast.Expr) string {
	f.b.Reset()
	printer.Fprint(&f.b, f.fset, x)
	return f.b.String()
}
<|endoftext|>


<commit_before><commit_msg>remove obsolete file<commit_after><|endoftext|>