<commit_before>package graval

import (
	"bufio"
	"fmt"
	"log"
	"net"
	"strings"
)

const (
	welcomeMessage = "Welcome to the Go FTP Server"
)

type FTPConn struct {
	cwd           string
	conn          *net.TCPConn
	controlReader *bufio.Reader
	controlWriter *bufio.Writer
	data          *net.TCPConn
	driver        FTPDriver
	reqUser       string
	user          string
}

// NewFTPConn constructs a new object that will handle the FTP protocol over
// an active net.TCPConn. The TCP connection should already be open before
// it is handed to this functions. driver is an instance of FTPDrive that
// will handle all auth and persistence details.
func NewFTPConn(tcpConn *net.TCPConn, driver FTPDriver) *FTPConn {
	c := new(FTPConn)
	c.cwd = "/"
	c.conn = tcpConn
	c.controlReader = bufio.NewReader(tcpConn)
	c.controlWriter = bufio.NewWriter(tcpConn)
	c.driver = driver
	return c
}

// Serve starts an endless loop that reads FTP commands from the client and
// responds appropriately. terminated is a channel that will receive a true
// message when the connection closes. This loop will be running inside a
// goroutine, so use this channel to be notified when the connection can be
// cleaned up.
func (ftpConn *FTPConn) Serve(terminated chan bool) {
	log.Print("Connection Established")
	// send welcome
	ftpConn.writeMessage(220, welcomeMessage)
	// read commands
	for {
		line, err := ftpConn.controlReader.ReadString('\n')
		if err == nil {
			ftpConn.receiveLine(line)
		}
	}
	terminated <- true
	log.Print("Connection Terminated")
}

// Close will manually close this connection, even if the client isn't ready.
func (ftpConn *FTPConn) Close() {
	ftpConn.conn.Close()
	if ftpConn.data != nil {
		ftpConn.data.Close()
	}
}

// receiveLine accepts a single line FTP command and co-ordinates an
// appropriate response.
func (ftpConn *FTPConn) receiveLine(line string) {
	log.Print(line)
	command, param := ftpConn.parseLine(line)
	switch command {
	case "USER":
		ftpConn.cmdUser(param)
		break
	case "PASS":
		ftpConn.cmdPass(param)
		break
	case "QUIT":
		ftpConn.Close()
		break
	default:
		ftpConn.writeMessage(500, "Command not found")
	}
}

// cmdUser responds to the USER FTP command by asking for the password
func (ftpConn *FTPConn) cmdUser(param string) {
	ftpConn.reqUser = param
	ftpConn.writeMessage(331, "User name ok, password required")
}

// cmdPass respond to the PASS FTP command by asking the driver if the supplied
// username and password are valid
func (ftpConn *FTPConn) cmdPass(param string) {
	if ftpConn.driver.Authenticate(ftpConn.reqUser, param) {
		ftpConn.user = ftpConn.reqUser
		ftpConn.reqUser = ""
		ftpConn.writeMessage(230, "Password ok, continue")
	} else {
		ftpConn.writeMessage(530, "Incorrect password, not logged in")
	}
}

func (ftpConn *FTPConn) parseLine(line string) (string, string) {
	params := strings.SplitN(strings.Trim(line, "\r\n"), " ", 2)
	if len(params) == 1 {
		return params[0], ""
	}
	return params[0], params[1]
}

// writeMessage will send a standard FTP response back to the client.
func (ftpConn *FTPConn) writeMessage(code int, message string) (wrote int, err error) {
	line := fmt.Sprintf("%d %s\r\n", code, message)
	wrote, err = ftpConn.controlWriter.WriteString(line)
	ftpConn.controlWriter.Flush()
	log.Print(message)
	return
}
<commit_msg>recognise the SYST command<commit_after>package graval

import (
	"bufio"
	"fmt"
	"log"
	"net"
	"strings"
)

const (
	welcomeMessage = "Welcome to the Go FTP Server"
)

type FTPConn struct {
	cwd           string
	conn          *net.TCPConn
	controlReader *bufio.Reader
	controlWriter *bufio.Writer
	data          *net.TCPConn
	driver        FTPDriver
	reqUser       string
	user          string
}

// NewFTPConn constructs a new object that will handle the FTP protocol over
// an active net.TCPConn. The TCP connection should already be open before
// it is handed to this functions. driver is an instance of FTPDrive that
// will handle all auth and persistence details.
func NewFTPConn(tcpConn *net.TCPConn, driver FTPDriver) *FTPConn {
	c := new(FTPConn)
	c.cwd = "/"
	c.conn = tcpConn
	c.controlReader = bufio.NewReader(tcpConn)
	c.controlWriter = bufio.NewWriter(tcpConn)
	c.driver = driver
	return c
}

// Serve starts an endless loop that reads FTP commands from the client and
// responds appropriately. terminated is a channel that will receive a true
// message when the connection closes. This loop will be running inside a
// goroutine, so use this channel to be notified when the connection can be
// cleaned up.
func (ftpConn *FTPConn) Serve(terminated chan bool) {
	log.Print("Connection Established")
	// send welcome
	ftpConn.writeMessage(220, welcomeMessage)
	// read commands
	for {
		line, err := ftpConn.controlReader.ReadString('\n')
		if err == nil {
			ftpConn.receiveLine(line)
		}
	}
	terminated <- true
	log.Print("Connection Terminated")
}

// Close will manually close this connection, even if the client isn't ready.
func (ftpConn *FTPConn) Close() {
	ftpConn.conn.Close()
	if ftpConn.data != nil {
		ftpConn.data.Close()
	}
}

// receiveLine accepts a single line FTP command and co-ordinates an
// appropriate response.
func (ftpConn *FTPConn) receiveLine(line string) {
	log.Print(line)
	command, param := ftpConn.parseLine(line)
	switch command {
	case "USER":
		ftpConn.cmdUser(param)
		break
	case "PASS":
		ftpConn.cmdPass(param)
		break
	case "QUIT":
		ftpConn.Close()
		break
	case "SYST":
		ftpConn.cmdSyst()
		break
	default:
		ftpConn.writeMessage(500, "Command not found")
	}
}

// cmdUser responds to the USER FTP command by asking for the password
func (ftpConn *FTPConn) cmdUser(param string) {
	ftpConn.reqUser = param
	ftpConn.writeMessage(331, "User name ok, password required")
}

// cmdPass respond to the PASS FTP command by asking the driver if the supplied
// username and password are valid
func (ftpConn *FTPConn) cmdPass(param string) {
	if ftpConn.driver.Authenticate(ftpConn.reqUser, param) {
		ftpConn.user = ftpConn.reqUser
		ftpConn.reqUser = ""
		ftpConn.writeMessage(230, "Password ok, continue")
	} else {
		ftpConn.writeMessage(530, "Incorrect password, not logged in")
	}
}

// cmdSyst responds to the SYST FTP command by providing a canned response.
func (ftpConn *FTPConn) cmdSyst() {
	ftpConn.writeMessage(215, "UNIX Type: L8")
}

func (ftpConn *FTPConn) parseLine(line string) (string, string) {
	params := strings.SplitN(strings.Trim(line, "\r\n"), " ", 2)
	if len(params) == 1 {
		return params[0], ""
	}
	return params[0], params[1]
}

// writeMessage will send a standard FTP response back to the client.
func (ftpConn *FTPConn) writeMessage(code int, message string) (wrote int, err error) {
	line := fmt.Sprintf("%d %s\r\n", code, message)
	wrote, err = ftpConn.controlWriter.WriteString(line)
	ftpConn.controlWriter.Flush()
	log.Print(message)
	return
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 Niklas Wolber
// This file is licensed under the MIT license.
// See the LICENSE file for more information.

package job

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"log"
	"net"
	"os"
	"os/exec"
	"strings"

	"context"

	"golang.org/x/crypto/ssh"
)

func doSCP(ctx context.Context, privateKey []byte, addr string) error {
	l, ok := ctx.Value(loggerKey).(*log.Logger)
	if !ok || l == nil {
		l = log.New(os.Stderr, "", log.LstdFlags)
	}

	config := &ssh.ServerConfig{
		KeyboardInteractiveCallback: func(c ssh.ConnMetadata, client ssh.KeyboardInteractiveChallenge) (*ssh.Permissions, error) {
			l.Println("client authenticated by keyboard interactive challenge")
			return nil, nil
		},
		PasswordCallback: func(s ssh.ConnMetadata, password []byte) (*ssh.Permissions, error) {
			l.Println("client authenticated by password challenge")
			return nil, nil
		},
		PublicKeyCallback: func(s ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
			l.Println("client authenticated by public key challenge")
			return nil, nil
		},
	}

	private, err := ssh.ParsePrivateKey(privateKey)
	if err != nil {
		err = fmt.Errorf("failed to parse private key %s", err)
		l.Println(err)
		return err
	}

	config.AddHostKey(private)

	listener, err := net.Listen("tcp", addr)
	if err != nil {
		err = fmt.Errorf("failed to listen for connection %s", err)
		l.Println(err)
		return err
	}

	go func() {
		acceptChan := accept(ctx, listener)

		for {
			select {
			case conn, ok := <-acceptChan:
				if !ok {
					l.Println("accept channel closed")
					return
				}

				if conn.error != nil {
					l.Println("error accepting connection", err)
					return
				}
				l.Println("accepted new connection")

				go handleSSHConnection(ctx, conn, config)

			case <-ctx.Done():
				return
			}
		}
	}()
	return nil
}

func handleSSHConnection(ctx context.Context, nConn net.Conn, config *ssh.ServerConfig) {
	defer nConn.Close()

	l, ok := ctx.Value(loggerKey).(*log.Logger)
	if !ok || l == nil {
		l = log.New(os.Stderr, "", log.LstdFlags)
	}

	_, chans, reqs, err := ssh.NewServerConn(nConn, config)
	if err != nil {
		l.Println("failed to handshake:", err)
		return
	}
	l.Println("handshake successful")

	go ssh.DiscardRequests(reqs)

	for {
		select {
		case newChannel, ok := <-chans:
			if !ok {
				return
			}

			l.Println("New channel:", newChannel.ChannelType())

			if newChannel.ChannelType() != "session" {
				newChannel.Reject(ssh.UnknownChannelType, "unknown channel type")
				continue
			}
			channel, requests, err := newChannel.Accept()
			if err != nil {
				l.Println("could not accept channel")
				continue
			}

			go func(ctx context.Context, in <-chan *ssh.Request) {
				for {
					select {
					case req, ok := <-in:
						if !ok {
							return
						}

						l.Printf("%q requested: %q", req.Type, req.Payload)
						switch req.Type {
						case "exec":
							go handleExecRequest(ctx, channel, req)
						default:
							req.Reply(false, nil)
						}

					case <-ctx.Done():
						return
					}
				}
			}(ctx, requests)

		case <-ctx.Done():
			return
		}
	}
	l.Println("handleSSHConnection: connection closed")
}

func handleExecRequest(ctx context.Context, channel ssh.Channel, req *ssh.Request) {
	defer channel.Close()

	l, ok := ctx.Value(loggerKey).(*log.Logger)
	if !ok || l == nil {
		l = log.New(os.Stderr, "", log.LstdFlags)
	}

	parts := strings.Split(string(req.Payload), " ")
	exe := parts[0][4:]

	if exe != "scp" {
		l.Println("remote requested", exe, "denying")
		req.Reply(false, nil)
		return
	}

	select {
	case <-ctx.Done():
		return
	default:
	}

	cmd := exec.Command(exe, parts[1:]...)
	cmd.Stdin = channel
	cmd.Stdout = channel
	cmd.Stderr = os.Stderr

	processTerminated := make(chan int)

	go func(cmd *exec.Cmd, c chan<- int) {
		if err := cmd.Run(); err != nil {
			l.Println("error running", exe, err)

			// TODO get exit code from err.(*exec.ExitStatus)
			c <- 1
		} else {
			l.Println(exe, "completed successfully")
			c <- 0
		}
	}(cmd, processTerminated)

	var exitCode int
	select {
	case exitCode = <-processTerminated:
	case <-ctx.Done():
		l.Println("context completed, killing process")
		cmd.Process.Kill()
		exitCode = 255
	}

	var buf bytes.Buffer
	if err := binary.Write(&buf, binary.BigEndian, int32(exitCode)); err != nil {
		l.Println("unable to convert int32 to byte")
		return
	}
	channel.SendRequest("exit-status", false, buf.Bytes())
}
<commit_msg>Use exec.CommandContext when running scp<commit_after>// Copyright (c) 2016 Niklas Wolber
// This file is licensed under the MIT license.
// See the LICENSE file for more information.

package job

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"log"
	"net"
	"os"
	"os/exec"
	"strings"

	"context"

	"golang.org/x/crypto/ssh"
)

