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

// DNS server implementation.

package dns

import (
        "io"
	"os"
	"net"
)

type Handler interface {
        ServeDNS(w ResponseWriter, r *Msg)
}

// You can ofcourse make YOUR OWN RESPONSE WRITTER that
// uses TSIG an other cool stuff
type ResponseWriter interface {
        // RemoteAddr returns the address of the client that sent the current request
        RemoteAddr() string

        Write([]byte) (int, os.Error)

        // IP based ACL mapping. The contains the string representation
        // of the IP address and a boolean saying it may connect (true) or not.
        Acl() map[string]bool

        // Tsig secrets. Its a mapping of key names to secrets.
        Tsig() map[string]string
}

type conn struct {
        remoteAddr net.Addr             // address of remote side (sans port)
        handler Handler                 // request handler
        request  []byte                 // bytes read
        connUDP *net.UDPConn
        connTCP *net.TCPConn
}

type response struct {
        conn *conn
        req *Msg
}

// ServeMux is an DNS request multiplexer. It matches the
// zone name of each incoming request against a list of
// registered patterns add calls the handler for the pattern
// that most closely matches the zone name.
type ServeMux struct {
        m map[string]Handler
}

// NewServeMux allocates and returns a new ServeMux.
func NewServeMux() *ServeMux { return &ServeMux{make(map[string]Handler)} }

// DefaultServeMux is the default ServeMux used by Serve.
var DefaultServeMux = NewServeMux()

// The HandlerFunc type is an adapter to allow the use of
// ordinary functions as DNS handlers.  If f is a function
// with the appropriate signature, HandlerFunc(f) is a
// Handler object that calls f.
type HandlerFunc func(ResponseWriter, *Msg)

// ServerDNS calls f(w, reg)
func (f HandlerFunc) ServeDNS(w ResponseWriter, r *Msg) {
        f(w, r)
}

// Helper handlers

// Error replies to the request with the specified error msg TODO(mg)
/*
func Error(w ResponseWriter) {  }

func NotFound(w ResponseWriter, r *Msg) {

func NotFoundHandler() Handler { return HandlerFunc(NotFound) }
*/

// HandleUDP handles one UDP connection. It reads the incoming
// message and then calls the function f.
// The function f is executed in a seperate goroutine at which point
// HandleUDP returns.
func HandleUDP(l *net.UDPConn, f func(*Conn, *Msg)) os.Error {
	for {
		m := make([]byte, DefaultMsgSize)
		n, addr, e := l.ReadFromUDP(m)
		if e != nil {
			continue
		}
		m = m[:n]

		d := new(Conn)
                // Use the remote addr as we got from ReadFromUDP
                d.SetUDPConn(l, addr)

		msg := new(Msg)
		if !msg.Unpack(m) {
			continue
		}
		go f(d, msg)
	}
	panic("not reached")
}

// HandleTCP handles one TCP connection. It reads the incoming
// message and then calls the function f.
// The function f is executed in a seperate goroutine at which point
// HandleTCP returns.
func HandleTCP(l *net.TCPListener, f func(*Conn, *Msg)) os.Error {
	for {
		c, e := l.AcceptTCP()
		if e != nil {
			return e
		}
		d := new(Conn)
                d.SetTCPConn(c, nil)

		msg := new(Msg)
		err := d.ReadMsg(msg)

		if err != nil {
			// Logging??
			continue
		}
		go f(d, msg)
	}
	panic("not reached")
}

func ListenAndServe(addr string, network string, handler Handler) os.Error {
        server := &Server{Addr: addr, Network: network, Handler: handler}
        return server.ListenAndServe()

}

// ListenAndServerTCP listens on the TCP network address addr and
// then calls HandleTCP with f to handle requests on incoming
// connections. The function f may not be nil.
func ListenAndServeTCP(addr string, f func(*Conn, *Msg)) os.Error {
	if f == nil {
		return ErrHandle
	}
	a, err := net.ResolveTCPAddr(addr)
	if err != nil {
		return err
	}
	l, err := net.ListenTCP("tcp", a)
	if err != nil {
		return err
	}
	err = HandleTCP(l, f)
	return err
}

// ListenAndServerUDP listens on the UDP network address addr and
// then calls HandleUDP with f to handle requests on incoming
// connections. The function f may not be nil.
func ListenAndServeUDP(addr string, f func(*Conn, *Msg)) os.Error {
	if f == nil {
		return &Error{Error: "The handle function may not be nil"}
	}
	a, err := net.ResolveUDPAddr(addr)
	if err != nil {
		return err
	}
	l, err := net.ListenUDP("udp", a)
	if err != nil {
		return err
	}
	err = HandleUDP(l, f)
	return err
}

func zoneMatch(pattern, zone string) bool {
        if len(pattern) == 0 {
                return false
        }
        n := len(pattern)
        return zone[:n] == pattern
}

func (mux *ServeMux) match(zone string) Handler {
        var h Handler
        var n = 0
        for k, v := range mux.m {
                if !zoneMatch(k, zone) {
                        continue
                }
                if h == nil || len(k) > n {
                        n = len(k)
                        h = v
                }
        }
        return h
}

func (mux *ServeMux) Handle(pattern string, handler Handler) {
        if pattern == "" {
                panic("dns: invalid pattern " + pattern)
        }
        mux.m[pattern] = handler
}

func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Msg)) {
        mux.Handle(pattern, HandlerFunc(handler))
}

// ServeDNS dispatches the request to the handler whose
// pattern most closely matches the request message.
func (mux *ServeMux) ServeDNS(w ResponseWriter, request *Msg) {
        h := mux.match(request.Question[0].Name)
        if h == nil {
//                h = NotFoundHandler()
        }
        h.ServeDNS(w, request)
}

// Handle register the handler the given pattern
// in the DefaultServeMux. The documentation for
// ServeMux explains how patters are matched.
func Handle(pattern string, handler Handler) { DefaultServeMux.Handle(pattern, handler) }

func HandleFunc(pattern string, handler func(ResponseWriter, *Msg)) {
        DefaultServeMux.HandleFunc(pattern, handler)
}

// Serve accepts incoming DNS request on the listener l,
// creating a new service thread for each.  The service threads
// read requests and then call handler to reply to them.
// Handler is typically nil, in which case the DefaultServeMux is used.
func Serve(l net.Listener, handler Handler) os.Error {
        srv := &Server{Handler: handler}
        return srv.Serve(l)
}

// A Server defines parameters for running an HTTP server.
type Server struct {
        Addr         string  // address to listen on, ":dns" if empty
        Network      string  // If "tcp" it will invoke a TCP listener, otherwise an UDP one
        Handler      Handler // handler to invoke, http.DefaultServeMux if nil
        ReadTimeout  int64   // the net.Conn.SetReadTimeout value for new connections
        WriteTimeout int64   // the net.Conn.SetWriteTimeout value for new connections
}

// Fixes for udp/tcp
func (srv *Server) ListenAndServe() os.Error {
        addr := srv.Addr
        if addr == "" {
                addr = ":domain"
        }
        switch srv.Network {
        case "tcp":
                a, e := net.ResolveTCPAddr(addr)
                if e != nil {
                        return e
                }
                l, e := net.ListenTCP("tcp", a)
                if e != nil {
                        return e
                }
                return srv.ServeTCP(l)
        case "udp":
                a, e := net.ResolveUDPAddr(addr)
                if e != nil {
                        return e
                }
                l, e := net.ListenUDP("udp", a)
                if e != nil {
                        return e
                }
                return srv.ServeUDP(l)
        }
        return nil      // os.Error with wrong network
}

func (srv *Server) ServeTCP(l *net.TCPListener) os.Error {
        defer l.Close()
        handler := srv.Handler
        if handler == nil {
                handler = DefaultServeMux
        }
        for {
                rw, e := l.AcceptTCP()
                if e != nil {
                        return e
                }
                if srv.ReadTimeout != 0 {
                        rw.SetReadTimeout(srv.ReadTimeout)
                }
                if srv.WriteTimeout != 0 {
                        rw.SetWriteTimeout(srv.WriteTimeout)
                }
                m := read /* read and set the buffer */
                d, err := newConn(rw, nil, rw.RemoteAddr(), nil, handler)
                d.ReadReqest()
                if err != nil {
                        continue
                }
                go d.serve()
        }
        panic("not reached")
}

func (srv *Server) ServeUDP(l *net.UDPConn) os.Error {
        defer l.Close()
        handler := srv.Handler
        if handler == nil {
                handler = DefaultServeMux
        }
        for {
                m := make([]byte, DefaultMsgSize)
                c, a, e := l.ReadFromUDP()
                if e != nil {
                        return e
                }
                m = m[:n]

                if srv.ReadTimeout != 0 {
                        rw.SetReadTimeout(srv.ReadTimeout)
                }
                if srv.WriteTimeout != 0 {
                        rw.SetWriteTimeout(srv.WriteTimeout)
                }
                d, err := newConn(rw, nil, addr, m, handler)
                if err != nil {
                        continue
                }
                go d.serve()
        }
        panic("not reached")
}

func newConn(t *net.TCPConn, u *net.UDPConn, a net.Addr, buf []byte, handler Handler) (c *conn, err os.Error) {
        c = new(conn)
        c.handler = handler
        c.TCPconn = t
        c.UDPconn = u
        c.RemoteAddr = a
        return c, err
}

func (c *conn) serve() {
        // c.ReadRequest

        // c.Handler.ServeDNS(w, w.req) // this does the writing
}

func (c *conn) ReadRequest() (w *response, err os.Error) {
        w = new(response)
        return w, nil
}
<commit_msg>It compiles again, but doesnt work yet<commit_after>// Copyright 2011 Miek Gieben. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// DNS server implementation.

package dns

import (
//        "io"
	"os"
	"net"
)

type Handler interface {
        ServeDNS(w ResponseWriter, r *Msg)
}

// TODO(mg): fit axfr responses in here too
// A ResponseWriter interface is used by an DNS handler to
// construct an DNS response.
type ResponseWriter interface {
        // RemoteAddr returns the address of the client that sent the current request
        RemoteAddr() string

        Write([]byte) (int, os.Error)

        // IP based ACL mapping. The contains the string representation
        // of the IP address and a boolean saying it may connect (true) or not.
        Acl() map[string]bool

        // Tsig secrets. Its a mapping of key names to secrets.
        Tsig() map[string]string
}

type conn struct {
        remoteAddr net.Addr             // address of remote side (sans port)
        port int                        // port of the remote side
        handler Handler                 // request handler
        request  []byte                 // bytes read
        _UDP *net.UDPConn            // i/o connection if UDP was used
        _TCP *net.TCPConn            // i/o connection if TCP was used
        hijacked bool                   // connection has been hijacked by hander TODO(mg)
}

type response struct {
        conn *conn
        req *Msg
        xfr  bool                       // {i/a}xfr was requested
}

// ServeMux is an DNS request multiplexer. It matches the
// zone name of each incoming request against a list of
// registered patterns add calls the handler for the pattern
// that most closely matches the zone name.
type ServeMux struct {
        m map[string]Handler
}

// NewServeMux allocates and returns a new ServeMux.
func NewServeMux() *ServeMux { return &ServeMux{make(map[string]Handler)} }

// DefaultServeMux is the default ServeMux used by Serve.
var DefaultServeMux = NewServeMux()

// The HandlerFunc type is an adapter to allow the use of
// ordinary functions as DNS handlers.  If f is a function
// with the appropriate signature, HandlerFunc(f) is a
// Handler object that calls f.
type HandlerFunc func(ResponseWriter, *Msg)

// ServerDNS calls f(w, reg)
func (f HandlerFunc) ServeDNS(w ResponseWriter, r *Msg) {
        f(w, r)
}

// Helper handlers

// Error replies to the request with the specified error msg TODO(mg)
/*
func Error(w ResponseWriter) {  }

func NotFound(w ResponseWriter, r *Msg) {

func NotFoundHandler() Handler { return HandlerFunc(NotFound) }
*/

// HandleUDP handles one UDP connection. It reads the incoming
// message and then calls the function f.
// The function f is executed in a seperate goroutine at which point
// HandleUDP returns.
func HandleUDP(l *net.UDPConn, f func(*Conn, *Msg)) os.Error {
	for {
		m := make([]byte, DefaultMsgSize)
		n, addr, e := l.ReadFromUDP(m)
		if e != nil {
			continue
		}
		m = m[:n]

		d := new(Conn)
                // Use the remote addr as we got from ReadFromUDP
                d.SetUDPConn(l, addr)

		msg := new(Msg)
		if !msg.Unpack(m) {
			continue
		}
		go f(d, msg)
	}
	panic("not reached")
}

