<commit_before>package main

import (
	"fmt"
	"net/http"

	"github.com/RangelReale/osin"
	"github.com/osin-mongo-storage/mgostore"
)

type Oauth struct {
	sconfig *osin.ServerConfig
	server  *osin.Server
	Storage *mgostore.MongoStorage
}

func (o *Oauth) AuthorizeClient(w http.ResponseWriter, r *http.Request) {
	server := oauth.server
	resp := server.NewResponse()
	if ar := server.HandleAuthorizeRequest(resp, r); ar != nil {

		// Handle the login page

		// if !example.HandleLoginPage(ar, w, r) {
		// return
		// }

		// ~to-do , needs to be added users data
		ar.UserData = UserData{"Login": "test"}
		ar.Authorized = true
		server.FinishAuthorizeRequest(resp, r, ar)

	}
	if resp.IsError && resp.InternalError != nil {
		fmt.Printf("ERROR: %s\n", resp.InternalError)
	}
	if !resp.IsError {
		resp.Output["custom_parameter"] = 187723
	}
	osin.OutputJSON(resp, w, r)
}

func (o *Oauth) GenerateToken(w http.ResponseWriter, r *http.Request) {
	server := oauth.server
	resp := server.NewResponse()
	if ar := server.HandleAccessRequest(resp, r); ar != nil {
		switch ar.Type {
		case osin.AUTHORIZATION_CODE:
			ar.Authorized = true
		case osin.REFRESH_TOKEN:
			ar.Authorized = true
		case osin.CLIENT_CREDENTIALS:
			ar.Authorized = true
		}
		server.FinishAccessRequest(resp, r, ar)
	}
	if resp.IsError && resp.InternalError != nil {
		fmt.Printf("ERROR: %s\n", resp.InternalError)
	}
	if !resp.IsError {
		resp.Output["custom_parameter"] = 19923
	}
	osin.OutputJSON(resp, w, r)
}
<commit_msg>go/oauth: add user data with oauth token<commit_after>package main

import (
	"errors"
	"fmt"
	"koding/db/models"
	"koding/db/mongodb/modelhelper"
	"net/http"

	"github.com/RangelReale/osin"
	"github.com/osin-mongo-storage/mgostore"
)

var (
	ErrClientIdNotFound    = errors.New("client id is not found")
	ErrCookieValueNotFound = errors.New("cookie value is not found")
	ErrSessionNotFound     = errors.New("session is not found")
)

type Oauth struct {
	sconfig *osin.ServerConfig
	server  *osin.Server
	Storage *mgostore.MongoStorage
}

func (o *Oauth) AuthorizeClient(w http.ResponseWriter, r *http.Request) {
	server := oauth.server
	resp := server.NewResponse()
	if ar := server.HandleAuthorizeRequest(resp, r); ar != nil {

		session, err := getSession(r)
		if err != nil {
			return w.Write([]byte(err))
		}

		// Handle the login page

		// if !example.HandleLoginPage(ar, w, r) {
		// return
		// }

		// ~to-do , needs to be added users data
		ar.UserData = session.Username
		ar.Authorized = true
		server.FinishAuthorizeRequest(resp, r, ar)

	}
	if resp.IsError && resp.InternalError != nil {
		fmt.Printf("ERROR: %s\n", resp.InternalError)
	}
	if !resp.IsError {
		resp.Output["custom_parameter"] = 187723
	}
	osin.OutputJSON(resp, w, r)
}

func (o *Oauth) GenerateToken(w http.ResponseWriter, r *http.Request) {
	server := oauth.server
	resp := server.NewResponse()
	if ar := server.HandleAccessRequest(resp, r); ar != nil {
		switch ar.Type {
		case osin.AUTHORIZATION_CODE:
			ar.Authorized = true
		case osin.REFRESH_TOKEN:
			ar.Authorized = true
		case osin.CLIENT_CREDENTIALS:
			ar.Authorized = true
		}
		server.FinishAccessRequest(resp, r, ar)
	}
	if resp.IsError && resp.InternalError != nil {
		fmt.Printf("ERROR: %s\n", resp.InternalError)
	}
	if !resp.IsError {
		resp.Output["custom_parameter"] = 19923
	}
	osin.OutputJSON(resp, w, r)
}

func getSession(r *http.Request) (*models.Session, error) {
	cookie, err := r.Cookie("clientId")
	if err != nil {
		return "", ErrClientIdNotFound
	}

	if cookie.Value == "" {
		return "", ErrCookieValueNotFound
	}

	session, err := modelhelper.GetSession(cookie.Value)
	if err != nil {
		return "", ErrSessionNotFound
	}

	return session, nil
}
<|endoftext|>