func doSCP(ctx context.Context, privateKey []byte, addr string) error {
	l, ok := ctx.Value(loggerKey).(*log.Logger)
	if !ok || l == nil {
		l = log.New(os.Stderr, "", log.LstdFlags)
	}

	config := &ssh.ServerConfig{
		KeyboardInteractiveCallback: func(c ssh.ConnMetadata, client ssh.KeyboardInteractiveChallenge) (*ssh.Permissions, error) {
			l.Println("client authenticated by keyboard interactive challenge")
			return nil, nil
		},
		PasswordCallback: func(s ssh.ConnMetadata, password []byte) (*ssh.Permissions, error) {
			l.Println("client authenticated by password challenge")
			return nil, nil
		},
		PublicKeyCallback: func(s ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
			l.Println("client authenticated by public key challenge")
			return nil, nil
		},
	}

	private, err := ssh.ParsePrivateKey(privateKey)
	if err != nil {
		err = fmt.Errorf("failed to parse private key %s", err)
		l.Println(err)
		return err
	}

	config.AddHostKey(private)

	listener, err := net.Listen("tcp", addr)
	if err != nil {
		err = fmt.Errorf("failed to listen for connection %s", err)
		l.Println(err)
		return err
	}

	go func() {
		acceptChan := accept(ctx, listener)

		for {
			select {
			case conn, ok := <-acceptChan:
				if !ok {
					l.Println("accept channel closed")
					return
				}

				if conn.error != nil {
					l.Println("error accepting connection", err)
					return
				}
				l.Println("accepted new connection")

				go handleSSHConnection(ctx, conn, config)

			case <-ctx.Done():
				return
			}
		}
	}()
	return nil
}

func handleSSHConnection(ctx context.Context, nConn net.Conn, config *ssh.ServerConfig) {
	defer nConn.Close()

	l, ok := ctx.Value(loggerKey).(*log.Logger)
	if !ok || l == nil {
		l = log.New(os.Stderr, "", log.LstdFlags)
	}

	_, chans, reqs, err := ssh.NewServerConn(nConn, config)
	if err != nil {
		l.Println("failed to handshake:", err)
		return
	}
	l.Println("handshake successful")

	go ssh.DiscardRequests(reqs)

	for {
		select {
		case newChannel, ok := <-chans:
			if !ok {
				return
			}

			l.Println("New channel:", newChannel.ChannelType())

			if newChannel.ChannelType() != "session" {
				newChannel.Reject(ssh.UnknownChannelType, "unknown channel type")
				continue
			}
			channel, requests, err := newChannel.Accept()
			if err != nil {
				l.Println("could not accept channel")
				continue
			}

			go func(ctx context.Context, in <-chan *ssh.Request) {
				for {
					select {
					case req, ok := <-in:
						if !ok {
							return
						}

						l.Printf("%q requested: %q", req.Type, req.Payload)
						switch req.Type {
						case "exec":
							go handleExecRequest(ctx, channel, req)
						default:
							req.Reply(false, nil)
						}

					case <-ctx.Done():
						return
					}
				}
			}(ctx, requests)

		case <-ctx.Done():
			return
		}
	}
	l.Println("handleSSHConnection: connection closed")
}

func handleExecRequest(ctx context.Context, channel ssh.Channel, req *ssh.Request) {
	defer channel.Close()

	l, ok := ctx.Value(loggerKey).(*log.Logger)
	if !ok || l == nil {
		l = log.New(os.Stderr, "", log.LstdFlags)
	}

	parts := strings.Split(string(req.Payload), " ")
	exe := parts[0][4:]

	if exe != "scp" {
		l.Println("remote requested", exe, "denying")
		req.Reply(false, nil)
		return
	}

	select {
	case <-ctx.Done():
		return
	default:
	}

	cmd := exec.CommandContext(ctx, exe, parts[1:]...)
	cmd.Stdin = channel
	cmd.Stdout = channel
	cmd.Stderr = os.Stderr

	exitCode := 0
	if err := cmd.Run(); err != nil {
		l.Println("error running", exe, err)
		exitCode = 1

		// TODO get exit code from err.(*exec.ExitStatus)
	} else {
		l.Println(exe, "completed successfully")
	}

	var buf bytes.Buffer
	if err := binary.Write(&buf, binary.BigEndian, int32(exitCode)); err != nil {
		l.Println("unable to convert int32 to byte")
		return
	}
	channel.SendRequest("exit-status", false, buf.Bytes())
}
<|endoftext|>


<commit_before>package git

import (
	"archive/tar"
	"bytes"
	"fmt"
	"io"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
	"time"
)

var logger = log.New(os.Stderr, "", 0)

type Repository struct {
	Origin    string
	LocalPath string
}

func (repo *Repository) cacheDir() string {
	return os.Getenv("HOME") + "/.dgtk/cache/git_repositories"
}

func (repo *Repository) Fetch() error {
	logger.Println("fetching origin")
	_, e := repo.executeGitCommand("fetch")
	return e
}

const githubPrefix = "git@github.com:"

func (repo *Repository) clone() error {
	logger.Printf("cloning %s into %s", repo.Origin, repo.localPath())
	cmd := exec.Command("git", "clone", "--bare", repo.Origin, repo.localPath())
	if b, e := cmd.CombinedOutput(); e != nil {
		logger.Printf("ERROR: %s", strings.TrimSpace(string(b)))
		return e
	}
	cmd = exec.Command("git", "--git-dir="+repo.localPath(), "config", "remote.origin.fetch", "refs/heads/*:refs/heads/*")
	if b, e := cmd.CombinedOutput(); e != nil {
		logger.Printf("ERROR: %s", strings.TrimSpace(string(b)))
		return e
	}
	return nil
}

func (repo *Repository) Init() error {
	e := os.MkdirAll(repo.cacheDir(), 0755)
	if e != nil {
		return e
	}

	if !fileExists(repo.localPath()) {
		if e := repo.clone(); e != nil {
			return e
		}
	} else {
		logger.Printf("already cloned %s to %s", repo.Origin, repo.localPath())
	}
	return nil
}

func (repo *Repository) createGitCommand(gitCommand ...string) *exec.Cmd {
	return exec.Command("git", append([]string{"--git-dir=" + repo.localPath()}, gitCommand...)...)
}

func (repo *Repository) executeGitCommand(gitCommand ...string) (b []byte, e error) {
	cmd := repo.createGitCommand(gitCommand...)
	b, e = cmd.CombinedOutput()
	if e != nil {
		logger.Printf("ERROR: %s (%v)", strings.TrimSpace(string(b)), cmd)
		return b, e
	}
	return b, nil
}

func (repo *Repository) MostRecentCommitFor(pattern string) (commit string, e error) {
	commits, e := repo.Commits(&CommitOptions{Limit: 1, Pattern: pattern})
	if e != nil {
		return "", e
	}
	if len(commits) == 0 {
		return "", e
	}
	return commits[0].Checksum, nil
}

var validTar = regexp.MustCompile("^([0-9a-f]{40})$")

// Writes tgz archive to the given tar writer.
func (repo *Repository) WriteArchiveToTar(revision string, w *tar.Writer) (e error) {
	if !validTar.MatchString(revision) {
		return fmt.Errorf("revision %q not valid (must be 40 digit git sha)", revision)
	}

	mtime, e := repo.DateOf(revision, ".")
	if e != nil {
		return e
	}

	e = repo.addArchiveToTar(revision, mtime, w)
	if e != nil {
		return e
	}

	return addFileToArchive("REVISION", []byte(revision), mtime, w)
}

func (repo *Repository) WriteFilesToTar(revision string, w *tar.Writer, files ...string) (e error) {
	if len(files) == 0 {
		return fmt.Errorf("empty file list given")
	}

	if !validTar.MatchString(revision) {
		return fmt.Errorf("revision %q not valid (must be 40 digit git sha)", revision)
	}

	for _, file := range files {
		mtime, e := repo.DateOf(revision, file)
		if e != nil {
			return e
		}

		buf, e := repo.getFileAtRevision(revision, file)
		if e != nil {
			return e
		}

		if e = addFileToArchive(file, buf, mtime, w); e != nil {
			return e
		}
	}

	return nil
}

func (repo *Repository) getFileAtRevision(revision, file string) (content []byte, e error) {
	buf := bytes.NewBuffer(nil)

	cmd := repo.createGitCommand("show", revision+":"+file)
	cmd.Stdout = buf

	if e = cmd.Run(); e != nil {
		return nil, e
	}

	return buf.Bytes(), nil
}

func addFileToArchive(name string, content []byte, modTime time.Time, w *tar.Writer) error {
	e := w.WriteHeader(&tar.Header{Name: name, Size: int64(len(content)), ModTime: modTime, Mode: 0644})
	if e != nil {
		return e
	}
	_, e = w.Write(content)
	return e
}

func (repo *Repository) addArchiveToTar(revision string, mtime time.Time, w *tar.Writer) (e error) {
	filename := repo.Name() + ".tar.gz"

	buf := bytes.NewBuffer(nil)

	cmd := repo.createGitCommand("archive", "--format=tar.gz", revision)
	cmd.Stdout = buf

	if e = cmd.Run(); e != nil {
		return e
	}

	e = w.WriteHeader(&tar.Header{Name: filename, Size: int64(buf.Len()), ModTime: mtime, Mode: 0644})
	if e != nil {
		return e
	}

	_, e = io.Copy(w, buf)
	return e
}

func (repo *Repository) Name() string {
	return strings.TrimSuffix(filepath.Base(repo.Origin), ".git")
}

func (repo *Repository) DateOf(revision, file string) (time.Time, error) {
	b, e := repo.executeGitCommand("log", "-1", "--format='%ct'", revision, "--", file)
	if e != nil {
		return time.Now(), e
	}
	d, e := strconv.Atoi(strings.Trim(string(b), "'\n"))
	if e != nil {
		return time.Now(), e
	}

	return time.Unix(int64(d), 0), nil
}

func (repo *Repository) localPath() string {
	if repo.LocalPath == "" {
		name := repo.Name()
		if strings.HasPrefix(repo.Origin, githubPrefix) {
			name = strings.TrimPrefix(repo.Origin, githubPrefix)
			repo.LocalPath = repo.cacheDir() + "/github.com/" + name
		} else {
			repo.LocalPath = repo.cacheDir() + "/" + repo.Name()
		}
	}
	return repo.LocalPath
}

func (repo *Repository) Commits(options *CommitOptions) (commits []*Commit, e error) {
	if options == nil {
		options = &CommitOptions{Limit: 10}
	}

	parts := []string{"log", "-n", strconv.Itoa(options.Limit), "--pretty=format:%H\t%at\t%s"}
	if options.Pattern != "" {
		parts = append(parts, options.Pattern)
	}
	b, e := repo.executeGitCommand(parts...)
	if e != nil {
		return nil, e
	}
	lines := strings.Split(string(b), "\n")
	commits = make([]*Commit, 0, len(lines))

	for _, line := range lines {
		parts := strings.SplitN(line, "\t", 3)
		if len(parts) == 3 {
			if t, e := strconv.ParseInt(parts[1], 10, 64); e == nil {
				commits = append(commits, &Commit{Checksum: parts[0], AuthorDate: time.Unix(t, 0), Message: parts[2]})
			} else {
				logger.Printf("ERROR: %s", e.Error())
			}
		}
	}
	return commits, nil
}

func fileExists(path string) bool {
	_, err := os.Stat(path)
	return err == nil || !os.IsNotExist(err)
}
<commit_msg>added force flag to git fetch<commit_after>package git

import (
	"archive/tar"
	"bytes"
	"fmt"
	"io"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
	"time"
)

var logger = log.New(os.Stderr, "", 0)

type Repository struct {
	Origin    string
	LocalPath string
}

func (repo *Repository) cacheDir() string {
	return os.Getenv("HOME") + "/.dgtk/cache/git_repositories"
}

func (repo *Repository) Fetch() error {
	logger.Println("fetching origin")
	// -f is required to make sure force pushes will properly update.
	_, e := repo.executeGitCommand("fetch", "-f")
	return e
}

const githubPrefix = "git@github.com:"

func (repo *Repository) clone() error {
	logger.Printf("cloning %s into %s", repo.Origin, repo.localPath())
	cmd := exec.Command("git", "clone", "--bare", repo.Origin, repo.localPath())
	if b, e := cmd.CombinedOutput(); e != nil {
		logger.Printf("ERROR: %s", strings.TrimSpace(string(b)))
		return e
	}
	cmd = exec.Command("git", "--git-dir="+repo.localPath(), "config", "remote.origin.fetch", "refs/heads/*:refs/heads/*")
	if b, e := cmd.CombinedOutput(); e != nil {
		logger.Printf("ERROR: %s", strings.TrimSpace(string(b)))
		return e
	}
	return nil
}

func (repo *Repository) Init() error {
	e := os.MkdirAll(repo.cacheDir(), 0755)
	if e != nil {
		return e
	}

	if !fileExists(repo.localPath()) {
		if e := repo.clone(); e != nil {
			return e
		}
	} else {
		logger.Printf("already cloned %s to %s", repo.Origin, repo.localPath())
	}
	return nil
}

func (repo *Repository) createGitCommand(gitCommand ...string) *exec.Cmd {
	return exec.Command("git", append([]string{"--git-dir=" + repo.localPath()}, gitCommand...)...)
}

func (repo *Repository) executeGitCommand(gitCommand ...string) (b []byte, e error) {
	cmd := repo.createGitCommand(gitCommand...)
	b, e = cmd.CombinedOutput()
	if e != nil {
		logger.Printf("ERROR: %s (%v)", strings.TrimSpace(string(b)), cmd)
		return b, e
	}
	return b, nil
}

func (repo *Repository) MostRecentCommitFor(pattern string) (commit string, e error) {
	commits, e := repo.Commits(&CommitOptions{Limit: 1, Pattern: pattern})
	if e != nil {
		return "", e
	}
	if len(commits) == 0 {
		return "", e
	}
	return commits[0].Checksum, nil
}

var validTar = regexp.MustCompile("^([0-9a-f]{40})$")