// HandleTCP handles one TCP connection. It reads the incoming
// message and then calls the function f.
// The function f is executed in a seperate goroutine at which point
// HandleTCP returns.
func HandleTCP(l *net.TCPListener, f func(*Conn, *Msg)) os.Error {
	for {
		c, e := l.AcceptTCP()
		if e != nil {
			return e
		}
		d := new(Conn)
                d.SetTCPConn(c, nil)

		msg := new(Msg)
		err := d.ReadMsg(msg)

		if err != nil {
			// Logging??
			continue
		}
		go f(d, msg)
	}
	panic("not reached")
}

func ListenAndServe(addr string, network string, handler Handler) os.Error {
        server := &Server{Addr: addr, Network: network, Handler: handler}
        return server.ListenAndServe()

}

func zoneMatch(pattern, zone string) bool {
        if len(pattern) == 0 {
                return false
        }
        n := len(pattern)
        return zone[:n] == pattern
}

func (mux *ServeMux) match(zone string) Handler {
        var h Handler
        var n = 0
        for k, v := range mux.m {
                if !zoneMatch(k, zone) {
                        continue
                }
                if h == nil || len(k) > n {
                        n = len(k)
                        h = v
                }
        }
        return h
}

func (mux *ServeMux) Handle(pattern string, handler Handler) {
        if pattern == "" {
                panic("dns: invalid pattern " + pattern)
        }
        mux.m[pattern] = handler
}

func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Msg)) {
        mux.Handle(pattern, HandlerFunc(handler))
}

// ServeDNS dispatches the request to the handler whose
// pattern most closely matches the request message.
func (mux *ServeMux) ServeDNS(w ResponseWriter, request *Msg) {
        h := mux.match(request.Question[0].Name)
        if h == nil {
//                h = NotFoundHandler()
        }
        h.ServeDNS(w, request)
}

// Handle register the handler the given pattern
// in the DefaultServeMux. The documentation for
// ServeMux explains how patters are matched.
func Handle(pattern string, handler Handler) { DefaultServeMux.Handle(pattern, handler) }

func HandleFunc(pattern string, handler func(ResponseWriter, *Msg)) {
        DefaultServeMux.HandleFunc(pattern, handler)
}

// Serve accepts incoming DNS request on the TCP listener l,
// creating a new service thread for each.  The service threads
// read requests and then call handler to reply to them.
// Handler is typically nil, in which case the DefaultServeMux is used.
func ServeTCP(l *net.TCPListener, handler Handler) os.Error {
        srv := &Server{Handler: handler, Network: "tcp"}
        return srv.ServeTCP(l)
}

// Serve accepts incoming DNS request on the UDP Conn l,
// creating a new service thread for each.  The service threads
// read requests and then call handler to reply to them.
// Handler is typically nil, in which case the DefaultServeMux is used.
func ServeUDP(l *net.UDPConn, handler Handler) os.Error {
        srv := &Server{Handler: handler, Network: "udp"}
        return srv.ServeUDP(l)
}

// A Server defines parameters for running an HTTP server.
type Server struct {
        Addr         string  // address to listen on, ":dns" if empty
        Network      string  // If "tcp" it will invoke a TCP listener, otherwise an UDP one
        Handler      Handler // handler to invoke, http.DefaultServeMux if nil
        ReadTimeout  int64   // the net.Conn.SetReadTimeout value for new connections
        WriteTimeout int64   // the net.Conn.SetWriteTimeout value for new connections
}

// Fixes for udp/tcp
func (srv *Server) ListenAndServe() os.Error {
        addr := srv.Addr
        if addr == "" {
                addr = ":domain"
        }
        switch srv.Network {
        case "tcp":
                a, e := net.ResolveTCPAddr(addr)
                if e != nil {
                        return e
                }
                l, e := net.ListenTCP("tcp", a)
                if e != nil {
                        return e
                }
                return srv.ServeTCP(l)
        case "udp":
                a, e := net.ResolveUDPAddr(addr)
                if e != nil {
                        return e
                }
                l, e := net.ListenUDP("udp", a)
                if e != nil {
                        return e
                }
                return srv.ServeUDP(l)
        }
        return nil      // os.Error with wrong network
}

func (srv *Server) ServeTCP(l *net.TCPListener) os.Error {
        defer l.Close()
        handler := srv.Handler
        if handler == nil {
                handler = DefaultServeMux
        }
        forever:
        for {
                rw, e := l.AcceptTCP()
                if e != nil {
                        return e
                }
                if srv.ReadTimeout != 0 {
                        rw.SetReadTimeout(srv.ReadTimeout)
                }
                if srv.WriteTimeout != 0 {
                        rw.SetWriteTimeout(srv.WriteTimeout)
                }
                l := make([]byte, 2)
                n, err := rw.Read(l)
                if err != nil || n != 2 {
                        continue
                }
                length, _ := unpackUint16(l, 0)
                if length == 0 {
                        continue
                }
                m := make([]byte, int(length))
                n, err = rw.Read(m[:int(length)])
                if err != nil {
                        continue
                }
                i := n
                for i < int(length) {
                        j, err := rw.Read(m[i:int(length)])
                        if err != nil {
                                continue forever
                        }
                        i += j
                }
                n = i
                d, err := newConn(rw, nil, rw.RemoteAddr(), m, handler)
                if err != nil {
                        continue
                }
                go d.serve()
        }
        panic("not reached")
}

func (srv *Server) ServeUDP(l *net.UDPConn) os.Error {
        defer l.Close()
        handler := srv.Handler
        if handler == nil {
                handler = DefaultServeMux
        }
        for {
                m := make([]byte, DefaultMsgSize)
                n, a, e := l.ReadFromUDP(m)
                if e != nil {
                        return e
                }
                m = m[:n]

                if srv.ReadTimeout != 0 {
                        l.SetReadTimeout(srv.ReadTimeout)
                }
                if srv.WriteTimeout != 0 {
                        l.SetWriteTimeout(srv.WriteTimeout)
                }
                d, err := newConn(nil, l, a, m, handler)
                if err != nil {
                        continue
                }
                go d.serve()
        }
        panic("not reached")
}

func newConn(t *net.TCPConn, u *net.UDPConn, a net.Addr, buf []byte, handler Handler) (c *conn, err os.Error) {
        c = new(conn)
        c.handler = handler
        c._TCP = t
        c._UDP = u
        c.remoteAddr = a
        c.request = buf
        if t != nil {
                c.port = a.(*net.TCPAddr).Port
        }
        if u != nil {
                c.port = a.(*net.UDPAddr).Port
        }
        return c, err
}

// Close the connection.
func (c *conn) close() {
        switch {
        case c._UDP != nil:
                c._UDP.Close()
                c._UDP = nil
        case c._TCP != nil:
                c._TCP.Close()
                c._TCP = nil
        }
}

// Serve a new connection.
func (c *conn) serve() {
        // c.ReadRequest

        // c.Handler.ServeDNS(w, w.req) // this does the writing
}

func (c *conn) readRequest() (w *response, err os.Error) {

        w = new(response)
        return w, nil
}
<|endoftext|>