<commit_before>/*
   Copyright 2017 Shlomi Noach, GitHub Inc.

   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 logic

import (
	"vitess.io/vitess/go/vt/orchestrator/inst"

	"vitess.io/vitess/go/vt/orchestrator/external/golib/sqlutils"
)

type SnapshotData struct {
	Keys             []inst.InstanceKey // Kept for backwards comapatibility
	MinimalInstances []inst.MinimalInstance
	RecoveryDisabled bool

	ClusterAlias,
	ClusterAliasOverride,
	ClusterDomainName,
	HostAttributes,
	InstanceTags,
	AccessToken,
	PoolInstances,
	InjectedPseudoGTIDClusters,
	HostnameResolves,
	HostnameUnresolves,
	DowntimedInstances,
	Candidates,
	Detections,
	KVStore,
	Recovery,
	RecoverySteps sqlutils.NamedResultData

	LeaderURI string
}

func NewSnapshotData() *SnapshotData {
	return &SnapshotData{}
}

type SnapshotDataCreatorApplier struct {
}

func NewSnapshotDataCreatorApplier() *SnapshotDataCreatorApplier {
	generator := &SnapshotDataCreatorApplier{}
	return generator
}
<commit_msg>delete unused snapshot_data.go<commit_after><|endoftext|>


<commit_before>package hdfsbackend

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"path"
	"regexp"
	"strconv"
	"sync"

	"code.uber.internal/infra/kraken/core"
	"code.uber.internal/infra/kraken/lib/backend/backenderrors"
	"code.uber.internal/infra/kraken/lib/backend/namepath"
	"code.uber.internal/infra/kraken/utils/httputil"
	"code.uber.internal/infra/kraken/utils/log"
	"code.uber.internal/infra/kraken/utils/memsize"
)

var errAllNameNodesUnavailable = errors.New(
	"exhausted the list of name nodes for the request without success")

func retryable(err error) bool {
	return httputil.IsForbidden(err) || httputil.IsNetworkError(err)
}

// Client is a backend.Client for HDFS.
type Client struct {
	config Config
	pather namepath.Pather
}

// NewClient returns a new Client.
func NewClient(config Config) (*Client, error) {
	config = config.applyDefaults()
	if len(config.NameNodes) == 0 {
		return nil, errors.New("namenodes required")
	}
	pather, err := namepath.New(config.RootDirectory, config.NamePath)
	if err != nil {
		return nil, fmt.Errorf("namepath: %s", err)
	}
	return &Client{config, pather}, nil
}

// Stat returns blob info for name.
func (c *Client) Stat(name string) (*core.BlobInfo, error) {
	path, err := c.pather.BlobPath(name)
	if err != nil {
		return nil, fmt.Errorf("blob path: %s", err)
	}
	fs, err := c.getFileStatus(path)
	if err != nil {
		return nil, err
	}
	return core.NewBlobInfo(fs.Length), nil
}

// Download downloads name into dst.
func (c *Client) Download(name string, dst io.Writer) error {
	path, err := c.pather.BlobPath(name)
	if err != nil {
		return fmt.Errorf("blob path: %s", err)
	}

	v := url.Values{}
	v.Set("op", "OPEN")
	c.setUserName(v)
	c.setBuffersize(v)

	for _, node := range c.config.NameNodes {
		resp, err := httputil.Get(fmt.Sprintf("http://%s/%s?%s", node, path, v.Encode()))
		if err != nil {
			if retryable(err) {
				continue
			}
			if httputil.IsNotFound(err) {
				return backenderrors.ErrBlobNotFound
			}
			return err
		}
		if n, err := io.Copy(dst, resp.Body); err != nil {
			return fmt.Errorf("copy response: %s", err)
		} else if n != resp.ContentLength {
			return fmt.Errorf(
				"transferred bytes %d does not match content length %d", n, resp.ContentLength)
		}
		return nil
	}
	return errAllNameNodesUnavailable
}

type exceededCapError error

// capBuffer is a buffer that returns errors if the buffer exceeds cap.
type capBuffer struct {
	cap int64
	buf *bytes.Buffer
}

func (b *capBuffer) Write(p []byte) (n int, err error) {
	if int64(len(p)+b.buf.Len()) > b.cap {
		return 0, exceededCapError(
			fmt.Errorf("buffer exceeded max capacity %s", memsize.Format(uint64(b.cap))))
	}
	return b.buf.Write(p)
}

type drainSrcError struct {
	err error
}

func (e drainSrcError) Error() string { return fmt.Sprintf("drain src: %s", e.err) }

// Upload uploads src to name.
func (c *Client) Upload(name string, src io.Reader) error {
	path, err := c.pather.BlobPath(name)
	if err != nil {
		return fmt.Errorf("blob path: %s", err)
	}

	// We must be able to replay src in the event that uploading to the data node
	// fails halfway through the upload, thus we attempt to upcast src to an io.Seeker
	// for this purpose. If src is not an io.Seeker, we drain it to an in-memory buffer
	// that can be replayed.
	readSeeker, ok := src.(io.ReadSeeker)
	if !ok {
		var b []byte
		if buf, ok := src.(*bytes.Buffer); ok {
			// Optimization to avoid draining an existing buffer.
			b = buf.Bytes()
		} else {
			log.With("path", path).Info("Draining HDFS upload source into replayable buffer")
			cbuf := &capBuffer{int64(c.config.BufferGuard), new(bytes.Buffer)}
			if _, err := io.Copy(cbuf, src); err != nil {
				return drainSrcError{err}
			}
			b = cbuf.buf.Bytes()
		}
		readSeeker = bytes.NewReader(b)
	}

	v := url.Values{}
	v.Set("op", "CREATE")
	c.setUserName(v)
	c.setBuffersize(v)
	v.Set("overwrite", "true")

	for _, node := range c.config.NameNodes {
		nameresp, err := httputil.Put(
			fmt.Sprintf("http://%s/%s?%s", node, path, v.Encode()),
			httputil.SendRedirect(func(req *http.Request, via []*http.Request) error {
				return http.ErrUseLastResponse
			}),
			httputil.SendAcceptedCodes(http.StatusTemporaryRedirect, http.StatusPermanentRedirect))
		if err != nil {
			if retryable(err) {
				continue
			}
			return err
		}
		defer nameresp.Body.Close()

		// Follow redirect location manually per WebHDFS protocol.
		loc, ok := nameresp.Header["Location"]
		if !ok || len(loc) == 0 {
			return fmt.Errorf("missing location field in response header: %s", nameresp.Header)
		}

		dataresp, err := httputil.Put(
			loc[0],
			httputil.SendBody(readSeeker),
			httputil.SendAcceptedCodes(http.StatusCreated))
		if err != nil {
			if retryable(err) {
				// Reset reader for next retry.
				if _, err := readSeeker.Seek(0, io.SeekStart); err != nil {
					return fmt.Errorf("seek: %s", err)
				}
				continue
			}
			return err
		}
		defer dataresp.Body.Close()

		return nil
	}
	return errAllNameNodesUnavailable
}

var (
	_ignoreRegex = regexp.MustCompile(
		"^.+/repositories/.+/(_layers|_uploads|_manifests/(revisions|tags/.+/index)).*")
	_stopRegex = regexp.MustCompile("^.+/repositories/.+/_manifests$")
)

// List lists names which start with prefix.
func (c *Client) List(prefix string) ([]string, error) {
	root := path.Join(c.pather.BasePath(), prefix)

	var wg sync.WaitGroup
	listJobs := make(chan string, c.config.ListConcurrency)
	errc := make(chan error, c.config.ListConcurrency)

	wg.Add(1)
	listJobs <- root

	go func() {
		wg.Wait()
		close(listJobs)
	}()

	var mu sync.Mutex
	var files []string

L:
	for {
		select {
		case err := <-errc:
			// Stop early on error.
			return nil, err
		case dir, ok := <-listJobs:
			if !ok {
				break L
			}
			go func() {
				defer wg.Done()

				contents, err := c.listFileStatus(dir)
				if err != nil {
					if !httputil.IsNotFound(err) {
						errc <- err
					}
					return
				}

				for _, fs := range contents {
					p := path.Join(dir, fs.PathSuffix)

					// TODO(codyg): This is an ugly hack to avoid walking through non-tags
					// during Docker catalog. Ideally, only tags are located in the repositories
					// directory, however in WBU2 HDFS, there are blobs here as well. At some
					// point, we must migrate the data into a structure which cleanly divides
					// blobs and tags (like we do in S3).
					if _ignoreRegex.MatchString(p) {
						continue
					}

					// TODO(codyg): Another ugly hack to speed up catalog performance by stopping
					// early when we hit tags...
					if _stopRegex.MatchString(p) {
						p = path.Join(p, "tags/dummy/current/link")
						fs.Type = "FILE"
					}

					if fs.Type == "DIRECTORY" {
						wg.Add(1)
						listJobs <- p
						continue
					}

					name, err := c.pather.NameFromBlobPath(p)
					if err != nil {
						log.With("path", p).Errorf("Error converting blob path into name: %s", err)
						continue
					}
					mu.Lock()
					files = append(files, name)
					mu.Unlock()
				}
			}()
		}
	}

	return files, nil
}

func (c *Client) getFileStatus(path string) (fileStatus, error) {
	v := url.Values{}
	v.Set("op", "GETFILESTATUS")
	c.setUserName(v)

	for _, node := range c.config.NameNodes {
		resp, err := httputil.Get(fmt.Sprintf("http://%s/%s?%s", node, path, v.Encode()))
		if err != nil {
			if retryable(err) {
				continue
			}
			if httputil.IsNotFound(err) {
				return fileStatus{}, backenderrors.ErrBlobNotFound
			}
			return fileStatus{}, err
		}
		defer resp.Body.Close()
		var fsr fileStatusResponse
		if err := json.NewDecoder(resp.Body).Decode(&fsr); err != nil {
			return fileStatus{}, fmt.Errorf("decode body: %s", err)
		}
		return fsr.FileStatus, nil
	}
	return fileStatus{}, errAllNameNodesUnavailable
}

func (c *Client) listFileStatus(path string) ([]fileStatus, error) {
	v := url.Values{}
	v.Set("op", "LISTSTATUS")
	c.setUserName(v)

	for _, node := range c.config.NameNodes {
		resp, err := httputil.Get(fmt.Sprintf("http://%s/%s?%s", node, path, v.Encode()))
		if err != nil {
			if retryable(err) {
				continue
			}
			return nil, err
		}
		defer resp.Body.Close()
		var lsr listStatusResponse
		if err := json.NewDecoder(resp.Body).Decode(&lsr); err != nil {
			return nil, fmt.Errorf("decode body: %s", err)
		}
		return lsr.FileStatuses.FileStatus, nil
	}
	return nil, errAllNameNodesUnavailable
}

func (c *Client) setBuffersize(v url.Values) {
	v.Set("buffersize", strconv.FormatInt(c.config.BuffSize, 10))
}

func (c *Client) setUserName(v url.Values) {
	if c.config.UserName != "" {
		v.Set("user.name", c.config.UserName)
	}
}
<commit_msg>Include original HDFS error when all name nodes fail<commit_after>package hdfsbackend

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"path"
	"regexp"
	"strconv"
	"sync"

	"code.uber.internal/infra/kraken/core"
	"code.uber.internal/infra/kraken/lib/backend/backenderrors"
	"code.uber.internal/infra/kraken/lib/backend/namepath"
	"code.uber.internal/infra/kraken/utils/httputil"
	"code.uber.internal/infra/kraken/utils/log"
	"code.uber.internal/infra/kraken/utils/memsize"
)

type allNameNodesFailedError struct {
	err error
}

func (e allNameNodesFailedError) Error() string {
	return fmt.Sprintf("all name nodes failed: %s", e.err)
}

func retryable(err error) bool {
	return httputil.IsForbidden(err) || httputil.IsNetworkError(err)
}

// Client is a backend.Client for HDFS.
type Client struct {
	config Config
	pather namepath.Pather
}

// NewClient returns a new Client.
func NewClient(config Config) (*Client, error) {
	config = config.applyDefaults()
	if len(config.NameNodes) == 0 {
		return nil, errors.New("namenodes required")
	}
	pather, err := namepath.New(config.RootDirectory, config.NamePath)
	if err != nil {
		return nil, fmt.Errorf("namepath: %s", err)
	}
	return &Client{config, pather}, nil
}

// Stat returns blob info for name.
func (c *Client) Stat(name string) (*core.BlobInfo, error) {
	path, err := c.pather.BlobPath(name)
	if err != nil {
		return nil, fmt.Errorf("blob path: %s", err)
	}
	fs, err := c.getFileStatus(path)
	if err != nil {
		return nil, err
	}
	return core.NewBlobInfo(fs.Length), nil
}

// Download downloads name into dst.
func (c *Client) Download(name string, dst io.Writer) error {
	path, err := c.pather.BlobPath(name)
	if err != nil {
		return fmt.Errorf("blob path: %s", err)
	}

	v := url.Values{}
	v.Set("op", "OPEN")
	c.setUserName(v)
	c.setBuffersize(v)

	var resp *http.Response
	var nnErr error
	for _, node := range c.config.NameNodes {
		resp, nnErr = httputil.Get(fmt.Sprintf("http://%s/%s?%s", node, path, v.Encode()))
		if nnErr != nil {
			if retryable(nnErr) {
				continue
			}
			if httputil.IsNotFound(nnErr) {
				return backenderrors.ErrBlobNotFound
			}
			return nnErr
		}
		if n, err := io.Copy(dst, resp.Body); err != nil {
			return fmt.Errorf("copy response: %s", err)
		} else if n != resp.ContentLength {
			return fmt.Errorf(
				"transferred bytes %d does not match content length %d", n, resp.ContentLength)
		}
		return nil
	}
	return allNameNodesFailedError{nnErr}
}

type exceededCapError error

// capBuffer is a buffer that returns errors if the buffer exceeds cap.
type capBuffer struct {
	cap int64
	buf *bytes.Buffer
}

func (b *capBuffer) Write(p []byte) (n int, err error) {
	if int64(len(p)+b.buf.Len()) > b.cap {
		return 0, exceededCapError(
			fmt.Errorf("buffer exceeded max capacity %s", memsize.Format(uint64(b.cap))))
	}
	return b.buf.Write(p)
}

type drainSrcError struct {
	err error
}

func (e drainSrcError) Error() string { return fmt.Sprintf("drain src: %s", e.err) }

// Upload uploads src to name.
func (c *Client) Upload(name string, src io.Reader) error {
	path, err := c.pather.BlobPath(name)
	if err != nil {
		return fmt.Errorf("blob path: %s", err)
	}

	// We must be able to replay src in the event that uploading to the data node
	// fails halfway through the upload, thus we attempt to upcast src to an io.Seeker
	// for this purpose. If src is not an io.Seeker, we drain it to an in-memory buffer
	// that can be replayed.
	readSeeker, ok := src.(io.ReadSeeker)
	if !ok {
		var b []byte
		if buf, ok := src.(*bytes.Buffer); ok {
			// Optimization to avoid draining an existing buffer.
			b = buf.Bytes()
		} else {
			log.With("path", path).Info("Draining HDFS upload source into replayable buffer")
			cbuf := &capBuffer{int64(c.config.BufferGuard), new(bytes.Buffer)}
			if _, err := io.Copy(cbuf, src); err != nil {
				return drainSrcError{err}
			}
			b = cbuf.buf.Bytes()
		}
		readSeeker = bytes.NewReader(b)
	}

	v := url.Values{}
	v.Set("op", "CREATE")
	c.setUserName(v)
	c.setBuffersize(v)
	v.Set("overwrite", "true")

	var nameresp, dataresp *http.Response
	var nnErr error
	for _, node := range c.config.NameNodes {
		nameresp, nnErr = httputil.Put(
			fmt.Sprintf("http://%s/%s?%s", node, path, v.Encode()),
			httputil.SendRedirect(func(req *http.Request, via []*http.Request) error {
				return http.ErrUseLastResponse
			}),
			httputil.SendAcceptedCodes(http.StatusTemporaryRedirect, http.StatusPermanentRedirect))
		if nnErr != nil {
			if retryable(nnErr) {
				continue
			}
			return nnErr
		}
		defer nameresp.Body.Close()

		// Follow redirect location manually per WebHDFS protocol.
		loc, ok := nameresp.Header["Location"]
		if !ok || len(loc) == 0 {
			return fmt.Errorf("missing location field in response header: %s", nameresp.Header)
		}

		dataresp, nnErr = httputil.Put(
			loc[0],
			httputil.SendBody(readSeeker),
			httputil.SendAcceptedCodes(http.StatusCreated))
		if nnErr != nil {
			if retryable(nnErr) {
				// Reset reader for next retry.
				if _, err := readSeeker.Seek(0, io.SeekStart); err != nil {
					return fmt.Errorf("seek: %s", err)
				}
				continue
			}
			return nnErr
		}
		defer dataresp.Body.Close()

		return nil
	}
	return allNameNodesFailedError{nnErr}
}

var (
	_ignoreRegex = regexp.MustCompile(
		"^.+/repositories/.+/(_layers|_uploads|_manifests/(revisions|tags/.+/index)).*")
	_stopRegex = regexp.MustCompile("^.+/repositories/.+/_manifests$")
)

// List lists names which start with prefix.
func (c *Client) List(prefix string) ([]string, error) {
	root := path.Join(c.pather.BasePath(), prefix)

	var wg sync.WaitGroup
	listJobs := make(chan string, c.config.ListConcurrency)
	errc := make(chan error, c.config.ListConcurrency)

	wg.Add(1)
	listJobs <- root

	go func() {
		wg.Wait()
		close(listJobs)
	}()

	var mu sync.Mutex
	var files []string

L:
	for {
		select {
		case err := <-errc:
			// Stop early on error.
			return nil, err
		case dir, ok := <-listJobs:
			if !ok {
				break L
			}
			go func() {
				defer wg.Done()

				contents, err := c.listFileStatus(dir)
				if err != nil {
					if !httputil.IsNotFound(err) {
						errc <- err
					}
					return
				}

				for _, fs := range contents {
					p := path.Join(dir, fs.PathSuffix)

					// TODO(codyg): This is an ugly hack to avoid walking through non-tags
					// during Docker catalog. Ideally, only tags are located in the repositories
					// directory, however in WBU2 HDFS, there are blobs here as well. At some
					// point, we must migrate the data into a structure which cleanly divides
					// blobs and tags (like we do in S3).
					if _ignoreRegex.MatchString(p) {
						continue
					}

					// TODO(codyg): Another ugly hack to speed up catalog performance by stopping
					// early when we hit tags...
					if _stopRegex.MatchString(p) {
						p = path.Join(p, "tags/dummy/current/link")
						fs.Type = "FILE"
					}

					if fs.Type == "DIRECTORY" {
						wg.Add(1)
						listJobs <- p
						continue
					}

					name, err := c.pather.NameFromBlobPath(p)
					if err != nil {
						log.With("path", p).Errorf("Error converting blob path into name: %s", err)
						continue
					}
					mu.Lock()
					files = append(files, name)
					mu.Unlock()
				}
			}()
		}
	}

	return files, nil
}

func (c *Client) getFileStatus(path string) (fileStatus, error) {
	v := url.Values{}
	v.Set("op", "GETFILESTATUS")
	c.setUserName(v)

	var resp *http.Response
	var nnErr error
	for _, node := range c.config.NameNodes {
		resp, nnErr = httputil.Get(fmt.Sprintf("http://%s/%s?%s", node, path, v.Encode()))
		if nnErr != nil {
			if retryable(nnErr) {
				continue
			}
			if httputil.IsNotFound(nnErr) {
				return fileStatus{}, backenderrors.ErrBlobNotFound
			}
			return fileStatus{}, nnErr
		}
		defer resp.Body.Close()
		var fsr fileStatusResponse
		if err := json.NewDecoder(resp.Body).Decode(&fsr); err != nil {
			return fileStatus{}, fmt.Errorf("decode body: %s", err)
		}
		return fsr.FileStatus, nil
	}
	return fileStatus{}, allNameNodesFailedError{nnErr}
}

func (c *Client) listFileStatus(path string) ([]fileStatus, error) {
	v := url.Values{}
	v.Set("op", "LISTSTATUS")
	c.setUserName(v)

	var resp *http.Response
	var nnErr error
	for _, node := range c.config.NameNodes {
		resp, nnErr = httputil.Get(fmt.Sprintf("http://%s/%s?%s", node, path, v.Encode()))
		if nnErr != nil {
			if retryable(nnErr) {
				continue
			}
			return nil, nnErr
		}
		defer resp.Body.Close()
		var lsr listStatusResponse
		if err := json.NewDecoder(resp.Body).Decode(&lsr); err != nil {
			return nil, fmt.Errorf("decode body: %s", err)
		}
		return lsr.FileStatuses.FileStatus, nil
	}
	return nil, allNameNodesFailedError{nnErr}
}

func (c *Client) setBuffersize(v url.Values) {
	v.Set("buffersize", strconv.FormatInt(c.config.BuffSize, 10))
}

func (c *Client) setUserName(v url.Values) {
	if c.config.UserName != "" {
		v.Set("user.name", c.config.UserName)
	}
}
<|endoftext|>


<commit_before>package ui

import (
	"fmt"
	"image"
	"image/color"
	"os"
	"time"

	"github.com/bugsnag/bugsnag-go"
	"github.com/ninjasphere/gestic-tools/go-gestic-sdk"
	"github.com/ninjasphere/go-ninja/api"
	"github.com/ninjasphere/go-ninja/config"
	"github.com/ninjasphere/go-ninja/model"
	owm "github.com/ninjasphere/openweathermap"
	"github.com/ninjasphere/sphere-go-led-controller/fonts/O4b03b"
	"github.com/ninjasphere/sphere-go-led-controller/fonts/clock"
	"github.com/ninjasphere/sphere-go-led-controller/util"
)

var enableWeatherPane = config.MustBool("led.weather.enabled")
var weatherUpdateInterval = config.MustDuration("led.weather.updateInterval")
var temperatureDisplayTime = config.Duration(time.Second*5, "led.weather.temperatureDisplayTime")

var globalSite *model.Site
var timezone *time.Location

type WeatherPane struct {
	siteModel   *ninja.ServiceClient
	site        *model.Site
	getWeather  *time.Timer
	tempTimeout *time.Timer
	temperature bool
	weather     *owm.ForecastWeatherData
	image       util.Image
}

func NewWeatherPane(conn *ninja.Connection) *WeatherPane {

	pane := &WeatherPane{
		siteModel: conn.GetServiceClient("$home/services/SiteModel"),
		image:     util.LoadImage(util.ResolveImagePath("weather/loading.gif")),
	}

	pane.tempTimeout = time.AfterFunc(0, func() {
		pane.temperature = false
	})

	if !enableWeatherPane {
		return pane
	}

	var err error
	pane.weather, err = owm.NewForecast("C")
	if err != nil {
		log.Warningf("Failed to load weather api:", err)
		enableWeatherPane = false
	} else {
		go pane.GetWeather()
	}

	return pane
}

func (p *WeatherPane) GetWeather() {

	enableWeatherPane = false

	for {
		site := &model.Site{}
		err := p.siteModel.Call("fetch", config.MustString("siteId"), site, time.Second*5)

		if err == nil && (site.Longitude != nil || site.Latitude != nil) {
			p.site = site
			globalSite = site

			if site.TimeZoneID != nil {
				if timezone, err = time.LoadLocation(*site.TimeZoneID); err != nil {
					log.Warningf("error while setting timezone (%s): %s", *site.TimeZoneID, err)
					timezone, _ = time.LoadLocation("Local")
				}
			}
			break
		}

		log.Infof("Failed to get site, or site has no location.")

		time.Sleep(time.Second * 2)
	}

	for {

		p.weather.DailyByCoordinates(
			&owm.Coordinates{
				Longitude: *p.site.Longitude,
				Latitude:  *p.site.Latitude,
			},
			1,
		)

		if len(p.weather.List) > 0 {

			filename := util.ResolveImagePath("weather/" + p.weather.List[0].Weather[0].Icon + ".png")

			if _, err := os.Stat(filename); os.IsNotExist(err) {
				enableWeatherPane = false
				fmt.Printf("Couldn't load image for weather: %s", filename)
				bugsnag.Notify(fmt.Errorf("Unknown weather icon: %s", filename), p.weather)
			} else {
				p.image = util.LoadImage(filename)
				enableWeatherPane = true
			}
		}

		time.Sleep(weatherUpdateInterval)

	}

}

func (p *WeatherPane) IsEnabled() bool {
	return enableWeatherPane && p.weather.Unit != ""
}

func (p *WeatherPane) Gesture(gesture *gestic.GestureMessage) {
	if gesture.Tap.Active() {
		log.Infof("Weather tap!")

		p.temperature = true
		p.tempTimeout.Reset(temperatureDisplayTime)
	}
}

func (p *WeatherPane) Render() (*image.RGBA, error) {
	if p.temperature {
		img := image.NewRGBA(image.Rect(0, 0, 16, 16))

		drawText := func(text string, col color.RGBA, top int) {
			width := clock.Font.DrawString(img, 0, 8, text, color.Black)
			start := int(16 - width - 2)

			//spew.Dump("text", text, "width", width, "start", start)

			O4b03b.Font.DrawString(img, start, top, text, col)
		}

		if p.weather.City.Country == "US" || p.weather.City.Country == "United States of America" {
			drawText(fmt.Sprintf("%dF", int(p.weather.List[0].Temp.Max*(9.0/5)-459.67)), color.RGBA{253, 151, 32, 255}, 1)
			drawText(fmt.Sprintf("%dF", int(p.weather.List[0].Temp.Min*(9.0/5)-459.67)), color.RGBA{69, 175, 249, 255}, 8)
		} else {
			drawText(fmt.Sprintf("%dC", int(p.weather.List[0].Temp.Max-273.15)), color.RGBA{253, 151, 32, 255}, 1)
			drawText(fmt.Sprintf("%dC", int(p.weather.List[0].Temp.Min-273.15)), color.RGBA{69, 175, 249, 255}, 8)
		}

		return img, nil
	} else {
		return p.image.GetNextFrame(), nil
	}
}

func (p *WeatherPane) IsDirty() bool {
	return true
}
<commit_msg>Fix: weather text alignment<commit_after>package ui

import (
	"fmt"
	"image"
	"image/color"
	"os"
	"time"

	"github.com/bugsnag/bugsnag-go"
	"github.com/ninjasphere/gestic-tools/go-gestic-sdk"
	"github.com/ninjasphere/go-ninja/api"
	"github.com/ninjasphere/go-ninja/config"
	"github.com/ninjasphere/go-ninja/model"
	owm "github.com/ninjasphere/openweathermap"
	"github.com/ninjasphere/sphere-go-led-controller/fonts/O4b03b"
	"github.com/ninjasphere/sphere-go-led-controller/fonts/clock"
	"github.com/ninjasphere/sphere-go-led-controller/util"
)

var enableWeatherPane = config.MustBool("led.weather.enabled")
var weatherUpdateInterval = config.MustDuration("led.weather.updateInterval")
var temperatureDisplayTime = config.Duration(time.Second*5, "led.weather.temperatureDisplayTime")

var globalSite *model.Site
var timezone *time.Location

type WeatherPane struct {
	siteModel   *ninja.ServiceClient
	site        *model.Site
	getWeather  *time.Timer
	tempTimeout *time.Timer
	temperature bool
	weather     *owm.ForecastWeatherData
	image       util.Image
}

func NewWeatherPane(conn *ninja.Connection) *WeatherPane {

	pane := &WeatherPane{
		siteModel: conn.GetServiceClient("$home/services/SiteModel"),
		image:     util.LoadImage(util.ResolveImagePath("weather/loading.gif")),
	}

	pane.tempTimeout = time.AfterFunc(0, func() {
		pane.temperature = false
	})

	if !enableWeatherPane {
		return pane
	}

	var err error
	pane.weather, err = owm.NewForecast("C")
	if err != nil {
		log.Warningf("Failed to load weather api:", err)
		enableWeatherPane = false
	} else {
		go pane.GetWeather()
	}

	return pane
}

func (p *WeatherPane) GetWeather() {

	enableWeatherPane = false

	for {
		site := &model.Site{}
		err := p.siteModel.Call("fetch", config.MustString("siteId"), site, time.Second*5)

		if err == nil && (site.Longitude != nil || site.Latitude != nil) {
			p.site = site
			globalSite = site

			if site.TimeZoneID != nil {
				if timezone, err = time.LoadLocation(*site.TimeZoneID); err != nil {
					log.Warningf("error while setting timezone (%s): %s", *site.TimeZoneID, err)
					timezone, _ = time.LoadLocation("Local")
				}
			}
			break
		}

		log.Infof("Failed to get site, or site has no location.")

		time.Sleep(time.Second * 2)
	}

	for {

		p.weather.DailyByCoordinates(
			&owm.Coordinates{
				Longitude: *p.site.Longitude,
				Latitude:  *p.site.Latitude,
			},
			1,
		)

		if len(p.weather.List) > 0 {

			filename := util.ResolveImagePath("weather/" + p.weather.List[0].Weather[0].Icon + ".png")

			if _, err := os.Stat(filename); os.IsNotExist(err) {
				enableWeatherPane = false
				fmt.Printf("Couldn't load image for weather: %s", filename)
				bugsnag.Notify(fmt.Errorf("Unknown weather icon: %s", filename), p.weather)
			} else {
				p.image = util.LoadImage(filename)
				enableWeatherPane = true
			}
		}

		time.Sleep(weatherUpdateInterval)

	}

}

func (p *WeatherPane) IsEnabled() bool {
	return enableWeatherPane && p.weather.Unit != ""
}

func (p *WeatherPane) Gesture(gesture *gestic.GestureMessage) {
	if gesture.Tap.Active() {
		log.Infof("Weather tap!")

		p.temperature = true
		p.tempTimeout.Reset(temperatureDisplayTime)
	}
}

func (p *WeatherPane) Render() (*image.RGBA, error) {
	if p.temperature {
		img := image.NewRGBA(image.Rect(0, 0, 16, 16))

		drawText := func(text string, col color.RGBA, top int) {
			width := O4b03b.Font.DrawString(img, 0, 8, text, color.Black)
			start := int(16 - width - 2)

			//spew.Dump("text", text, "width", width, "start", start)

			O4b03b.Font.DrawString(img, start, top, text, col)
		}

		if p.weather.City.Country == "US" || p.weather.City.Country == "United States of America" {
			drawText(fmt.Sprintf("%dF", int(p.weather.List[0].Temp.Max*(9.0/5)-459.67)), color.RGBA{253, 151, 32, 255}, 1)
			drawText(fmt.Sprintf("%dF", int(p.weather.List[0].Temp.Min*(9.0/5)-459.67)), color.RGBA{69, 175, 249, 255}, 8)
		} else {
			drawText(fmt.Sprintf("%dC", int(p.weather.List[0].Temp.Max-273.15)), color.RGBA{253, 151, 32, 255}, 1)
			drawText(fmt.Sprintf("%dC", int(p.weather.List[0].Temp.Min-273.15)), color.RGBA{69, 175, 249, 255}, 8)
		}

		return img, nil
	} else {
		return p.image.GetNextFrame(), nil
	}
}

func (p *WeatherPane) IsDirty() bool {
	return true
}
<|endoftext|>


<commit_before>// Copyright 2013 Google Inc.  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 usb

// #include <libusb-1.0/libusb.h>
import "C"

type Descriptor struct {
	// Bus information
	Bus     uint8 // The bus on which the device was detected
	Address uint8 // The address of the device on the bus

	// Version information
	Spec   BCD // USB Specification Release Number
	Device BCD // The device version

	// Product information
	Vendor  ID // The Vendor identifer
	Product ID // The Product identifier

	// Protocol information
	Class    uint8 // The class of this device
	SubClass uint8 // The sub-class (within the class) of this device
	Protocol uint8 // The protocol (within the sub-class) of this device

	// Configuration information
	Configs []ConfigInfo
}

func newDescriptor(dev *C.libusb_device) (*Descriptor, error) {
	var desc C.struct_libusb_device_descriptor
	if errno := C.libusb_get_device_descriptor(dev, &desc); errno < 0 {
		return nil, usbError(errno)
	}

	// Enumerate configurations
	var cfgs []ConfigInfo
	for i := 0; i < int(desc.bNumConfigurations); i++ {
		var cfg *C.struct_libusb_config_descriptor
		if errno := C.libusb_get_config_descriptor(dev, C.uint8_t(i), &cfg); errno < 0 {
			return nil, usbError(errno)
		}
		cfgs = append(cfgs, newConfig(dev, cfg))
		C.libusb_free_config_descriptor(cfg)
	}

	return &Descriptor{
		Bus:      uint8(C.libusb_get_bus_number(dev)),
		Address:  uint8(C.libusb_get_device_address(dev)),
		Spec:     BCD(desc.bcdUSB),
		Device:   BCD(desc.bcdDevice),
		Vendor:   ID(desc.idVendor),
		Product:  ID(desc.idProduct),
		Class:    uint8(desc.bDeviceClass),
		SubClass: uint8(desc.bDeviceSubClass),
		Protocol: uint8(desc.bDeviceProtocol),
		Configs:  cfgs,
	}, nil
}
<commit_msg>Add Open method to Descriptor.<commit_after>// Copyright 2013 Google Inc.  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 usb

// #include <libusb-1.0/libusb.h>
import "C"

type Descriptor struct {
	// Bus information
	Bus     uint8 // The bus on which the device was detected
	Address uint8 // The address of the device on the bus

	// Version information
	Spec   BCD // USB Specification Release Number
	Device BCD // The device version

	// Product information
	Vendor  ID // The Vendor identifer
	Product ID // The Product identifier

	// Protocol information
	Class    uint8 // The class of this device
	SubClass uint8 // The sub-class (within the class) of this device
	Protocol uint8 // The protocol (within the sub-class) of this device

	// Configuration information
	Configs []ConfigInfo

	// libusb_device
	dev *C.libusb_device
}

func newDescriptor(dev *C.libusb_device) (*Descriptor, error) {
	var desc C.struct_libusb_device_descriptor
	if errno := C.libusb_get_device_descriptor(dev, &desc); errno < 0 {
		return nil, usbError(errno)
	}

	// Enumerate configurations
	var cfgs []ConfigInfo
	for i := 0; i < int(desc.bNumConfigurations); i++ {
		var cfg *C.struct_libusb_config_descriptor
		if errno := C.libusb_get_config_descriptor(dev, C.uint8_t(i), &cfg); errno < 0 {
			return nil, usbError(errno)
		}
		cfgs = append(cfgs, newConfig(dev, cfg))
		C.libusb_free_config_descriptor(cfg)
	}

	return &Descriptor{
		Bus:      uint8(C.libusb_get_bus_number(dev)),
		Address:  uint8(C.libusb_get_device_address(dev)),
		Spec:     BCD(desc.bcdUSB),
		Device:   BCD(desc.bcdDevice),
		Vendor:   ID(desc.idVendor),
		Product:  ID(desc.idProduct),
		Class:    uint8(desc.bDeviceClass),
		SubClass: uint8(desc.bDeviceSubClass),
		Protocol: uint8(desc.bDeviceProtocol),
		Configs:  cfgs,
		dev:      dev,
	}, nil
}

// Opens the device and returns a new Device instance
func (d *Descriptor) Open() (*Device, error) {
	var handle *C.libusb_device_handle
	if errno := C.libusb_open(d.dev, &handle); errno != 0 {
		return nil, usbError(errno)
	}
	return newDevice(handle, d), nil
}
<|endoftext|>


<commit_before>package util

import (
	"crypto/md5"
	"fmt"
	"golang.org/x/net/context"
	"io"
	"testing"
	"testing/quick"
	capnp "zenhack.net/go/sandstorm/capnp/util"
)

type writeNoopCloser struct {
	io.Writer
}

func (w writeNoopCloser) Close() error {
	return nil
}

// compute the md5 sum of p both directly and by writing it through
// the bytestream interface, returns true if the results are the same.
func checkMd5(p []byte) bool {
	// TODO: would be nice if we could use t.Logf in here, but we
	// need to restructure the control flow a bit to get access to it.
	if p == nil {
		// We don't want to deal with this
		return true
	}
	hash := md5.New()
	hash.Write(p)
	directDigest := fmt.Sprintf("%x", hash.Sum([]byte{}))

	hash.Reset()
	fmt.Printf("Direct digest: %q\n", directDigest)

	bsServer := &WriteCloserByteStream{writeNoopCloser{hash}}
	bsClient := ByteStreamWriteCloser{
		Ctx: context.Background(),
		Obj: capnp.ByteStream_ServerToClient(bsServer),
	}
	n, err := bsClient.Write(p)
	if err != nil || n != len(p) {
		return false
	}
	_, err = bsClient.Obj.Done(
		bsClient.Ctx,
		func(p capnp.ByteStream_done_Params) error {
			return nil
		}).Struct()
	if err != nil {
		return false
	}

	rpcDigest := fmt.Sprintf("%x", hash.Sum([]byte{}))
	fmt.Printf("RPC digest: %q\n", rpcDigest)

	return rpcDigest == directDigest
}

func TestMd5(t *testing.T) {
	err := quick.Check(checkMd5, nil)
	if err != nil {
		t.Fatal(err)
	}
}
<commit_msg>Slight cleanup in tests<commit_after>package util

import (
	"crypto/md5"
	"fmt"
	"golang.org/x/net/context"
	"io"
	"testing"
	"testing/quick"
	capnp "zenhack.net/go/sandstorm/capnp/util"
)

type writeNoopCloser struct {
	io.Writer
}

func (w writeNoopCloser) Close() error {
	return nil
}

// compute the md5 sum of p both directly and by writing it through
// the bytestream interface, returns true if the results are the same.
// We take a *testing.T for the logging facilites, but it is never
// flagged as failing.
func checkMd5(t *testing.T, p []byte) bool {
	if p == nil {
		// We don't want to deal with this
		return true
	}
	hash := md5.New()
	hash.Write(p)
	directDigest := fmt.Sprintf("%x", hash.Sum([]byte{}))

	hash.Reset()
	t.Logf("Direct digest: %q\n", directDigest)

	bsServer := &WriteCloserByteStream{writeNoopCloser{hash}}
	bsClient := ByteStreamWriteCloser{
		Ctx: context.Background(),
		Obj: capnp.ByteStream_ServerToClient(bsServer),
	}
	n, err := bsClient.Write(p)
	if err != nil || n != len(p) {
		t.Logf("Error: %v", err)
		return false
	}
	_, err = bsClient.Obj.Done(
		bsClient.Ctx,
		func(p capnp.ByteStream_done_Params) error {
			return nil
		}).Struct()
	if err != nil {
		t.Logf("Error: %v", err)
		return false
	}

	rpcDigest := fmt.Sprintf("%x", hash.Sum([]byte{}))
	t.Logf("RPC digest: %q\n", rpcDigest)

	return rpcDigest == directDigest
}

func TestMd5(t *testing.T) {
	err := quick.Check(func(p []byte) bool {
		return checkMd5(t, p)
	}, nil)
	if err != nil {
		t.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package students

import (
	"fmt"
	"time"

	"appengine"
	"appengine/datastore"

	"github.com/decitrig/innerhearth/auth"
	"github.com/decitrig/innerhearth/classes"
)

var (
	ErrStudentNotFound   = fmt.Errorf("students: student not found")
	ErrClassIsFull       = fmt.Errorf("students: class is full")
	ErrAlreadyRegistered = fmt.Errorf("students: already registered for class")
)

// A Student is a single registration in a single class. A UserAccount
// may have multiple Students associated with it.
type Student struct {
	AccountID string
	auth.UserInfo

	ClassID   int64
	ClassType classes.Type

	Date   time.Time
	DropIn bool
}

// New creates a new session Student registration for a user in a class.
func New(user *auth.UserAccount, class *classes.Class) *Student {
	return &Student{
		AccountID: user.AccountID,
		UserInfo:  user.UserInfo,
		ClassID:   class.ID,
		ClassType: classes.Regular,
	}
}

// NewDropIn creates a new drop-in Student registration for a user in
// a class on a specific date.
func NewDropIn(user *auth.UserAccount, class *classes.Class, date time.Time) *Student {
	return &Student{
		AccountID: user.AccountID,
		UserInfo:  user.UserInfo,
		ClassID:   class.ID,
		ClassType: classes.Regular,
		DropIn:    true,
		Date:      date,
	}
}

// WithID returns a list of all Students with an account ID.
func WithID(c appengine.Context, id string) ([]*Student, error) {
	q := datastore.NewQuery("Student").
		Filter("AccountID =", id)
	students := []*Student{}
	_, err := q.GetAll(c, &students)
	if err != nil {
		return nil, err
	}
	return students, nil
}

// WithEmail returns a list of all Students with an email.
func WithEmail(c appengine.Context, email string) ([]*Student, error) {
	q := datastore.NewQuery("Student").
		Filter("Email =", email)
	students := []*Student{}
	_, err := q.GetAll(c, &students)
	if err != nil {
		return nil, err
	}
	return students, nil
}

// In returns a list of all Students registered for a class. The list
// will include only those drop-in Students whose date is not in the
// past.
func In(c appengine.Context, class *classes.Class, now time.Time) ([]*Student, error) {
	q := datastore.NewQuery("Student").
		Ancestor(class.Key(c))
	students := []*Student{}
	_, err := q.GetAll(c, &students)
	if err != nil {
		return nil, err
	}
	filtered := []*Student{}
	for _, student := range students {
		if student.DropIn && student.Date.Before(now) {
			continue
		}
		filtered = append(filtered, student)
	}
	return filtered, nil
}

// Add attempts to write a new Student entity; it will not overwrite
// any existing Students. Returns ErrClassFull if the class is full as
// of the given date.
func (s *Student) Add(c appengine.Context, asOf time.Time) error {
	key := s.key(c)
	var txnErr error
	for i := 0; i < 25; i++ {
		txnErr = datastore.RunInTransaction(c, func(c appengine.Context) error {
			old := &Student{}
			switch err := datastore.Get(c, key, old); err {
			case datastore.ErrNoSuchEntity:
				break
			case nil:
				if old.DropIn && old.Date.Before(asOf) {
					// Old registration is an expired drop-in. Allow re-registering.
					break
				}
				// Old registration is still active; drop.
				c.Warningf("Attempted duplicate registration of %q in %d", s.AccountID, s.ClassID)
				return nil
			default:
				return fmt.Errorf("students: failed to look up existing student: %s", err)
			}
			class, err := classes.ClassWithID(c, s.ClassID)
			if err != nil {
				return err
			}
			in, err := In(c, class, asOf)
			if err != nil {
				return fmt.Errorf("students: failed to look up registered students")
			}
			if int32(len(in)) >= class.Capacity {
				return ErrClassIsFull
			}
			if err := class.Update(c); err != nil {
				return fmt.Errorf("students: failed to update class: %s", err)
			}
			if _, err := datastore.Put(c, key, s); err != nil {
				return fmt.Errorf("students: failed to write student: %s", err)
			}
			return nil
		}, nil)
		if txnErr != datastore.ErrConcurrentTransaction {
			break
		}
	}
	switch txnErr {
	case nil:
		return nil
	case datastore.ErrConcurrentTransaction:
		return fmt.Errorf("students: too many concurrent updates to class %d", s.ClassID)
	default:
		return txnErr
	}
}

func (s *Student) key(c appengine.Context) *datastore.Key {
	return datastore.NewKey(c, "Student", s.AccountID, 0, classes.NewClassKey(c, s.ClassID))
}

// ByName sorts Students in alphabetial order by first and then last name.
type ByName []*Student

func (l ByName) Len() int      { return len(l) }
func (l ByName) Swap(i, j int) { l[i], l[j] = l[j], l[i] }
func (l ByName) Less(i, j int) bool {
	switch a, b := l[i], l[j]; {
	case a.FirstName != b.FirstName:
		return a.FirstName < b.FirstName
	case a.LastName != b.LastName:
		return a.LastName < b.LastName
	default:
		return false
	}
}
<commit_msg>Clarified semantics of "active registrations."<commit_after>package students

import (
	"fmt"
	"time"

	"appengine"
	"appengine/datastore"

	"github.com/decitrig/innerhearth/auth"
	"github.com/decitrig/innerhearth/classes"
)

var (
	ErrStudentNotFound = fmt.Errorf("students: student not found")
	ErrClassIsFull     = fmt.Errorf("students: class is full")
)

// A Student is a single registration in a single class. A UserAccount
// may have multiple Students associated with it.
type Student struct {
	AccountID string
	auth.UserInfo

	ClassID   int64
	ClassType classes.Type

	Date   time.Time
	DropIn bool
}

// New creates a new session Student registration for a user in a class.
func New(user *auth.UserAccount, class *classes.Class) *Student {
	return &Student{
		AccountID: user.AccountID,
		UserInfo:  user.UserInfo,
		ClassID:   class.ID,
		ClassType: classes.Regular,
	}
}

// NewDropIn creates a new drop-in Student registration for a user in
// a class on a specific date.
func NewDropIn(user *auth.UserAccount, class *classes.Class, date time.Time) *Student {
	return &Student{
		AccountID: user.AccountID,
		UserInfo:  user.UserInfo,
		ClassID:   class.ID,
		ClassType: classes.Regular,
		DropIn:    true,
		Date:      date,
	}
}

// WithID returns a list of all Students with an account ID.
func WithID(c appengine.Context, id string) ([]*Student, error) {
	q := datastore.NewQuery("Student").
		Filter("AccountID =", id)
	students := []*Student{}
	_, err := q.GetAll(c, &students)
	if err != nil {
		return nil, err
	}
	return students, nil
}

// WithEmail returns a list of all Students with an email.
func WithEmail(c appengine.Context, email string) ([]*Student, error) {
	q := datastore.NewQuery("Student").
		Filter("Email =", email)
	students := []*Student{}
	_, err := q.GetAll(c, &students)
	if err != nil {
		return nil, err
	}
	return students, nil
}

// In returns a list of all Students registered for a class. The list
// will include only those drop-in Students whose date is not in the
// past.
func In(c appengine.Context, class *classes.Class, now time.Time) ([]*Student, error) {
	q := datastore.NewQuery("Student").
		Ancestor(class.Key(c))
	students := []*Student{}
	_, err := q.GetAll(c, &students)
	if err != nil {
		return nil, err
	}
	filtered := []*Student{}
	for _, student := range students {
		if student.DropIn && student.Date.Before(now) {
			continue
		}
		filtered = append(filtered, student)
	}
	return filtered, nil
}

// Add attempts to write a new Student entity; it will not overwrite
// any existing Students. Returns ErrClassFull if the class is full as
// of the given date. The number of students "currently registered"
// for a class is the number of session-registered students plus any
// future drop ins. This may be smaller than the number of students
// registered on a particular day, and so may prevent drop-ins which
// may otherwise have succeeded. In other words, a student can only
// drop in if we can prove that there is room for them to register for
// the rest of the session.
func (s *Student) Add(c appengine.Context, asOf time.Time) error {
	key := s.key(c)
	var txnErr error
	for i := 0; i < 25; i++ {
		txnErr = datastore.RunInTransaction(c, func(c appengine.Context) error {
			old := &Student{}
			switch err := datastore.Get(c, key, old); err {
			case datastore.ErrNoSuchEntity:
				break
			case nil:
				if old.DropIn && old.Date.Before(asOf) {
					// Old registration is an expired drop-in. Allow re-registering.
					break
				}
				// Old registration is still active; do nothing.
				c.Warningf("Attempted duplicate registration of %q in %d", s.AccountID, s.ClassID)
				return nil
			default:
				return fmt.Errorf("students: failed to look up existing student: %s", err)
			}
			class, err := classes.ClassWithID(c, s.ClassID)
			if err != nil {
				return err
			}
			in, err := In(c, class, asOf)
			if err != nil {
				return fmt.Errorf("students: failed to look up registered students")
			}
			if int32(len(in)) >= class.Capacity {
				return ErrClassIsFull
			}
			if err := class.Update(c); err != nil {
				return fmt.Errorf("students: failed to update class: %s", err)
			}
			if _, err := datastore.Put(c, key, s); err != nil {
				return fmt.Errorf("students: failed to write student: %s", err)
			}
			return nil
		}, nil)
		if txnErr != datastore.ErrConcurrentTransaction {
			break
		}
	}
	switch txnErr {
	case nil:
		return nil
	case datastore.ErrConcurrentTransaction:
		return fmt.Errorf("students: too many concurrent updates to class %d", s.ClassID)
	default:
		return txnErr
	}
}

func (s *Student) key(c appengine.Context) *datastore.Key {
	return datastore.NewKey(c, "Student", s.AccountID, 0, classes.NewClassKey(c, s.ClassID))
}

// ByName sorts Students in alphabetial order by first and then last name.
type ByName []*Student

func (l ByName) Len() int      { return len(l) }
func (l ByName) Swap(i, j int) { l[i], l[j] = l[j], l[i] }
func (l ByName) Less(i, j int) bool {
	switch a, b := l[i], l[j]; {
	case a.FirstName != b.FirstName:
		return a.FirstName < b.FirstName
	case a.LastName != b.LastName:
		return a.LastName < b.LastName
	default:
		return false
	}
}
<|endoftext|>


<commit_before>package metadata

import (
	"golang.org/x/net/context"
)

type metaKey struct{}

type Metadata map[string]string

func FromContext(ctx context.Context) (Metadata, bool) {
	md, ok := ctx.Value(metaKey{}).(Metadata)
	return md, ok
}

func NewContext(ctx context.Context, md Metadata) context.Context {
	if emd, ok := ctx.Value(metaKey{}).(Metadata); ok {
		for k, v := range emd {
			if _, ok := md[k]; !ok {
				md[k] = v
			}
		}
	}
	return context.WithValue(ctx, metaKey{}, md)
}
<commit_msg>Add metadata comment<commit_after>package metadata

import (
	"golang.org/x/net/context"
)

type metaKey struct{}

// Metadata is our way of representing request headers internally.
// They're used at the RPC level and translate back and forth
// from Transport headers.
type Metadata map[string]string

func FromContext(ctx context.Context) (Metadata, bool) {
	md, ok := ctx.Value(metaKey{}).(Metadata)
	return md, ok
}

func NewContext(ctx context.Context, md Metadata) context.Context {
	if emd, ok := ctx.Value(metaKey{}).(Metadata); ok {
		for k, v := range emd {
			if _, ok := md[k]; !ok {
				md[k] = v
			}
		}
	}
	return context.WithValue(ctx, metaKey{}, md)
}
<|endoftext|>


<commit_before>// Copyright 2017 Thibault Chataigner <thibault.chataigner@gmail.com>
// 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 utils

import (
	"errors"
	"strings"
	"text/template"
)

func replace(input interface{}, from string, to string) (string, error) {
	if input == nil {
		return "", errors.New("input does not exist, cannot replace")
	}
	return strings.Replace(input.(string), from, to, -1), nil
}

func split(input interface{}, delimiter string) ([]string, error) {
	return strings.Split(input.(string), delimiter), nil
}

func escape(input interface{}) string {
	return Escape(input.(string))
}

// TmplFuncMap expose custom go template functions
var TmplFuncMap = template.FuncMap{
	"replace": replace,
	"split":   split,
	"escape":  escape,
}
<commit_msg>Provide a `isSet` template function for field existence<commit_after>// Copyright 2017 Thibault Chataigner <thibault.chataigner@gmail.com>
// 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 utils

import (
	"errors"
	"reflect"
	"strings"
	"text/template"
)

func replace(input interface{}, from string, to string) (string, error) {
	if input == nil {
		return "", errors.New("input does not exist, cannot replace")
	}
	return strings.Replace(input.(string), from, to, -1), nil
}

func split(input interface{}, delimiter string) ([]string, error) {
	return strings.Split(input.(string), delimiter), nil
}

func escape(input interface{}) string {
	return Escape(input.(string))
}

// isSet indicate is a field is defined in the template data
func isSet(v interface{}, name string) bool {
	rv := reflect.ValueOf(v)
	if rv.Kind() == reflect.Ptr {
		rv = rv.Elem()
	}
	if rv.Kind() != reflect.Struct {
		return false
	}
	return rv.FieldByName(name).IsValid()
}

// TmplFuncMap expose custom go template functions
var TmplFuncMap = template.FuncMap{
	"replace": replace,
	"split":   split,
	"escape":  escape,
	"isSet": isSet,
}
<|endoftext|>


<commit_before>package middleware

import (
	"github.com/beatgammit/artichoke"
	"net/http"
	"os"
	"path"
)

func Static(root string) artichoke.Middleware {
	return func(w http.ResponseWriter, r *http.Request, d artichoke.Data) bool {
		fPath := path.Join(root, r.URL.Path)

		// if the path doesn't exist, continue down the stack
		f, err := os.Open(fPath)
		if err != nil && os.IsNotExist(err) {
			return false
		}

		f.Close()

		http.ServeFile(w, r, fPath)
		return true
	}
}
<commit_msg>Make sure to only close file on success<commit_after>package middleware

import (
	"github.com/beatgammit/artichoke"
	"net/http"
	"os"
	"path"
)

func Static(root string) artichoke.Middleware {
	return func(w http.ResponseWriter, r *http.Request, d artichoke.Data) bool {
		fPath := path.Join(root, r.URL.Path)

		// if the path doesn't exist, continue down the stack
		f, err := os.Open(fPath)
		if err != nil {
			if os.IsNotExist(err) {
				return false
			}
		} else {
			f.Close()
		}

		http.ServeFile(w, r, fPath)
		return true
	}
}
<|endoftext|>


<commit_before>package view

import (
	"io"
	"strconv"
	"time"

	"github.com/ungerik/go-start/config"
	"github.com/ungerik/go-start/errs"
	"github.com/ungerik/go-start/templatesystem"
	"github.com/ungerik/go-start/utils"
	"github.com/ungerik/web.go"

//	"github.com/ungerik/go-start/debug"
)

var viewIdChan = make(chan string, 16)
var viewIdCounter int64

func init() {
	go func() {
		for {
			viewIdCounter++
			// Use base32 encoding for ids to make them shorter
			viewIdChan <- "i" + strconv.FormatInt(viewIdCounter, 32)
		}
	}()
}

// var viewsByID map[string]View = map[string]View{}
var viewsByPath = map[string]View{}

func NewViewID(view View) (id string) {
	id = <-viewIdChan
	// viewsByID[id] = view
	return id
}

// func DeleteViewID(id string) {
// 	if _, exists := viewsByID[id]; !exists {
// 		panic("View ID '" + id + "' does not exist")
// 	}
// 	delete(viewsByID, id)
// }

func FindStaticFile(filename string) (filePath string, found bool, modifiedTime time.Time) {
	return utils.FindFile2ModifiedTime(Config.BaseDirs, Config.StaticDirs, filename)
}

func FindTemplateFile(filename string) (filePath string, found bool, modifiedTime time.Time) {
	return utils.FindFile2ModifiedTime(Config.BaseDirs, Config.TemplateDirs, filename)
}

//func ViewChanged(view View) {
//}

// RunServer starts a webserver with the given paths.
// If paths is nil, only static files will be served.
func RunServer(paths *ViewPath) {
	if !Config.initialized {
		err := Config.Init()
		if err != nil {
			panic(err)
		}
	}
	addr := Config.ListenAndServeAt
	if !Config.IsProductionServer && Config.Debug.ListenAndServeAt != "" {
		addr = Config.Debug.ListenAndServeAt
	}
	RunServerAddr(addr, paths)
}

// RunServerAddr starts a webserver with the given paths and address.
// If paths is nil, only static files will be served.
func RunServerAddr(addr string, paths *ViewPath) {
	if !Config.initialized {
		err := Config.Init()
		if err != nil {
			panic(err)
		}
	}
	config.Logger.Print("view.Config.IsProductionServer = ", Config.IsProductionServer)
	config.Logger.Print("view.Config.Debug.Mode = ", Config.Debug.Mode)

	if paths != nil {
		paths.initAndRegisterViewsRecursive("/")
	}

	web.Config.StaticDirs = utils.CombineDirs(Config.BaseDirs, Config.StaticDirs)
	web.Config.RecoverPanic = Config.Debug.Mode
	web.Config.CookieSecret = Config.CookieSecret

	web.Run(addr)
}

func RenderTemplate(filename string, out io.Writer, context interface{}) (err error) {
	filePath, found, _ := FindTemplateFile(filename)
	if !found {
		return errs.Format("Template file not found: %s", filename)
	}

	var templ templatesystem.Template
	templ, err = Config.TemplateSystem.ParseFile(filePath)
	if err != nil {
		return
	}

	// context = append(context, Config)
	return templ.Render(out, context)
}

func RenderTemplateString(tmplString string, name string, out io.Writer, context interface{}) (err error) {
	var templ templatesystem.Template
	templ, err = Config.TemplateSystem.ParseString(tmplString, name)
	if err != nil {
		return
	}

	// context = append(context, Config)
	return templ.Render(out, context)
}

func RenderChildViewsHTML(parent View, ctx *Context) (err error) {
	parent.IterateChildren(func(parent View, child View) (next bool) {
		if child != nil {
			err = child.Render(ctx)
			if err != nil {
				return false
			}
		}
		return true
	})
	return err
}
<commit_msg>Added TLS encryption.<commit_after>package view

import (
	"io"
	"strconv"
	"time"

	"github.com/ungerik/go-start/config"
	"github.com/ungerik/go-start/errs"
	"github.com/ungerik/go-start/templatesystem"
	"github.com/ungerik/go-start/utils"
	"github.com/ungerik/web.go"

//	"github.com/ungerik/go-start/debug"
)

var viewIdChan = make(chan string, 16)
var viewIdCounter int64

func init() {
	go func() {
		for {
			viewIdCounter++
			// Use base32 encoding for ids to make them shorter
			viewIdChan <- "i" + strconv.FormatInt(viewIdCounter, 32)
		}
	}()
}

// var viewsByID map[string]View = map[string]View{}
var viewsByPath = map[string]View{}

func NewViewID(view View) (id string) {
	id = <-viewIdChan
	// viewsByID[id] = view
	return id
}

// func DeleteViewID(id string) {
// 	if _, exists := viewsByID[id]; !exists {
// 		panic("View ID '" + id + "' does not exist")
// 	}
// 	delete(viewsByID, id)
// }

func FindStaticFile(filename string) (filePath string, found bool, modifiedTime time.Time) {
	return utils.FindFile2ModifiedTime(Config.BaseDirs, Config.StaticDirs, filename)
}

func FindTemplateFile(filename string) (filePath string, found bool, modifiedTime time.Time) {
	return utils.FindFile2ModifiedTime(Config.BaseDirs, Config.TemplateDirs, filename)
}

//func ViewChanged(view View) {
//}

func initAndGetAddr() string {
	if !Config.initialized {
		err := Config.Init()
		if err != nil {
			panic(err)
		}
	}
	addr := Config.ListenAndServeAt
	if !Config.IsProductionServer && Config.Debug.ListenAndServeAt != "" {
		addr = Config.Debug.ListenAndServeAt
	}
	return addr
}

// RunServer starts a webserver with the given paths.
// If paths is nil, only static files will be served.
func RunServer(paths *ViewPath) {
	addr := initAndGetAddr()
	RunServerAddr(addr, paths)
}

func RunServerTLS(certFile, keyFile string, paths *ViewPath) {
	addr := initAndGetAddr()
	RunServerAddrTLS(addr, certFile, keyFile, paths)
}

func initWebAndPaths(paths *ViewPath) {
	if !Config.initialized {
		err := Config.Init()
		if err != nil {
			panic(err)
		}
	}
	config.Logger.Print("view.Config.IsProductionServer = ", Config.IsProductionServer)
	config.Logger.Print("view.Config.Debug.Mode = ", Config.Debug.Mode)

	if paths != nil {
		paths.initAndRegisterViewsRecursive("/")
	}

	web.Config.StaticDirs = utils.CombineDirs(Config.BaseDirs, Config.StaticDirs)
	web.Config.RecoverPanic = Config.Debug.Mode
	web.Config.CookieSecret = Config.CookieSecret
}

// RunServerAddr starts a webserver with the given paths and address.
// If paths is nil, only static files will be served.
func RunServerAddr(addr string, paths *ViewPath) {
	initWebAndPaths(paths)
	web.Run(addr)
}

func RunServerAddrTLS(addr, certFile, keyFile string, paths *ViewPath) {
	initWebAndPaths(paths)
	web.RunTLS(addr, certFile, keyFile)
}

func RenderTemplate(filename string, out io.Writer, context interface{}) (err error) {
	filePath, found, _ := FindTemplateFile(filename)
	if !found {
		return errs.Format("Template file not found: %s", filename)
	}

	var templ templatesystem.Template
	templ, err = Config.TemplateSystem.ParseFile(filePath)
	if err != nil {
		return
	}

	// context = append(context, Config)
	return templ.Render(out, context)
}

func RenderTemplateString(tmplString string, name string, out io.Writer, context interface{}) (err error) {
	var templ templatesystem.Template
	templ, err = Config.TemplateSystem.ParseString(tmplString, name)
	if err != nil {
		return
	}

	// context = append(context, Config)
	return templ.Render(out, context)
}

func RenderChildViewsHTML(parent View, ctx *Context) (err error) {
	parent.IterateChildren(func(parent View, child View) (next bool) {
		if child != nil {
			err = child.Render(ctx)
			if err != nil {
				return false
			}
		}
		return true
	})
	return err
}
<|endoftext|>


<commit_before>package providercache

import (
	"context"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"

	getter "github.com/hashicorp/go-getter"

	"github.com/hashicorp/terraform/httpclient"
	"github.com/hashicorp/terraform/internal/copydir"
	"github.com/hashicorp/terraform/internal/getproviders"
)

// We borrow the "unpack a zip file into a target directory" logic from
// go-getter, even though we're not otherwise using go-getter here.
// (We don't need the same flexibility as we have for modules, because
// providers _always_ come from provider registries, which have a very
// specific protocol and set of expectations.)
var unzip = getter.ZipDecompressor{}

func installFromHTTPURL(ctx context.Context, meta getproviders.PackageMeta, targetDir string) (*getproviders.PackageAuthenticationResult, error) {
	url := meta.Location.String()

	// When we're installing from an HTTP URL we expect the URL to refer to
	// a zip file. We'll fetch that into a temporary file here and then
	// delegate to installFromLocalArchive below to actually extract it.
	// (We're not using go-getter here because its HTTP getter has a bunch
	// of extraneous functionality we don't need or want, like indirection
	// through X-Terraform-Get header, attempting partial fetches for
	// files that already exist, etc.)

	httpClient := httpclient.New()
	req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
	if err != nil {
		return nil, fmt.Errorf("invalid provider download request: %s", err)
	}
	resp, err := httpClient.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("unsuccessful request to %s: %s", url, resp.Status)
	}

	f, err := ioutil.TempFile("", "terraform-provider")
	if err != nil {
		return nil, fmt.Errorf("failed to open temporary file to download from %s", url)
	}
	defer f.Close()

	// We'll borrow go-getter's "cancelable copy" implementation here so that
	// the download can potentially be interrupted partway through.
	n, err := getter.Copy(ctx, f, resp.Body)
	if err == nil && n < resp.ContentLength {
		err = fmt.Errorf("incorrect response size: expected %d bytes, but got %d bytes", resp.ContentLength, n)
	}
	if err != nil {
		return nil, err
	}

	archiveFilename := f.Name()
	localLocation := getproviders.PackageLocalArchive(archiveFilename)

	var authResult *getproviders.PackageAuthenticationResult
	if meta.Authentication != nil {
		if authResult, err = meta.Authentication.AuthenticatePackage(localLocation); err != nil {
			return authResult, err
		}
	}

	// We can now delegate to installFromLocalArchive for extraction. To do so,
	// we construct a new package meta description using the local archive
	// path as the location, and skipping authentication.
	localMeta := getproviders.PackageMeta{
		Provider:         meta.Provider,
		Version:          meta.Version,
		ProtocolVersions: meta.ProtocolVersions,
		TargetPlatform:   meta.TargetPlatform,
		Filename:         meta.Filename,
		Location:         localLocation,
		Authentication:   nil,
	}
	if _, err := installFromLocalArchive(ctx, localMeta, targetDir); err != nil {
		return nil, err
	}
	return authResult, nil
}

func installFromLocalArchive(ctx context.Context, meta getproviders.PackageMeta, targetDir string) (*getproviders.PackageAuthenticationResult, error) {
	var authResult *getproviders.PackageAuthenticationResult
	if meta.Authentication != nil {
		var err error
		if authResult, err = meta.Authentication.AuthenticatePackage(meta.Location); err != nil {
			return nil, err
		}
	}
	filename := meta.Location.String()

	err := unzip.Decompress(targetDir, filename, true)
	if err != nil {
		return authResult, err
	}

	return authResult, nil
}

// installFromLocalDir is the implementation of both installing a package from
// a local directory source _and_ of linking a package from another cache
// in LinkFromOtherCache, because they both do fundamentally the same
// operation: symlink if possible, or deep-copy otherwise.
func installFromLocalDir(ctx context.Context, meta getproviders.PackageMeta, targetDir string) (*getproviders.PackageAuthenticationResult, error) {
	sourceDir := meta.Location.String()

	absNew, err := filepath.Abs(targetDir)
	if err != nil {
		return nil, fmt.Errorf("failed to make target path %s absolute: %s", targetDir, err)
	}
	absCurrent, err := filepath.Abs(sourceDir)
	if err != nil {
		return nil, fmt.Errorf("failed to make source path %s absolute: %s", sourceDir, err)
	}

	// Before we do anything else, we'll do a quick check to make sure that
	// these two paths are not pointing at the same physical directory on
	// disk. This compares the files by their OS-level device and directory
	// entry identifiers, not by their virtual filesystem paths.
	if same, err := copydir.SameFile(absNew, absCurrent); same {
		return nil, fmt.Errorf("cannot install existing provider directory %s to itself", targetDir)
	} else if err != nil {
		return nil, fmt.Errorf("failed to determine if %s and %s are the same: %s", sourceDir, targetDir, err)
	}

	// Delete anything that's already present at this path first.
	err = os.RemoveAll(targetDir)
	if err != nil && !os.IsNotExist(err) {
		return nil, fmt.Errorf("failed to remove existing %s before linking it to %s: %s", sourceDir, targetDir, err)
	}

	// We'll prefer to create a symlink if possible, but we'll fall back to
	// a recursive copy if symlink creation fails. It could fail for a number
	// of reasons, including being on Windows 8 without administrator
	// privileges or being on a legacy filesystem like FAT that has no way
	// to represent a symlink. (Generalized symlink support for Windows was
	// introduced in a Windows 10 minor update.)
	//
	// We use an absolute path for the symlink to reduce the risk of it being
	// broken by moving things around later, since the source directory is
	// likely to be a shared directory independent on any particular target
	// and thus we can't assume that they will move around together.
	linkTarget := absCurrent

	parentDir := filepath.Dir(absNew)
	err = os.MkdirAll(parentDir, 0755)
	if err != nil && os.IsExist(err) {
		return nil, fmt.Errorf("failed to create parent directories leading to %s: %s", targetDir, err)
	}

	err = os.Symlink(linkTarget, absNew)
	if err == nil {
		// Success, then!
		return nil, nil
	}

	// If we get down here then symlinking failed and we need a deep copy
	// instead.
	err = copydir.CopyDir(absNew, absCurrent)
	if err != nil {
		return nil, fmt.Errorf("failed to either symlink or copy %s to %s: %s", absCurrent, absNew, err)
	}

	// If we got here then apparently our copy succeeded, so we're done.
	return nil, nil
}
<commit_msg>internal/providercache: Fix bug when symlink fails<commit_after>package providercache

import (
	"context"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"

	getter "github.com/hashicorp/go-getter"

	"github.com/hashicorp/terraform/httpclient"
	"github.com/hashicorp/terraform/internal/copydir"
	"github.com/hashicorp/terraform/internal/getproviders"
)

// We borrow the "unpack a zip file into a target directory" logic from
// go-getter, even though we're not otherwise using go-getter here.
// (We don't need the same flexibility as we have for modules, because
// providers _always_ come from provider registries, which have a very
// specific protocol and set of expectations.)
var unzip = getter.ZipDecompressor{}

func installFromHTTPURL(ctx context.Context, meta getproviders.PackageMeta, targetDir string) (*getproviders.PackageAuthenticationResult, error) {
	url := meta.Location.String()

	// When we're installing from an HTTP URL we expect the URL to refer to
	// a zip file. We'll fetch that into a temporary file here and then
	// delegate to installFromLocalArchive below to actually extract it.
	// (We're not using go-getter here because its HTTP getter has a bunch
	// of extraneous functionality we don't need or want, like indirection
	// through X-Terraform-Get header, attempting partial fetches for
	// files that already exist, etc.)

	httpClient := httpclient.New()
	req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
	if err != nil {
		return nil, fmt.Errorf("invalid provider download request: %s", err)
	}
	resp, err := httpClient.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("unsuccessful request to %s: %s", url, resp.Status)
	}

	f, err := ioutil.TempFile("", "terraform-provider")
	if err != nil {
		return nil, fmt.Errorf("failed to open temporary file to download from %s", url)
	}
	defer f.Close()

	// We'll borrow go-getter's "cancelable copy" implementation here so that
	// the download can potentially be interrupted partway through.
	n, err := getter.Copy(ctx, f, resp.Body)
	if err == nil && n < resp.ContentLength {
		err = fmt.Errorf("incorrect response size: expected %d bytes, but got %d bytes", resp.ContentLength, n)
	}
	if err != nil {
		return nil, err
	}

	archiveFilename := f.Name()
	localLocation := getproviders.PackageLocalArchive(archiveFilename)

	var authResult *getproviders.PackageAuthenticationResult
	if meta.Authentication != nil {
		if authResult, err = meta.Authentication.AuthenticatePackage(localLocation); err != nil {
			return authResult, err
		}
	}

	// We can now delegate to installFromLocalArchive for extraction. To do so,
	// we construct a new package meta description using the local archive
	// path as the location, and skipping authentication.
	localMeta := getproviders.PackageMeta{
		Provider:         meta.Provider,
		Version:          meta.Version,
		ProtocolVersions: meta.ProtocolVersions,
		TargetPlatform:   meta.TargetPlatform,
		Filename:         meta.Filename,
		Location:         localLocation,
		Authentication:   nil,
	}
	if _, err := installFromLocalArchive(ctx, localMeta, targetDir); err != nil {
		return nil, err
	}
	return authResult, nil
}

func installFromLocalArchive(ctx context.Context, meta getproviders.PackageMeta, targetDir string) (*getproviders.PackageAuthenticationResult, error) {
	var authResult *getproviders.PackageAuthenticationResult
	if meta.Authentication != nil {
		var err error
		if authResult, err = meta.Authentication.AuthenticatePackage(meta.Location); err != nil {
			return nil, err
		}
	}
	filename := meta.Location.String()

	err := unzip.Decompress(targetDir, filename, true)
	if err != nil {
		return authResult, err
	}

	return authResult, nil
}

// installFromLocalDir is the implementation of both installing a package from
// a local directory source _and_ of linking a package from another cache
// in LinkFromOtherCache, because they both do fundamentally the same
// operation: symlink if possible, or deep-copy otherwise.
func installFromLocalDir(ctx context.Context, meta getproviders.PackageMeta, targetDir string) (*getproviders.PackageAuthenticationResult, error) {
	sourceDir := meta.Location.String()

	absNew, err := filepath.Abs(targetDir)
	if err != nil {
		return nil, fmt.Errorf("failed to make target path %s absolute: %s", targetDir, err)
	}
	absCurrent, err := filepath.Abs(sourceDir)
	if err != nil {
		return nil, fmt.Errorf("failed to make source path %s absolute: %s", sourceDir, err)
	}

	// Before we do anything else, we'll do a quick check to make sure that
	// these two paths are not pointing at the same physical directory on
	// disk. This compares the files by their OS-level device and directory
	// entry identifiers, not by their virtual filesystem paths.
	if same, err := copydir.SameFile(absNew, absCurrent); same {
		return nil, fmt.Errorf("cannot install existing provider directory %s to itself", targetDir)
	} else if err != nil {
		return nil, fmt.Errorf("failed to determine if %s and %s are the same: %s", sourceDir, targetDir, err)
	}

	// Delete anything that's already present at this path first.
	err = os.RemoveAll(targetDir)
	if err != nil && !os.IsNotExist(err) {
		return nil, fmt.Errorf("failed to remove existing %s before linking it to %s: %s", sourceDir, targetDir, err)
	}

	// We'll prefer to create a symlink if possible, but we'll fall back to
	// a recursive copy if symlink creation fails. It could fail for a number
	// of reasons, including being on Windows 8 without administrator
	// privileges or being on a legacy filesystem like FAT that has no way
	// to represent a symlink. (Generalized symlink support for Windows was
	// introduced in a Windows 10 minor update.)
	//
	// We use an absolute path for the symlink to reduce the risk of it being
	// broken by moving things around later, since the source directory is
	// likely to be a shared directory independent on any particular target
	// and thus we can't assume that they will move around together.
	linkTarget := absCurrent

	parentDir := filepath.Dir(absNew)
	err = os.MkdirAll(parentDir, 0755)
	if err != nil {
		return nil, fmt.Errorf("failed to create parent directories leading to %s: %s", targetDir, err)
	}

	err = os.Symlink(linkTarget, absNew)
	if err == nil {
		// Success, then!
		return nil, nil
	}

	// If we get down here then symlinking failed and we need a deep copy
	// instead. To make a copy, we first need to create the target directory,
	// which would otherwise be a symlink.
	err = os.Mkdir(absNew, 0755)
	if err != nil && os.IsExist(err) {
		return nil, fmt.Errorf("failed to create directory %s: %s", absNew, err)
	}
	err = copydir.CopyDir(absNew, absCurrent)
	if err != nil {
		return nil, fmt.Errorf("failed to either symlink or copy %s to %s: %s", absCurrent, absNew, err)
	}

	// If we got here then apparently our copy succeeded, so we're done.
	return nil, nil
}
<|endoftext|>


<commit_before>package controllers_test

import (
	"net/url"
	"testing"

	"github.com/anonx/sunplate/internal/skeleton/assets/handlers"
	"github.com/anonx/sunplate/internal/skeleton/routes"

	"github.com/anonx/sunplate/assert"
)

func TestAppIndex(t *testing.T) {
	a := assert.New()

	handlers.App.Index(a.Get("/").Args())
	a.StatusOK().ContentType("text/html; charset=utf-8")
	a.Body.Contains("Hello, world!")
}

func TestAppPostGreet_Integration(t *testing.T) {
	a := assert.New().TryStartServer(routes.List.Build())
	defer a.StopServer()

	a.PostForm("/greet/James", url.Values{
		"message": {"Good day"},
	}).Do()
	a.StatusOK()
	a.Body.Contains("Good day")
	a.Body.Contains("James")
}
<commit_msg>Rename skeleton app controller's test<commit_after>package controllers_test

import (
	"net/url"
	"testing"

	"github.com/anonx/sunplate/internal/skeleton/assets/handlers"
	"github.com/anonx/sunplate/internal/skeleton/routes"

	"github.com/anonx/sunplate/assert"
)

func TestAppIndex(t *testing.T) {
	a := assert.New()

	handlers.App.Index(a.Get("/").Args())
	a.StatusOK().ContentType("text/html; charset=utf-8")
	a.Body.Contains("Hello, world!")
}

func TestAppPostGreet(t *testing.T) {
	a := assert.New().TryStartServer(routes.List.Build())
	defer a.StopServer()

	a.PostForm("/greet/James", url.Values{
		"message": {"Good day"},
	}).Do().StatusOK()

	a.Body.Contains("James")
	a.Body.Contains("Good day")
}
<|endoftext|>


<commit_before>package styxproto

import (
	"bufio"
	"errors"
	"io"
	"io/ioutil"
)

var (
	errFillOverflow = errors.New("cannot fill buffer past maxInt")
)

// Design goals of the parser:
//   - minimize allocations
//   - resilient to malicious input (invalid/overlarge sizes)
//   - streaming: a 4GB (max uint32) Twrite should not take 4G of memory

// NewDecoder returns a Decoder with an internal buffer of size
// DefaultBufSize.
func NewDecoder(r io.Reader) *Decoder {
	return NewDecoderSize(r, DefaultBufSize)
}

// NewDecoderSize returns a Decoder with an internal buffer of size
// max(MinBufSize, bufsize) bytes. A Decoder with a larger buffer can
// provide more 9P messages at once, if they are available. This may
// improve performance on connections that are heavily multiplexed,
// where there messages from independent sessions that can be handled
// in any order.
func NewDecoderSize(r io.Reader, bufsize int) *Decoder {
	if bufsize < MinBufSize {
		bufsize = MinBufSize
	}
	return &Decoder{r: r, br: bufio.NewReaderSize(r, bufsize), MaxSize: -1}
}

// A Decoder provides an interface for reading a stream of 9P
// messages from an io.Reader. Successive calls to the Next
// method of a Decoder will fetch and validate 9P messages
// from the input stream, until EOF is encountered, or another
// error is encountered.
//
// A Decoder is not safe for concurrent use. Usage of any Decoder
// method should be delegated to a single thread of execution or
// protected by a mutex.
type Decoder struct {
	// MaxSize is the maximum size message that a Decoder will accept. If
	// MaxSize is -1, a Decoder will accept any size message.
	MaxSize int64

	// input source. we need to expose this so we can stitch together
	// an io.Reader for large Twrite/Rread messages.
	r io.Reader

	// internal buffer is used to store messages
	br *bufio.Reader

	// current selection in the buffered data
	start, pos int

	// Last fetched messages. slices on r's internal buffers, so
	// only valid until next call to r.Read, r.Discard.
	msg []Msg

	// Last error encountered when reading from r
	// or during parsing
	err error
}

// Reset resets a Decoder with a new io.Reader.
func (s *Decoder) Reset(r io.Reader) {
	s.MaxSize = -1
	s.r = r
	s.br.Reset(s.r)
	s.start = 0
	s.pos = 0
	s.msg = s.msg[:0]
	s.err = nil
}

// Err returns the first error encountered during parsing.
// If the underyling io.Reader was closed in the middle of
// a message, Err will return io.ErrUnexpectedEOF. Otherwise,
// io.EOF is not considered to be an error, and is not relayed
// by Err.
//
// Invalid messages are not considered errors, and are
// represented in the Messages slice as values of type BadMessage.
// Only problems with the underlying I/O device are
// considered errors.
func (s *Decoder) Err() error {
	if s.err == io.EOF {
		return nil
	}
	return s.err
}

// Messages returns the 9P messages fetched from the last
// call to Next. The returned messages are only valid until
// the next call to the Decoder's Next method. All Twrite
// and Rread messages must be closed before the next
// call to Next.
func (s *Decoder) Messages() []Msg {
	return s.msg
}

// Next fetches the next 9P messages from the Decoder's underlying
// io.Reader. If an error is encountered, either with the underlying
// IO, Next will return false, and the Decoder's Err method will return
// the first error encountered.
//
// If Next returns true, at least one 9P message will be returned from
// the next call to the Messages method of the Decoder. If multiple
// messages can be retrieved with a single call to Read, they will be
// validated at once and available via the Messages method. If the
// Decoder encounters a Tversion or Rversion message, parsing will
// stop even if additional messages are pending, so that new messages
// can be parsed based on the protocol version and maximum size.
func (s *Decoder) Next() bool {
	s.exhaustReaders()
	s.dropMessages()
	s.resetdot()
	if s.err != nil {
		return false
	}

	if err := s.fetchMessages(); err != nil {
		return false
	}
	return true
}

// Before reading the next batch of messages, it is crucial that any
// associated io.Reader's are exhausted, because one of them may
// be pulling directly from the underlying Reader, and attempting
// to parse before the message is fully read and out of the buffer
// will not work.
func (s *Decoder) exhaustReaders() {
	for _, msg := range s.msg {
		if r, ok := msg.(io.Reader); ok {
			if _, err := io.Copy(ioutil.Discard, r); err != nil {
				s.err = err
				break
			}
		}
	}
}

// A bufio.Reader is not just a way to smooth out I/O performance;
// it can also be used as a "sliding window" over a byte stream.
// If the terminology below seems odd, it is inspired by the sam
// text editor, where "dot" refers to the current text selection.
func (s *Decoder) dot() []byte {
	if s.pos > s.br.Buffered() {
		panic("decoder position out of bounds")
	}
	buf, err := s.br.Peek(s.pos)
	if err != nil {
		panic(err) // this should never happen, it's buffered
	}
	return buf[s.start:]
}

func (s *Decoder) resetdot() {
	s.start, s.pos = 0, 0
}

func (s *Decoder) advance(n int) {
	if s.buflen() < n {
		panic("advance decoder out of bounds")
	}
	s.pos += n
}

func (s *Decoder) shrinkdot(n int) {
	if s.dotlen() < n {
		panic("shrink dot out of bounds")
	}
	s.pos -= n
}

// advance start of dot to end of dot
func (s *Decoder) mark() {
	s.start = s.pos
}

// number of bytes buffered after dot
func (s *Decoder) buflen() int {
	return s.br.Buffered() - s.pos
}

func (s *Decoder) dotlen() int {
	return s.pos - s.start
}

// extends dot to be n bytes long, performing
// IO if necessary. returns dot
func (s *Decoder) growdot(n int) ([]byte, error) {
	if err := s.fill(n - s.dotlen()); err != nil {
		return nil, err
	}
	s.advance(n - s.dotlen())
	return s.dot(), nil
}

// guarantees that s.buflen() >= n if error is nil
func (s *Decoder) fill(n int) error {
	if maxInt-n < s.pos {
		return errFillOverflow
	}
	_, err := s.br.Peek(s.pos + n)
	return err
}

func discard(r *bufio.Reader, n int64) error {
	_, err := io.CopyN(ioutil.Discard, r, n)
	return err
}

// free up buffer space for the next parsing cycle
func (s *Decoder) dropMessages() {
	for _, msg := range s.msg {
		if err := discard(s.br, msg.nbytes()); err != nil {
			s.err = err
			break
		}
	}
	s.msg = s.msg[:0]
}
<commit_msg>Do not exit decoder loop prematurely<commit_after>package styxproto

import (
	"bufio"
	"errors"
	"io"
	"io/ioutil"
)

var (
	errFillOverflow = errors.New("cannot fill buffer past maxInt")
)

// Design goals of the parser:
//   - minimize allocations
//   - resilient to malicious input (invalid/overlarge sizes)
//   - streaming: a 4GB (max uint32) Twrite should not take 4G of memory

// NewDecoder returns a Decoder with an internal buffer of size
// DefaultBufSize.
func NewDecoder(r io.Reader) *Decoder {
	return NewDecoderSize(r, DefaultBufSize)
}

// NewDecoderSize returns a Decoder with an internal buffer of size
// max(MinBufSize, bufsize) bytes. A Decoder with a larger buffer can
// provide more 9P messages at once, if they are available. This may
// improve performance on connections that are heavily multiplexed,
// where there messages from independent sessions that can be handled
// in any order.
func NewDecoderSize(r io.Reader, bufsize int) *Decoder {
	if bufsize < MinBufSize {
		bufsize = MinBufSize
	}
	return &Decoder{r: r, br: bufio.NewReaderSize(r, bufsize), MaxSize: -1}
}

// A Decoder provides an interface for reading a stream of 9P
// messages from an io.Reader. Successive calls to the Next
// method of a Decoder will fetch and validate 9P messages
// from the input stream, until EOF is encountered, or another
// error is encountered.
//
// A Decoder is not safe for concurrent use. Usage of any Decoder
// method should be delegated to a single thread of execution or
// protected by a mutex.
type Decoder struct {
	// MaxSize is the maximum size message that a Decoder will accept. If
	// MaxSize is -1, a Decoder will accept any size message.
	MaxSize int64

	// input source. we need to expose this so we can stitch together
	// an io.Reader for large Twrite/Rread messages.
	r io.Reader

	// internal buffer is used to store messages
	br *bufio.Reader

	// current selection in the buffered data
	start, pos int

	// Last fetched messages. slices on r's internal buffers, so
	// only valid until next call to r.Read, r.Discard.
	msg []Msg

	// Last error encountered when reading from r
	// or during parsing
	err error
}

// Reset resets a Decoder with a new io.Reader.
func (s *Decoder) Reset(r io.Reader) {
	s.MaxSize = -1
	s.r = r
	s.br.Reset(s.r)
	s.start = 0
	s.pos = 0
	s.msg = s.msg[:0]
	s.err = nil
}

// Err returns the first error encountered during parsing.
// If the underyling io.Reader was closed in the middle of
// a message, Err will return io.ErrUnexpectedEOF. Otherwise,
// io.EOF is not considered to be an error, and is not relayed
// by Err.
//
// Invalid messages are not considered errors, and are
// represented in the Messages slice as values of type BadMessage.
// Only problems with the underlying I/O device are
// considered errors.
func (s *Decoder) Err() error {
	if s.err == io.EOF {
		return nil
	}
	return s.err
}

// Messages returns the 9P messages fetched from the last
// call to Next. The returned messages are only valid until
// the next call to the Decoder's Next method. All Twrite
// and Rread messages must be closed before the next
// call to Next.
func (s *Decoder) Messages() []Msg {
	return s.msg
}

// Next fetches the next 9P messages from the Decoder's underlying
// io.Reader. If an error is encountered, either with the underlying
// IO, Next will return false, and the Decoder's Err method will return
// the first error encountered.
//
// If Next returns true, at least one 9P message will be returned from
// the next call to the Messages method of the Decoder. If multiple
// messages can be retrieved with a single call to Read, they will be
// validated at once and available via the Messages method. If the
// Decoder encounters a Tversion or Rversion message, parsing will
// stop even if additional messages are pending, so that new messages
// can be parsed based on the protocol version and maximum size.
func (s *Decoder) Next() bool {
	s.exhaustReaders()
	s.dropMessages()
	s.resetdot()
	if s.err != nil {
		return false
	}

	if err := s.fetchMessages(); err != nil {
		return len(s.msg) > 0
	}
	return true
}

// Before reading the next batch of messages, it is crucial that any
// associated io.Reader's are exhausted, because one of them may
// be pulling directly from the underlying Reader, and attempting
// to parse before the message is fully read and out of the buffer
// will not work.
func (s *Decoder) exhaustReaders() {
	for _, msg := range s.msg {
		if r, ok := msg.(io.Reader); ok {
			if _, err := io.Copy(ioutil.Discard, r); err != nil {
				s.err = err
				break
			}
		}
	}
}

// A bufio.Reader is not just a way to smooth out I/O performance;
// it can also be used as a "sliding window" over a byte stream.
// If the terminology below seems odd, it is inspired by the sam
// text editor, where "dot" refers to the current text selection.
func (s *Decoder) dot() []byte {
	if s.pos > s.br.Buffered() {
		panic("decoder position out of bounds")
	}
	buf, err := s.br.Peek(s.pos)
	if err != nil {
		panic(err) // this should never happen, it's buffered
	}
	return buf[s.start:]
}

func (s *Decoder) resetdot() {
	s.start, s.pos = 0, 0
}

func (s *Decoder) advance(n int) {
	if s.buflen() < n {
		panic("advance decoder out of bounds")
	}
	s.pos += n
}

func (s *Decoder) shrinkdot(n int) {
	if s.dotlen() < n {
		panic("shrink dot out of bounds")
	}
	s.pos -= n
}

// advance start of dot to end of dot
func (s *Decoder) mark() {
	s.start = s.pos
}

// number of bytes buffered after dot
func (s *Decoder) buflen() int {
	return s.br.Buffered() - s.pos
}

func (s *Decoder) dotlen() int {
	return s.pos - s.start
}

// extends dot to be n bytes long, performing
// IO if necessary. returns dot
func (s *Decoder) growdot(n int) ([]byte, error) {
	if err := s.fill(n - s.dotlen()); err != nil {
		return nil, err
	}
	s.advance(n - s.dotlen())
	return s.dot(), nil
}

// guarantees that s.buflen() >= n if error is nil
func (s *Decoder) fill(n int) error {
	if maxInt-n < s.pos {
		return errFillOverflow
	}
	_, err := s.br.Peek(s.pos + n)
	return err
}

func discard(r *bufio.Reader, n int64) error {
	_, err := io.CopyN(ioutil.Discard, r, n)
	return err
}

// free up buffer space for the next parsing cycle
func (s *Decoder) dropMessages() {
	for _, msg := range s.msg {
		if err := discard(s.br, msg.nbytes()); err != nil {
			s.err = err
			break
		}
	}
	s.msg = s.msg[:0]
}
<|endoftext|>