// Writes tgz archive to the given tar writer.
func (repo *Repository) WriteArchiveToTar(revision string, w *tar.Writer) (e error) {
	if !validTar.MatchString(revision) {
		return fmt.Errorf("revision %q not valid (must be 40 digit git sha)", revision)
	}

	mtime, e := repo.DateOf(revision, ".")
	if e != nil {
		return e
	}

	e = repo.addArchiveToTar(revision, mtime, w)
	if e != nil {
		return e
	}

	return addFileToArchive("REVISION", []byte(revision), mtime, w)
}

func (repo *Repository) WriteFilesToTar(revision string, w *tar.Writer, files ...string) (e error) {
	if len(files) == 0 {
		return fmt.Errorf("empty file list given")
	}

	if !validTar.MatchString(revision) {
		return fmt.Errorf("revision %q not valid (must be 40 digit git sha)", revision)
	}

	for _, file := range files {
		mtime, e := repo.DateOf(revision, file)
		if e != nil {
			return e
		}

		buf, e := repo.getFileAtRevision(revision, file)
		if e != nil {
			return e
		}

		if e = addFileToArchive(file, buf, mtime, w); e != nil {
			return e
		}
	}

	return nil
}

func (repo *Repository) getFileAtRevision(revision, file string) (content []byte, e error) {
	buf := bytes.NewBuffer(nil)

	cmd := repo.createGitCommand("show", revision+":"+file)
	cmd.Stdout = buf

	if e = cmd.Run(); e != nil {
		return nil, e
	}

	return buf.Bytes(), nil
}

func addFileToArchive(name string, content []byte, modTime time.Time, w *tar.Writer) error {
	e := w.WriteHeader(&tar.Header{Name: name, Size: int64(len(content)), ModTime: modTime, Mode: 0644})
	if e != nil {
		return e
	}
	_, e = w.Write(content)
	return e
}

func (repo *Repository) addArchiveToTar(revision string, mtime time.Time, w *tar.Writer) (e error) {
	filename := repo.Name() + ".tar.gz"

	buf := bytes.NewBuffer(nil)

	cmd := repo.createGitCommand("archive", "--format=tar.gz", revision)
	cmd.Stdout = buf

	if e = cmd.Run(); e != nil {
		return e
	}

	e = w.WriteHeader(&tar.Header{Name: filename, Size: int64(buf.Len()), ModTime: mtime, Mode: 0644})
	if e != nil {
		return e
	}

	_, e = io.Copy(w, buf)
	return e
}

func (repo *Repository) Name() string {
	return strings.TrimSuffix(filepath.Base(repo.Origin), ".git")
}

func (repo *Repository) DateOf(revision, file string) (time.Time, error) {
	b, e := repo.executeGitCommand("log", "-1", "--format='%ct'", revision, "--", file)
	if e != nil {
		return time.Now(), e
	}
	d, e := strconv.Atoi(strings.Trim(string(b), "'\n"))
	if e != nil {
		return time.Now(), e
	}

	return time.Unix(int64(d), 0), nil
}

func (repo *Repository) localPath() string {
	if repo.LocalPath == "" {
		name := repo.Name()
		if strings.HasPrefix(repo.Origin, githubPrefix) {
			name = strings.TrimPrefix(repo.Origin, githubPrefix)
			repo.LocalPath = repo.cacheDir() + "/github.com/" + name
		} else {
			repo.LocalPath = repo.cacheDir() + "/" + repo.Name()
		}
	}
	return repo.LocalPath
}

func (repo *Repository) Commits(options *CommitOptions) (commits []*Commit, e error) {
	if options == nil {
		options = &CommitOptions{Limit: 10}
	}

	parts := []string{"log", "-n", strconv.Itoa(options.Limit), "--pretty=format:%H\t%at\t%s"}
	if options.Pattern != "" {
		parts = append(parts, options.Pattern)
	}
	b, e := repo.executeGitCommand(parts...)
	if e != nil {
		return nil, e
	}
	lines := strings.Split(string(b), "\n")
	commits = make([]*Commit, 0, len(lines))

	for _, line := range lines {
		parts := strings.SplitN(line, "\t", 3)
		if len(parts) == 3 {
			if t, e := strconv.ParseInt(parts[1], 10, 64); e == nil {
				commits = append(commits, &Commit{Checksum: parts[0], AuthorDate: time.Unix(t, 0), Message: parts[2]})
			} else {
				logger.Printf("ERROR: %s", e.Error())
			}
		}
	}
	return commits, nil
}

func fileExists(path string) bool {
	_, err := os.Stat(path)
	return err == nil || !os.IsNotExist(err)
}
<|endoftext|>


<commit_before>// Copyright 2016 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

package main

import (
	"bytes"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"runtime"
	"sort"
	"strings"

	"github.com/google/syzkaller/pkg/ast"
	"github.com/google/syzkaller/pkg/compiler"
	"github.com/google/syzkaller/pkg/osutil"
	"github.com/google/syzkaller/sys/targets"
)

var (
	flagOS        = flag.String("os", runtime.GOOS, "target OS")
	flagBuild     = flag.Bool("build", false, "regenerate arch-specific kernel headers")
	flagSourceDir = flag.String("sourcedir", "", "path to kernel source checkout dir")
	flagIncludes  = flag.String("includedirs", "", "path to other kernel source include dirs separated by commas")
	flagBuildDir  = flag.String("builddir", "", "path to kernel build dir")
	flagArch      = flag.String("arch", "", "comma-separated list of arches to generate (all by default)")
)

type Arch struct {
	target      *targets.Target
	sourceDir   string
	includeDirs string
	buildDir    string
	build       bool
	files       []*File
	err         error
	done        chan bool
}

type File struct {
	arch       *Arch
	name       string
	consts     map[string]uint64
	undeclared map[string]bool
	info       *compiler.ConstInfo
	err        error
	done       chan bool
}

type Extractor interface {
	prepare(sourcedir string, build bool, arches []string) error
	prepareArch(arch *Arch) error
	processFile(arch *Arch, info *compiler.ConstInfo) (map[string]uint64, map[string]bool, error)
}

var extractors = map[string]Extractor{
	"akaros":  new(akaros),
	"linux":   new(linux),
	"freebsd": new(freebsd),
	"netbsd":  new(netbsd),
	"openbsd": new(openbsd),
	"android": new(linux),
	"fuchsia": new(fuchsia),
	"windows": new(windows),
	"trusty":  new(trusty),
}

func main() {
	failf := func(msg string, args ...interface{}) {
		fmt.Fprintf(os.Stderr, msg+"\n", args...)
		os.Exit(1)
	}
	flag.Parse()
	if *flagBuild && *flagBuildDir != "" {
		failf("-build and -builddir is an invalid combination")
	}

	OS, archArray, files, err := archFileList(*flagOS, *flagArch, flag.Args())
	if err != nil {
		failf("%v", err)
	}

	extractor := extractors[OS]
	if extractor == nil {
		failf("unknown os: %v", OS)
	}
	if err := extractor.prepare(*flagSourceDir, *flagBuild, archArray); err != nil {
		failf("%v", err)
	}

	arches, err := createArches(OS, archArray, files)
	if err != nil {
		failf("%v", err)
	}
	jobC := make(chan interface{}, len(archArray)*len(files))
	for _, arch := range arches {
		jobC <- arch
	}

	for p := 0; p < runtime.GOMAXPROCS(0); p++ {
		go func() {
			for job := range jobC {
				switch j := job.(type) {
				case *Arch:
					infos, err := processArch(extractor, j)
					j.err = err
					close(j.done)
					if j.err == nil {
						for _, f := range j.files {
							f.info = infos[f.name]
							jobC <- f
						}
					}
				case *File:
					j.consts, j.undeclared, j.err = processFile(extractor, j.arch, j)
					close(j.done)
				}
			}
		}()
	}

	failed := false
	for _, arch := range arches {
		fmt.Printf("generating %v/%v...\n", arch.target.OS, arch.target.Arch)
		<-arch.done
		if arch.err != nil {
			failed = true
			fmt.Printf("	%v\n", arch.err)
			continue
		}
		for _, f := range arch.files {
			<-f.done
			if f.err != nil {
				failed = true
				fmt.Printf("%v: %v\n", f.name, f.err)
				continue
			}
		}
	}

	if !failed {
		failed = checkUnsupportedCalls(arches)
	}
	for _, arch := range arches {
		if arch.build {
			os.RemoveAll(arch.buildDir)
		}
	}
	if failed {
		os.Exit(1)
	}
}

func createArches(OS string, archArray, files []string) ([]*Arch, error) {
	var arches []*Arch
	for _, archStr := range archArray {
		buildDir := ""
		if *flagBuild {
			dir, err := ioutil.TempDir("", "syzkaller-kernel-build")
			if err != nil {
				return nil, fmt.Errorf("failed to create temp dir: %v", err)
			}
			buildDir = dir
		} else if *flagBuildDir != "" {
			buildDir = *flagBuildDir
		} else {
			buildDir = *flagSourceDir
		}

		target := targets.Get(OS, archStr)
		if target == nil {
			return nil, fmt.Errorf("unknown arch: %v", archStr)
		}

		arch := &Arch{
			target:      target,
			sourceDir:   *flagSourceDir,
			includeDirs: *flagIncludes,
			buildDir:    buildDir,
			build:       *flagBuild,
			done:        make(chan bool),
		}
		for _, f := range files {
			arch.files = append(arch.files, &File{
				arch: arch,
				name: f,
				done: make(chan bool),
			})
		}
		arches = append(arches, arch)
	}
	return arches, nil
}

func checkUnsupportedCalls(arches []*Arch) bool {
	supported := make(map[string]bool)
	unsupported := make(map[string]string)
	for _, arch := range arches {
		for _, f := range arch.files {
			for name := range f.consts {
				supported[name] = true
			}
			for name := range f.undeclared {
				unsupported[name] = f.name
			}
		}
	}
	failed := false
	for name, file := range unsupported {
		if supported[name] {
			continue
		}
		failed = true
		fmt.Printf("%v: %v is unsupported on all arches (typo?)\n",
			file, name)
	}
	return failed
}

func archFileList(os, arch string, files []string) (string, []string, []string, error) {
	// Note: this is linux-specific and should be part of Extractor and moved to linux.go.
	android := false
	if os == "android" {
		android = true
		os = "linux"
	}
	var arches []string
	if arch != "" {
		arches = strings.Split(arch, ",")
	} else {
		for arch := range targets.List[os] {
			arches = append(arches, arch)
		}
		if android {
			arches = []string{"386", "amd64", "arm", "arm64"}
		}
		sort.Strings(arches)
	}
	if len(files) == 0 {
		matches, err := filepath.Glob(filepath.Join("sys", os, "*.txt"))
		if err != nil || len(matches) == 0 {
			return "", nil, nil, fmt.Errorf("failed to find sys files: %v", err)
		}
		manualFiles := map[string]bool{
			// Not upstream, generated on https://github.com/multipath-tcp/mptcp_net-next
			"mptcp.txt": true,
			// Not upstream, generated on unknown tree.
			"futex.txt": true,
			// Was in linux-next, but then was removed, fate is unknown.
			"watch_queue.txt": true,
		}
		androidFiles := map[string]bool{
			"dev_tlk_device.txt": true,
			// This was generated on:
			// https://source.codeaurora.org/quic/la/kernel/msm-4.9 msm-4.9
			"dev_video4linux.txt": true,
		}
		for _, f := range matches {
			f = filepath.Base(f)
			if manualFiles[f] || os == "linux" && android != androidFiles[f] {
				continue
			}
			files = append(files, f)
		}
		sort.Strings(files)
	}
	return os, arches, files, nil
}

func processArch(extractor Extractor, arch *Arch) (map[string]*compiler.ConstInfo, error) {
	errBuf := new(bytes.Buffer)
	eh := func(pos ast.Pos, msg string) {
		fmt.Fprintf(errBuf, "%v: %v\n", pos, msg)
	}
	top := ast.ParseGlob(filepath.Join("sys", arch.target.OS, "*.txt"), eh)
	if top == nil {
		return nil, fmt.Errorf("%v", errBuf.String())
	}
	infos := compiler.ExtractConsts(top, arch.target, eh)
	if infos == nil {
		return nil, fmt.Errorf("%v", errBuf.String())
	}
	if err := extractor.prepareArch(arch); err != nil {
		return nil, err
	}
	return infos, nil
}

func processFile(extractor Extractor, arch *Arch, file *File) (map[string]uint64, map[string]bool, error) {
	inname := filepath.Join("sys", arch.target.OS, file.name)
	outname := strings.TrimSuffix(inname, ".txt") + "_" + arch.target.Arch + ".const"
	if file.info == nil {
		return nil, nil, fmt.Errorf("input file %v is missing", inname)
	}
	if len(file.info.Consts) == 0 {
		os.Remove(outname)
		return nil, nil, nil
	}
	consts, undeclared, err := extractor.processFile(arch, file.info)
	if err != nil {
		return nil, nil, err
	}
	data := compiler.SerializeConsts(consts, undeclared)
	if err := osutil.WriteFile(outname, data); err != nil {
		return nil, nil, fmt.Errorf("failed to write output file: %v", err)
	}
	return consts, undeclared, nil
}
<commit_msg>sys/syz-extract: fix output formatting<commit_after>// Copyright 2016 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

package main

import (
	"bytes"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"runtime"
	"sort"
	"strings"

	"github.com/google/syzkaller/pkg/ast"
	"github.com/google/syzkaller/pkg/compiler"
	"github.com/google/syzkaller/pkg/osutil"
	"github.com/google/syzkaller/sys/targets"
)