<commit_before>/*
Copyright 2017 The go-marathon Authors All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package marathon

// PodContainer describes a container in a pod
type PodContainer struct {
	Name         string             `json:"name,omitempty"`
	Exec         *PodExec           `json:"exec,omitempty"`
	Resources    *Resources         `json:"resources,omitempty"`
	Endpoints    []*PodEndpoint     `json:"endpoints,omitempty"`
	Image        *PodContainerImage `json:"image,omitempty"`
	Env          map[string]string  `json:"-"`
	Secrets      map[string]Secret  `json:"-"`
	User         string             `json:"user,omitempty"`
	HealthCheck  *PodHealthCheck    `json:"healthCheck,omitempty"`
	VolumeMounts []*PodVolumeMount  `json:"volumeMounts,omitempty"`
	Artifacts    []*PodArtifact     `json:"artifacts,omitempty"`
	Labels       map[string]string  `json:"labels,omitempty"`
	Lifecycle    PodLifecycle       `json:"lifecycle,omitempty"`
}

// PodLifecycle describes the lifecycle of a pod
type PodLifecycle struct {
	KillGracePeriodSeconds *float64 `json:"killGracePeriodSeconds,omitempty"`
}

// PodCommand is the command to run as the entrypoint of the container
type PodCommand struct {
	Shell string `json:"shell,omitempty"`
}

// PodExec contains the PodCommand
type PodExec struct {
	Command PodCommand `json:"command,omitempty"`
}

// PodArtifact describes how to obtain a generic artifact for a pod
type PodArtifact struct {
	URI        string `json:"uri,omitempty"`
	Extract    bool   `json:"extract,omitempty"`
	Executable bool   `json:"executable,omitempty"`
	Cache      bool   `json:"cache,omitempty"`
	DestPath   string `json:"destPath,omitempty"`
}

// NewPodContainer creates an empty PodContainer
func NewPodContainer() *PodContainer {
	return &PodContainer{
		Endpoints:    []*PodEndpoint{},
		Env:          map[string]string{},
		VolumeMounts: []*PodVolumeMount{},
		Artifacts:    []*PodArtifact{},
		Labels:       map[string]string{},
		Resources:    NewResources(),
	}
}

// SetName sets the name of a pod container
func (p *PodContainer) SetName(name string) *PodContainer {
	p.Name = name
	return p
}

// SetCommand sets the shell command of a pod container
func (p *PodContainer) SetCommand(name string) *PodContainer {
	p.Exec = &PodExec{
		Command: PodCommand{
			Shell: name,
		},
	}
	return p
}

// CPUs sets the CPUs of a pod container
func (p *PodContainer) CPUs(cpu float64) *PodContainer {
	p.Resources.Cpus = cpu
	return p
}

// Memory sets the memory of a pod container
func (p *PodContainer) Memory(memory float64) *PodContainer {
	p.Resources.Mem = memory
	return p
}

// Storage sets the storage capacity of a pod container
func (p *PodContainer) Storage(disk float64) *PodContainer {
	p.Resources.Disk = disk
	return p
}

// GPUs sets the GPU requirements of a pod container
func (p *PodContainer) GPUs(gpu int32) *PodContainer {
	p.Resources.Gpus = gpu
	return p
}

// AddEndpoint appends an endpoint for a pod container
func (p *PodContainer) AddEndpoint(endpoint *PodEndpoint) *PodContainer {
	p.Endpoints = append(p.Endpoints, endpoint)
	return p
}

// SetImage sets the image of a pod container
func (p *PodContainer) SetImage(image *PodContainerImage) *PodContainer {
	p.Image = image
	return p
}

// EmptyEnvironment initialized env to empty
func (p *PodContainer) EmptyEnvs() *PodContainer {
	p.Env = make(map[string]string)
	return p
}

// AddEnvironment adds an environment variable for a pod container
func (p *PodContainer) AddEnv(name, value string) *PodContainer {
	if p.Env == nil {
		p = p.EmptyEnvs()
	}
	p.Env[name] = value
	return p
}

// ExtendEnvironment extends the environment for a pod container
func (p *PodContainer) ExtendEnv(env map[string]string) *PodContainer {
	if p.Env == nil {
		p = p.EmptyEnvs()
	}
	for k, v := range env {
		p.AddEnv(k, v)
	}
	return p
}

// AddSecret adds a secret to the environment for a pod container
func (p *PodContainer) AddSecret(name, secretName string) *PodContainer {
	if p.Env == nil {
		p = p.EmptyEnvs()
	}
	p.Env[name] = secretName
	return p
}

// SetUser sets the user to run the pod as
func (p *PodContainer) SetUser(user string) *PodContainer {
	p.User = user
	return p
}

// SetHealthCheck sets the health check of a pod container
func (p *PodContainer) SetHealthCheck(healthcheck *PodHealthCheck) *PodContainer {
	p.HealthCheck = healthcheck
	return p
}

// AddVolumeMount appends a volume mount to a pod container
func (p *PodContainer) AddVolumeMount(mount *PodVolumeMount) *PodContainer {
	p.VolumeMounts = append(p.VolumeMounts, mount)
	return p
}

// AddArtifact appends an artifact to a pod container
func (p *PodContainer) AddArtifact(artifact *PodArtifact) *PodContainer {
	p.Artifacts = append(p.Artifacts, artifact)
	return p
}

// AddLabel adds a label to a pod container
func (p *PodContainer) AddLabel(key, value string) *PodContainer {
	p.Labels[key] = value
	return p
}

// SetLifecycle sets the lifecycle of a pod container
func (p *PodContainer) SetLifecycle(lifecycle PodLifecycle) *PodContainer {
	p.Lifecycle = lifecycle
	return p
}
<commit_msg>Fix function comments based on best practices from Effective Go<commit_after>/*
Copyright 2017 The go-marathon Authors All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package marathon

// PodContainer describes a container in a pod
type PodContainer struct {
	Name         string             `json:"name,omitempty"`
	Exec         *PodExec           `json:"exec,omitempty"`
	Resources    *Resources         `json:"resources,omitempty"`
	Endpoints    []*PodEndpoint     `json:"endpoints,omitempty"`
	Image        *PodContainerImage `json:"image,omitempty"`
	Env          map[string]string  `json:"-"`
	Secrets      map[string]Secret  `json:"-"`
	User         string             `json:"user,omitempty"`
	HealthCheck  *PodHealthCheck    `json:"healthCheck,omitempty"`
	VolumeMounts []*PodVolumeMount  `json:"volumeMounts,omitempty"`
	Artifacts    []*PodArtifact     `json:"artifacts,omitempty"`
	Labels       map[string]string  `json:"labels,omitempty"`
	Lifecycle    PodLifecycle       `json:"lifecycle,omitempty"`
}

// PodLifecycle describes the lifecycle of a pod
type PodLifecycle struct {
	KillGracePeriodSeconds *float64 `json:"killGracePeriodSeconds,omitempty"`
}

// PodCommand is the command to run as the entrypoint of the container
type PodCommand struct {
	Shell string `json:"shell,omitempty"`
}

// PodExec contains the PodCommand
type PodExec struct {
	Command PodCommand `json:"command,omitempty"`
}

// PodArtifact describes how to obtain a generic artifact for a pod
type PodArtifact struct {
	URI        string `json:"uri,omitempty"`
	Extract    bool   `json:"extract,omitempty"`
	Executable bool   `json:"executable,omitempty"`
	Cache      bool   `json:"cache,omitempty"`
	DestPath   string `json:"destPath,omitempty"`
}

// NewPodContainer creates an empty PodContainer
func NewPodContainer() *PodContainer {
	return &PodContainer{
		Endpoints:    []*PodEndpoint{},
		Env:          map[string]string{},
		VolumeMounts: []*PodVolumeMount{},
		Artifacts:    []*PodArtifact{},
		Labels:       map[string]string{},
		Resources:    NewResources(),
	}
}

// SetName sets the name of a pod container
func (p *PodContainer) SetName(name string) *PodContainer {
	p.Name = name
	return p
}

// SetCommand sets the shell command of a pod container
func (p *PodContainer) SetCommand(name string) *PodContainer {
	p.Exec = &PodExec{
		Command: PodCommand{
			Shell: name,
		},
	}
	return p
}

// CPUs sets the CPUs of a pod container
func (p *PodContainer) CPUs(cpu float64) *PodContainer {
	p.Resources.Cpus = cpu
	return p
}

// Memory sets the memory of a pod container
func (p *PodContainer) Memory(memory float64) *PodContainer {
	p.Resources.Mem = memory
	return p
}

// Storage sets the storage capacity of a pod container
func (p *PodContainer) Storage(disk float64) *PodContainer {
	p.Resources.Disk = disk
	return p
}

// GPUs sets the GPU requirements of a pod container
func (p *PodContainer) GPUs(gpu int32) *PodContainer {
	p.Resources.Gpus = gpu
	return p
}

// AddEndpoint appends an endpoint for a pod container
func (p *PodContainer) AddEndpoint(endpoint *PodEndpoint) *PodContainer {
	p.Endpoints = append(p.Endpoints, endpoint)
	return p
}

// SetImage sets the image of a pod container
func (p *PodContainer) SetImage(image *PodContainerImage) *PodContainer {
	p.Image = image
	return p
}

// EmptyEnvs initialized env to empty
func (p *PodContainer) EmptyEnvs() *PodContainer {
	p.Env = make(map[string]string)
	return p
}

// AddEnv adds an environment variable for a pod container
func (p *PodContainer) AddEnv(name, value string) *PodContainer {
	if p.Env == nil {
		p = p.EmptyEnvs()
	}
	p.Env[name] = value
	return p
}

// ExtendEnv extends the environment for a pod container
func (p *PodContainer) ExtendEnv(env map[string]string) *PodContainer {
	if p.Env == nil {
		p = p.EmptyEnvs()
	}
	for k, v := range env {
		p.AddEnv(k, v)
	}
	return p
}

// AddSecret adds a secret to the environment for a pod container
func (p *PodContainer) AddSecret(name, secretName string) *PodContainer {
	if p.Env == nil {
		p = p.EmptyEnvs()
	}
	p.Env[name] = secretName
	return p
}

// SetUser sets the user to run the pod as
func (p *PodContainer) SetUser(user string) *PodContainer {
	p.User = user
	return p
}

// SetHealthCheck sets the health check of a pod container
func (p *PodContainer) SetHealthCheck(healthcheck *PodHealthCheck) *PodContainer {
	p.HealthCheck = healthcheck
	return p
}

// AddVolumeMount appends a volume mount to a pod container
func (p *PodContainer) AddVolumeMount(mount *PodVolumeMount) *PodContainer {
	p.VolumeMounts = append(p.VolumeMounts, mount)
	return p
}

// AddArtifact appends an artifact to a pod container
func (p *PodContainer) AddArtifact(artifact *PodArtifact) *PodContainer {
	p.Artifacts = append(p.Artifacts, artifact)
	return p
}

// AddLabel adds a label to a pod container
func (p *PodContainer) AddLabel(key, value string) *PodContainer {
	p.Labels[key] = value
	return p
}

// SetLifecycle sets the lifecycle of a pod container
func (p *PodContainer) SetLifecycle(lifecycle PodLifecycle) *PodContainer {
	p.Lifecycle = lifecycle
	return p
}
<|endoftext|>


<commit_before>// Pooler is a tool to automate the creation of typed sync.Pool wrappers.
// Given the name of a type T, pooler will create a new self-contained Go source file implementing
//
//  type TPool struct { sync.Pool }
//  func NewTPool() *TPool
//  func (*TPool) Get() *T
//  func (*TPool) Put(*T)
//
// The file is created in the same package and directory as the package that defines T.
// It has helpful defaults designed for use with go generate.
//
// For example, given this snippet,
//
//  package painkiller
//
//  type Pill struct { i int }
//
// running this command
//
//  pooler -type=Pill
//
// in the same directory will create the file pill_pool.go, in package painkiller,
// containing a definition of
//  type PillPool      struct { sync.Pool }
//  func NewPillPool() *PillPool
//  func (*PillPool)   Get() *Pill
//  func (*PillPool)   Put(*Pill)
//
// So now running
//  pp := NewPillPool()
//  p := pp.Get()
//  p.i = 2
//  pp.Put(p)
//  p2 := pp.Get() // p2 & p points to same var
//
// Will result in only one memory allocation of a Pill.
//
// Typically this process would be run using go generate, like this:
//
//  //go:generate pooler -type=Pill
//
// With no arguments, it processes the package in the current directory.
// Otherwise, the arguments must name a single directory holding a Go package
// or a set of Go source files that represent a single Go package.
//
// The -type flag accepts a comma-separated list of types so a single run can
// generate methods for multiple types. The default output file is t_pool.go,
// where t is the lower-cased name of the first type listed. It can be overridden
// with the -output flag.
//
// This code is a small update from https://godoc.org/golang.org/x/tools/cmd/stringer .
package main // import "github.com/azr/generators/pooler"

import (
	"bytes"
	"flag"
	"fmt"
	"go/ast"
	"go/build"
	"go/format"
	"go/parser"
	"go/token"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strings"

	"go/types"

	_ "go/importer"
)

var (
	typeNames = flag.String("type", "", "comma-separated list of type names; must be set")
	output    = flag.String("output", "", "output file name; default srcdir/<type>_pool.go")
)

// 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, "\tpooler [flags] -type T [directory]\n")
	fmt.Fprintf(os.Stderr, "\tpooler [flags] -type T files... # Must be a single package\n")
	fmt.Fprintf(os.Stderr, "For more information, see:\n")
	fmt.Fprintf(os.Stderr, "\thttp://godoc.org/github.com/azr/pooler\n")
	fmt.Fprintf(os.Stderr, "Flags:\n")
	flag.PrintDefaults()
}

func main() {
	log.SetFlags(0)
	log.SetPrefix("pooler: ")
	flag.Usage = Usage
	flag.Parse()
	if len(*typeNames) == 0 {
		flag.Usage()
		os.Exit(2)
	}
	types := strings.Split(*typeNames, ",")

	// We accept either one directory or a list of files. Which do we have?
	args := flag.Args()
	if len(args) == 0 {
		// Default: process whole package in current directory.
		args = []string{"."}
	}

	// Parse the package once.
	var (
		dir string
		g   Generator
	)
	if len(args) == 1 && isDirectory(args[0]) {
		dir = args[0]
		g.parsePackageDir(args[0])
	} else {
		dir = filepath.Dir(args[0])
		g.parsePackageFiles(args)
	}

	// Print the header and package clause.
	g.Printf("// Code generated by \"pooler %s\"; DO NOT EDIT\n", strings.Join(os.Args[1:], " "))
	g.Printf("\n")
	g.Printf("package %s", g.pkg.name)
	g.Printf("\n")
	g.Printf("import \"sync\"\n") // Used by all methods.

	// Run generate for each type.
	for _, typeName := range types {
		g.generate(typeName)
	}

	// Format the output.
	src := g.format()

	// Write to file.
	outputName := *output
	if outputName == "" {
		baseName := fmt.Sprintf("%s_pool.go", types[0])
		outputName = filepath.Join(dir, strings.ToLower(baseName))
	}
	err := ioutil.WriteFile(outputName, src, 0644)
	if err != nil {
		log.Fatalf("writing output: %s", err)
	}
}

// isDirectory reports whether the named file is a directory.
func isDirectory(name string) bool {
	info, err := os.Stat(name)
	if err != nil {
		log.Fatal(err)
	}
	return info.IsDir()
}

// Generator holds the state of the analysis. Primarily used to buffer
// the output for format.Source.
type Generator struct {
	buf bytes.Buffer // Accumulated output.
	pkg *Package     // Package we are scanning.
}

func (g *Generator) Printf(format string, args ...interface{}) {
	fmt.Fprintf(&g.buf, format, args...)
}

// File holds a single parsed file and associated data.
type File struct {
	pkg  *Package  // Package to which this file belongs.
	file *ast.File // Parsed AST.
	// These fields are reset for each type being generated.
	typeName string // Name of the type.
	found    bool
}

type Package struct {
	dir      string
	name     string
	defs     map[*ast.Ident]types.Object
	files    []*File
	typesPkg *types.Package
}

// parsePackageDir parses the package residing in the directory.
func (g *Generator) parsePackageDir(directory string) {
	pkg, err := build.Default.ImportDir(directory, 0)
	if err != nil {
		log.Fatalf("cannot process directory %s: %s", directory, err)
	}
	var names []string
	names = append(names, pkg.GoFiles...)
	names = append(names, pkg.CgoFiles...)
	// TODO: Need to think about constants in test files. Maybe write type_string_test.go
	// in a separate pass? For later.
	// names = append(names, pkg.TestGoFiles...) // These are also in the "foo" package.
	names = append(names, pkg.SFiles...)
	names = prefixDirectory(directory, names)
	g.parsePackage(directory, names, nil)
}

// parsePackageFiles parses the package occupying the named files.
func (g *Generator) parsePackageFiles(names []string) {
	g.parsePackage(".", names, nil)
}

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

// parsePackage analyzes the single package constructed from the named files.
// If text is non-nil, it is a string to be used instead of the content of the file,
// to be used for testing. parsePackage exits if there is an error.
func (g *Generator) parsePackage(directory string, names []string, text interface{}) {
	var files []*File
	var astFiles []*ast.File
	g.pkg = new(Package)
	fs := token.NewFileSet()
	for _, name := range names {
		if !strings.HasSuffix(name, ".go") {
			continue
		}
		parsedFile, err := parser.ParseFile(fs, name, text, 0)
		if err != nil {
			log.Fatalf("parsing package: %s: %s", name, err)
		}
		astFiles = append(astFiles, parsedFile)
		files = append(files, &File{
			file: parsedFile,
			pkg:  g.pkg,
		})
	}
	if len(astFiles) == 0 {
		log.Fatalf("%s: no buildable Go files", directory)
	}
	g.pkg.name = astFiles[0].Name.Name
	g.pkg.files = files
	g.pkg.dir = directory
	// Type check the package.
	g.pkg.check(fs, astFiles)
}

// check type-checks the package. The package must be OK to proceed.
func (pkg *Package) check(fs *token.FileSet, astFiles []*ast.File) {
	pkg.defs = make(map[*ast.Ident]types.Object)
	config := types.Config{FakeImportC: true}
	info := &types.Info{
		Defs: pkg.defs,
	}
	typesPkg, err := config.Check(pkg.dir, fs, astFiles, info)
	if err != nil {
		log.Fatalf("checking package: %s", err)
	}
	pkg.typesPkg = typesPkg
}

// generate produces the String method for the named type.
func (g *Generator) generate(typeName string) {
	found := false
	for _, file := range g.pkg.files {
		// Set the state for this run of the walker.
		file.typeName = typeName
		if file.file != nil {
			ast.Inspect(file.file, file.genDecl)
			if file.found {
				found = true
			}
		}
	}

	if found {
		g.build(typeName)
	} else {
		fmt.Printf("Type not found: %s", typeName)
	}
}

// format returns the gofmt-ed contents of the Generator's buffer.
func (g *Generator) format() []byte {
	src, err := format.Source(g.buf.Bytes())
	if err != nil {
		// Should never happen, but can arise when developing this code.
		// The user can compile the output to see the error.
		log.Printf("warning: internal error: invalid Go generated: %s", err)
		log.Printf("warning: compile the package to analyze the error")
		return g.buf.Bytes()
	}
	return src
}

// genDecl processes one declaration clause.
func (f *File) genDecl(node ast.Node) bool {
	decl, ok := node.(*ast.GenDecl)
	if !ok || decl.Tok != token.TYPE {
		// We only care about type declarations.
		return true
	}

	for _, spec := range decl.Specs {
		vspec := spec.(*ast.TypeSpec) // Guaranteed to succeed as this is Type.
		if vspec.Name.String() != f.typeName {
			continue
		}
		f.found = true
	}
	return false
}

// build generates the variables and String method for a single run of contiguous values.
func (g *Generator) build(typeName string) {
	g.Printf("\n")
	g.Printf(poolWrapp, typeName)
}

// Arguments to format are:
//  [1]: type name

// Argument to format is the type name.
const poolWrapp = `
type %[1]sPool struct {
    sync.Pool
}

func New%[1]sPool() *%[1]sPool {
    return &%[1]sPool{
        sync.Pool{
            New: func() interface{} {
                return new(%[1]s)
            },
        },
    }
}

func (p %[1]sPool) Get() *%[1]s {
   return p.Pool.Get().(*%[1]s)
}

func (pp %[1]sPool) Put(p *%[1]s)  {
   pp.Pool.Put(p)
}
`
<commit_msg>fix pooler, use importer in case a file import a pkg<commit_after>// Pooler is a tool to automate the creation of typed sync.Pool wrappers.
// Given the name of a type T, pooler will create a new self-contained Go source file implementing
//
//  type TPool struct { sync.Pool }
//  func NewTPool() *TPool
//  func (*TPool) Get() *T
//  func (*TPool) Put(*T)
//
// The file is created in the same package and directory as the package that defines T.
// It has helpful defaults designed for use with go generate.
//
// For example, given this snippet,
//
//  package painkiller
//
//  type Pill struct { i int }
//
// running this command
//
//  pooler -type=Pill
//
// in the same directory will create the file pill_pool.go, in package painkiller,
// containing a definition of
//  type PillPool      struct { sync.Pool }
//  func NewPillPool() *PillPool
//  func (*PillPool)   Get() *Pill
//  func (*PillPool)   Put(*Pill)
//
// So now running
//  pp := NewPillPool()
//  p := pp.Get()
//  p.i = 2
//  pp.Put(p)
//  p2 := pp.Get() // p2 & p points to same var
//
// Will result in only one memory allocation of a Pill.
//
// Typically this process would be run using go generate, like this:
//
//  //go:generate pooler -type=Pill
//
// With no arguments, it processes the package in the current directory.
// Otherwise, the arguments must name a single directory holding a Go package
// or a set of Go source files that represent a single Go package.
//
// The -type flag accepts a comma-separated list of types so a single run can
// generate methods for multiple types. The default output file is t_pool.go,
// where t is the lower-cased name of the first type listed. It can be overridden
// with the -output flag.
//
// This code is a small update from https://godoc.org/golang.org/x/tools/cmd/stringer .
package main // import "github.com/azr/generators/pooler"

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

var (
	typeNames = flag.String("type", "", "comma-separated list of type names; must be set")
	output    = flag.String("output", "", "output file name; default srcdir/<type>_pool.go")
)

// 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, "\tpooler [flags] -type T [directory]\n")
	fmt.Fprintf(os.Stderr, "\tpooler [flags] -type T files... # Must be a single package\n")
	fmt.Fprintf(os.Stderr, "For more information, see:\n")
	fmt.Fprintf(os.Stderr, "\thttp://godoc.org/github.com/azr/pooler\n")
	fmt.Fprintf(os.Stderr, "Flags:\n")
	flag.PrintDefaults()
}

func main() {
	log.SetFlags(0)
	log.SetPrefix("pooler: ")
	flag.Usage = Usage
	flag.Parse()
	if len(*typeNames) == 0 {
		flag.Usage()
		os.Exit(2)
	}
	types := strings.Split(*typeNames, ",")

	// We accept either one directory or a list of files. Which do we have?
	args := flag.Args()
	if len(args) == 0 {
		// Default: process whole package in current directory.
		args = []string{"."}
	}

	// Parse the package once.
	var (
		dir string
		g   Generator
	)
	if len(args) == 1 && isDirectory(args[0]) {
		dir = args[0]
		g.parsePackageDir(args[0])
	} else {
		dir = filepath.Dir(args[0])
		g.parsePackageFiles(args)
	}

	// Print the header and package clause.
	g.Printf("// Code generated by \"pooler %s\"; DO NOT EDIT\n", strings.Join(os.Args[1:], " "))
	g.Printf("\n")
	g.Printf("package %s", g.pkg.name)
	g.Printf("\n")
	g.Printf("import \"sync\"\n") // Used by all methods.

	// Run generate for each type.
	for _, typeName := range types {
		g.generate(typeName)
	}

	// Format the output.
	src := g.format()

	// Write to file.
	outputName := *output
	if outputName == "" {
		baseName := fmt.Sprintf("%s_pool.go", types[0])
		outputName = filepath.Join(dir, strings.ToLower(baseName))
	}
	err := ioutil.WriteFile(outputName, src, 0644)
	if err != nil {
		log.Fatalf("writing output: %s", err)
	}
}

// isDirectory reports whether the named file is a directory.
func isDirectory(name string) bool {
	info, err := os.Stat(name)
	if err != nil {
		log.Fatal(err)
	}
	return info.IsDir()
}

// Generator holds the state of the analysis. Primarily used to buffer
// the output for format.Source.
type Generator struct {
	buf bytes.Buffer // Accumulated output.
	pkg *Package     // Package we are scanning.
}

func (g *Generator) Printf(format string, args ...interface{}) {
	fmt.Fprintf(&g.buf, format, args...)
}

// File holds a single parsed file and associated data.
type File struct {
	pkg  *Package  // Package to which this file belongs.
	file *ast.File // Parsed AST.
	// These fields are reset for each type being generated.
	typeName string // Name of the type.
	found    bool
}

type Package struct {
	dir      string
	name     string
	defs     map[*ast.Ident]types.Object
	files    []*File
	typesPkg *types.Package
}

// parsePackageDir parses the package residing in the directory.
func (g *Generator) parsePackageDir(directory string) {
	pkg, err := build.Default.ImportDir(directory, 0)
	if err != nil {
		log.Fatalf("cannot process directory %s: %s", directory, err)
	}
	var names []string
	names = append(names, pkg.GoFiles...)
	names = append(names, pkg.CgoFiles...)
	// TODO: Need to think about constants in test files. Maybe write type_string_test.go
	// in a separate pass? For later.
	// names = append(names, pkg.TestGoFiles...) // These are also in the "foo" package.
	names = append(names, pkg.SFiles...)
	names = prefixDirectory(directory, names)
	g.parsePackage(directory, names, nil)
}

// parsePackageFiles parses the package occupying the named files.
func (g *Generator) parsePackageFiles(names []string) {
	g.parsePackage(".", names, nil)
}

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

// parsePackage analyzes the single package constructed from the named files.
// If text is non-nil, it is a string to be used instead of the content of the file,
// to be used for testing. parsePackage exits if there is an error.
func (g *Generator) parsePackage(directory string, names []string, text interface{}) {
	var files []*File
	var astFiles []*ast.File
	g.pkg = new(Package)
	fs := token.NewFileSet()
	for _, name := range names {
		if !strings.HasSuffix(name, ".go") {
			continue
		}
		parsedFile, err := parser.ParseFile(fs, name, text, 0)
		if err != nil {
			log.Fatalf("parsing package: %s: %s", name, err)
		}
		astFiles = append(astFiles, parsedFile)
		files = append(files, &File{
			file: parsedFile,
			pkg:  g.pkg,
		})
	}
	if len(astFiles) == 0 {
		log.Fatalf("%s: no buildable Go files", directory)
	}
	g.pkg.name = astFiles[0].Name.Name
	g.pkg.files = files
	g.pkg.dir = directory
	// Type check the package.
	g.pkg.check(fs, astFiles)
}

// check type-checks the package. The package must be OK to proceed.
func (pkg *Package) check(fs *token.FileSet, astFiles []*ast.File) {
	pkg.defs = make(map[*ast.Ident]types.Object)
	config := types.Config{
		FakeImportC: true,
		Importer:    importer.Default(),
	}
	info := &types.Info{
		Defs: pkg.defs,
	}
	typesPkg, err := config.Check(pkg.dir, fs, astFiles, info)
	if err != nil {
		log.Fatalf("checking package: %s", err)
	}
	pkg.typesPkg = typesPkg
}

// generate produces the String method for the named type.
func (g *Generator) generate(typeName string) {
	found := false
	for _, file := range g.pkg.files {
		// Set the state for this run of the walker.
		file.typeName = typeName
		if file.file != nil {
			ast.Inspect(file.file, file.genDecl)
			if file.found {
				found = true
			}
		}
	}

	if found {
		g.build(typeName)
	} else {
		fmt.Printf("Type not found: %s", typeName)
	}
}

// format returns the gofmt-ed contents of the Generator's buffer.
func (g *Generator) format() []byte {
	src, err := format.Source(g.buf.Bytes())
	if err != nil {
		// Should never happen, but can arise when developing this code.
		// The user can compile the output to see the error.
		log.Printf("warning: internal error: invalid Go generated: %s", err)
		log.Printf("warning: compile the package to analyze the error")
		return g.buf.Bytes()
	}
	return src
}

// genDecl processes one declaration clause.
func (f *File) genDecl(node ast.Node) bool {
	decl, ok := node.(*ast.GenDecl)
	if !ok || decl.Tok != token.TYPE {
		// We only care about type declarations.
		return true
	}

	for _, spec := range decl.Specs {
		vspec := spec.(*ast.TypeSpec) // Guaranteed to succeed as this is Type.
		if vspec.Name.String() != f.typeName {
			continue
		}
		f.found = true
	}
	return false
}

// build generates the variables and String method for a single run of contiguous values.
func (g *Generator) build(typeName string) {
	g.Printf("\n")
	g.Printf(poolWrapp, typeName)
}

// Arguments to format are:
//  [1]: type name

// Argument to format is the type name.
const poolWrapp = `
type %[1]sPool struct {
    sync.Pool
}

func New%[1]sPool() *%[1]sPool {
    return &%[1]sPool{
        sync.Pool{
            New: func() interface{} {
                return new(%[1]s)
            },
        },
    }
}

func (p %[1]sPool) Get() *%[1]s {
   return p.Pool.Get().(*%[1]s)
}

func (pp %[1]sPool) Put(p *%[1]s)  {
   pp.Pool.Put(p)
}
`
<|endoftext|>


<commit_before>package main

import (
	"archive/zip"
	"encoding/binary"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"strconv"
	"strings"
)

var (
	file_index = 1
)

func main() {
	max_mln, err := strconv.Atoi(os.Args[1])
	if err != nil || max_mln < 1 || max_mln > 50 {
		fmt.Println("prime_grabber [max mln]")
		fmt.Println("Default if 50 Mln Prime numbers. Please provide number between 1-50")
		os.Exit(1)
	}

	for file_index <= max_mln {
		filename := fmt.Sprintf("primes%d.zip", file_index)
		txt_file := fmt.Sprintf("primes%d.txt", file_index)

		fmt.Println("Downloading file -> ", filename)
		resp, err := http.Get(fmt.Sprintf("http://primes.utm.edu/lists/small/millions/primes%d.zip", file_index))
		if err != nil {
			fmt.Println("File Index -> ", file_index)
			panic(err)
		}

		f, err := os.Create(filename)
		if err != nil {
			fmt.Println("File Index -> ", file_index)
			panic(err)
		}

		io.Copy(f, resp.Body)
		f.Close()
		resp.Body.Close()

		fmt.Println("Unziping file -> ", filename, " to ", txt_file)

		unzip(filename, "./")

		fmt.Println("Reading Primes Text -> ", txt_file)

		text_file_data, err := ioutil.ReadFile(txt_file)
		if err != nil {
			panic(err)
		}

		text := string(text_file_data)
		number_data := make([]byte, 0)

		lines := strings.Split(text, "\n")
		for _, line := range lines {
			words := strings.Split(line, " ")
			for _, w := range words {
				num, err := strconv.Atoi(w)
				if err == nil {
					num_bytes := make([]byte, 4)
					binary.BigEndian.PutUint32(num_bytes, uint32(num))
					number_data = append(number_data, num_bytes...)
				}
			}
		}

		fmt.Println("Removing downloaded file -> ", filename)
		os.Remove(filename)
		os.Remove(txt_file)

		fmt.Println("Appending data -> ", len(number_data))
		prime_file, err := os.OpenFile("primes.data", os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
		if err != nil {
			fmt.Println("File Index -> ", file_index)
			panic(err)
		}

		prime_file.Write(number_data)
		prime_file.Close()

		file_index++
	}

	fmt.Println("Done !!!")
}

func unzip(archive, target string) error {
	reader, err := zip.OpenReader(archive)
	if err != nil {
		return err
	}

	if err := os.MkdirAll(target, 0755); err != nil {
		return err
	}

	for _, file := range reader.File {
		path := filepath.Join(target, file.Name)
		if file.FileInfo().IsDir() {
			os.MkdirAll(path, file.Mode())
			continue
		}

		fileReader, err := file.Open()
		if err != nil {
			return err
		}
		defer fileReader.Close()

		targetFile, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, file.Mode())
		if err != nil {
			return err
		}
		defer targetFile.Close()

		if _, err := io.Copy(targetFile, fileReader); err != nil {
			return err
		}
	}

	return nil
}
<commit_msg>grabbing within given number range<commit_after>package main

import (
	"archive/zip"
	"encoding/binary"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"strconv"
	"strings"
)

var (
	file_index = 1
)

func main() {
	var err error
	max_mln := 50
	if len(os.Args) > 1 {
		max_mln, err = strconv.Atoi(os.Args[1])
		if err != nil || max_mln < 1 || max_mln > 50 {
			fmt.Println("prime_grabber [max mln]")
			fmt.Println("Default if 50 Mln Prime numbers. Please provide number between 1-50")
			os.Exit(1)
		}
	}

	for file_index <= max_mln {
		filename := fmt.Sprintf("primes%d.zip", file_index)
		txt_file := fmt.Sprintf("primes%d.txt", file_index)

		fmt.Println("Downloading file -> ", filename)
		resp, err := http.Get(fmt.Sprintf("http://primes.utm.edu/lists/small/millions/primes%d.zip", file_index))
		if err != nil {
			fmt.Println("File Index -> ", file_index)
			panic(err)
		}

		f, err := os.Create(filename)
		if err != nil {
			fmt.Println("File Index -> ", file_index)
			panic(err)
		}

		io.Copy(f, resp.Body)
		f.Close()
		resp.Body.Close()

		fmt.Println("Unziping file -> ", filename, " to ", txt_file)

		unzip(filename, "./")

		fmt.Println("Reading Primes Text -> ", txt_file)

		text_file_data, err := ioutil.ReadFile(txt_file)
		if err != nil {
			panic(err)
		}

		text := string(text_file_data)
		number_data := make([]byte, 0)

		lines := strings.Split(text, "\n")
		for _, line := range lines {
			words := strings.Split(line, " ")
			for _, w := range words {
				num, err := strconv.Atoi(w)
				if err == nil {
					num_bytes := make([]byte, 4)
					binary.BigEndian.PutUint32(num_bytes, uint32(num))
					number_data = append(number_data, num_bytes...)
				}
			}
		}

		fmt.Println("Removing downloaded file -> ", filename)
		os.Remove(filename)
		os.Remove(txt_file)

		fmt.Println("Appending data -> ", len(number_data))
		prime_file, err := os.OpenFile("primes.data", os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
		if err != nil {
			fmt.Println("File Index -> ", file_index)
			panic(err)
		}

		prime_file.Write(number_data)
		prime_file.Close()

		file_index++
	}

	fmt.Println("Done !!!")
}

func unzip(archive, target string) error {
	reader, err := zip.OpenReader(archive)
	if err != nil {
		return err
	}

	if err := os.MkdirAll(target, 0755); err != nil {
		return err
	}

	for _, file := range reader.File {
		path := filepath.Join(target, file.Name)
		if file.FileInfo().IsDir() {
			os.MkdirAll(path, file.Mode())
			continue
		}

		fileReader, err := file.Open()
		if err != nil {
			return err
		}
		defer fileReader.Close()

		targetFile, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, file.Mode())
		if err != nil {
			return err
		}
		defer targetFile.Close()

		if _, err := io.Copy(targetFile, fileReader); err != nil {
			return err
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package printer

import (
	"bytes"
	"fmt"
	"io"

	"github.com/fatih/hcl/ast"
)

const (
	blank   = byte(' ')
	newline = byte('\n')
	tab     = byte('\t')
)

func (p *printer) printNode(n ast.Node) []byte {
	var buf bytes.Buffer

	switch t := n.(type) {
	case *ast.ObjectList:
		for i, item := range t.Items {
			buf.Write(p.printObjectItem(item))
			if i != len(t.Items)-1 {
				buf.Write([]byte{newline, newline})
			}
		}
	case *ast.ObjectKey:
		buf.WriteString(t.Token.Text)
	case *ast.ObjectItem:
		buf.Write(p.printObjectItem(t))
	case *ast.LiteralType:
		buf.WriteString(t.Token.Text)
	case *ast.ListType:
		buf.Write(p.printList(t))
	case *ast.ObjectType:
		buf.Write(p.printObjectType(t))
	default:
		fmt.Printf(" unknown type: %T\n", n)
	}

	return buf.Bytes()
}

func (p *printer) printObjectItem(o *ast.ObjectItem) []byte {
	var buf bytes.Buffer

	for i, k := range o.Keys {
		buf.WriteString(k.Token.Text)
		buf.WriteByte(blank)

		// reach end of key
		if i == len(o.Keys)-1 {
			buf.WriteString("=")
			buf.WriteByte(blank)
		}
	}

	buf.Write(p.printNode(o.Val))
	return buf.Bytes()
}

func (p *printer) printLiteral(l *ast.LiteralType) []byte {
	return []byte(l.Token.Text)
}

func (p *printer) printObjectType(o *ast.ObjectType) []byte {
	var buf bytes.Buffer
	buf.WriteString("{")
	buf.WriteByte(newline)

	for _, item := range o.List.Items {
		// buf.WriteByte(tab)
		// buf.Write(p.printObjectItem(item))

		a := p.printObjectItem(item)
		a = indent(a)
		buf.Write(a)

		buf.WriteByte(newline)
	}

	buf.WriteString("}")
	return buf.Bytes()
}

func (p *printer) printList(l *ast.ListType) []byte {
	var buf bytes.Buffer
	buf.WriteString("[")

	for i, item := range l.List {
		if item.Pos().Line != l.Lbrack.Line {
			// not same line
			buf.WriteByte(newline)
		}

		buf.WriteByte(tab)
		buf.Write(p.printNode(item))

		if i != len(l.List)-1 {
			buf.WriteString(",")
			buf.WriteByte(blank)
		} else if item.Pos().Line != l.Lbrack.Line {
			buf.WriteString(",")
			buf.WriteByte(newline)
		}
	}

	buf.WriteString("]")
	return buf.Bytes()
}

func writeBlank(buf io.ByteWriter, indent int) {
	for i := 0; i < indent; i++ {
		buf.WriteByte(blank)
	}
}

func indent(buf []byte) []byte {
	splitted := bytes.Split(buf, []byte{newline})
	newBuf := make([]byte, len(splitted))
	for i, s := range splitted {
		s = append(s, 0)
		copy(s[1:], s[0:])
		s[0] = tab
		newBuf = append(newBuf, s...)

		if i != len(splitted)-1 {
			newBuf = append(newBuf, newline)
		}
	}

	return newBuf
}
<commit_msg>printer: simplify indenting of objects<commit_after>package printer

import (
	"bytes"
	"fmt"
	"io"

	"github.com/fatih/hcl/ast"
)

const (
	blank   = byte(' ')
	newline = byte('\n')
	tab     = byte('\t')
)

func (p *printer) printNode(n ast.Node) []byte {
	var buf bytes.Buffer

	switch t := n.(type) {
	case *ast.ObjectList:
		for i, item := range t.Items {
			buf.Write(p.printObjectItem(item))
			if i != len(t.Items)-1 {
				buf.Write([]byte{newline, newline})
			}
		}
	case *ast.ObjectKey:
		buf.WriteString(t.Token.Text)
	case *ast.ObjectItem:
		buf.Write(p.printObjectItem(t))
	case *ast.LiteralType:
		buf.WriteString(t.Token.Text)
	case *ast.ListType:
		buf.Write(p.printList(t))
	case *ast.ObjectType:
		buf.Write(p.printObjectType(t))
	default:
		fmt.Printf(" unknown type: %T\n", n)
	}

	return buf.Bytes()
}

func (p *printer) printObjectItem(o *ast.ObjectItem) []byte {
	var buf bytes.Buffer

	for i, k := range o.Keys {
		buf.WriteString(k.Token.Text)
		buf.WriteByte(blank)

		// reach end of key
		if i == len(o.Keys)-1 {
			buf.WriteString("=")
			buf.WriteByte(blank)
		}
	}

	buf.Write(p.printNode(o.Val))
	return buf.Bytes()
}

func (p *printer) printLiteral(l *ast.LiteralType) []byte {
	return []byte(l.Token.Text)
}

func (p *printer) printObjectType(o *ast.ObjectType) []byte {
	var buf bytes.Buffer
	buf.WriteString("{")
	buf.WriteByte(newline)

	for _, item := range o.List.Items {
		buf.Write(indent(p.printObjectItem(item)))
		buf.WriteByte(newline)
	}

	buf.WriteString("}")
	return buf.Bytes()
}

func (p *printer) printList(l *ast.ListType) []byte {
	var buf bytes.Buffer
	buf.WriteString("[")

	for i, item := range l.List {
		if item.Pos().Line != l.Lbrack.Line {
			// not same line
			buf.WriteByte(newline)
		}

		buf.WriteByte(tab)
		buf.Write(p.printNode(item))

		if i != len(l.List)-1 {
			buf.WriteString(",")
			buf.WriteByte(blank)
		} else if item.Pos().Line != l.Lbrack.Line {
			buf.WriteString(",")
			buf.WriteByte(newline)
		}
	}

	buf.WriteString("]")
	return buf.Bytes()
}

func writeBlank(buf io.ByteWriter, indent int) {
	for i := 0; i < indent; i++ {
		buf.WriteByte(blank)
	}
}

func indent(buf []byte) []byte {
	splitted := bytes.Split(buf, []byte{newline})
	newBuf := make([]byte, len(splitted))
	for i, s := range splitted {
		s = append(s, 0)
		copy(s[1:], s[0:])
		s[0] = tab
		newBuf = append(newBuf, s...)

		if i != len(splitted)-1 {
			newBuf = append(newBuf, newline)
		}
	}

	return newBuf
}
<|endoftext|>


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

package gl

// #include "gl.h"
//
// // Workaround for https://github.com/go-gl/gl/issues/104
// void gogl_glGetShaderSource(GLuint shader, GLsizei bufsize, GLsizei* len, GLchar* source) {
//     glGetShaderSource(shader, bufsize, len, source);
// }
//
import "C"

// Shader

type Shader Object

func CreateShader(type_ GLenum) Shader { return Shader(C.glCreateShader(C.GLenum(type_))) }

func (shader Shader) Delete() { C.glDeleteShader(C.GLuint(shader)) }

func (shader Shader) GetInfoLog() string {
	var length C.GLint
	C.glGetShaderiv(C.GLuint(shader), C.GLenum(INFO_LOG_LENGTH), &length)
	// length is buffer size including null character

	if length > 1 {
		log := C.malloc(C.size_t(length))
		defer C.free(log)
		C.glGetShaderInfoLog(C.GLuint(shader), C.GLsizei(length), nil, (*C.GLchar)(log))
		return C.GoString((*C.char)(log))
	}
	return ""
}

func (shader Shader) GetSource() string {
	var length C.GLint
	C.glGetShaderiv(C.GLuint(shader), C.GLenum(SHADER_SOURCE_LENGTH), &length)

	log := C.malloc(C.size_t(len + 1))
	C.gogl_glGetShaderSource(C.GLuint(shader), C.GLsizei(len), nil, (*C.GLchar)(log))

	defer C.free(log)

	if length > 1 {
		log := C.malloc(C.size_t(length + 1))
		defer C.free(log)
		C.glGetShaderSource(C.GLuint(shader), C.GLsizei(length), nil, (*C.GLchar)(log))
		return C.GoString((*C.char)(log))
	}
	return ""
}

func (shader Shader) Source(source string) {

	csource := glString(source)
	defer freeString(csource)

	var one C.GLint = C.GLint(len(source))

	C.glShaderSource(C.GLuint(shader), 1, &csource, &one)
}

func (shader Shader) Compile() { C.glCompileShader(C.GLuint(shader)) }

func (shader Shader) Get(param GLenum) int {
	var rv C.GLint

	C.glGetShaderiv(C.GLuint(shader), C.GLenum(param), &rv)
	return int(rv)
}
<commit_msg>Fixed compilation errors relating to issue 104<commit_after>// Copyright 2012 The go-gl Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package gl

// #include "gl.h"
//
// // Workaround for https://github.com/go-gl/gl/issues/104
// void gogl_glGetShaderSource(GLuint shader, GLsizei bufsize, GLsizei* len, GLchar* source) {
//     glGetShaderSource(shader, bufsize, len, source);
// }
//
import "C"

// Shader

type Shader Object

func CreateShader(type_ GLenum) Shader { return Shader(C.glCreateShader(C.GLenum(type_))) }

func (shader Shader) Delete() { C.glDeleteShader(C.GLuint(shader)) }

func (shader Shader) GetInfoLog() string {
	var length C.GLint
	C.glGetShaderiv(C.GLuint(shader), C.GLenum(INFO_LOG_LENGTH), &length)
	// length is buffer size including null character

	if length > 1 {
		log := C.malloc(C.size_t(length))
		defer C.free(log)
		C.glGetShaderInfoLog(C.GLuint(shader), C.GLsizei(length), nil, (*C.GLchar)(log))
		return C.GoString((*C.char)(log))
	}
	return ""
}

func (shader Shader) GetSource() string {
	var length C.GLint
	C.glGetShaderiv(C.GLuint(shader), C.GLenum(SHADER_SOURCE_LENGTH), &length)

	log := C.malloc(C.size_t(length + 1))
	C.gogl_glGetShaderSource(C.GLuint(shader), C.GLsizei(length), nil, (*C.GLchar)(log))

	defer C.free(log)

	if length > 1 {
		log := C.malloc(C.size_t(length + 1))
		defer C.free(log)
		C.gogl_glGetShaderSource(C.GLuint(shader), C.GLsizei(length), nil, (*C.GLchar)(log))
		return C.GoString((*C.char)(log))
	}
	return ""
}

func (shader Shader) Source(source string) {

	csource := glString(source)
	defer freeString(csource)

	var one C.GLint = C.GLint(len(source))

	C.glShaderSource(C.GLuint(shader), 1, &csource, &one)
}

func (shader Shader) Compile() { C.glCompileShader(C.GLuint(shader)) }

func (shader Shader) Get(param GLenum) int {
	var rv C.GLint

	C.glGetShaderiv(C.GLuint(shader), C.GLenum(param), &rv)
	return int(rv)
}
<|endoftext|>


<commit_before>package torrent

import (
	"fmt"
	"net"
	"os"
	"path/filepath"
	"testing"

	"github.com/anacrolix/missinggo"
	"github.com/bradfitz/iter"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"

	"github.com/anacrolix/torrent/bencode"
	"github.com/anacrolix/torrent/internal/testutil"
	"github.com/anacrolix/torrent/metainfo"
	pp "github.com/anacrolix/torrent/peer_protocol"
	"github.com/anacrolix/torrent/storage"
)

func r(i, b, l pp.Integer) request {
	return request{i, chunkSpec{b, l}}
}

// Check the given Request is correct for various torrent offsets.
func TestTorrentRequest(t *testing.T) {
	const s = 472183431 // Length of torrent.
	for _, _case := range []struct {
		off int64   // An offset into the torrent.
		req request // The expected Request. The zero value means !ok.
	}{
		// Invalid offset.
		{-1, request{}},
		{0, r(0, 0, 16384)},
		// One before the end of a piece.
		{1<<18 - 1, r(0, 1<<18-16384, 16384)},
		// Offset beyond torrent length.
		{472 * 1 << 20, request{}},
		// One before the end of the torrent. Complicates the chunk length.
		{s - 1, r((s-1)/(1<<18), (s-1)%(1<<18)/(16384)*(16384), 12935)},
		{1, r(0, 0, 16384)},
		// One before end of chunk.
		{16383, r(0, 0, 16384)},
		// Second chunk.
		{16384, r(0, 16384, 16384)},
	} {
		req, ok := torrentOffsetRequest(472183431, 1<<18, 16384, _case.off)
		if (_case.req == request{}) == ok {
			t.Fatalf("expected %v, got %v", _case.req, req)
		}
		if req != _case.req {
			t.Fatalf("expected %v, got %v", _case.req, req)
		}
	}
}

func TestAppendToCopySlice(t *testing.T) {
	orig := []int{1, 2, 3}
	dupe := append([]int{}, orig...)
	dupe[0] = 4
	if orig[0] != 1 {
		t.FailNow()
	}
}

func TestTorrentString(t *testing.T) {
	tor := &Torrent{}
	s := tor.InfoHash().HexString()
	if s != "0000000000000000000000000000000000000000" {
		t.FailNow()
	}
}

// This benchmark is from the observation that a lot of overlapping Readers on
// a large torrent with small pieces had a lot of overhead in recalculating
// piece priorities everytime a reader (possibly in another Torrent) changed.
func BenchmarkUpdatePiecePriorities(b *testing.B) {
	const (
		numPieces   = 13410
		pieceLength = 256 << 10
	)
	cl := &Client{config: &ClientConfig{}}
	cl.initLogger()
	t := cl.newTorrent(metainfo.Hash{}, nil)
	require.NoError(b, t.setInfo(&metainfo.Info{
		Pieces:      make([]byte, metainfo.HashSize*numPieces),
		PieceLength: pieceLength,
		Length:      pieceLength * numPieces,
	}))
	assert.EqualValues(b, 13410, t.numPieces())
	for range iter.N(7) {
		r := t.NewReader()
		r.SetReadahead(32 << 20)
		r.Seek(3500000, 0)
	}
	assert.Len(b, t.readers, 7)
	for i := 0; i < int(t.numPieces()); i += 3 {
		t._completedPieces.Set(i, true)
	}
	t.DownloadPieces(0, t.numPieces())
	for range iter.N(b.N) {
		t.updateAllPiecePriorities()
	}
}

// Check that a torrent containing zero-length file(s) will start, and that
// they're created in the filesystem. The client storage is assumed to be
// file-based on the native filesystem based.
func testEmptyFilesAndZeroPieceLength(t *testing.T, cfg *ClientConfig) {
	cl, err := NewClient(cfg)
	require.NoError(t, err)
	defer cl.Close()
	ib, err := bencode.Marshal(metainfo.Info{
		Name:        "empty",
		Length:      0,
		PieceLength: 0,
	})
	require.NoError(t, err)
	fp := filepath.Join(cfg.DataDir, "empty")
	os.Remove(fp)
	assert.False(t, missinggo.FilePathExists(fp))
	tt, err := cl.AddTorrent(&metainfo.MetaInfo{
		InfoBytes: ib,
	})
	require.NoError(t, err)
	defer tt.Drop()
	tt.DownloadAll()
	require.True(t, cl.WaitAll())
	assert.True(t, missinggo.FilePathExists(fp))
}

func TestEmptyFilesAndZeroPieceLengthWithFileStorage(t *testing.T) {
	cfg := TestingConfig()
	ci := storage.NewFile(cfg.DataDir)
	defer ci.Close()
	cfg.DefaultStorage = ci
	testEmptyFilesAndZeroPieceLength(t, cfg)
}

func TestEmptyFilesAndZeroPieceLengthWithMMapStorage(t *testing.T) {
	cfg := TestingConfig()
	ci := storage.NewMMap(cfg.DataDir)
	defer ci.Close()
	cfg.DefaultStorage = ci
	testEmptyFilesAndZeroPieceLength(t, cfg)
}

func TestPieceHashFailed(t *testing.T) {
	mi := testutil.GreetingMetaInfo()
	cl := new(Client)
	cl.config = TestingConfig()
	cl.initLogger()
	tt := cl.newTorrent(mi.HashInfoBytes(), badStorage{})
	tt.setChunkSize(2)
	require.NoError(t, tt.setInfoBytes(mi.InfoBytes))
	tt.cl.lock()
	tt.pieces[1]._dirtyChunks.AddRange(0, 3)
	require.True(t, tt.pieceAllDirty(1))
	tt.pieceHashed(1, false)
	// Dirty chunks should be cleared so we can try again.
	require.False(t, tt.pieceAllDirty(1))
	tt.cl.unlock()
}

// Check the behaviour of Torrent.Metainfo when metadata is not completed.
func TestTorrentMetainfoIncompleteMetadata(t *testing.T) {
	cfg := TestingConfig()
	cfg.Debug = true
	cl, err := NewClient(cfg)
	require.NoError(t, err)
	defer cl.Close()

	mi := testutil.GreetingMetaInfo()
	ih := mi.HashInfoBytes()

	tt, _ := cl.AddTorrentInfoHash(ih)
	assert.Nil(t, tt.Metainfo().InfoBytes)
	assert.False(t, tt.haveAllMetadataPieces())

	nc, err := net.Dial("tcp", fmt.Sprintf(":%d", cl.LocalPort()))
	require.NoError(t, err)
	defer nc.Close()

	var pex PeerExtensionBits
	pex.SetBit(pp.ExtensionBitExtended)
	hr, err := pp.Handshake(nc, &ih, [20]byte{}, pex)
	require.NoError(t, err)
	assert.True(t, hr.PeerExtensionBits.GetBit(pp.ExtensionBitExtended))
	assert.EqualValues(t, cl.PeerID(), hr.PeerID)
	assert.EqualValues(t, ih, hr.Hash)

	assert.EqualValues(t, 0, tt.metadataSize())

	func() {
		cl.lock()
		defer cl.unlock()
		go func() {
			_, err = nc.Write(pp.Message{
				Type:       pp.Extended,
				ExtendedID: pp.HandshakeExtendedID,
				ExtendedPayload: func() []byte {
					d := map[string]interface{}{
						"metadata_size": len(mi.InfoBytes),
					}
					b, err := bencode.Marshal(d)
					if err != nil {
						panic(err)
					}
					return b
				}(),
			}.MustMarshalBinary())
			require.NoError(t, err)
		}()
		tt.metadataChanged.Wait()
	}()
	assert.Equal(t, make([]byte, len(mi.InfoBytes)), tt.metadataBytes)
	assert.False(t, tt.haveAllMetadataPieces())
	assert.Nil(t, tt.Metainfo().InfoBytes)
}
<commit_msg>Fix panic in benchmark due to requestStrategy changes<commit_after>package torrent

import (
	"fmt"
	"net"
	"os"
	"path/filepath"
	"testing"

	"github.com/anacrolix/missinggo"
	"github.com/bradfitz/iter"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"

	"github.com/anacrolix/torrent/bencode"
	"github.com/anacrolix/torrent/internal/testutil"
	"github.com/anacrolix/torrent/metainfo"
	pp "github.com/anacrolix/torrent/peer_protocol"
	"github.com/anacrolix/torrent/storage"
)

func r(i, b, l pp.Integer) request {
	return request{i, chunkSpec{b, l}}
}

// Check the given Request is correct for various torrent offsets.
func TestTorrentRequest(t *testing.T) {
	const s = 472183431 // Length of torrent.
	for _, _case := range []struct {
		off int64   // An offset into the torrent.
		req request // The expected Request. The zero value means !ok.
	}{
		// Invalid offset.
		{-1, request{}},
		{0, r(0, 0, 16384)},
		// One before the end of a piece.
		{1<<18 - 1, r(0, 1<<18-16384, 16384)},
		// Offset beyond torrent length.
		{472 * 1 << 20, request{}},
		// One before the end of the torrent. Complicates the chunk length.
		{s - 1, r((s-1)/(1<<18), (s-1)%(1<<18)/(16384)*(16384), 12935)},
		{1, r(0, 0, 16384)},
		// One before end of chunk.
		{16383, r(0, 0, 16384)},
		// Second chunk.
		{16384, r(0, 16384, 16384)},
	} {
		req, ok := torrentOffsetRequest(472183431, 1<<18, 16384, _case.off)
		if (_case.req == request{}) == ok {
			t.Fatalf("expected %v, got %v", _case.req, req)
		}
		if req != _case.req {
			t.Fatalf("expected %v, got %v", _case.req, req)
		}
	}
}

func TestAppendToCopySlice(t *testing.T) {
	orig := []int{1, 2, 3}
	dupe := append([]int{}, orig...)
	dupe[0] = 4
	if orig[0] != 1 {
		t.FailNow()
	}
}

func TestTorrentString(t *testing.T) {
	tor := &Torrent{}
	s := tor.InfoHash().HexString()
	if s != "0000000000000000000000000000000000000000" {
		t.FailNow()
	}
}

// This benchmark is from the observation that a lot of overlapping Readers on
// a large torrent with small pieces had a lot of overhead in recalculating
// piece priorities everytime a reader (possibly in another Torrent) changed.
func BenchmarkUpdatePiecePriorities(b *testing.B) {
	const (
		numPieces   = 13410
		pieceLength = 256 << 10
	)
	cl := &Client{config: TestingConfig()}
	cl.initLogger()
	t := cl.newTorrent(metainfo.Hash{}, nil)
	require.NoError(b, t.setInfo(&metainfo.Info{
		Pieces:      make([]byte, metainfo.HashSize*numPieces),
		PieceLength: pieceLength,
		Length:      pieceLength * numPieces,
	}))
	assert.EqualValues(b, 13410, t.numPieces())
	for range iter.N(7) {
		r := t.NewReader()
		r.SetReadahead(32 << 20)
		r.Seek(3500000, 0)
	}
	assert.Len(b, t.readers, 7)
	for i := 0; i < int(t.numPieces()); i += 3 {
		t._completedPieces.Set(i, true)
	}
	t.DownloadPieces(0, t.numPieces())
	for range iter.N(b.N) {
		t.updateAllPiecePriorities()
	}
}

// Check that a torrent containing zero-length file(s) will start, and that
// they're created in the filesystem. The client storage is assumed to be
// file-based on the native filesystem based.
func testEmptyFilesAndZeroPieceLength(t *testing.T, cfg *ClientConfig) {
	cl, err := NewClient(cfg)
	require.NoError(t, err)
	defer cl.Close()
	ib, err := bencode.Marshal(metainfo.Info{
		Name:        "empty",
		Length:      0,
		PieceLength: 0,
	})
	require.NoError(t, err)
	fp := filepath.Join(cfg.DataDir, "empty")
	os.Remove(fp)
	assert.False(t, missinggo.FilePathExists(fp))
	tt, err := cl.AddTorrent(&metainfo.MetaInfo{
		InfoBytes: ib,
	})
	require.NoError(t, err)
	defer tt.Drop()
	tt.DownloadAll()
	require.True(t, cl.WaitAll())
	assert.True(t, missinggo.FilePathExists(fp))
}

func TestEmptyFilesAndZeroPieceLengthWithFileStorage(t *testing.T) {
	cfg := TestingConfig()
	ci := storage.NewFile(cfg.DataDir)
	defer ci.Close()
	cfg.DefaultStorage = ci
	testEmptyFilesAndZeroPieceLength(t, cfg)
}

func TestEmptyFilesAndZeroPieceLengthWithMMapStorage(t *testing.T) {
	cfg := TestingConfig()
	ci := storage.NewMMap(cfg.DataDir)
	defer ci.Close()
	cfg.DefaultStorage = ci
	testEmptyFilesAndZeroPieceLength(t, cfg)
}

func TestPieceHashFailed(t *testing.T) {
	mi := testutil.GreetingMetaInfo()
	cl := new(Client)
	cl.config = TestingConfig()
	cl.initLogger()
	tt := cl.newTorrent(mi.HashInfoBytes(), badStorage{})
	tt.setChunkSize(2)
	require.NoError(t, tt.setInfoBytes(mi.InfoBytes))
	tt.cl.lock()
	tt.pieces[1]._dirtyChunks.AddRange(0, 3)
	require.True(t, tt.pieceAllDirty(1))
	tt.pieceHashed(1, false)
	// Dirty chunks should be cleared so we can try again.
	require.False(t, tt.pieceAllDirty(1))
	tt.cl.unlock()
}

// Check the behaviour of Torrent.Metainfo when metadata is not completed.
func TestTorrentMetainfoIncompleteMetadata(t *testing.T) {
	cfg := TestingConfig()
	cfg.Debug = true
	cl, err := NewClient(cfg)
	require.NoError(t, err)
	defer cl.Close()

	mi := testutil.GreetingMetaInfo()
	ih := mi.HashInfoBytes()

	tt, _ := cl.AddTorrentInfoHash(ih)
	assert.Nil(t, tt.Metainfo().InfoBytes)
	assert.False(t, tt.haveAllMetadataPieces())

	nc, err := net.Dial("tcp", fmt.Sprintf(":%d", cl.LocalPort()))
	require.NoError(t, err)
	defer nc.Close()

	var pex PeerExtensionBits
	pex.SetBit(pp.ExtensionBitExtended)
	hr, err := pp.Handshake(nc, &ih, [20]byte{}, pex)
	require.NoError(t, err)
	assert.True(t, hr.PeerExtensionBits.GetBit(pp.ExtensionBitExtended))
	assert.EqualValues(t, cl.PeerID(), hr.PeerID)
	assert.EqualValues(t, ih, hr.Hash)

	assert.EqualValues(t, 0, tt.metadataSize())

	func() {
		cl.lock()
		defer cl.unlock()
		go func() {
			_, err = nc.Write(pp.Message{
				Type:       pp.Extended,
				ExtendedID: pp.HandshakeExtendedID,
				ExtendedPayload: func() []byte {
					d := map[string]interface{}{
						"metadata_size": len(mi.InfoBytes),
					}
					b, err := bencode.Marshal(d)
					if err != nil {
						panic(err)
					}
					return b
				}(),
			}.MustMarshalBinary())
			require.NoError(t, err)
		}()
		tt.metadataChanged.Wait()
	}()
	assert.Equal(t, make([]byte, len(mi.InfoBytes)), tt.metadataBytes)
	assert.False(t, tt.haveAllMetadataPieces())
	assert.Nil(t, tt.Metainfo().InfoBytes)
}
<|endoftext|>


<commit_before>// +build integration

package dal_test

import (
	"github.com/stretchr/testify/suite"
	"strings"
	"testing"
	"vmango/cfg"
	"vmango/dal"
	"vmango/models"
	"vmango/testool"
)

type ProviderLibvirtSuite struct {
	suite.Suite
	testool.LibvirtTest
	Provider *dal.LibvirtProvider
}

func (suite *ProviderLibvirtSuite) SetupSuite() {
	suite.LibvirtTest.SetupSuite()
	suite.LibvirtTest.Fixtures.Domains = []string{"one", "two"}
	suite.LibvirtTest.Fixtures.Networks = []string{"vmango-test"}
	suite.LibvirtTest.Fixtures.Pools = []testool.LibvirtTestPoolFixture{
		{
			Name:    "vmango-vms-test",
			Volumes: []string{"one_disk", "one_config.iso", "two_disk", "two_config.iso"},
		},
		{
			Name:    "vmango-images-test",
			Volumes: []string{},
		},
	}
}

func (suite *ProviderLibvirtSuite) SetupTest() {
	suite.LibvirtTest.SetupTest()
	provider, err := dal.NewLibvirtProvider(cfg.HypervisorConfig{
		Name:             "testhv",
		Url:              suite.LibvirtTest.VirURI,
		RootStoragePool:  suite.Fixtures.Pools[0].Name,
		ImageStoragePool: suite.Fixtures.Pools[1].Name,
		Network:          suite.Fixtures.Networks[0],
		VmTemplate:       suite.VMTplPath,
		VolTemplate:      suite.VolTplPath,
		IgnoreVms:        []string{},
	})
	if err != nil {
		panic(err)
	}
	suite.Provider = provider
}

func (suite *ProviderLibvirtSuite) TestStatusOk() {
	status := &models.StatusInfo{}
	err := suite.Provider.Status(status)
	suite.Require().NoError(err)

	suite.Equal("testhv", status.Name)
	suite.Equal("libvirt", status.Type)
	suite.True(strings.HasPrefix(status.Description, "KVM hypervisor"), status.Description)
	suite.Equal(suite.LibvirtTest.VirURI, status.Connection)
	suite.Equal(2, status.MachineCount)
	suite.True(status.Memory.Total > 0, status.Memory.Total)
	suite.True(status.Memory.Usage > 0, status.Memory.Usage)
	suite.True(status.Storage.Total > 0, status.Storage.Total)
	suite.True(status.Storage.Usage > 0, status.Storage.Usage)

}

func TestProviderLibvirtSuite(t *testing.T) {
	suite.Run(t, new(ProviderLibvirtSuite))
}
<commit_msg>Fix libvirt provider status test<commit_after>// +build integration

package dal_test

import (
	"github.com/stretchr/testify/suite"
	"strings"
	"testing"
	"vmango/cfg"
	"vmango/dal"
	"vmango/models"
	"vmango/testool"
)

type ProviderLibvirtSuite struct {
	suite.Suite
	testool.LibvirtTest
	Provider *dal.LibvirtProvider
}

func (suite *ProviderLibvirtSuite) SetupSuite() {
	suite.LibvirtTest.SetupSuite()
	suite.LibvirtTest.Fixtures.Domains = []string{"one", "two"}
	suite.LibvirtTest.Fixtures.Networks = []string{"vmango-test"}
	suite.LibvirtTest.Fixtures.Pools = []testool.LibvirtTestPoolFixture{
		{
			Name:    "vmango-vms-test",
			Volumes: []string{"one_disk", "one_config.iso", "two_disk", "two_config.iso"},
		},
		{
			Name:    "vmango-images-test",
			Volumes: []string{},
		},
	}
}

func (suite *ProviderLibvirtSuite) SetupTest() {
	suite.LibvirtTest.SetupTest()
	provider, err := dal.NewLibvirtProvider(cfg.HypervisorConfig{
		Name:             "testhv",
		Url:              suite.LibvirtTest.VirURI,
		RootStoragePool:  suite.Fixtures.Pools[0].Name,
		ImageStoragePool: suite.Fixtures.Pools[1].Name,
		Network:          suite.Fixtures.Networks[0],
		VmTemplate:       suite.VMTplPath,
		VolTemplate:      suite.VolTplPath,
		IgnoreVms:        []string{},
	})
	if err != nil {
		panic(err)
	}
	suite.Provider = provider
}

func (suite *ProviderLibvirtSuite) TestStatusOk() {
	status := &models.StatusInfo{}
	err := suite.Provider.Status(status)
	suite.Require().NoError(err)

	suite.Equal("testhv", status.Name)
	suite.Equal("libvirt", status.Type)
	suite.True(strings.HasPrefix(status.Description, "KVM hypervisor"), status.Description)
	suite.Equal(suite.LibvirtTest.VirURI, status.Connection)
	suite.Equal(2, status.MachineCount)
	suite.NotEqual(0, status.Memory.Total)
	suite.NotEqual(0, status.Storage.Total)
	// TODO: How to check it?
	// suite.NotEqual(0, status.Memory.Usage)
	// suite.NotEqual(0, status.Storage.Usage)

}

func TestProviderLibvirtSuite(t *testing.T) {
	suite.Run(t, new(ProviderLibvirtSuite))
}
<|endoftext|>


<commit_before>package main

import (
	"io/ioutil"
	"regexp"
	"strconv"
	"strings"

	"golang.org/x/net/context"
	"golang.org/x/oauth2/google"
	"gopkg.in/Iwark/spreadsheet.v2"
)

// Represents the board members of a Toastmasters meeting.
type board struct {
	president, vpe, vpm, vppr, secretary, treasurer, saa string
}

// Factory method using a spreadsheet to fill in board members.
func (board) new(sheet *spreadsheet.Sheet) board {
	board := board{}
	board.president = sheet.Columns[1][0].Value
	board.vpe = sheet.Columns[1][1].Value
	board.vpm = sheet.Columns[1][2].Value
	board.vppr = sheet.Columns[1][3].Value
	board.secretary = sheet.Columns[1][4].Value
	board.treasurer = sheet.Columns[1][5].Value
	board.saa = sheet.Columns[1][6].Value

	return board
}

// Represents the editable fields on a Toastmasters agenda.
type agendaRoles struct {
	toastmaster, ge, timer, ahCounter, grammarian string
	tableTopicsMaster, jokeMaster                 string
	speakers                                      []speaker
	boardMembers                                  board
	futureWeeks                                   [][]string
}

// Factory method to create agenda roles based on the date of the meeting.
func (agendaRoles) new(agendaDate string) agendaRoles {
	spreadsheets := getSheet()
	boardMembers := board{}.new(spreadsheets.boardSheet)

	agendaRoles := agendaRoles{}
	agendaRoles.boardMembers = boardMembers

	rolesSheet := spreadsheets.meetingRoles
	for i := range rolesSheet.Columns {
		if rolesSheet.Columns[i][0].Value == agendaDate {
			agendaRoles.toastmaster = rolesSheet.Columns[i][1].Value
			agendaRoles.jokeMaster = rolesSheet.Columns[i][2].Value
			agendaRoles.ge = rolesSheet.Columns[i][3].Value
			agendaRoles.timer = rolesSheet.Columns[i][4].Value
			agendaRoles.ahCounter = rolesSheet.Columns[i][5].Value
			agendaRoles.grammarian = rolesSheet.Columns[i][6].Value

			for j := 7; j <= 13; j += 2 {
				agendaRoles.speakers = append(agendaRoles.speakers, speaker{}.new(rolesSheet.Columns[i][j].Value, rolesSheet.Columns[i][j+1].Value))
			}

			agendaRoles.tableTopicsMaster = rolesSheet.Columns[i][16].Value
			agendaRoles.futureWeeks = getFutureWeeks(agendaDate, rolesSheet)
			break
		}
	}
	return agendaRoles
}

//  Represents a speaker in a Toastmasters meeting.
type speaker struct {
	name string
	speech
	evaluator string
}

// Factory method to create a speaker based on the spreadsheet speaker and evaluator.
func (speaker) new(s string, eval string) speaker {
	name, manual, number := parseManualAndNumber(s)
	info := speech{}.new(manual, number)

	speaker := speaker{}
	speaker.name = name
	speaker.evaluator = eval
	speaker.speech = info

	return speaker
}

// Helper method that returns the first name of a speaker.
func (s speaker) firstName() string {
	return strings.Split(s.name, " ")[0]
}

// Represents the spreadsheet tabs.
type googleDocsSheet struct {
	boardSheet   *spreadsheet.Sheet
	meetingRoles *spreadsheet.Sheet
}

//  GetSheet reads a Google Docs spreadsheet and returns a sheet with roles and another sheet with the board members.
func getSheet() googleDocsSheet {
	data, err := ioutil.ReadFile("client_secret.json")
	if err != nil {
		panic("cannot read client_secret.json")
	}

	conf, err := google.JWTConfigFromJSON(data, spreadsheet.Scope)
	if err != nil {
		panic("problem with google.JWTConfigFromJSON(data, spreadsheet.Scope)")
	}

	client := conf.Client(context.TODO())

	service := spreadsheet.NewServiceWithClient(client)
	spreadsheet, err := service.FetchSpreadsheet("1CBlORqCzL6YvyAUZTk8jezvhyuDzjjumghwGKk5VIK8")
	if err != nil {
		panic("cannot fetch spread sheet: ")
	}

	roles, err := spreadsheet.SheetByIndex(0)
	if err != nil {
		panic("Cannot read spreadsheet by index 0")
	}

	board, err := spreadsheet.SheetByIndex(1)
	if err != nil {
		panic("Cannot read spreadsheet by index 1")
	}

	return googleDocsSheet{boardSheet: board, meetingRoles: roles}
}

// Find the speaker name, manual and number from a string that looks like "Ann Addicks\nCC #9".
func parseManualAndNumber(speaker string) (string, string, int) {
	re := regexp.MustCompile(`([a-zA-Z]+ [a-zA-Z]+)\n([a-zA-Z]+) #(\d{1,2})`)
	result := re.FindStringSubmatch(speaker)
	name := speaker
	manual := ""
	speechNum := 0

	if len(result) > 0 {
		name = result[1]
		manual = result[2]
		speechNum, _ = strconv.Atoi(result[3])
	}
	return name, manual, speechNum
}

// The number of weeks in the future to capture.
const futureWeeks = 4

// GetFutureWeeks finds the next several weeks after the current week based on the constant futureWeeks.
func getFutureWeeks(agendaDate string, sheet *spreadsheet.Sheet) [][]string {
	week := 0
	var nextSchedule = make([][]string, 0, futureWeeks)

	for i := 0; i < len(sheet.Columns) && week <= futureWeeks; i++ {
		if week == 0 {
			if sheet.Columns[i][0].Value == agendaDate {
				week = 1
			}
		} else {
			nextWeek := make([]string, 17)

			for j := 0; j < 17; j++ {
				nextWeek[j] = sheet.Columns[i][j].Value
			}
			nextSchedule = append(nextSchedule, nextWeek)
			week++
		}
	}
	return nextSchedule
}
<commit_msg>each field gets their own line.<commit_after>package main

import (
	"io/ioutil"
	"regexp"
	"strconv"
	"strings"

	"golang.org/x/net/context"
	"golang.org/x/oauth2/google"
	"gopkg.in/Iwark/spreadsheet.v2"
)

// Represents the board members of a Toastmasters meeting.
type board struct {
	president string
	vpe       string
	vpm       string
	vppr      string
	secretary string
	treasurer string
	saa       string
}

// Factory method using a spreadsheet to fill in board members.
func (board) new(sheet *spreadsheet.Sheet) board {
	board := board{}
	board.president = sheet.Columns[1][0].Value
	board.vpe = sheet.Columns[1][1].Value
	board.vpm = sheet.Columns[1][2].Value
	board.vppr = sheet.Columns[1][3].Value
	board.secretary = sheet.Columns[1][4].Value
	board.treasurer = sheet.Columns[1][5].Value
	board.saa = sheet.Columns[1][6].Value

	return board
}

// Represents the editable fields on a Toastmasters agenda.
type agendaRoles struct {
	toastmaster       string
	ge                string
	timer             string
	ahCounter         string
	grammarian        string
	tableTopicsMaster string
	jokeMaster        string
	speakers          []speaker
	boardMembers      board
	futureWeeks       [][]string
}

// Factory method to create agenda roles based on the date of the meeting.
func (agendaRoles) new(agendaDate string) agendaRoles {
	spreadsheets := getSheet()
	boardMembers := board{}.new(spreadsheets.boardSheet)

	agendaRoles := agendaRoles{}
	agendaRoles.boardMembers = boardMembers

	rolesSheet := spreadsheets.meetingRoles
	for i := range rolesSheet.Columns {
		if rolesSheet.Columns[i][0].Value == agendaDate {
			agendaRoles.toastmaster = rolesSheet.Columns[i][1].Value
			agendaRoles.jokeMaster = rolesSheet.Columns[i][2].Value
			agendaRoles.ge = rolesSheet.Columns[i][3].Value
			agendaRoles.timer = rolesSheet.Columns[i][4].Value
			agendaRoles.ahCounter = rolesSheet.Columns[i][5].Value
			agendaRoles.grammarian = rolesSheet.Columns[i][6].Value

			for j := 7; j <= 13; j += 2 {
				agendaRoles.speakers = append(agendaRoles.speakers, speaker{}.new(rolesSheet.Columns[i][j].Value, rolesSheet.Columns[i][j+1].Value))
			}

			agendaRoles.tableTopicsMaster = rolesSheet.Columns[i][16].Value
			agendaRoles.futureWeeks = getFutureWeeks(agendaDate, rolesSheet)
			break
		}
	}
	return agendaRoles
}

//  Represents a speaker in a Toastmasters meeting.
type speaker struct {
	name string
	speech
	evaluator string
}

// Factory method to create a speaker based on the spreadsheet speaker and evaluator.
func (speaker) new(s string, eval string) speaker {
	name, manual, number := parseManualAndNumber(s)
	info := speech{}.new(manual, number)

	speaker := speaker{}
	speaker.name = name
	speaker.evaluator = eval
	speaker.speech = info

	return speaker
}

// Helper method that returns the first name of a speaker.
func (s speaker) firstName() string {
	return strings.Split(s.name, " ")[0]
}

// Represents the spreadsheet tabs.
type googleDocsSheet struct {
	boardSheet   *spreadsheet.Sheet
	meetingRoles *spreadsheet.Sheet
}

//  GetSheet reads a Google Docs spreadsheet and returns a sheet with roles and another sheet with the board members.
func getSheet() googleDocsSheet {
	data, err := ioutil.ReadFile("client_secret.json")
	if err != nil {
		panic("cannot read client_secret.json")
	}

	conf, err := google.JWTConfigFromJSON(data, spreadsheet.Scope)
	if err != nil {
		panic("problem with google.JWTConfigFromJSON(data, spreadsheet.Scope)")
	}

	client := conf.Client(context.TODO())

	service := spreadsheet.NewServiceWithClient(client)
	spreadsheet, err := service.FetchSpreadsheet("1CBlORqCzL6YvyAUZTk8jezvhyuDzjjumghwGKk5VIK8")
	if err != nil {
		panic("cannot fetch spread sheet: ")
	}

	roles, err := spreadsheet.SheetByIndex(0)
	if err != nil {
		panic("Cannot read spreadsheet by index 0")
	}

	board, err := spreadsheet.SheetByIndex(1)
	if err != nil {
		panic("Cannot read spreadsheet by index 1")
	}

	return googleDocsSheet{boardSheet: board, meetingRoles: roles}
}

// Find the speaker name, manual and number from a string that looks like "Ann Addicks\nCC #9".
func parseManualAndNumber(speaker string) (string, string, int) {
	re := regexp.MustCompile(`([a-zA-Z]+ [a-zA-Z]+)\n([a-zA-Z]+) #(\d{1,2})`)
	result := re.FindStringSubmatch(speaker)
	name := speaker
	manual := ""
	speechNum := 0

	if len(result) > 0 {
		name = result[1]
		manual = result[2]
		speechNum, _ = strconv.Atoi(result[3])
	}
	return name, manual, speechNum
}

// The number of weeks in the future to capture.
const futureWeeks = 4

// GetFutureWeeks finds the next several weeks after the current week based on the constant futureWeeks.
func getFutureWeeks(agendaDate string, sheet *spreadsheet.Sheet) [][]string {
	week := 0
	var nextSchedule = make([][]string, 0, futureWeeks)

	for i := 0; i < len(sheet.Columns) && week <= futureWeeks; i++ {
		if week == 0 {
			if sheet.Columns[i][0].Value == agendaDate {
				week = 1
			}
		} else {
			nextWeek := make([]string, 17)

			for j := 0; j < 17; j++ {
				nextWeek[j] = sheet.Columns[i][j].Value
			}
			nextSchedule = append(nextSchedule, nextWeek)
			week++
		}
	}
	return nextSchedule
}
<|endoftext|>