var (
	flagOS        = flag.String("os", runtime.GOOS, "target OS")
	flagBuild     = flag.Bool("build", false, "regenerate arch-specific kernel headers")
	flagSourceDir = flag.String("sourcedir", "", "path to kernel source checkout dir")
	flagIncludes  = flag.String("includedirs", "", "path to other kernel source include dirs separated by commas")
	flagBuildDir  = flag.String("builddir", "", "path to kernel build dir")
	flagArch      = flag.String("arch", "", "comma-separated list of arches to generate (all by default)")
)

type Arch struct {
	target      *targets.Target
	sourceDir   string
	includeDirs string
	buildDir    string
	build       bool
	files       []*File
	err         error
	done        chan bool
}

type File struct {
	arch       *Arch
	name       string
	consts     map[string]uint64
	undeclared map[string]bool
	info       *compiler.ConstInfo
	err        error
	done       chan bool
}

type Extractor interface {
	prepare(sourcedir string, build bool, arches []string) error
	prepareArch(arch *Arch) error
	processFile(arch *Arch, info *compiler.ConstInfo) (map[string]uint64, map[string]bool, error)
}

var extractors = map[string]Extractor{
	"akaros":  new(akaros),
	"linux":   new(linux),
	"freebsd": new(freebsd),
	"netbsd":  new(netbsd),
	"openbsd": new(openbsd),
	"android": new(linux),
	"fuchsia": new(fuchsia),
	"windows": new(windows),
	"trusty":  new(trusty),
}

func main() {
	failf := func(msg string, args ...interface{}) {
		fmt.Fprintf(os.Stderr, msg+"\n", args...)
		os.Exit(1)
	}
	flag.Parse()
	if *flagBuild && *flagBuildDir != "" {
		failf("-build and -builddir is an invalid combination")
	}

	OS, archArray, files, err := archFileList(*flagOS, *flagArch, flag.Args())
	if err != nil {
		failf("%v", err)
	}

	extractor := extractors[OS]
	if extractor == nil {
		failf("unknown os: %v", OS)
	}
	if err := extractor.prepare(*flagSourceDir, *flagBuild, archArray); err != nil {
		failf("%v", err)
	}

	arches, err := createArches(OS, archArray, files)
	if err != nil {
		failf("%v", err)
	}
	jobC := make(chan interface{}, len(archArray)*len(files))
	for _, arch := range arches {
		jobC <- arch
	}

	for p := 0; p < runtime.GOMAXPROCS(0); p++ {
		go func() {
			for job := range jobC {
				switch j := job.(type) {
				case *Arch:
					infos, err := processArch(extractor, j)
					j.err = err
					close(j.done)
					if j.err == nil {
						for _, f := range j.files {
							f.info = infos[f.name]
							jobC <- f
						}
					}
				case *File:
					j.consts, j.undeclared, j.err = processFile(extractor, j.arch, j)
					close(j.done)
				}
			}
		}()
	}

	failed := false
	for _, arch := range arches {
		fmt.Printf("generating %v/%v...\n", arch.target.OS, arch.target.Arch)
		<-arch.done
		if arch.err != nil {
			failed = true
			fmt.Printf("%v\n", arch.err)
			continue
		}
		for _, f := range arch.files {
			<-f.done
			if f.err != nil {
				failed = true
				fmt.Printf("%v: %v\n", f.name, f.err)
				continue
			}
		}
	}

	if !failed {
		failed = checkUnsupportedCalls(arches)
	}
	for _, arch := range arches {
		if arch.build {
			os.RemoveAll(arch.buildDir)
		}
	}
	if failed {
		os.Exit(1)
	}
}

func createArches(OS string, archArray, files []string) ([]*Arch, error) {
	var arches []*Arch
	for _, archStr := range archArray {
		buildDir := ""
		if *flagBuild {
			dir, err := ioutil.TempDir("", "syzkaller-kernel-build")
			if err != nil {
				return nil, fmt.Errorf("failed to create temp dir: %v", err)
			}
			buildDir = dir
		} else if *flagBuildDir != "" {
			buildDir = *flagBuildDir
		} else {
			buildDir = *flagSourceDir
		}

		target := targets.Get(OS, archStr)
		if target == nil {
			return nil, fmt.Errorf("unknown arch: %v", archStr)
		}

		arch := &Arch{
			target:      target,
			sourceDir:   *flagSourceDir,
			includeDirs: *flagIncludes,
			buildDir:    buildDir,
			build:       *flagBuild,
			done:        make(chan bool),
		}
		for _, f := range files {
			arch.files = append(arch.files, &File{
				arch: arch,
				name: f,
				done: make(chan bool),
			})
		}
		arches = append(arches, arch)
	}
	return arches, nil
}

func checkUnsupportedCalls(arches []*Arch) bool {
	supported := make(map[string]bool)
	unsupported := make(map[string]string)
	for _, arch := range arches {
		for _, f := range arch.files {
			for name := range f.consts {
				supported[name] = true
			}
			for name := range f.undeclared {
				unsupported[name] = f.name
			}
		}
	}
	failed := false
	for name, file := range unsupported {
		if supported[name] {
			continue
		}
		failed = true
		fmt.Printf("%v: %v is unsupported on all arches (typo?)\n",
			file, name)
	}
	return failed
}

func archFileList(os, arch string, files []string) (string, []string, []string, error) {
	// Note: this is linux-specific and should be part of Extractor and moved to linux.go.
	android := false
	if os == "android" {
		android = true
		os = "linux"
	}
	var arches []string
	if arch != "" {
		arches = strings.Split(arch, ",")
	} else {
		for arch := range targets.List[os] {
			arches = append(arches, arch)
		}
		if android {
			arches = []string{"386", "amd64", "arm", "arm64"}
		}
		sort.Strings(arches)
	}
	if len(files) == 0 {
		matches, err := filepath.Glob(filepath.Join("sys", os, "*.txt"))
		if err != nil || len(matches) == 0 {
			return "", nil, nil, fmt.Errorf("failed to find sys files: %v", err)
		}
		manualFiles := map[string]bool{
			// Not upstream, generated on https://github.com/multipath-tcp/mptcp_net-next
			"mptcp.txt": true,
			// Not upstream, generated on unknown tree.
			"futex.txt": true,
			// Was in linux-next, but then was removed, fate is unknown.
			"watch_queue.txt": true,
		}
		androidFiles := map[string]bool{
			"dev_tlk_device.txt": true,
			// This was generated on:
			// https://source.codeaurora.org/quic/la/kernel/msm-4.9 msm-4.9
			"dev_video4linux.txt": true,
		}
		for _, f := range matches {
			f = filepath.Base(f)
			if manualFiles[f] || os == "linux" && android != androidFiles[f] {
				continue
			}
			files = append(files, f)
		}
		sort.Strings(files)
	}
	return os, arches, files, nil
}

func processArch(extractor Extractor, arch *Arch) (map[string]*compiler.ConstInfo, error) {
	errBuf := new(bytes.Buffer)
	eh := func(pos ast.Pos, msg string) {
		fmt.Fprintf(errBuf, "%v: %v\n", pos, msg)
	}
	top := ast.ParseGlob(filepath.Join("sys", arch.target.OS, "*.txt"), eh)
	if top == nil {
		return nil, fmt.Errorf("%v", errBuf.String())
	}
	infos := compiler.ExtractConsts(top, arch.target, eh)
	if infos == nil {
		return nil, fmt.Errorf("%v", errBuf.String())
	}
	if err := extractor.prepareArch(arch); err != nil {
		return nil, err
	}
	return infos, nil
}

func processFile(extractor Extractor, arch *Arch, file *File) (map[string]uint64, map[string]bool, error) {
	inname := filepath.Join("sys", arch.target.OS, file.name)
	outname := strings.TrimSuffix(inname, ".txt") + "_" + arch.target.Arch + ".const"
	if file.info == nil {
		return nil, nil, fmt.Errorf("input file %v is missing", inname)
	}
	if len(file.info.Consts) == 0 {
		os.Remove(outname)
		return nil, nil, nil
	}
	consts, undeclared, err := extractor.processFile(arch, file.info)
	if err != nil {
		return nil, nil, err
	}
	data := compiler.SerializeConsts(consts, undeclared)
	if err := osutil.WriteFile(outname, data); err != nil {
		return nil, nil, fmt.Errorf("failed to write output file: %v", err)
	}
	return consts, undeclared, nil
}
<|endoftext|>


<commit_before>package models

import (
	"fmt"
	"html/template"
	"regexp"
	"strings"
	"time"

	"appengine"
	"appengine/datastore"

	"github.com/kennygrant/sanitize"
	"github.com/russross/blackfriday"
)

type Entry struct {
	Id       int64     `json:"id"`
	Title    string    `json:"title"`                     // optional
	Content  string    `datastore:",noindex" json:"text"` // Markdown
	Datetime time.Time `json:"date"`
	Created  time.Time `json:"created"`
	Modified time.Time `json:"modified"`
	Tags     []string  `json:"tags"`
	Public   bool      `json:"-"`
}

var HashtagRegex *regexp.Regexp = regexp.MustCompile(`(\s)#(\w+)`)
var TwitterHandleRegex *regexp.Regexp = regexp.MustCompile(`(\s)@([_A-Za-z0-9]+)`)

func NewEntry(title string, content string, datetime time.Time, public bool, tags []string) *Entry {
	e := new(Entry)

	// User supplied content
	e.Title = title
	e.Content = content
	e.Datetime = datetime
	e.Tags = tags
	e.Public = public

	// Computer generated content
	e.Created = time.Now()
	e.Modified = time.Now()

	return e
}

func ParseTags(text string) ([]string, error) {
	// http://golang.org/pkg/regexp/#Regexp.FindAllStringSubmatch
	finds := HashtagRegex.FindAllStringSubmatch(text, -1)
	ret := make([]string, 0)
	for _, v := range finds {
		if len(v) > 2 {
			ret = append(ret, strings.ToLower(v[2]))
		}
	}

	return ret, nil
}

func GetEntry(c appengine.Context, id int64) (*Entry, error) {
	var entry Entry
	q := datastore.NewQuery("Entry").Filter("Id =", id).Limit(1)
	_, err := q.Run(c).Next(&entry)
	if err != nil {
		c.Warningf("Error getting entry %d", id)
		return nil, err
	}

	return &entry, nil
}

func MaxId(c appengine.Context) (int64, error) {
	var entry Entry
	q := datastore.NewQuery("Entry").Order("-Id").Limit(1)
	_, err := q.Run(c).Next(&entry)
	if err != nil {
		return 0, err
	}
	return entry.Id, nil
}

func AllPosts(c appengine.Context) (*[]Entry, error) {
	return Posts(c, -1, true)
}

func Posts(c appengine.Context, limit int, recentFirst bool) (*[]Entry, error) {
	q := datastore.NewQuery("Entry").Filter("Public =", true)

	if recentFirst {
		q = q.Order("-Datetime")
	} else {
		q = q.Order("Datetime")
	}

	if limit > 0 {
		q = q.Limit(limit)
	}

	entries := new([]Entry)
	_, err := q.GetAll(c, entries)
	return entries, err
}

func RecentPosts(c appengine.Context) (*[]Entry, error) {
	return Posts(c, 20, true)
}

func (e *Entry) HasId() bool {
	return (e.Id > 0)
}

func (e *Entry) Save(c appengine.Context) error {
	var k *datastore.Key
	if !e.HasId() {
		id, _ := MaxId(c)
		e.Id = id + 1
		k = datastore.NewIncompleteKey(c, "Entry", nil)
	} else {
		// Find the key
		var err error
		q := datastore.NewQuery("Entry").Filter("Id =", e.Id).Limit(1).KeysOnly()
		k, err = q.Run(c).Next(nil)
		if err != nil {
			return err
		}
	}

	// Pull out links
	GetLinksFromContent(c, e.Content)

	// Figure out Tags
	tags, err := ParseTags(e.Content)
	if err != nil {
		return err
	}
	e.Tags = tags

	k2, err := datastore.Put(c, k, e)
	if err == nil {
		c.Infof("Wrote %+v", e)
		c.Infof("Old key: %+v; New Key: %+v", k, k2)
	} else {
		c.Warningf("Error writing entry: %v", e)
	}
	return err
}

func (e *Entry) Url() string {
	return fmt.Sprintf("/post/%d", e.Id)
}

func (e *Entry) EditUrl() string {
	return fmt.Sprintf("/edit/%d", e.Id)
}

func (e *Entry) Html() template.HTML {
	return Markdown(e.Content)
}

func (e *Entry) Summary() string {
	// truncate(strip_tags(m(p.text)), :length => 100).strip
	stripped := sanitize.HTML(string(e.Html()))
	if len(stripped) > 100 {
		return fmt.Sprintf("%s...", stripped[:100])
	} else {
		return stripped
	}
}

func (e *Entry) PrevPost(c appengine.Context) string {
	var entry Entry
	q := datastore.NewQuery("Entry").Order("-Datetime").Filter("Datetime <", e.Datetime).Limit(1)
	_, err := q.Run(c).Next(&entry)
	if err != nil {
		c.Infof("Error getting previous post for %d.", e.Id)
		return ""
	}

	return entry.Url()
}

func (e *Entry) NextPost(c appengine.Context) string {
	var entry Entry
	q := datastore.NewQuery("Entry").Order("Datetime").Filter("Datetime >", e.Datetime).Limit(1)
	_, err := q.Run(c).Next(&entry)
	if err != nil {
		c.Infof("Error getting next post for %d.", e.Id)
		return ""
	}

	return entry.Url()
}

// TODO(icco): Actually finish this.
func GetLinksFromContent(c appengine.Context, content string) ([]string, error) {
	httpRegex := regexp.MustCompile(`http:\/\/((\w|\.)+)`)
	matches := httpRegex.FindAllString(content, -1)
	if matches == nil {
		return []string{}, nil
	}

	for _, match := range matches {
		c.Infof("%+v", match)
	}

	return []string{}, nil
}

func PostsWithTag(c appengine.Context, tag string) (*map[int64]Entry, error) {
	aliases := new([]Alias)
	entries := make(map[int64]Entry, 0)

	q := datastore.NewQuery("Alias").Filter("Tag =", tag)
	_, err := q.GetAll(c, aliases)
	if err != nil {
		return nil, err
	}

	for _, v := range *aliases {
		more_entries := new([]Entry)
		q := datastore.NewQuery("Entry").Order("-Datetime").Filter("Tags =", tag)
		_, err := q.GetAll(c, more_entries)
		for _, e := range *more_entries {
			entries[e.Id] = e
		}
	}

	return &entries, err
}

// Markdown.
func Markdown(args ...interface{}) template.HTML {
	inc := []byte(fmt.Sprintf("%s", args...))
	inc = twitterHandleToMarkdown(inc)
	inc = hashTagsToMarkdown(inc)
	s := blackfriday.MarkdownCommon(inc)
	return template.HTML(s)
}

func twitterHandleToMarkdown(in []byte) []byte {
	return TwitterHandleRegex.ReplaceAll(in, []byte("$1[@$2](http://twitter.com/$2)"))
}

func hashTagsToMarkdown(in []byte) []byte {
	return HashtagRegex.ReplaceAll(in, []byte("$1[#$2](/tags/$2)"))
}
<commit_msg>maybe<commit_after>package models

import (
	"fmt"
	"html/template"
	"regexp"
	"strings"
	"time"

	"appengine"
	"appengine/datastore"

	"github.com/kennygrant/sanitize"
	"github.com/russross/blackfriday"
)

type Entry struct {
	Id       int64     `json:"id"`
	Title    string    `json:"title"`                     // optional
	Content  string    `datastore:",noindex" json:"text"` // Markdown
	Datetime time.Time `json:"date"`
	Created  time.Time `json:"created"`
	Modified time.Time `json:"modified"`
	Tags     []string  `json:"tags"`
	Public   bool      `json:"-"`
}

var HashtagRegex *regexp.Regexp = regexp.MustCompile(`(\s)#(\w+)`)
var TwitterHandleRegex *regexp.Regexp = regexp.MustCompile(`(\s)@([_A-Za-z0-9]+)`)

func NewEntry(title string, content string, datetime time.Time, public bool, tags []string) *Entry {
	e := new(Entry)

	// User supplied content
	e.Title = title
	e.Content = content
	e.Datetime = datetime
	e.Tags = tags
	e.Public = public

	// Computer generated content
	e.Created = time.Now()
	e.Modified = time.Now()

	return e
}

func ParseTags(text string) ([]string, error) {
	// http://golang.org/pkg/regexp/#Regexp.FindAllStringSubmatch
	finds := HashtagRegex.FindAllStringSubmatch(text, -1)
	ret := make([]string, 0)
	for _, v := range finds {
		if len(v) > 2 {
			ret = append(ret, strings.ToLower(v[2]))
		}
	}

	return ret, nil
}

func GetEntry(c appengine.Context, id int64) (*Entry, error) {
	var entry Entry
	q := datastore.NewQuery("Entry").Filter("Id =", id).Limit(1)
	_, err := q.Run(c).Next(&entry)
	if err != nil {
		c.Warningf("Error getting entry %d", id)
		return nil, err
	}

	return &entry, nil
}

func MaxId(c appengine.Context) (int64, error) {
	var entry Entry
	q := datastore.NewQuery("Entry").Order("-Id").Limit(1)
	_, err := q.Run(c).Next(&entry)
	if err != nil {
		return 0, err
	}
	return entry.Id, nil
}

func AllPosts(c appengine.Context) (*[]Entry, error) {
	return Posts(c, -1, true)
}

func Posts(c appengine.Context, limit int, recentFirst bool) (*[]Entry, error) {
	q := datastore.NewQuery("Entry").Filter("Public =", true)

	if recentFirst {
		q = q.Order("-Datetime")
	} else {
		q = q.Order("Datetime")
	}

	if limit > 0 {
		q = q.Limit(limit)
	}

	entries := new([]Entry)
	_, err := q.GetAll(c, entries)
	return entries, err
}

func RecentPosts(c appengine.Context) (*[]Entry, error) {
	return Posts(c, 20, true)
}

func (e *Entry) HasId() bool {
	return (e.Id > 0)
}

func (e *Entry) Save(c appengine.Context) error {
	var k *datastore.Key
	if !e.HasId() {
		id, _ := MaxId(c)
		e.Id = id + 1
		k = datastore.NewIncompleteKey(c, "Entry", nil)
	} else {
		// Find the key
		var err error
		q := datastore.NewQuery("Entry").Filter("Id =", e.Id).Limit(1).KeysOnly()
		k, err = q.Run(c).Next(nil)
		if err != nil {
			return err
		}
	}

	// Pull out links
	GetLinksFromContent(c, e.Content)

	// Figure out Tags
	tags, err := ParseTags(e.Content)
	if err != nil {
		return err
	}
	e.Tags = tags

	k2, err := datastore.Put(c, k, e)
	if err == nil {
		c.Infof("Wrote %+v", e)
		c.Infof("Old key: %+v; New Key: %+v", k, k2)
	} else {
		c.Warningf("Error writing entry: %v", e)
	}
	return err
}

func (e *Entry) Url() string {
	return fmt.Sprintf("/post/%d", e.Id)
}

func (e *Entry) EditUrl() string {
	return fmt.Sprintf("/edit/%d", e.Id)
}

func (e *Entry) Html() template.HTML {
	return Markdown(e.Content)
}

func (e *Entry) Summary() string {
	// truncate(strip_tags(m(p.text)), :length => 100).strip
	stripped := sanitize.HTML(string(e.Html()))
	if len(stripped) > 100 {
		return fmt.Sprintf("%s...", stripped[:100])
	} else {
		return stripped
	}
}

func (e *Entry) PrevPost(c appengine.Context) string {
	var entry Entry
	q := datastore.NewQuery("Entry").Order("-Datetime").Filter("Datetime <", e.Datetime).Limit(1)
	_, err := q.Run(c).Next(&entry)
	if err != nil {
		c.Infof("Error getting previous post for %d.", e.Id)
		return ""
	}

	return entry.Url()
}

func (e *Entry) NextPost(c appengine.Context) string {
	var entry Entry
	q := datastore.NewQuery("Entry").Order("Datetime").Filter("Datetime >", e.Datetime).Limit(1)
	_, err := q.Run(c).Next(&entry)
	if err != nil {
		c.Infof("Error getting next post for %d.", e.Id)
		return ""
	}

	return entry.Url()
}

// TODO(icco): Actually finish this.
func GetLinksFromContent(c appengine.Context, content string) ([]string, error) {
	httpRegex := regexp.MustCompile(`http:\/\/((\w|\.)+)`)
	matches := httpRegex.FindAllString(content, -1)
	if matches == nil {
		return []string{}, nil
	}

	for _, match := range matches {
		c.Infof("%+v", match)
	}

	return []string{}, nil
}

func PostsWithTag(c appengine.Context, tag string) (*map[int64]Entry, error) {
	aliases := new([]Alias)
	entries := make(map[int64]Entry, 0)

	q := datastore.NewQuery("Alias").Filter("Tag =", tag)
	_, err := q.GetAll(c, aliases)
	if err != nil {
		return nil, err
	}

	for _, v := range *aliases {
		more_entries := new([]Entry)
		q := datastore.NewQuery("Entry").Order("-Datetime").Filter("Tags =", v.Tag)
		_, err := q.GetAll(c, more_entries)
		if err != nil {
			return &entries, err
		}
		for _, e := range *more_entries {
			entries[e.Id] = e
		}
	}

	return &entries, nil
}

// Markdown.
func Markdown(args ...interface{}) template.HTML {
	inc := []byte(fmt.Sprintf("%s", args...))
	inc = twitterHandleToMarkdown(inc)
	inc = hashTagsToMarkdown(inc)
	s := blackfriday.MarkdownCommon(inc)
	return template.HTML(s)
}

func twitterHandleToMarkdown(in []byte) []byte {
	return TwitterHandleRegex.ReplaceAll(in, []byte("$1[@$2](http://twitter.com/$2)"))
}

func hashTagsToMarkdown(in []byte) []byte {
	return HashtagRegex.ReplaceAll(in, []byte("$1[#$2](/tags/$2)"))
}
<|endoftext|>


<commit_before>package models

import (
	"bytes"
	"database/sql"
	"errors"
	"net/http"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	"github.com/chadweimer/gomp/upload"
	"github.com/disintegration/imaging"
	"github.com/jmoiron/sqlx"
	"github.com/rwcarlsen/goexif/exif"
)

// RecipeImageModel provides functionality to edit and retrieve images attached to recipes
type RecipeImageModel struct {
	*Model
	upl upload.Driver
}

// RecipeImage represents the data associated with an image attached to a recipe
type RecipeImage struct {
	ID           int64     `json:"id" db:"id"`
	RecipeID     int64     `json:"recipeId" db:"recipe_id"`
	Name         string    `json:"name" db:"name"`
	URL          string    `json:"url" db:"url"`
	ThumbnailURL string    `json:"thumbnailUrl" db:"thumbnail_url"`
	CreatedAt    time.Time `json:"createdAt" db:"created_at"`
	ModifiedAt   time.Time `json:"modifiedAt" db:"modified_at"`
}

// Create saves the image using the backing upload.Driver and creates
// an associated record in the database using a dedicated transation
// that is committed if there are not errors.
func (m *RecipeImageModel) Create(imageInfo *RecipeImage, imageData []byte) error {
	return m.tx(func(tx *sqlx.Tx) error {
		return m.CreateTx(imageInfo, imageData, tx)
	})
}

// CreateTx saves the image using the backing upload.Driver and creates
// an associated record in the database using the specified transaction.
func (m *RecipeImageModel) CreateTx(imageInfo *RecipeImage, imageData []byte, tx *sqlx.Tx) error {
	origURL, thumbURL, err := m.save(imageInfo, imageData)
	if err != nil {
		return err
	}

	// Since uploading the image was successful, add a record to the DB
	imageInfo.URL = origURL
	imageInfo.ThumbnailURL = thumbURL
	return m.createImpl(imageInfo, tx)
}

func (m *RecipeImageModel) createImpl(image *RecipeImage, tx *sqlx.Tx) error {
	now := time.Now()
	stmt := "INSERT INTO recipe_image (recipe_id, name, url, thumbnail_url, created_at, modified_at) " +
		"VALUES ($1, $2, $3, $4, $5, $6) RETURNING id"

	if err := tx.Get(image, stmt, image.RecipeID, image.Name, image.URL, image.ThumbnailURL, now, now); err != nil {
		return err
	}

	// Switch to a new main image if necessary, since this might be the first image attached
	return m.setMainImageIfNecessary(image.RecipeID, tx)
}

func (m *RecipeImageModel) save(imageInfo *RecipeImage, data []byte) (string, string, error) {
	ok, contentType := isImageFile(data)
	if !ok {
		return "", "", errors.New("Attachment must be an image")
	}

	// First decode the image
	image, err := imaging.Decode(bytes.NewReader(data))
	if err != nil {
		return "", "", err
	}

	// Then generate a thumbnail image
	thumbImage := imaging.Thumbnail(image, 250, 250, imaging.Box)

	// Use the EXIF data to determine the orientation of the original image.
	// This data is lost when generating the thumbnail, so it's needed into
	// order to potentially explicitly rotate it.
	exifData, err := exif.Decode(bytes.NewReader(data))
	if err == nil {
		orientationTag, err := exifData.Get(exif.Orientation)
		if err == nil {
			orientationVal, err := orientationTag.Int(0)
			if err == nil {
				switch orientationVal {
				case 3:
					thumbImage = imaging.Rotate180(thumbImage)
				case 6:
					thumbImage = imaging.Rotate270(thumbImage)
				case 8:
					thumbImage = imaging.Rotate90(thumbImage)
				}
			}
		}
	}
	thumbBuf := new(bytes.Buffer)
	err = imaging.Encode(thumbBuf, thumbImage, getImageFormat(contentType))
	if err != nil {
		return "", "", err
	}

	// Save the original image
	origDir := getDirPathForImage(imageInfo.RecipeID)
	origPath := filepath.Join(origDir, imageInfo.Name)
	origURL := filepath.ToSlash(filepath.Join("/uploads/", origPath))
	err = m.upl.Save(origPath, data)
	if err != nil {
		return "", "", err
	}

	// Save the thumbnail image
	thumbDir := getDirPathForThumbnail(imageInfo.RecipeID)
	thumbPath := filepath.Join(thumbDir, imageInfo.Name)
	thumbURL := filepath.ToSlash(filepath.Join("/uploads/", thumbPath))
	err = m.upl.Save(thumbPath, thumbBuf.Bytes())
	if err != nil {
		return "", "", err
	}

	return origURL, thumbURL, nil
}

// ReadTx retrieves the information about the image from the database, if found,
// using the specified transaction. If no image exists with the specified ID,
// a ErrNotFound error is returned.
func (m *RecipeImageModel) ReadTx(id int64, tx *sqlx.Tx) (*RecipeImage, error) {
	image := new(RecipeImage)
	err := tx.Get(image, "SELECT * FROM recipe_image WHERE id = $1", id)
	if err == sql.ErrNoRows {
		return nil, ErrNotFound
	} else if err != nil {
		return nil, err
	}

	return image, nil
}

// ReadMainImage retrieves the information about the main image for the specified recipe
// image from the database. If no main image exists, a ErrNotFound error is returned.
func (m *RecipeImageModel) ReadMainImage(recipeID int64) (*RecipeImage, error) {
	image := new(RecipeImage)
	err := m.db.Get(image, "SELECT * FROM recipe_image WHERE id = (SELECT image_id FROM recipe WHERE id = $1)", recipeID)
	if err == sql.ErrNoRows {
		return nil, ErrNotFound
	} else if err != nil {
		return nil, err
	}

	return image, nil
}

// UpdateMainImage sets the id of the main image for the specified recipe
// using a dedicated transation that is committed if there are not errors.
func (m *RecipeImageModel) UpdateMainImage(image *RecipeImage) error {
	return m.tx(func(tx *sqlx.Tx) error {
		return m.UpdateMainImageTx(image, tx)
	})
}

// UpdateMainImageTx sets the id of the main image for the specified recipe
// using the specified transaction.
func (m *RecipeImageModel) UpdateMainImageTx(image *RecipeImage, tx *sqlx.Tx) error {
	_, err := tx.Exec(
		"UPDATE recipe SET image_id = $1 WHERE id = $2",
		image.ID, image.RecipeID)

	return err
}

// List returns a RecipeImage slice that contains data for all images
// attached to the specified recipe.
func (m *RecipeImageModel) List(recipeID int64) (*[]RecipeImage, error) {
	var images []RecipeImage

	if err := m.db.Select(&images, "SELECT * FROM recipe_image WHERE recipe_id = $1 ORDER BY created_at ASC", recipeID); err != nil {
		return nil, err
	}

	return &images, nil
}

// Delete removes the specified image from the backing store and database
// using a dedicated transation that is committed if there are not errors.
func (m *RecipeImageModel) Delete(id int64) error {
	return m.tx(func(tx *sqlx.Tx) error {
		return m.DeleteTx(id, tx)
	})
}

// DeleteTx removes the specified image from the backing store and database
// using the specified transaction.
func (m *RecipeImageModel) DeleteTx(id int64, tx *sqlx.Tx) error {
	image, err := m.ReadTx(id, tx)
	if err != nil {
		return err
	}

	origPath := filepath.Join(getDirPathForImage(image.RecipeID), image.Name)
	if err := m.upl.Delete(origPath); err != nil {
		return err
	}
	thumbPath := filepath.Join(getDirPathForThumbnail(image.RecipeID), image.Name)
	if err := m.upl.Delete(thumbPath); err != nil {
		return err
	}

	if _, err = tx.Exec("DELETE FROM recipe_image WHERE id = $1", id); err != nil {
		return err
	}

	// Switch to a new main image if necessary, since the image we just deleted may have been the main image
	return m.setMainImageIfNecessary(image.RecipeID, tx)
}

func (m *RecipeImageModel) setMainImageIfNecessary(recipeID int64, tx *sqlx.Tx) error {
	_, err := tx.Exec(
		"UPDATE recipe "+
			"SET image_id = (SELECT recipe_image.id FROM recipe_image WHERE recipe_image.recipe_id = recipe.id LIMIT 1)"+
			"WHERE id = $1 AND image_id IS NULL",
		recipeID)
	return err
}

// DeleteAll removes all images for the specified recipe from the database
// using a dedicated transation that is committed if there are not errors.
func (m *RecipeImageModel) DeleteAll(recipeID int64) error {
	return m.tx(func(tx *sqlx.Tx) error {
		return m.DeleteAllTx(recipeID, tx)
	})
}

// DeleteAllTx removes all images for the specified recipe from the database
// using the specified transaction.
func (m *RecipeImageModel) DeleteAllTx(recipeID int64, tx *sqlx.Tx) error {
	dirPath := getDirPathForRecipe(recipeID)
	err := m.upl.DeleteAll(dirPath)
	if err != nil {
		return err
	}

	_, err = tx.Exec(
		"DELETE FROM recipe_image WHERE recipe_id = $1",
		recipeID)
	return err
}

func isImageFile(data []byte) (bool, string) {
	contentType := http.DetectContentType(data)
	if strings.Index(contentType, "image/") != -1 {
		return true, contentType
	}
	return false, ""
}

func getImageFormat(contentType string) imaging.Format {
	switch contentType {
	case "image/jpeg":
		return imaging.JPEG
	case "image/png":
		return imaging.PNG
	case "image/gif":
		return imaging.GIF
	case "image/bmp":
		return imaging.BMP
	case "image/tiff":
		return imaging.TIFF
	}
	return imaging.JPEG
}

func getDirPathForRecipe(recipeID int64) string {
	return filepath.Join("recipes", strconv.FormatInt(recipeID, 10))
}

func getDirPathForImage(recipeID int64) string {
	return filepath.Join(getDirPathForRecipe(recipeID), "images")
}

func getDirPathForThumbnail(recipeID int64) string {
	return filepath.Join(getDirPathForRecipe(recipeID), "thumbs")
}
<commit_msg>Thumbnails should be similar byte size as before, but 4 times the resolution. Quality tradeoff is acceptable since detailed images (i.e. food)  tend to do better with jpeg compression (#160)<commit_after>package models

import (
	"bytes"
	"database/sql"
	"errors"
	"net/http"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	"github.com/chadweimer/gomp/upload"
	"github.com/disintegration/imaging"
	"github.com/jmoiron/sqlx"
	"github.com/rwcarlsen/goexif/exif"
)

// RecipeImageModel provides functionality to edit and retrieve images attached to recipes
type RecipeImageModel struct {
	*Model
	upl upload.Driver
}

// RecipeImage represents the data associated with an image attached to a recipe
type RecipeImage struct {
	ID           int64     `json:"id" db:"id"`
	RecipeID     int64     `json:"recipeId" db:"recipe_id"`
	Name         string    `json:"name" db:"name"`
	URL          string    `json:"url" db:"url"`
	ThumbnailURL string    `json:"thumbnailUrl" db:"thumbnail_url"`
	CreatedAt    time.Time `json:"createdAt" db:"created_at"`
	ModifiedAt   time.Time `json:"modifiedAt" db:"modified_at"`
}

// Create saves the image using the backing upload.Driver and creates
// an associated record in the database using a dedicated transation
// that is committed if there are not errors.
func (m *RecipeImageModel) Create(imageInfo *RecipeImage, imageData []byte) error {
	return m.tx(func(tx *sqlx.Tx) error {
		return m.CreateTx(imageInfo, imageData, tx)
	})
}

// CreateTx saves the image using the backing upload.Driver and creates
// an associated record in the database using the specified transaction.
func (m *RecipeImageModel) CreateTx(imageInfo *RecipeImage, imageData []byte, tx *sqlx.Tx) error {
	origURL, thumbURL, err := m.save(imageInfo, imageData)
	if err != nil {
		return err
	}

	// Since uploading the image was successful, add a record to the DB
	imageInfo.URL = origURL
	imageInfo.ThumbnailURL = thumbURL
	return m.createImpl(imageInfo, tx)
}

func (m *RecipeImageModel) createImpl(image *RecipeImage, tx *sqlx.Tx) error {
	now := time.Now()
	stmt := "INSERT INTO recipe_image (recipe_id, name, url, thumbnail_url, created_at, modified_at) " +
		"VALUES ($1, $2, $3, $4, $5, $6) RETURNING id"

	if err := tx.Get(image, stmt, image.RecipeID, image.Name, image.URL, image.ThumbnailURL, now, now); err != nil {
		return err
	}

	// Switch to a new main image if necessary, since this might be the first image attached
	return m.setMainImageIfNecessary(image.RecipeID, tx)
}

func (m *RecipeImageModel) save(imageInfo *RecipeImage, data []byte) (string, string, error) {
	ok, contentType := isImageFile(data)
	if !ok {
		return "", "", errors.New("Attachment must be an image")
	}

	// First decode the image
	image, err := imaging.Decode(bytes.NewReader(data))
	if err != nil {
		return "", "", err
	}

	// Then generate a thumbnail image
	thumbImage := imaging.Thumbnail(image, 500, 500, imaging.NearestNeighbor)

	// Use the EXIF data to determine the orientation of the original image.
	// This data is lost when generating the thumbnail, so it's needed into
	// order to potentially explicitly rotate it.
	exifData, err := exif.Decode(bytes.NewReader(data))
	if err == nil {
		orientationTag, err := exifData.Get(exif.Orientation)
		if err == nil {
			orientationVal, err := orientationTag.Int(0)
			if err == nil {
				switch orientationVal {
				case 3:
					thumbImage = imaging.Rotate180(thumbImage)
				case 6:
					thumbImage = imaging.Rotate270(thumbImage)
				case 8:
					thumbImage = imaging.Rotate90(thumbImage)
				}
			}
		}
	}

	thumbBuf := new(bytes.Buffer)
	err = imaging.Encode(thumbBuf, thumbImage, getImageFormat(contentType), imaging.JPEGQuality(80))
	if err != nil {
		return "", "", err
	}

	// Save the original image
	origDir := getDirPathForImage(imageInfo.RecipeID)
	origPath := filepath.Join(origDir, imageInfo.Name)
	origURL := filepath.ToSlash(filepath.Join("/uploads/", origPath))
	err = m.upl.Save(origPath, data)
	if err != nil {
		return "", "", err
	}

	// Save the thumbnail image
	thumbDir := getDirPathForThumbnail(imageInfo.RecipeID)
	thumbPath := filepath.Join(thumbDir, imageInfo.Name)
	thumbURL := filepath.ToSlash(filepath.Join("/uploads/", thumbPath))
	err = m.upl.Save(thumbPath, thumbBuf.Bytes())
	if err != nil {
		return "", "", err
	}

	return origURL, thumbURL, nil
}

// ReadTx retrieves the information about the image from the database, if found,
// using the specified transaction. If no image exists with the specified ID,
// a ErrNotFound error is returned.
func (m *RecipeImageModel) ReadTx(id int64, tx *sqlx.Tx) (*RecipeImage, error) {
	image := new(RecipeImage)
	err := tx.Get(image, "SELECT * FROM recipe_image WHERE id = $1", id)
	if err == sql.ErrNoRows {
		return nil, ErrNotFound
	} else if err != nil {
		return nil, err
	}

	return image, nil
}

// ReadMainImage retrieves the information about the main image for the specified recipe
// image from the database. If no main image exists, a ErrNotFound error is returned.
func (m *RecipeImageModel) ReadMainImage(recipeID int64) (*RecipeImage, error) {
	image := new(RecipeImage)
	err := m.db.Get(image, "SELECT * FROM recipe_image WHERE id = (SELECT image_id FROM recipe WHERE id = $1)", recipeID)
	if err == sql.ErrNoRows {
		return nil, ErrNotFound
	} else if err != nil {
		return nil, err
	}

	return image, nil
}

// UpdateMainImage sets the id of the main image for the specified recipe
// using a dedicated transation that is committed if there are not errors.
func (m *RecipeImageModel) UpdateMainImage(image *RecipeImage) error {
	return m.tx(func(tx *sqlx.Tx) error {
		return m.UpdateMainImageTx(image, tx)
	})
}

// UpdateMainImageTx sets the id of the main image for the specified recipe
// using the specified transaction.
func (m *RecipeImageModel) UpdateMainImageTx(image *RecipeImage, tx *sqlx.Tx) error {
	_, err := tx.Exec(
		"UPDATE recipe SET image_id = $1 WHERE id = $2",
		image.ID, image.RecipeID)

	return err
}

// List returns a RecipeImage slice that contains data for all images
// attached to the specified recipe.
func (m *RecipeImageModel) List(recipeID int64) (*[]RecipeImage, error) {
	var images []RecipeImage

	if err := m.db.Select(&images, "SELECT * FROM recipe_image WHERE recipe_id = $1 ORDER BY created_at ASC", recipeID); err != nil {
		return nil, err
	}

	return &images, nil
}

// Delete removes the specified image from the backing store and database
// using a dedicated transation that is committed if there are not errors.
func (m *RecipeImageModel) Delete(id int64) error {
	return m.tx(func(tx *sqlx.Tx) error {
		return m.DeleteTx(id, tx)
	})
}

// DeleteTx removes the specified image from the backing store and database
// using the specified transaction.
func (m *RecipeImageModel) DeleteTx(id int64, tx *sqlx.Tx) error {
	image, err := m.ReadTx(id, tx)
	if err != nil {
		return err
	}

	origPath := filepath.Join(getDirPathForImage(image.RecipeID), image.Name)
	if err := m.upl.Delete(origPath); err != nil {
		return err
	}
	thumbPath := filepath.Join(getDirPathForThumbnail(image.RecipeID), image.Name)
	if err := m.upl.Delete(thumbPath); err != nil {
		return err
	}

	if _, err = tx.Exec("DELETE FROM recipe_image WHERE id = $1", id); err != nil {
		return err
	}

	// Switch to a new main image if necessary, since the image we just deleted may have been the main image
	return m.setMainImageIfNecessary(image.RecipeID, tx)
}

func (m *RecipeImageModel) setMainImageIfNecessary(recipeID int64, tx *sqlx.Tx) error {
	_, err := tx.Exec(
		"UPDATE recipe "+
			"SET image_id = (SELECT recipe_image.id FROM recipe_image WHERE recipe_image.recipe_id = recipe.id LIMIT 1)"+
			"WHERE id = $1 AND image_id IS NULL",
		recipeID)
	return err
}

// DeleteAll removes all images for the specified recipe from the database
// using a dedicated transation that is committed if there are not errors.
func (m *RecipeImageModel) DeleteAll(recipeID int64) error {
	return m.tx(func(tx *sqlx.Tx) error {
		return m.DeleteAllTx(recipeID, tx)
	})
}

// DeleteAllTx removes all images for the specified recipe from the database
// using the specified transaction.
func (m *RecipeImageModel) DeleteAllTx(recipeID int64, tx *sqlx.Tx) error {
	dirPath := getDirPathForRecipe(recipeID)
	err := m.upl.DeleteAll(dirPath)
	if err != nil {
		return err
	}

	_, err = tx.Exec(
		"DELETE FROM recipe_image WHERE recipe_id = $1",
		recipeID)
	return err
}

func isImageFile(data []byte) (bool, string) {
	contentType := http.DetectContentType(data)
	if strings.Index(contentType, "image/") != -1 {
		return true, contentType
	}
	return false, ""
}

func getImageFormat(contentType string) imaging.Format {
	switch contentType {
	case "image/jpeg":
		return imaging.JPEG
	case "image/png":
		return imaging.PNG
	case "image/gif":
		return imaging.GIF
	case "image/bmp":
		return imaging.BMP
	case "image/tiff":
		return imaging.TIFF
	}
	return imaging.JPEG
}

func getDirPathForRecipe(recipeID int64) string {
	return filepath.Join("recipes", strconv.FormatInt(recipeID, 10))
}

func getDirPathForImage(recipeID int64) string {
	return filepath.Join(getDirPathForRecipe(recipeID), "images")
}

func getDirPathForThumbnail(recipeID int64) string {
	return filepath.Join(getDirPathForRecipe(recipeID), "thumbs")
}
<|endoftext|>


<commit_before>package models

import (
	"io/ioutil"
	"log"
	"net/http"
	"strconv"
	"strings"
)

type Stock struct {
	Name  string
	Ask   float64
	Bid   float64
	Price int
}

func CheckStock(symbol string) *Stock {
	client := new(http.Client)
	res, err := client.Get("http://finance.yahoo.com/d/quotes.csv?s=" + symbol + "&f=nab")
	if err != nil {
		log.Panic(err)
	}

	var stock = new(Stock) // Make a new instance of the Stock struct

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		log.Panic(err)
	}

	response := strings.Split(string(body), ",")

	ask, _ := strconv.ParseFloat(response[1], 64)
	bid, _ := strconv.ParseFloat(response[2], 64)

	stock.Name = response[0]
	stock.Ask = ask * 100
	stock.Bid = bid * 100

	if stock.Ask > stock.Bid { // Ghetto and temporary
		stock.Price = int(stock.Ask)
	} else {
		stock.Price = int(stock.Bid)
	}

	return stock
}
<commit_msg>Finally fixing the root of the problem<commit_after>package models

import (
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"strconv"
	"strings"
)

type Stock struct {
	Name  string
	Price int
}

func CheckStock(symbol string) *Stock {
	client := new(http.Client)
	res, err := client.Get("http://finance.yahoo.com/d/quotes.csv?s=" + symbol + "&f=l1on")
	if err != nil {
		log.Panic(err)
	}

	var stock = new(Stock) // Make a new instance of the Stock struct

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		log.Panic(err)
	}

	response := strings.Split(string(body), ",")

	price, err := strconv.ParseFloat(response[0], 64)
	if err != nil {
		log.Panic(err)
	}

	for i := 2; i < len(response); i++ { // Takes care of stupid stocks with names like "Groupon, Inc." that throw off the strings.Split() method above
		stock.Name = fmt.Sprint(stock.Name, response[i])
	}

	stock.Name = strings.TrimSuffix(stock.Name, "\n") // Kill the silly newline character

	stock.Price = int(price * 100) // Convert to turnips

	return stock
}
<|endoftext|>


<commit_before>// Implementation of I2C module interface for systems using device tree.

package hwio

// references:
// - http://datko.net/2013/11/03/bbb_i2c/
// - http://elinux.org/Interfacing_with_I2C_Devices
// - http://grokbase.com/t/gg/golang-nuts/1296kz4tkg/go-nuts-how-to-call-linux-kernel-method-i2c-smbus-write-byte-from-go
// - http://learn.adafruit.com/setting-up-io-python-library-on-beaglebone-black/i2c
// - https://bitbucket.org/gmcbay/i2c/src/1235f1776ee749f0eaeb6de69d8804a6dd70d9d5/i2c_bus.go?at=master
// - http://derekmolloy.ie/beaglebone/beaglebone-an-i2c-tutorial-interfacing-to-a-bma180-accelerometer/'

import (
	"fmt"
	"os"
	"sync"
	"syscall"
	"unsafe"
)

// A list of the pins that are allocated when the bus is enabled. We don't need to know what these mean within the
// module. We just need them so we can mark them allocated.
type DTI2CModulePins []Pin

type DTI2CModule struct {
	sync.Mutex

	name        string
	deviceFile  string
	definedPins DTI2CModulePins

	// File used to represent the bus once it's opened
	fd *os.File
}

// Data that is passed to/from ioctl calls
type i2c_smbus_ioctl_data struct {
	read_write uint8
	command    uint8
	size       int
	data       uintptr
}

// Constants used by ioctl, from i2c-dev.h
const (
	I2C_SMBUS_READ           = 1
	I2C_SMBUS_WRITE          = 0
	I2C_SMBUS_BYTE_DATA      = 2
	I2C_SMBUS_I2C_BLOCK_DATA = 8
	I2C_SMBUS_BLOCK_MAX      = 32

	// Talk to bus
	I2C_SMBUS = 0x0720

	// Set bus slave
	I2C_SLAVE = 0x0703
)

func NewDTI2CModule(name string) (result *DTI2CModule) {
	result = &DTI2CModule{name: name}
	return result
}

// Accept options for the I2C module. Expected options include:
// - "device" - a string that identifies the device file, e.g. "/dev/i2c-1".
// - "pins" - an object of type DTI2CModulePins that identifies the pins that will be assigned
//	 when this module is enabled.
func (module *DTI2CModule) SetOptions(options map[string]interface{}) error {
	// get the device
	vd := options["device"]
	if vd == nil {
		return fmt.Errorf("Module '%s' SetOptions() did not get 'device' value", module.GetName())
	}

	module.deviceFile = vd.(string)

	// get the pins
	vp := options["pins"]
	if vp == nil {
		return fmt.Errorf("Module '%s' SetOptions() did not get 'pins' values", module.GetName())
	}

	module.definedPins = vp.(DTI2CModulePins)

	return nil
}

// enable this I2C module
func (module *DTI2CModule) Enable() error {
	// Assign the pins so nothing else can allocate them.
	for _, pin := range module.definedPins {
		fmt.Printf("assigning pin %d\n", pin)
		AssignPin(pin, module)
	}

	// @todo consider lazily opening the file. Since Enable is called automatically by BBB driver, this
	// @todo file will always be open even if i2c is not used.
	fd, e := os.OpenFile(module.deviceFile, os.O_RDWR, os.ModeExclusive)
	if e != nil {
		return e
	}
	module.fd = fd

	return nil
}

// disables module and release any pins assigned.
func (module *DTI2CModule) Disable() error {
	if e := module.fd.Close(); e != nil {
		return e
	}

	for _, pin := range module.definedPins {
		UnassignPin(pin)
	}

	return nil
}

func (module *DTI2CModule) GetName() string {
	return module.name
}

func (module *DTI2CModule) GetDevice(address int) I2CDevice {
	return NewDTI2CDevice(module, address)
}

type DTI2CDevice struct {
	module  *DTI2CModule
	address int
}

func NewDTI2CDevice(module *DTI2CModule, address int) *DTI2CDevice {
	return &DTI2CDevice{module, address}
}

func (device *DTI2CDevice) Write(command byte, data []byte) (e error) {
	device.module.Lock()
	defer device.module.Unlock()

	device.sendSlaveAddress()

	buffer := make([]byte, len(data)+1)
	buffer[0] = byte(len(data))
	copy(buffer[1:], data)

	//	buffer := make([]byte, numBytes+2)

	busData := i2c_smbus_ioctl_data{
		read_write: I2C_SMBUS_WRITE,
		command:    command,
		size:       I2C_SMBUS_I2C_BLOCK_DATA,
		data:       uintptr(unsafe.Pointer(&buffer[0])),
	}

	_, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(device.module.fd.Fd()), I2C_SMBUS, uintptr(unsafe.Pointer(&busData)))
	if err != 0 {
		return syscall.Errno(err)
	}

	return nil
}

func (device *DTI2CDevice) Read(command byte, numBytes int) ([]byte, error) {
	device.module.Lock()
	defer device.module.Unlock()

	device.sendSlaveAddress()

	buffer := make([]byte, numBytes+1)
	buffer[0] = byte(numBytes)

	//	buffer := make([]byte, numBytes+2)

	busData := i2c_smbus_ioctl_data{
		read_write: I2C_SMBUS_READ,
		command:    command,
		size:       I2C_SMBUS_I2C_BLOCK_DATA,
		data:       uintptr(unsafe.Pointer(&buffer[0])),
	}

	_, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(device.module.fd.Fd()), I2C_SMBUS, uintptr(unsafe.Pointer(&busData)))
	if err != 0 {
		return nil, syscall.Errno(err)
	}

	result := make([]byte, numBytes)
	copy(result, buffer[1:])

	return result, nil
}

// Read 1 byte from the bus
func (device *DTI2CDevice) ReadByte(command byte) (byte, error) {
	device.module.Lock()
	defer device.module.Unlock()

	e := device.sendSlaveAddress()
	if e != nil {
		return 0, e
	}

	data := uint8(0)

	busData := i2c_smbus_ioctl_data{
		read_write: I2C_SMBUS_READ,
		command:    command,
		size:       I2C_SMBUS_BYTE_DATA,
		data:       uintptr(unsafe.Pointer(&data)),
	}

	_, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(device.module.fd.Fd()), I2C_SMBUS, uintptr(unsafe.Pointer(&busData)))
	if err != 0 {
		return 0, syscall.Errno(err)
	}

	return data, nil
}

func (device *DTI2CDevice) WriteByte(command byte, value byte) error {
	device.module.Lock()
	defer device.module.Unlock()

	e := device.sendSlaveAddress()
	if e != nil {
		return e
	}

	busData := i2c_smbus_ioctl_data{
		read_write: I2C_SMBUS_WRITE,
		command:    command,
		size:       I2C_SMBUS_BYTE_DATA,
		data:       uintptr(unsafe.Pointer(&value)),
	}

	_, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(device.module.fd.Fd()), I2C_SMBUS, uintptr(unsafe.Pointer(&busData)))
	if err != 0 {
		return syscall.Errno(err)
	}

	return nil
}

func (device *DTI2CDevice) sendSlaveAddress() error {
	_, _, enum := syscall.Syscall(syscall.SYS_IOCTL, uintptr(device.module.fd.Fd()), I2C_SLAVE, uintptr(device.address))
	if enum != 0 {
		return fmt.Errorf("Could not open I2C bus on module %s", device.module.GetName())
	}
	return nil
}
<commit_msg>removed debugging<commit_after>// Implementation of I2C module interface for systems using device tree.

package hwio

// references:
// - http://datko.net/2013/11/03/bbb_i2c/
// - http://elinux.org/Interfacing_with_I2C_Devices
// - http://grokbase.com/t/gg/golang-nuts/1296kz4tkg/go-nuts-how-to-call-linux-kernel-method-i2c-smbus-write-byte-from-go
// - http://learn.adafruit.com/setting-up-io-python-library-on-beaglebone-black/i2c
// - https://bitbucket.org/gmcbay/i2c/src/1235f1776ee749f0eaeb6de69d8804a6dd70d9d5/i2c_bus.go?at=master
// - http://derekmolloy.ie/beaglebone/beaglebone-an-i2c-tutorial-interfacing-to-a-bma180-accelerometer/'

import (
	"fmt"
	"os"
	"sync"
	"syscall"
	"unsafe"
)

// A list of the pins that are allocated when the bus is enabled. We don't need to know what these mean within the
// module. We just need them so we can mark them allocated.
type DTI2CModulePins []Pin

type DTI2CModule struct {
	sync.Mutex

	name        string
	deviceFile  string
	definedPins DTI2CModulePins

	// File used to represent the bus once it's opened
	fd *os.File
}

// Data that is passed to/from ioctl calls
type i2c_smbus_ioctl_data struct {
	read_write uint8
	command    uint8
	size       int
	data       uintptr
}

// Constants used by ioctl, from i2c-dev.h
const (
	I2C_SMBUS_READ           = 1
	I2C_SMBUS_WRITE          = 0
	I2C_SMBUS_BYTE_DATA      = 2
	I2C_SMBUS_I2C_BLOCK_DATA = 8
	I2C_SMBUS_BLOCK_MAX      = 32

	// Talk to bus
	I2C_SMBUS = 0x0720

	// Set bus slave
	I2C_SLAVE = 0x0703
)

func NewDTI2CModule(name string) (result *DTI2CModule) {
	result = &DTI2CModule{name: name}
	return result
}

// Accept options for the I2C module. Expected options include:
// - "device" - a string that identifies the device file, e.g. "/dev/i2c-1".
// - "pins" - an object of type DTI2CModulePins that identifies the pins that will be assigned
//	 when this module is enabled.
func (module *DTI2CModule) SetOptions(options map[string]interface{}) error {
	// get the device
	vd := options["device"]
	if vd == nil {
		return fmt.Errorf("Module '%s' SetOptions() did not get 'device' value", module.GetName())
	}

	module.deviceFile = vd.(string)

	// get the pins
	vp := options["pins"]
	if vp == nil {
		return fmt.Errorf("Module '%s' SetOptions() did not get 'pins' values", module.GetName())
	}

	module.definedPins = vp.(DTI2CModulePins)

	return nil
}

// enable this I2C module
func (module *DTI2CModule) Enable() error {
	// Assign the pins so nothing else can allocate them.
	for _, pin := range module.definedPins {
		// fmt.Printf("assigning pin %d\n", pin)
		AssignPin(pin, module)
	}

	// @todo consider lazily opening the file. Since Enable is called automatically by BBB driver, this
	// @todo file will always be open even if i2c is not used.
	fd, e := os.OpenFile(module.deviceFile, os.O_RDWR, os.ModeExclusive)
	if e != nil {
		return e
	}
	module.fd = fd

	return nil
}

// disables module and release any pins assigned.
func (module *DTI2CModule) Disable() error {
	if e := module.fd.Close(); e != nil {
		return e
	}

	for _, pin := range module.definedPins {
		UnassignPin(pin)
	}

	return nil
}

func (module *DTI2CModule) GetName() string {
	return module.name
}

func (module *DTI2CModule) GetDevice(address int) I2CDevice {
	return NewDTI2CDevice(module, address)
}

type DTI2CDevice struct {
	module  *DTI2CModule
	address int
}

func NewDTI2CDevice(module *DTI2CModule, address int) *DTI2CDevice {
	return &DTI2CDevice{module, address}
}

func (device *DTI2CDevice) Write(command byte, data []byte) (e error) {
	device.module.Lock()
	defer device.module.Unlock()

	device.sendSlaveAddress()

	buffer := make([]byte, len(data)+1)
	buffer[0] = byte(len(data))
	copy(buffer[1:], data)

	//	buffer := make([]byte, numBytes+2)

	busData := i2c_smbus_ioctl_data{
		read_write: I2C_SMBUS_WRITE,
		command:    command,
		size:       I2C_SMBUS_I2C_BLOCK_DATA,
		data:       uintptr(unsafe.Pointer(&buffer[0])),
	}

	_, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(device.module.fd.Fd()), I2C_SMBUS, uintptr(unsafe.Pointer(&busData)))
	if err != 0 {
		return syscall.Errno(err)
	}

	return nil
}

func (device *DTI2CDevice) Read(command byte, numBytes int) ([]byte, error) {
	device.module.Lock()
	defer device.module.Unlock()

	device.sendSlaveAddress()

	buffer := make([]byte, numBytes+1)
	buffer[0] = byte(numBytes)

	//	buffer := make([]byte, numBytes+2)

	busData := i2c_smbus_ioctl_data{
		read_write: I2C_SMBUS_READ,
		command:    command,
		size:       I2C_SMBUS_I2C_BLOCK_DATA,
		data:       uintptr(unsafe.Pointer(&buffer[0])),
	}

	_, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(device.module.fd.Fd()), I2C_SMBUS, uintptr(unsafe.Pointer(&busData)))
	if err != 0 {
		return nil, syscall.Errno(err)
	}

	result := make([]byte, numBytes)
	copy(result, buffer[1:])

	return result, nil
}

// Read 1 byte from the bus
func (device *DTI2CDevice) ReadByte(command byte) (byte, error) {
	device.module.Lock()
	defer device.module.Unlock()

	e := device.sendSlaveAddress()
	if e != nil {
		return 0, e
	}

	data := uint8(0)

	busData := i2c_smbus_ioctl_data{
		read_write: I2C_SMBUS_READ,
		command:    command,
		size:       I2C_SMBUS_BYTE_DATA,
		data:       uintptr(unsafe.Pointer(&data)),
	}

	_, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(device.module.fd.Fd()), I2C_SMBUS, uintptr(unsafe.Pointer(&busData)))
	if err != 0 {
		return 0, syscall.Errno(err)
	}

	return data, nil
}

func (device *DTI2CDevice) WriteByte(command byte, value byte) error {
	device.module.Lock()
	defer device.module.Unlock()

	e := device.sendSlaveAddress()
	if e != nil {
		return e
	}

	busData := i2c_smbus_ioctl_data{
		read_write: I2C_SMBUS_WRITE,
		command:    command,
		size:       I2C_SMBUS_BYTE_DATA,
		data:       uintptr(unsafe.Pointer(&value)),
	}

	_, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(device.module.fd.Fd()), I2C_SMBUS, uintptr(unsafe.Pointer(&busData)))
	if err != 0 {
		return syscall.Errno(err)
	}

	return nil
}

func (device *DTI2CDevice) sendSlaveAddress() error {
	_, _, enum := syscall.Syscall(syscall.SYS_IOCTL, uintptr(device.module.fd.Fd()), I2C_SLAVE, uintptr(device.address))
	if enum != 0 {
		return fmt.Errorf("Could not open I2C bus on module %s", device.module.GetName())
	}
	return nil
}
<|endoftext|>


<commit_before>/*
Package jwt makes it possible to authorize API requests usin JSON Web Tokens,
see https://jwt.io/introduction/

Middleware

The package provides a middleware that can be mounted on controllers that require authentication.
The JWT middleware is instantiated using the package Middleware function. This function accepts
a specification that describes the various properties used by the JWT signature and validation
algorithms.

	spec := &jwt.Specification{
		AllowParam:       false,      // Pass tokens in headers only
		AuthOptions:      false,      // Do not authorize OPTIONS requests
		TTLMinutes:       1440,       // Tokens are valid for 24 hours
		Issuer:           "me.com",   // me.com issued the token
		KeySigningMethod: jwt.RSA256, // Use the RSA256 hashing algorithm to sign tokens
		SigningKeyFunc:   privateKey, // privateKey returns the key used to sign tokens
		ValidationFunc:   pubKey,     // pubKey returns the key used to validate tokens
	}
	authorizedController.Use(jwt.Middleware(spec))

Token Manager

The package also exposes a token manager that creates the JWT tokens. The manager is instantiated
using the same specification used to create the middleware:

	var tm *jwt.TokenManager = jwt.NewTokenManager(spec)

	func Login(ctx *goa.Context) error {
		// ...
		// Authorize request using ctx, initialize tenant id if necessary etc.
		// ...
		claims := map[string]interface{}{
			"accountID": accountID,
		}
		token, err := tm.Create(claims)
		if err != nil {
			return err
		}
		return ctx.Respond(200, token) // You'll probably need something different here
	}
*/
package jwt
<commit_msg>Fix doc typo<commit_after>/*
Package jwt makes it possible to authorize API requests using JSON Web Tokens,
see https://jwt.io/introduction/

Middleware

The package provides a middleware that can be mounted on controllers that require authentication.
The JWT middleware is instantiated using the package Middleware function. This function accepts
a specification that describes the various properties used by the JWT signature and validation
algorithms.

	spec := &jwt.Specification{
		AllowParam:       false,      // Pass tokens in headers only
		AuthOptions:      false,      // Do not authorize OPTIONS requests
		TTLMinutes:       1440,       // Tokens are valid for 24 hours
		Issuer:           "me.com",   // me.com issued the token
		KeySigningMethod: jwt.RSA256, // Use the RSA256 hashing algorithm to sign tokens
		SigningKeyFunc:   privateKey, // privateKey returns the key used to sign tokens
		ValidationFunc:   pubKey,     // pubKey returns the key used to validate tokens
	}
	authorizedController.Use(jwt.Middleware(spec))

Token Manager

The package also exposes a token manager that creates the JWT tokens. The manager is instantiated
using the same specification used to create the middleware:

	var tm *jwt.TokenManager = jwt.NewTokenManager(spec)

	func Login(ctx *goa.Context) error {
		// ...
		// Authorize request using ctx, initialize tenant id if necessary etc.
		// ...
		claims := map[string]interface{}{
			"accountID": accountID,
		}
		token, err := tm.Create(claims)
		if err != nil {
			return err
		}
		return ctx.Respond(200, token) // You'll probably need something different here
	}
*/
package jwt
<|endoftext|>


<commit_before>package httpauth-mgo

import (
    "errors"
    "gopkg.in/mgo.v2"
    "gopkg.in/mgo.v2/bson"
    "fmt"
)

type udata struct {
	Userame	string	`bson:"Username"`
	Email  	string	`bson:"Email"`
	Hash  	[]byte 	`bson:"Hash"`
	Role 	string	`bson:"Role"`
}

// MongodbAuthBackend stores database connection information.
type MongodbAuthBackend struct {
    mongoUrl string
    database string
}

// NewMongodbAuthBackend initializes a new backend.
func NewMongodbBackend(mongoUrl string, database string) (b MongodbAuthBackend, err error) {
    b.mongoUrl = mongoUrl
    b.database = database
    _, err = mgo.Dial(b.mongoUrl)
    if err != nil {
        return b, errors.New("Can't connect to mongodb: " + err.Error())
    }
    return b, nil
}

func (b MongodbAuthBackend) connect() (c *mgo.Collection, err error) {
    sesh, err := mgo.Dial(b.mongoUrl)
    if err != nil {
        return c, errors.New("Can't connect to mongodb: " + err.Error())
    }
    return sesh.DB(b.database).C("goauth"), nil
}

// User returns the user with the given username.
func (b MongodbAuthBackend) User(username string) (user UserData, ok bool) {
    c, err := b.connect()
    if err != nil {
        panic(err)
    }
    var result UserData

    err = c.Find(bson.M{"Username": username}).One(&result)
    if err != nil {
	fmt.Println("Cannot find specified user (" + username + ")")
    	return result, false
    }
    return result, true
}

// Users returns a slice of all users.
func (b MongodbAuthBackend) Users() (us []UserData) {
    c, err := b.connect()
    if err != nil {
        panic(err)
    }
    var results []UserData
    err = c.Find(bson.M{}).All(&results)
    if err != nil {
	fmt.Printf("got an error finding a doc %v\n")
    }
    return results
}

// SaveUser adds a new user, replacing one with the same username.
func (b MongodbAuthBackend) SaveUser(user UserData) error {
    c, err := b.connect()
    if err != nil {
        panic(err)
    }
    hash := string(user.Hash)
    err = c.Insert(bson.M{ "Username": user.Username, "Hash": hash, "Email": user.Email, "Role": user.Role })
    return err
}

// DeleteUser removes a user.
func (b MongodbAuthBackend) DeleteUser(username string) error {
    c, err := b.connect()
    if err != nil {
        panic(err)
    }
    err = c.Remove(bson.M{"Username": username})
    return err
}
<commit_msg>renamed package in mongobackend.go<commit_after>package httpauth

import (
    "errors"
    "gopkg.in/mgo.v2"
    "gopkg.in/mgo.v2/bson"
    "fmt"
)

type udata struct {
	Userame	string	`bson:"Username"`
	Email  	string	`bson:"Email"`
	Hash  	[]byte 	`bson:"Hash"`
	Role 	string	`bson:"Role"`
}

// MongodbAuthBackend stores database connection information.
type MongodbAuthBackend struct {
    mongoUrl string
    database string
}

// NewMongodbAuthBackend initializes a new backend.
func NewMongodbBackend(mongoUrl string, database string) (b MongodbAuthBackend, err error) {
    b.mongoUrl = mongoUrl
    b.database = database
    _, err = mgo.Dial(b.mongoUrl)
    if err != nil {
        return b, errors.New("Can't connect to mongodb: " + err.Error())
    }
    return b, nil
}

func (b MongodbAuthBackend) connect() (c *mgo.Collection, err error) {
    sesh, err := mgo.Dial(b.mongoUrl)
    if err != nil {
        return c, errors.New("Can't connect to mongodb: " + err.Error())
    }
    return sesh.DB(b.database).C("goauth"), nil
}

// User returns the user with the given username.
func (b MongodbAuthBackend) User(username string) (user UserData, ok bool) {
    c, err := b.connect()
    if err != nil {
        panic(err)
    }
    var result UserData

    err = c.Find(bson.M{"Username": username}).One(&result)
    if err != nil {
	fmt.Println("Cannot find specified user (" + username + ")")
    	return result, false
    }
    return result, true
}

// Users returns a slice of all users.
func (b MongodbAuthBackend) Users() (us []UserData) {
    c, err := b.connect()
    if err != nil {
        panic(err)
    }
    var results []UserData
    err = c.Find(bson.M{}).All(&results)
    if err != nil {
	fmt.Printf("got an error finding a doc %v\n")
    }
    return results
}

// SaveUser adds a new user, replacing one with the same username.
func (b MongodbAuthBackend) SaveUser(user UserData) error {
    c, err := b.connect()
    if err != nil {
        panic(err)
    }
    hash := string(user.Hash)
    err = c.Insert(bson.M{ "Username": user.Username, "Hash": hash, "Email": user.Email, "Role": user.Role })
    return err
}

// DeleteUser removes a user.
func (b MongodbAuthBackend) DeleteUser(username string) error {
    c, err := b.connect()
    if err != nil {
        panic(err)
    }
    err = c.Remove(bson.M{"Username": username})
    return err
}
<|endoftext|>