<commit_before>package crypto

import (
	"crypto/cipher"
	"io"

	"v2ray.com/core/common"
	"v2ray.com/core/common/buf"
	"v2ray.com/core/common/protocol"
)

type BytesGenerator interface {
	Next() []byte
}

type NoOpBytesGenerator struct {
	buffer [1]byte
}

func (v NoOpBytesGenerator) Next() []byte {
	return v.buffer[:0]
}

type StaticBytesGenerator struct {
	Content []byte
}

func (v StaticBytesGenerator) Next() []byte {
	return v.Content
}

type Authenticator interface {
	NonceSize() int
	Overhead() int
	Open(dst, cipherText []byte) ([]byte, error)
	Seal(dst, plainText []byte) ([]byte, error)
}

type AEADAuthenticator struct {
	cipher.AEAD
	NonceGenerator          BytesGenerator
	AdditionalDataGenerator BytesGenerator
}

func (v *AEADAuthenticator) Open(dst, cipherText []byte) ([]byte, error) {
	iv := v.NonceGenerator.Next()
	if len(iv) != v.AEAD.NonceSize() {
		return nil, newError("invalid AEAD nonce size: ", len(iv))
	}

	additionalData := v.AdditionalDataGenerator.Next()
	return v.AEAD.Open(dst, iv, cipherText, additionalData)
}

func (v *AEADAuthenticator) Seal(dst, plainText []byte) ([]byte, error) {
	iv := v.NonceGenerator.Next()
	if len(iv) != v.AEAD.NonceSize() {
		return nil, newError("invalid AEAD nonce size: ", len(iv))
	}

	additionalData := v.AdditionalDataGenerator.Next()
	return v.AEAD.Seal(dst, iv, plainText, additionalData), nil
}

type AuthenticationReader struct {
	auth         Authenticator
	buffer       *buf.Buffer
	reader       io.Reader
	sizeParser   ChunkSizeDecoder
	size         int
	transferType protocol.TransferType
}

const (
	readerBufferSize = 32 * 1024
)

func NewAuthenticationReader(auth Authenticator, sizeParser ChunkSizeDecoder, reader io.Reader, transferType protocol.TransferType) *AuthenticationReader {
	return &AuthenticationReader{
		auth:         auth,
		buffer:       buf.NewLocal(readerBufferSize),
		reader:       reader,
		sizeParser:   sizeParser,
		size:         -1,
		transferType: transferType,
	}
}

func (r *AuthenticationReader) readSize() error {
	if r.size >= 0 {
		return nil
	}

	sizeBytes := r.sizeParser.SizeBytes()
	if r.buffer.Len() < sizeBytes {
		r.buffer.Reset(buf.ReadFrom(r.buffer))
		delta := sizeBytes - r.buffer.Len()
		if err := r.buffer.AppendSupplier(buf.ReadAtLeastFrom(r.reader, delta)); err != nil {
			return err
		}
	}
	size, err := r.sizeParser.Decode(r.buffer.BytesTo(sizeBytes))
	if err != nil {
		return err
	}
	r.size = int(size)
	r.buffer.SliceFrom(sizeBytes)
	return nil
}

func (r *AuthenticationReader) readChunk(waitForData bool) ([]byte, error) {
	if err := r.readSize(); err != nil {
		return nil, err
	}
	if r.size > readerBufferSize-r.sizeParser.SizeBytes() {
		return nil, newError("size too large ", r.size).AtWarning()
	}

	if r.size == r.auth.Overhead() {
		return nil, io.EOF
	}

	if r.buffer.Len() < r.size {
		if !waitForData {
			return nil, io.ErrNoProgress
		}

		if r.buffer.IsEmpty() {
			r.buffer.Clear()
		} else {
			common.Must(r.buffer.Reset(buf.ReadFrom(r.buffer)))
		}

		delta := r.size - r.buffer.Len()
		if err := r.buffer.AppendSupplier(buf.ReadAtLeastFrom(r.reader, delta)); err != nil {
			return nil, err
		}
	}

	b, err := r.auth.Open(r.buffer.BytesTo(0), r.buffer.BytesTo(r.size))
	if err != nil {
		return nil, err
	}
	r.buffer.SliceFrom(r.size)
	r.size = -1
	return b, nil
}

func (r *AuthenticationReader) Read() (buf.MultiBuffer, error) {
	b, err := r.readChunk(true)
	if err != nil {
		return nil, err
	}

	mb := buf.NewMultiBuffer()
	if r.transferType == protocol.TransferTypeStream {
		mb.Write(b)
	} else {
		var bb *buf.Buffer
		if len(b) < buf.Size {
			bb = buf.New()
		} else {
			bb = buf.NewLocal(len(b))
		}
		bb.Append(b)
		mb.Append(bb)
	}

	for r.buffer.Len() >= r.sizeParser.SizeBytes() {
		b, err := r.readChunk(false)
		if err != nil {
			break
		}
		if r.transferType == protocol.TransferTypeStream {
			mb.Write(b)
		} else {
			var bb *buf.Buffer
			if len(b) < buf.Size {
				bb = buf.New()
			} else {
				bb = buf.NewLocal(len(b))
			}
			bb.Append(b)
			mb.Append(bb)
		}
	}

	return mb, nil
}

type AuthenticationWriter struct {
	auth         Authenticator
	buffer       []byte
	payload      []byte
	writer       *buf.BufferedWriter
	sizeParser   ChunkSizeEncoder
	transferType protocol.TransferType
}

func NewAuthenticationWriter(auth Authenticator, sizeParser ChunkSizeEncoder, writer io.Writer, transferType protocol.TransferType) *AuthenticationWriter {
	const payloadSize = 1024
	return &AuthenticationWriter{
		auth:         auth,
		buffer:       make([]byte, payloadSize+sizeParser.SizeBytes()+auth.Overhead()),
		payload:      make([]byte, payloadSize),
		writer:       buf.NewBufferedWriterSize(writer, readerBufferSize),
		sizeParser:   sizeParser,
		transferType: transferType,
	}
}

func (w *AuthenticationWriter) append(b []byte) error {
	encryptedSize := len(b) + w.auth.Overhead()
	buffer := w.sizeParser.Encode(uint16(encryptedSize), w.buffer[:0])

	buffer, err := w.auth.Seal(buffer, b)
	if err != nil {
		return err
	}

	if _, err := w.writer.Write(buffer); err != nil {
		return err
	}

	return nil
}

func (w *AuthenticationWriter) writeStream(mb buf.MultiBuffer) error {
	defer mb.Release()

	for {
		n, _ := mb.Read(w.payload)
		if err := w.append(w.payload[:n]); err != nil {
			return err
		}
		if mb.IsEmpty() {
			break
		}
	}

	return w.writer.Flush()
}

func (w *AuthenticationWriter) writePacket(mb buf.MultiBuffer) error {
	defer mb.Release()

	for {
		b := mb.SplitFirst()
		if b == nil {
			b = buf.New()
		}
		if err := w.append(b.Bytes()); err != nil {
			b.Release()
			return err
		}
		b.Release()
		if mb.IsEmpty() {
			break
		}
	}

	return w.writer.Flush()
}

func (w *AuthenticationWriter) Write(mb buf.MultiBuffer) error {
	if w.transferType == protocol.TransferTypeStream {
		return w.writeStream(mb)
	}

	return w.writePacket(mb)
}
<commit_msg>fix lint warning<commit_after>package crypto

import (
	"crypto/cipher"
	"io"

	"v2ray.com/core/common"
	"v2ray.com/core/common/buf"
	"v2ray.com/core/common/protocol"
)

type BytesGenerator interface {
	Next() []byte
}

type NoOpBytesGenerator struct {
	buffer [1]byte
}

func (v NoOpBytesGenerator) Next() []byte {
	return v.buffer[:0]
}

type StaticBytesGenerator struct {
	Content []byte
}

func (v StaticBytesGenerator) Next() []byte {
	return v.Content
}

type Authenticator interface {
	NonceSize() int
	Overhead() int
	Open(dst, cipherText []byte) ([]byte, error)
	Seal(dst, plainText []byte) ([]byte, error)
}

type AEADAuthenticator struct {
	cipher.AEAD
	NonceGenerator          BytesGenerator
	AdditionalDataGenerator BytesGenerator
}

func (v *AEADAuthenticator) Open(dst, cipherText []byte) ([]byte, error) {
	iv := v.NonceGenerator.Next()
	if len(iv) != v.AEAD.NonceSize() {
		return nil, newError("invalid AEAD nonce size: ", len(iv))
	}

	additionalData := v.AdditionalDataGenerator.Next()
	return v.AEAD.Open(dst, iv, cipherText, additionalData)
}

func (v *AEADAuthenticator) Seal(dst, plainText []byte) ([]byte, error) {
	iv := v.NonceGenerator.Next()
	if len(iv) != v.AEAD.NonceSize() {
		return nil, newError("invalid AEAD nonce size: ", len(iv))
	}

	additionalData := v.AdditionalDataGenerator.Next()
	return v.AEAD.Seal(dst, iv, plainText, additionalData), nil
}

type AuthenticationReader struct {
	auth         Authenticator
	buffer       *buf.Buffer
	reader       io.Reader
	sizeParser   ChunkSizeDecoder
	size         int
	transferType protocol.TransferType
}

const (
	readerBufferSize = 32 * 1024
)

func NewAuthenticationReader(auth Authenticator, sizeParser ChunkSizeDecoder, reader io.Reader, transferType protocol.TransferType) *AuthenticationReader {
	return &AuthenticationReader{
		auth:         auth,
		buffer:       buf.NewLocal(readerBufferSize),
		reader:       reader,
		sizeParser:   sizeParser,
		size:         -1,
		transferType: transferType,
	}
}

func (r *AuthenticationReader) readSize() error {
	if r.size >= 0 {
		return nil
	}

	sizeBytes := r.sizeParser.SizeBytes()
	if r.buffer.Len() < sizeBytes {
		common.Must(r.buffer.Reset(buf.ReadFrom(r.buffer)))
		delta := sizeBytes - r.buffer.Len()
		if err := r.buffer.AppendSupplier(buf.ReadAtLeastFrom(r.reader, delta)); err != nil {
			return err
		}
	}
	size, err := r.sizeParser.Decode(r.buffer.BytesTo(sizeBytes))
	if err != nil {
		return err
	}
	r.size = int(size)
	r.buffer.SliceFrom(sizeBytes)
	return nil
}

func (r *AuthenticationReader) readChunk(waitForData bool) ([]byte, error) {
	if err := r.readSize(); err != nil {
		return nil, err
	}
	if r.size > readerBufferSize-r.sizeParser.SizeBytes() {
		return nil, newError("size too large ", r.size).AtWarning()
	}

	if r.size == r.auth.Overhead() {
		return nil, io.EOF
	}

	if r.buffer.Len() < r.size {
		if !waitForData {
			return nil, io.ErrNoProgress
		}

		if r.buffer.IsEmpty() {
			r.buffer.Clear()
		} else {
			common.Must(r.buffer.Reset(buf.ReadFrom(r.buffer)))
		}

		delta := r.size - r.buffer.Len()
		if err := r.buffer.AppendSupplier(buf.ReadAtLeastFrom(r.reader, delta)); err != nil {
			return nil, err
		}
	}

	b, err := r.auth.Open(r.buffer.BytesTo(0), r.buffer.BytesTo(r.size))
	if err != nil {
		return nil, err
	}
	r.buffer.SliceFrom(r.size)
	r.size = -1
	return b, nil
}

func (r *AuthenticationReader) Read() (buf.MultiBuffer, error) {
	b, err := r.readChunk(true)
	if err != nil {
		return nil, err
	}

	mb := buf.NewMultiBuffer()
	if r.transferType == protocol.TransferTypeStream {
		mb.Write(b)
	} else {
		var bb *buf.Buffer
		if len(b) < buf.Size {
			bb = buf.New()
		} else {
			bb = buf.NewLocal(len(b))
		}
		bb.Append(b)
		mb.Append(bb)
	}

	for r.buffer.Len() >= r.sizeParser.SizeBytes() {
		b, err := r.readChunk(false)
		if err != nil {
			break
		}
		if r.transferType == protocol.TransferTypeStream {
			mb.Write(b)
		} else {
			var bb *buf.Buffer
			if len(b) < buf.Size {
				bb = buf.New()
			} else {
				bb = buf.NewLocal(len(b))
			}
			bb.Append(b)
			mb.Append(bb)
		}
	}

	return mb, nil
}

type AuthenticationWriter struct {
	auth         Authenticator
	buffer       []byte
	payload      []byte
	writer       *buf.BufferedWriter
	sizeParser   ChunkSizeEncoder
	transferType protocol.TransferType
}

func NewAuthenticationWriter(auth Authenticator, sizeParser ChunkSizeEncoder, writer io.Writer, transferType protocol.TransferType) *AuthenticationWriter {
	const payloadSize = 1024
	return &AuthenticationWriter{
		auth:         auth,
		buffer:       make([]byte, payloadSize+sizeParser.SizeBytes()+auth.Overhead()),
		payload:      make([]byte, payloadSize),
		writer:       buf.NewBufferedWriterSize(writer, readerBufferSize),
		sizeParser:   sizeParser,
		transferType: transferType,
	}
}

func (w *AuthenticationWriter) append(b []byte) error {
	encryptedSize := len(b) + w.auth.Overhead()
	buffer := w.sizeParser.Encode(uint16(encryptedSize), w.buffer[:0])

	buffer, err := w.auth.Seal(buffer, b)
	if err != nil {
		return err
	}

	if _, err := w.writer.Write(buffer); err != nil {
		return err
	}

	return nil
}

func (w *AuthenticationWriter) writeStream(mb buf.MultiBuffer) error {
	defer mb.Release()

	for {
		n, _ := mb.Read(w.payload)
		if err := w.append(w.payload[:n]); err != nil {
			return err
		}
		if mb.IsEmpty() {
			break
		}
	}

	return w.writer.Flush()
}

func (w *AuthenticationWriter) writePacket(mb buf.MultiBuffer) error {
	defer mb.Release()

	for {
		b := mb.SplitFirst()
		if b == nil {
			b = buf.New()
		}
		if err := w.append(b.Bytes()); err != nil {
			b.Release()
			return err
		}
		b.Release()
		if mb.IsEmpty() {
			break
		}
	}

	return w.writer.Flush()
}

func (w *AuthenticationWriter) Write(mb buf.MultiBuffer) error {
	if w.transferType == protocol.TransferTypeStream {
		return w.writeStream(mb)
	}

	return w.writePacket(mb)
}
<|endoftext|>


<commit_before>package auth

import (
	"encoding/json"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
)

// Abstract implementation of OAuth2 for user authentication.
type OAuth2Mixin struct {
	ClientId     string
	ClientSecret string
	RedirectUrl  string
}

// RedirectRequired returns a boolean value indicating if the request should
// be redirected to the Provider's login screen, in order to provide an OAuth
// Access Token.
func (self *OAuth2Mixin) RedirectRequired(r *http.Request) bool {
	return r.URL.Query().Get("code") == ""
}

func (self *OAuth2Mixin) GetAccessToken(endpoint string, params url.Values,
	headers http.Header) (string, error) {

	//create the access token url params
	if params == nil {
		params = make(url.Values)
	}

	//add the client id, client secret and code to the query params
	params.Add("client_id", self.ClientId)
	params.Add("client_secret", self.ClientSecret)
	if self.RedirectUrl != "" {
		params.Add("redirect_uri", self.RedirectUrl)
	}

	//create the access token request url
	accessTokenUrl, _ := url.Parse(endpoint)
	accessTokenUrl.RawQuery = params.Encode()

	//create the http request
	req := http.Request{
		URL:        accessTokenUrl,
		Method:     "POST",
		ProtoMajor: 1,
		ProtoMinor: 1,
		Close:      true,
	}

	//set the header variables
	req.Header = headers

	//HACK for Google implementation
	//need to find a better way to handle this
	if headers != nil {
		req.URL.RawQuery = ""
		reader := strings.NewReader(params.Encode())
		req.Body = ioutil.NopCloser(reader)
	}

	//do the http request and get the response
	response, err := http.DefaultClient.Do(&req)
	if err != nil {
		return "", err
	}

	//get the response body
	accessToken, err := ioutil.ReadAll(response.Body)
	defer response.Body.Close()

	if err != nil {
		return "", err
	}

	return string(accessToken), nil
}

func (self *OAuth2Mixin) AuthorizeRedirect(w http.ResponseWriter, r *http.Request,
	endpoint string, params url.Values) {

	if params == nil {
		params = make(url.Values)
	}
	params.Add("client_id", self.ClientId)
	if self.RedirectUrl != "" {
		params.Add("redirect_uri", self.RedirectUrl)
	}

	// create auth url
	loginUrl, _ := url.Parse(endpoint)
	loginUrl.RawQuery = params.Encode()

	//HACK encode() with encode the "+" that separates the scopes
	//we will do a find / replace to change this
	loginUrl.RawQuery = strings.Replace(loginUrl.RawQuery, "%2B", "+", -1)

	// redirect to login
	http.Redirect(w, r, loginUrl.String(), http.StatusSeeOther)
}

func (self *OAuth2Mixin) GetAuthenticatedUser(endpoint string, accessToken string,
	headers http.Header, resp interface{}) error {

	//create the user url
	endpointUrl, _ := url.Parse(endpoint)
	endpointUrl.RawQuery = accessToken

	//create the http request for the user Url
	req := http.Request{
		URL:        endpointUrl,
		Method:     "GET",
		ProtoMajor: 1,
		ProtoMinor: 1,
		Close:      true,
	}

	//add request headers
	req.Header = headers

	//do the http request and get the response
	r, err := http.DefaultClient.Do(&req)
	if err != nil {
		return err
	}

	//get the response body
	userData, err := ioutil.ReadAll(r.Body)
	defer r.Body.Close()
	if err != nil {
		return err
	}

	//unmarshal user json
	json.Unmarshal(userData, &resp)
	return nil
}
<commit_msg>modified GetAuthenticatedUser to return unmarshalling error<commit_after>package auth

import (
	"encoding/json"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
)

// Abstract implementation of OAuth2 for user authentication.
type OAuth2Mixin struct {
	ClientId     string
	ClientSecret string
	RedirectUrl  string
}

// RedirectRequired returns a boolean value indicating if the request should
// be redirected to the Provider's login screen, in order to provide an OAuth
// Access Token.
func (self *OAuth2Mixin) RedirectRequired(r *http.Request) bool {
	return r.URL.Query().Get("code") == ""
}

func (self *OAuth2Mixin) GetAccessToken(endpoint string, params url.Values,
	headers http.Header) (string, error) {

	//create the access token url params
	if params == nil {
		params = make(url.Values)
	}

	//add the client id, client secret and code to the query params
	params.Add("client_id", self.ClientId)
	params.Add("client_secret", self.ClientSecret)
	if self.RedirectUrl != "" {
		params.Add("redirect_uri", self.RedirectUrl)
	}

	//create the access token request url
	accessTokenUrl, _ := url.Parse(endpoint)
	accessTokenUrl.RawQuery = params.Encode()

	//create the http request
	req := http.Request{
		URL:        accessTokenUrl,
		Method:     "POST",
		ProtoMajor: 1,
		ProtoMinor: 1,
		Close:      true,
	}

	//set the header variables
	req.Header = headers

	//HACK for Google implementation
	//need to find a better way to handle this
	if headers != nil {
		req.URL.RawQuery = ""
		reader := strings.NewReader(params.Encode())
		req.Body = ioutil.NopCloser(reader)
	}

	//do the http request and get the response
	response, err := http.DefaultClient.Do(&req)
	if err != nil {
		return "", err
	}

	//get the response body
	accessToken, err := ioutil.ReadAll(response.Body)
	defer response.Body.Close()

	if err != nil {
		return "", err
	}

	return string(accessToken), nil
}

func (self *OAuth2Mixin) AuthorizeRedirect(w http.ResponseWriter, r *http.Request,
	endpoint string, params url.Values) {

	if params == nil {
		params = make(url.Values)
	}
	params.Add("client_id", self.ClientId)
	if self.RedirectUrl != "" {
		params.Add("redirect_uri", self.RedirectUrl)
	}

	// create auth url
	loginUrl, _ := url.Parse(endpoint)
	loginUrl.RawQuery = params.Encode()

	//HACK encode() with encode the "+" that separates the scopes
	//we will do a find / replace to change this
	loginUrl.RawQuery = strings.Replace(loginUrl.RawQuery, "%2B", "+", -1)

	// redirect to login
	http.Redirect(w, r, loginUrl.String(), http.StatusSeeOther)
}

func (self *OAuth2Mixin) GetAuthenticatedUser(endpoint string, accessToken string,
	headers http.Header, resp interface{}) error {

	//create the user url
	endpointUrl, _ := url.Parse(endpoint)
	endpointUrl.RawQuery = accessToken

	//create the http request for the user Url
	req := http.Request{
		URL:        endpointUrl,
		Method:     "GET",
		ProtoMajor: 1,
		ProtoMinor: 1,
		Close:      true,
	}

	//add request headers
	req.Header = headers

	//do the http request and get the response
	r, err := http.DefaultClient.Do(&req)
	if err != nil {
		return err
	}

	//get the response body
	userData, err := ioutil.ReadAll(r.Body)
	defer r.Body.Close()
	if err != nil {
		return err
	}

	//unmarshal user json
	return json.Unmarshal(userData, &resp)
}
<|endoftext|>


<commit_before>package main

import (
    "fmt"
    "os"
)

func main() {
    fmt.Println("Initializing Octave CPU...")

    file, err := os.Open(os.Args[1])

    if err != nil {
        return
    }

    defer file.Close()

    stat, err := file.Stat()

    if err != nil {
        return
    }

    instructions := make([]uint8, stat.Size())
    _, err = file.Read(instructions)

    if err != nil {
        return
    }

    for _, i := range instructions {
        execute(decode(i))
    }
}

type CPU struct {
    memory [65536]uint8
    r0 uint8
    r1 uint8
    r2 uint8
    r3 uint8
    pc uint16
}

type instruction func(uint8)

func decode(i uint8) (instruction, uint8) {
    switch i >> 5 {
        case 0:
            return mem, i
        case 1:
            return loadi, i
        case 2:
            if (i << 3) < 25 {
                return stack, i
            } else {
                return inte, i
            }
        case 3:
            return jmp, i
        case 4:
            return math, i
        case 5:
            return logic, i
        case 6:
            return in, i
        case 7:
            return out, i
    }

    return illegal, i
}

func execute(inst_func instruction, i uint8) {
    inst_func(i)
}

func mem(i uint8) {
    fmt.Println("mem")
}

func loadi(i uint8) {
    fmt.Println("loadi")
}

func stack(i uint8) {
    fmt.Println("stack")
}

func inte(i uint8) {
    fmt.Println("inte")
}

func jmp(i uint8) {
    fmt.Println("jmp")
}

func math(i uint8) {
    fmt.Println("math")
}

func logic(i uint8) {
    fmt.Println("logic")
}

func in(i uint8) {
    fmt.Println("in")
}

func out(i uint8) {
    fmt.Println("out")
}

func illegal(i uint8) {
    fmt.Println("illegal")
}
<commit_msg>CPU execution<commit_after>package main

import (
    "fmt"
    "os"
)

func main() {
    fmt.Println("Initializing Octave CPU...")

    cpu := new(CPU)
    cpu.running = true

    file, err := os.Open(os.Args[1])

    if err != nil {
        return
    }

    defer file.Close()

    stat, err := file.Stat()

    if err != nil {
        return
    }

    cpu.memory = make([]uint8, stat.Size())
    _, err = file.Read(cpu.memory)

    if err != nil {
        return
    }

    for cpu.running {
        inst_byte := fetch(cpu)
        inst_func := decode(inst_byte)
        inst_func(inst_byte, cpu)
    }
}

type CPU struct {
    memory []uint8
    r0 uint8
    r1 uint8
    r2 uint8
    r3 uint8
    pc uint16
    running bool
}

type instruction func(uint8, *CPU)

func fetch(cpu *CPU) uint8 {
    inst := cpu.memory[cpu.pc]
    cpu.pc = cpu.pc + 1
    return inst
}

func decode(i uint8) instruction {
    inst := illegal

    switch i >> 5 {
        case 0:
            inst = mem
        case 1:
            inst = loadi
        case 2:
            if (i << 3) < 25 {
                inst = stack
            } else {
                inst = inte
            }
        case 3:
            inst = jmp
        case 4:
            inst = math
        case 5:
            inst = logic
        case 6:
            inst = in
        case 7:
            inst = out
    }

    return inst
}

func mem(i uint8, cpu *CPU) {
    fmt.Println("mem")
}

func loadi(i uint8, cpu *CPU) {
    fmt.Println("loadi")
}

func stack(i uint8, cpu *CPU) {
    fmt.Println("stack")
}

func inte(i uint8, cpu *CPU) {
    fmt.Println("inte")
}

func jmp(i uint8, cpu *CPU) {
    if i == 96 {
        cpu.running = false
    }

    fmt.Println("jmp")
}

func math(i uint8, cpu *CPU) {
    fmt.Println("math")
}

func logic(i uint8, cpu *CPU) {
    fmt.Println("logic")
}

func in(i uint8, cpu *CPU) {
    fmt.Println("in")
}

func out(i uint8, cpu *CPU) {
    fmt.Println("out")
}

func illegal(i uint8, cpu *CPU) {
    fmt.Println("illegal")
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"os"
)

func main() {
	fmt.Println("Initializing Octave CPU...")

	cpu := &CPU{running: true}

	file, err := os.Open(os.Args[1])

	if err != nil {
		return
	}

	defer file.Close()

	cpu.memory, err = ioutil.ReadAll(file)

	if err != nil {
		return
	}

	for cpu.running {
		inst_byte := fetch(cpu)
		inst_func := decode(inst_byte)
		inst_func(inst_byte, cpu)

		fmt.Printf("R0: %v\n", cpu.registers[0])
		fmt.Printf("R1: %v\n", cpu.registers[1])
		fmt.Printf("R2: %v\n", cpu.registers[2])
		fmt.Printf("R3: %v\n", cpu.registers[3])
		fmt.Println("")
	}
}

type CPU struct {
	memory    []uint8
	registers [4]uint8
	pc        uint16
	running   bool
}

type instruction func(uint8, *CPU)

func fetch(cpu *CPU) uint8 {
	inst := cpu.memory[cpu.pc]
	cpu.pc = cpu.pc + 1
	return inst
}

func decode(i uint8) instruction {
	inst := illegal

	switch i >> 5 {
	case 0:
		inst = mem
	case 1:
		inst = loadi
	case 2:
		inst = stack
	case 3:
		inst = jmp
	case 4:
		inst = math
	case 5:
		inst = logic
	case 6:
		inst = in
	case 7:
		inst = out
	}

	return inst
}

func mem(i uint8, cpu *CPU) {
}

func loadi(i uint8, cpu *CPU) {
	cpu.registers[0] = i << 3 >> 3
}

func stack(i uint8, cpu *CPU) {
}

func jmp(i uint8, cpu *CPU) {
	if i == 96 {
		cpu.running = false
	}
}

func math(i uint8, cpu *CPU) {
	operation := i << 3 >> 7
	destination := i << 4 >> 6
	source := i << 6 >> 6

	if operation == 0 {
		cpu.registers[destination] = cpu.registers[destination] + cpu.registers[source]
	} else {
		cpu.registers[destination] = cpu.registers[destination] / cpu.registers[source]
	}
}

func logic(i uint8, cpu *CPU) {
}

func in(i uint8, cpu *CPU) {
}

func out(i uint8, cpu *CPU) {
}

func illegal(i uint8, cpu *CPU) {
}
<commit_msg>Reorder instructions for new ISA<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"os"
)

func main() {
	fmt.Println("Initializing Octave CPU...")

	cpu := &CPU{running: true}

	file, err := os.Open(os.Args[1])

	if err != nil {
		return
	}

	defer file.Close()

	cpu.memory, err = ioutil.ReadAll(file)

	if err != nil {
		return
	}

	for cpu.running {
		inst_byte := fetch(cpu)
		inst_func := decode(inst_byte)
		inst_func(inst_byte, cpu)

		fmt.Printf("R0: %v\n", cpu.registers[0])
		fmt.Printf("R1: %v\n", cpu.registers[1])
		fmt.Printf("R2: %v\n", cpu.registers[2])
		fmt.Printf("R3: %v\n", cpu.registers[3])
		fmt.Println("")
	}
}

type CPU struct {
	memory    []uint8
	registers [4]uint8
	pc        uint16
	running   bool
}

type instruction func(uint8, *CPU)

func fetch(cpu *CPU) uint8 {
	inst := cpu.memory[cpu.pc]
	cpu.pc = cpu.pc + 1
	return inst
}

func decode(i uint8) instruction {
	inst := illegal

	switch i >> 5 {
	case 0:
		inst = jmp
	case 1:
		inst = loadi
	case 2:
		inst = math
	case 3:
		inst = logic
	case 4:
		inst = mem
	case 5:
		inst = stack
	case 6:
		inst = in
	case 7:
		inst = out
	}

	return inst
}

func jmp(i uint8, cpu *CPU) {
	if i == 0 {
		cpu.running = false
	}
}

func loadi(i uint8, cpu *CPU) {
	cpu.registers[0] = i << 3 >> 3
}

func math(i uint8, cpu *CPU) {
	operation := i << 3 >> 7
	destination := i << 4 >> 6
	source := i << 6 >> 6

	if operation == 0 {
		cpu.registers[destination] = cpu.registers[destination] + cpu.registers[source]
	} else {
		cpu.registers[destination] = cpu.registers[destination] / cpu.registers[source]
	}
}

func logic(i uint8, cpu *CPU) {
}

func mem(i uint8, cpu *CPU) {
}

func stack(i uint8, cpu *CPU) {
}

func in(i uint8, cpu *CPU) {
}

func out(i uint8, cpu *CPU) {
}

func illegal(i uint8, cpu *CPU) {
}
<|endoftext|>


<commit_before>package mysql

import (
	"database/sql"
	"errors"
	"strings"
	"sync"

	_ "github.com/go-sql-driver/mysql"

	"github.com/henrylee2cn/pholcus/common/util"
	"github.com/henrylee2cn/pholcus/config"
	"github.com/henrylee2cn/pholcus/logs"
)

/************************ Mysql 输出 ***************************/
//sql转换结构体
type MyTable struct {
	tableName        string
	columnNames      [][2]string // 标题字段
	rows             [][]string  // 多行数据
	sqlCode          string
	customPrimaryKey bool
	size             int //内容大小的近似值
}

var (
	db                 *sql.DB
	err                error
	stmtChan           = make(chan bool, config.MYSQL_CONN_CAP)
	max_allowed_packet = config.MYSQL_MAX_ALLOWED_PACKET - 1024
	lock               sync.RWMutex
)

func DB() (*sql.DB, error) {
	return db, err
}

func Refresh() {
	lock.Lock()
	defer lock.Unlock()
	db, err = sql.Open("mysql", config.MYSQL_CONN_STR+"/"+config.DB_NAME+"?charset=utf8")
	if err != nil {
		logs.Log.Error("Mysql：%v\n", err)
		return
	}
	db.SetMaxOpenConns(config.MYSQL_CONN_CAP)
	db.SetMaxIdleConns(config.MYSQL_CONN_CAP)
	if err = db.Ping(); err != nil {
		logs.Log.Error("Mysql：%v\n", err)
	}
}

func New() *MyTable {
	return &MyTable{}
}

//设置表名
func (self *MyTable) SetTableName(name string) *MyTable {
	self.tableName = name
	return self
}

//设置表单列
func (self *MyTable) AddColumn(names ...string) *MyTable {
	for _, name := range names {
		name = strings.Trim(name, " ")
		idx := strings.Index(name, " ")
		self.columnNames = append(self.columnNames, [2]string{string(name[:idx]), string(name[idx+1:])})
	}
	return self
}

//设置主键的语句（可选）
func (self *MyTable) CustomPrimaryKey(primaryKeyCode string) *MyTable {
	self.AddColumn(primaryKeyCode)
	self.customPrimaryKey = true
	return self
}

//生成"创建表单"的语句，执行前须保证SetTableName()、AddColumn()已经执行
func (self *MyTable) Create() error {
	if len(self.columnNames) == 0 {
		return errors.New("Column can not be empty")
	}
	self.sqlCode = `create table if not exists ` + "`" + self.tableName + "`" + `(`
	if !self.customPrimaryKey {
		self.sqlCode += `id int(12) not null primary key auto_increment,`
	}
	for _, title := range self.columnNames {
        self.sqlCode += "`" + title[0] + "`" + ` ` + title[1] + `,`
	}
	self.sqlCode = string(self.sqlCode[:len(self.sqlCode)-1])
	self.sqlCode += `);`

	stmtChan <- true
	defer func() {
		<-stmtChan
	}()
	lock.RLock()
	defer lock.RUnlock()
	stmt, err := db.Prepare(self.sqlCode)
	if err != nil {
		return err
	}
	_, err = stmt.Exec()
	return err
}

//设置插入的1行数据
func (self *MyTable) addRow(value []string) *MyTable {
	self.rows = append(self.rows, value)
	return self
}

//智能插入数据，每次1行
func (self *MyTable) AutoInsert(value []string) *MyTable {
	var nsize int
	for _, v := range value {
		nsize += len(v)
	}
	if nsize > max_allowed_packet {
		logs.Log.Error("%v", "packet for query is too large. Try adjusting the 'maxallowedpacket'variable in the 'config.ini'")
		return self
	}
	self.size += nsize
	if self.size > max_allowed_packet {
		util.CheckErr(self.FlushInsert())
		return self.AutoInsert(value)
	}
	return self.addRow(value)
}

//向sqlCode添加"插入数据"的语句，执行前须保证Create()、AutoInsert()已经执行
//insert into table1(field1,field2) values(rows[0]),(rows[1])...
func (self *MyTable) FlushInsert() error {
	if len(self.rows) == 0 {
		return nil
	}

	self.sqlCode = `insert into ` + "`" + self.tableName + "`" + `(`
	if len(self.columnNames) != 0 {
		for _, v := range self.columnNames {
			self.sqlCode += "`" + v[0] + "`,"
		}
		self.sqlCode = self.sqlCode[:len(self.sqlCode)-1] + `)values`
	}
	for _, row := range self.rows {
		self.sqlCode += `(`
		for _, v := range row {
			v = strings.Replace(v, `"`, `\"`, -1)
			self.sqlCode += `"` + v + `",`
		}
		self.sqlCode = self.sqlCode[:len(self.sqlCode)-1] + `),`
	}
	self.sqlCode = self.sqlCode[:len(self.sqlCode)-1] + `;`

	stmtChan <- true
	defer func() {
		<-stmtChan
	}()
	lock.RLock()
	defer lock.RUnlock()
	defer func() {
		// 清空临时数据
		self.rows = [][]string{}
		self.size = 0
		self.sqlCode = ""
	}()
	stmt, err := db.Prepare(self.sqlCode)
	if err != nil {
		return err
	}
	_, err = stmt.Exec()
	return err
}

// 获取全部数据
func (self *MyTable) SelectAll() (*sql.Rows, error) {
	if self.tableName == "" {
		return nil, errors.New("表名不能为空")
	}
	self.sqlCode = `select * from ` + "`" + self.tableName + "`" + `;`
	lock.RLock()
	defer lock.RUnlock()
	return db.Query(self.sqlCode)
}
<commit_msg>Format code<commit_after>package mysql

import (
	"database/sql"
	"errors"
	"strings"
	"sync"

	_ "github.com/go-sql-driver/mysql"

	"github.com/henrylee2cn/pholcus/common/util"
	"github.com/henrylee2cn/pholcus/config"
	"github.com/henrylee2cn/pholcus/logs"
)

/************************ Mysql 输出 ***************************/
//sql转换结构体
type MyTable struct {
	tableName        string
	columnNames      [][2]string // 标题字段
	rows             [][]string  // 多行数据
	sqlCode          string
	customPrimaryKey bool
	size             int //内容大小的近似值
}

var (
	db                 *sql.DB
	err                error
	stmtChan           = make(chan bool, config.MYSQL_CONN_CAP)
	max_allowed_packet = config.MYSQL_MAX_ALLOWED_PACKET - 1024
	lock               sync.RWMutex
)

func DB() (*sql.DB, error) {
	return db, err
}

func Refresh() {
	lock.Lock()
	defer lock.Unlock()
	db, err = sql.Open("mysql", config.MYSQL_CONN_STR+"/"+config.DB_NAME+"?charset=utf8")
	if err != nil {
		logs.Log.Error("Mysql：%v\n", err)
		return
	}
	db.SetMaxOpenConns(config.MYSQL_CONN_CAP)
	db.SetMaxIdleConns(config.MYSQL_CONN_CAP)
	if err = db.Ping(); err != nil {
		logs.Log.Error("Mysql：%v\n", err)
	}
}

func New() *MyTable {
	return &MyTable{}
}

//设置表名
func (self *MyTable) SetTableName(name string) *MyTable {
	self.tableName = name
	return self
}

//设置表单列
func (self *MyTable) AddColumn(names ...string) *MyTable {
	for _, name := range names {
		name = strings.Trim(name, " ")
		idx := strings.Index(name, " ")
		self.columnNames = append(self.columnNames, [2]string{string(name[:idx]), string(name[idx+1:])})
	}
	return self
}

//设置主键的语句（可选）
func (self *MyTable) CustomPrimaryKey(primaryKeyCode string) *MyTable {
	self.AddColumn(primaryKeyCode)
	self.customPrimaryKey = true
	return self
}

//生成"创建表单"的语句，执行前须保证SetTableName()、AddColumn()已经执行
func (self *MyTable) Create() error {
	if len(self.columnNames) == 0 {
		return errors.New("Column can not be empty")
	}
	self.sqlCode = `create table if not exists ` + "`" + self.tableName + "`" + `(`
	if !self.customPrimaryKey {
		self.sqlCode += `id int(12) not null primary key auto_increment,`
	}
	for _, title := range self.columnNames {
		self.sqlCode += "`" + title[0] + "`" + ` ` + title[1] + `,`
	}
	self.sqlCode = string(self.sqlCode[:len(self.sqlCode)-1])
	self.sqlCode += `);`

	stmtChan <- true
	defer func() {
		<-stmtChan
	}()
	lock.RLock()
	defer lock.RUnlock()
	stmt, err := db.Prepare(self.sqlCode)
	if err != nil {
		return err
	}
	_, err = stmt.Exec()
	return err
}

//设置插入的1行数据
func (self *MyTable) addRow(value []string) *MyTable {
	self.rows = append(self.rows, value)
	return self
}

//智能插入数据，每次1行
func (self *MyTable) AutoInsert(value []string) *MyTable {
	var nsize int
	for _, v := range value {
		nsize += len(v)
	}
	if nsize > max_allowed_packet {
		logs.Log.Error("%v", "packet for query is too large. Try adjusting the 'maxallowedpacket'variable in the 'config.ini'")
		return self
	}
	self.size += nsize
	if self.size > max_allowed_packet {
		util.CheckErr(self.FlushInsert())
		return self.AutoInsert(value)
	}
	return self.addRow(value)
}

//向sqlCode添加"插入数据"的语句，执行前须保证Create()、AutoInsert()已经执行
//insert into table1(field1,field2) values(rows[0]),(rows[1])...
func (self *MyTable) FlushInsert() error {
	if len(self.rows) == 0 {
		return nil
	}

	self.sqlCode = `insert into ` + "`" + self.tableName + "`" + `(`
	if len(self.columnNames) != 0 {
		for _, v := range self.columnNames {
			self.sqlCode += "`" + v[0] + "`,"
		}
		self.sqlCode = self.sqlCode[:len(self.sqlCode)-1] + `)values`
	}
	for _, row := range self.rows {
		self.sqlCode += `(`
		for _, v := range row {
			v = strings.Replace(v, `"`, `\"`, -1)
			self.sqlCode += `"` + v + `",`
		}
		self.sqlCode = self.sqlCode[:len(self.sqlCode)-1] + `),`
	}
	self.sqlCode = self.sqlCode[:len(self.sqlCode)-1] + `;`

	stmtChan <- true
	defer func() {
		<-stmtChan
	}()
	lock.RLock()
	defer lock.RUnlock()
	defer func() {
		// 清空临时数据
		self.rows = [][]string{}
		self.size = 0
		self.sqlCode = ""
	}()
	stmt, err := db.Prepare(self.sqlCode)
	if err != nil {
		return err
	}
	_, err = stmt.Exec()
	return err
}

// 获取全部数据
func (self *MyTable) SelectAll() (*sql.Rows, error) {
	if self.tableName == "" {
		return nil, errors.New("表名不能为空")
	}
	self.sqlCode = `select * from ` + "`" + self.tableName + "`" + `;`
	lock.RLock()
	defer lock.RUnlock()
	return db.Query(self.sqlCode)
}
<|endoftext|>


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

package s3git

import (
	"os"
	"fmt"
	"path/filepath"
	"github.com/s3git/s3git-go/internal/kv"
	"github.com/s3git/s3git-go/internal/cas"
	"github.com/s3git/s3git-go/internal/core"
	"github.com/s3git/s3git-go/internal/backend"
	"github.com/s3git/s3git-go/internal/backend/s3"
	"io"
	"errors"
	"encoding/hex"
)

// Create a snapshot for the repository
func (repo Repository) SnapshotCreate(path, message string) (hash string, empty bool, err error) {

	// Create snapshot
	snapshot, err := core.StoreSnapshotObject(path, func(filename string) (string, error) {

		// Test for deduped storage of file, then we can safely skip it
		deduped, key, _, err := cas.CheckLevel1HashFollowedByLeafHashes(filename)
		if err != nil {
			return "", err
		}
		if deduped { // It is stored in deduped format, so return key immediately
			return key, nil
		}

		// Otherwise compute the hash based on the contents of the file
		file, err := os.Open(filename)
		if err != nil {
			return "", err
		}
		defer file.Close()

		key, _, err = repo.Add(file)
		return key, err
	})
	if err != nil {
		return "", false, err
	}

	// TODO: Make sure we commit a new object, even when no new blobs added (ListStage is empty)
	return repo.commit(message, "master", snapshot, []string{})
}

// Checkout a snapshot for the repository
func (repo Repository) SnapshotCheckout(path, commit string, dedupe bool) error {

	snapshot, err := getSnapshotFromCommit(commit)
	if err != nil {
		return err
	}

	// TODO: Check that status is clean (create 'stashing' like behaviour for temp changes?)

	// For dedupe is false  --> store full contents
	fWriteHydrate := func(hash, filename string, mode os.FileMode) {

		// Compute hash in order to prevent rewriting the content when file already exists
		if _, err := os.Stat(filename); err == nil {

			digest, err := cas.Sum(filename)
			if err != nil {
				return
			}

			if digest == hash {	// Contents unchanged --> exit out early
				return
			}
		}

		r, err := repo.Get(hash)
		if err != nil {
			return
		}

		f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, mode)
		if err != nil {
			return
		}

		io.Copy(f, r)
	}

	// For dedupe is true --> store all leaf hashes as contents followed by final 64 bytes with level 1 hash
	fWriteDeduped := func(hash, filename string, mode os.FileMode) {

		// TODO: Can we prevent (re)writing the content (run a check when file exists)?

		cas.WriteLevel1HashFollowedByLeafHashes(hash, filename, mode)
	}

	var fWrite func(hash, filename string, perm os.FileMode)
	if dedupe {
		fWrite = fWriteDeduped
	} else {
		fWrite = fWriteHydrate
	}

	return core.SnapshotCheckout(path, snapshot, fWrite)
}

type snapshotListOptions struct {
	showHash bool
	presignedUrls bool
	jsonOutput bool
}

func SnapshotListOptionSetShowHash(showHash bool) func(optns *snapshotListOptions) {
	return func(optns *snapshotListOptions) {
		optns.showHash = showHash
	}
}

func SnapshotListOptionSetPresignedUrls(presignedUrls bool) func(optns *snapshotListOptions) {
	return func(optns *snapshotListOptions) {
		optns.presignedUrls = presignedUrls
	}
}

func SnapshotListOptionSetJsonOutput(jsonOutput bool) func(optns *snapshotListOptions) {
	return func(optns *snapshotListOptions) {
		optns.jsonOutput = jsonOutput
	}
}

type SnapshotListOptions func(*snapshotListOptions)

// List a snapshot for the repository
func (repo Repository) SnapshotList(commit string, options ...SnapshotListOptions) error {

	optns := &snapshotListOptions{}
	for _, op := range options {
		op(optns)
	}

	snapshot, err := getSnapshotFromCommit(commit)
	if err != nil {
		return err
	}

	funcPresignedUrl := func(hash string) (string, error) { return "", nil }
	if optns.presignedUrls {
		client, err := backend.GetDefaultClient()
		if err != nil {
			return err
		}

		// Look for S3 back end
		s3, ok := client.(*s3.Client)
		if ok {
			// And if so generate function to generate presigned url
			funcPresignedUrl = func(hash string) (string, error) {
				return s3.GetPresignedUrl(hash)
			}
		}
	}

	// List snapshot
	err = core.SnapshotList(snapshot, func(entry core.SnapshotEntry, base string) {

		// TODO: Dump result in JSON format if requested

		url, _ := funcPresignedUrl(entry.Blob)
		if url != "" {
			fmt.Printf("%s --> %s\n", filepath.Join(base, entry.Name), url)
		} else if optns.showHash {
			fmt.Println(filepath.Join(base, entry.Name), entry.Blob)
		} else {
			fmt.Println(filepath.Join(base, entry.Name))
		}
	}, func(base string) {}, func(base string, entries []core.SnapshotEntry) {})

	return err
}

// Show status for a snapshot of the repository
func (repo Repository) SnapshotStatus(path, commit string) error {

	snapshot, err := getSnapshotFromCommit(commit)
	if err != nil {
		return err
	}

	// Get status of snapshot
	err = core.SnapshotStatus(path, snapshot)

	return err
}

func getSnapshotFromCommit(commit string) (string, error) {

	if commit == "" {	// Unspecified, so default to last commit
		commits, err := kv.ListTopMostCommits()
		if err != nil {
			return "", err
		}
		parents := []string{}
		for c := range commits {
			parents = append(parents, hex.EncodeToString(c))
		}
		if len(parents) == 1 {
			commit = parents[0]
		} else {
			// TODO: Do extra check whether the trees are the same, in that case we can safely ignore the warning
			return "", errors.New("Multiple top most commits founds as parents")
		}
	} else {

		result := make(chan string)

		go func() {
			// make sure we always close the channel
			defer close(result)

			keys, err := kv.ListLevel1Commits(commit)
			if err != nil {
				return
			}

			for key := range keys {
				result <- hex.EncodeToString(key)
			}
		}()

		var err error
		commit, err = getUnique(result)
		if err != nil {
			return "", err
		}
	}

	co, err := core.GetCommitObject(commit)
	if err != nil {
		return "", err
	}

	if co.S3gitSnapshot == "" {
		return "", errors.New(fmt.Sprintf("Commit %s does not contain snapshot", commit))
	}

	return co.S3gitSnapshot, nil
}<commit_msg>Pull snapshots down on demand<commit_after>/*
 * Copyright 2016 Frank Wessels <fwessels@xs4all.nl>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package s3git

import (
	"os"
	"fmt"
	"path/filepath"
	"github.com/s3git/s3git-go/internal/kv"
	"github.com/s3git/s3git-go/internal/cas"
	"github.com/s3git/s3git-go/internal/core"
	"github.com/s3git/s3git-go/internal/backend"
	"github.com/s3git/s3git-go/internal/backend/s3"
	"io"
	"errors"
	"encoding/hex"
	"sync"
)

// Create a snapshot for the repository
func (repo Repository) SnapshotCreate(path, message string) (hash string, empty bool, err error) {

	// Create snapshot
	snapshot, err := core.StoreSnapshotObject(path, func(filename string) (string, error) {

		// Test for deduped storage of file, then we can safely skip it
		deduped, key, _, err := cas.CheckLevel1HashFollowedByLeafHashes(filename)
		if err != nil {
			return "", err
		}
		if deduped { // It is stored in deduped format, so return key immediately
			return key, nil
		}

		// Otherwise compute the hash based on the contents of the file
		file, err := os.Open(filename)
		if err != nil {
			return "", err
		}
		defer file.Close()

		key, _, err = repo.Add(file)
		return key, err
	})
	if err != nil {
		return "", false, err
	}

	// TODO: Make sure we commit a new object, even when no new blobs added (ListStage is empty)
	return repo.commit(message, "master", snapshot, []string{})
}

// Checkout a snapshot for the repository
func (repo Repository) SnapshotCheckout(path, commit string, dedupe bool) error {

	snapshot, err := getSnapshotFromCommit(commit)
	if err != nil {
		return err
	}

	// TODO: Check that status is clean (create 'stashing' like behaviour for temp changes?)

	// For dedupe is false  --> store full contents
	fWriteHydrate := func(hash, filename string, mode os.FileMode) {

		// Compute hash in order to prevent rewriting the content when file already exists
		if _, err := os.Stat(filename); err == nil {

			digest, err := cas.Sum(filename)
			if err != nil {
				return
			}

			if digest == hash {	// Contents unchanged --> exit out early
				return
			}
		}

		r, err := repo.Get(hash)
		if err != nil {
			return
		}

		f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, mode)
		if err != nil {
			return
		}

		io.Copy(f, r)
	}

	// For dedupe is true --> store all leaf hashes as contents followed by final 64 bytes with level 1 hash
	fWriteDeduped := func(hash, filename string, mode os.FileMode) {

		// TODO: Can we prevent (re)writing the content (run a check when file exists)?

		cas.WriteLevel1HashFollowedByLeafHashes(hash, filename, mode)
	}

	var fWrite func(hash, filename string, perm os.FileMode)
	if dedupe {
		fWrite = fWriteDeduped
	} else {
		fWrite = fWriteHydrate
	}

	return core.SnapshotCheckout(path, snapshot, fWrite)
}

type snapshotListOptions struct {
	showHash bool
	presignedUrls bool
	jsonOutput bool
}

func SnapshotListOptionSetShowHash(showHash bool) func(optns *snapshotListOptions) {
	return func(optns *snapshotListOptions) {
		optns.showHash = showHash
	}
}

func SnapshotListOptionSetPresignedUrls(presignedUrls bool) func(optns *snapshotListOptions) {
	return func(optns *snapshotListOptions) {
		optns.presignedUrls = presignedUrls
	}
}

func SnapshotListOptionSetJsonOutput(jsonOutput bool) func(optns *snapshotListOptions) {
	return func(optns *snapshotListOptions) {
		optns.jsonOutput = jsonOutput
	}
}

type SnapshotListOptions func(*snapshotListOptions)

// List a snapshot for the repository
func (repo Repository) SnapshotList(commit string, options ...SnapshotListOptions) error {

	optns := &snapshotListOptions{}
	for _, op := range options {
		op(optns)
	}

	snapshot, err := getSnapshotFromCommit(commit)
	if err != nil {
		return err
	}

	funcPresignedUrl := func(hash string) (string, error) { return "", nil }
	if optns.presignedUrls {
		client, err := backend.GetDefaultClient()
		if err != nil {
			return err
		}

		// Look for S3 back end
		s3, ok := client.(*s3.Client)
		if ok {
			// And if so generate function to generate presigned url
			funcPresignedUrl = func(hash string) (string, error) {
				return s3.GetPresignedUrl(hash)
			}
		}
	}

	// List snapshot
	err = core.SnapshotList(snapshot, func(entry core.SnapshotEntry, base string) {

		// TODO: Dump result in JSON format if requested

		url, _ := funcPresignedUrl(entry.Blob)
		if url != "" {
			fmt.Printf("%s --> %s\n", filepath.Join(base, entry.Name), url)
		} else if optns.showHash {
			fmt.Println(filepath.Join(base, entry.Name), entry.Blob)
		} else {
			fmt.Println(filepath.Join(base, entry.Name))
		}
	}, func(base string) {}, func(base string, entries []core.SnapshotEntry) {})

	return err
}

// Show status for a snapshot of the repository
func (repo Repository) SnapshotStatus(path, commit string) error {

	snapshot, err := getSnapshotFromCommit(commit)
	if err != nil {
		return err
	}

	// Get status of snapshot
	err = core.SnapshotStatus(path, snapshot)

	return err
}

func getSnapshotFromCommit(commit string) (string, error) {

	if commit == "" {	// Unspecified, so default to last commit
		commits, err := kv.ListTopMostCommits()
		if err != nil {
			return "", err
		}
		parents := []string{}
		for c := range commits {
			parents = append(parents, hex.EncodeToString(c))
		}
		if len(parents) == 1 {
			commit = parents[0]
		} else {
			// TODO: Do extra check whether the trees are the same, in that case we can safely ignore the warning
			return "", errors.New("Multiple top most commits founds as parents")
		}
	} else {

		result := make(chan string)

		go func() {
			// make sure we always close the channel
			defer close(result)

			keys, err := kv.ListLevel1Commits(commit)
			if err != nil {
				return
			}

			for key := range keys {
				result <- hex.EncodeToString(key)
			}
		}()

		var err error
		commit, err = getUnique(result)
		if err != nil {
			return "", err
		}
	}

	co, err := core.GetCommitObject(commit)
	if err != nil {
		return "", err
	}

	if co.S3gitSnapshot == "" {
		return "", errors.New(fmt.Sprintf("Commit %s does not contain snapshot", commit))
	}

	b, _ := hex.DecodeString(co.S3gitSnapshot)
	leafHashes, _, err := kv.GetLevel1(b)
	if err != nil {
		return "", err
	}

	// Has snapshot not yet been pulled down to disk?
	if len(leafHashes) == 0 {
		client, err := backend.GetDefaultClient()
		if err != nil {
			return "", err
		}

		err = pullSnapshotWithChildren(co.S3gitSnapshot, client)
		if err != nil {
			return "", err
		}
	}

	return co.S3gitSnapshot, nil
}

func pullSnapshotWithChildren(hash string, client backend.Backend) error {

	const pullSnapshotRoutines = 100

	var wg sync.WaitGroup
	var msgs = make(chan string, pullSnapshotRoutines*2)
	var results = make(chan error, pullSnapshotRoutines*2)

	for i := 0; i < pullSnapshotRoutines; i++ {

		go func() {
			for hash := range msgs {

				//fmt.Println("Pull snapshot", hash)
				// Now pull down snapshot object
				snapshotName, snapshotBytes, err := fetchBlobTempFileAndContents(hash, client)
				if err != nil {
					//return err
				}
				defer os.Remove(snapshotName)

				so, err := core.GetSnapshotObjectFromString(string(snapshotBytes))

				for _, entry := range so.S3gitEntries {
					if entry.IsDirectory() {
						//fmt.Println("wg.Add for", entry.Blob)
						wg.Add(1)
						msgs <- entry.Blob
					}
				}

				// Add snapshot object to cas
				_, err = cas.StoreBlobInCache(snapshotName, kv.SNAPSHOT)
				if err != nil {
					//return err
				}

				//fmt.Println("wg.Done for", hash)
				wg.Done()
			}
		}()
	}

	wg.Add(1)
	msgs <- hash

	go func() {
		wg.Wait()
		close(msgs)
		close(results)
	}()

	var err error
	for e := range results {
		if e != nil {
			err = e
		}
	}

	return err
}<|endoftext|>


<commit_before>package heroku

import (
	"fmt"
	"os"
	"testing"

	"github.com/cyberdelia/heroku-go/v3"
	"github.com/hashicorp/terraform/helper/acctest"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"
)

func TestAccHerokuApp_Basic(t *testing.T) {
	var app heroku.App
	appName := fmt.Sprintf("tftest-%s", acctest.RandString(10))

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckHerokuAppDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccCheckHerokuAppConfig_basic(appName),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckHerokuAppExists("heroku_app.foobar", &app),
					testAccCheckHerokuAppAttributes(&app, appName),
					resource.TestCheckResourceAttr(
						"heroku_app.foobar", "name", appName),
					resource.TestCheckResourceAttr(
						"heroku_app.foobar", "config_vars.0.FOO", "bar"),
				),
			},
		},
	})
}

func TestAccHerokuApp_NameChange(t *testing.T) {
	var app heroku.App
	appName := fmt.Sprintf("tftest-%s", acctest.RandString(10))
	appName2 := fmt.Sprintf("%s-v2", appName)

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckHerokuAppDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccCheckHerokuAppConfig_basic(appName),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckHerokuAppExists("heroku_app.foobar", &app),
					testAccCheckHerokuAppAttributes(&app, appName),
					resource.TestCheckResourceAttr(
						"heroku_app.foobar", "name", appName),
					resource.TestCheckResourceAttr(
						"heroku_app.foobar", "config_vars.0.FOO", "bar"),
				),
			},
			resource.TestStep{
				Config: testAccCheckHerokuAppConfig_updated(appName2),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckHerokuAppExists("heroku_app.foobar", &app),
					testAccCheckHerokuAppAttributesUpdated(&app, appName2),
					resource.TestCheckResourceAttr(
						"heroku_app.foobar", "name", appName2),
					resource.TestCheckResourceAttr(
						"heroku_app.foobar", "config_vars.0.FOO", "bing"),
					resource.TestCheckResourceAttr(
						"heroku_app.foobar", "config_vars.0.BAZ", "bar"),
				),
			},
		},
	})
}

func TestAccHerokuApp_NukeVars(t *testing.T) {
	var app heroku.App
	appName := fmt.Sprintf("tftest-%s", acctest.RandString(10))

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckHerokuAppDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccCheckHerokuAppConfig_basic(appName),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckHerokuAppExists("heroku_app.foobar", &app),
					testAccCheckHerokuAppAttributes(&app, appName),
					resource.TestCheckResourceAttr(
						"heroku_app.foobar", "name", appName),
					resource.TestCheckResourceAttr(
						"heroku_app.foobar", "config_vars.0.FOO", "bar"),
				),
			},
			resource.TestStep{
				Config: testAccCheckHerokuAppConfig_no_vars(appName),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckHerokuAppExists("heroku_app.foobar", &app),
					testAccCheckHerokuAppAttributesNoVars(&app, appName),
					resource.TestCheckResourceAttr(
						"heroku_app.foobar", "name", appName),
					resource.TestCheckResourceAttr(
						"heroku_app.foobar", "config_vars.0.FOO", ""),
				),
			},
		},
	})
}

func TestAccHerokuApp_Organization(t *testing.T) {
	var app heroku.OrganizationApp
	appName := fmt.Sprintf("tftest-%s", acctest.RandString(10))
	org := os.Getenv("HEROKU_ORGANIZATION")

	resource.Test(t, resource.TestCase{
		PreCheck: func() {
			testAccPreCheck(t)
			if org == "" {
				t.Skip("HEROKU_ORGANIZATION is not set; skipping test.")
			}
		},
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckHerokuAppDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccCheckHerokuAppConfig_organization(appName, org),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckHerokuAppExistsOrg("heroku_app.foobar", &app),
					testAccCheckHerokuAppAttributesOrg(&app, appName, org),
				),
			},
		},
	})
}

func testAccCheckHerokuAppDestroy(s *terraform.State) error {
	client := testAccProvider.Meta().(*heroku.Service)

	for _, rs := range s.RootModule().Resources {
		if rs.Type != "heroku_app" {
			continue
		}

		_, err := client.AppInfo(rs.Primary.ID)

		if err == nil {
			return fmt.Errorf("App still exists")
		}
	}

	return nil
}

func testAccCheckHerokuAppAttributes(app *heroku.App, appName string) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		client := testAccProvider.Meta().(*heroku.Service)

		if app.Region.Name != "us" {
			return fmt.Errorf("Bad region: %s", app.Region.Name)
		}

		if app.Stack.Name != "cedar-14" {
			return fmt.Errorf("Bad stack: %s", app.Stack.Name)
		}

		if app.Name != appName {
			return fmt.Errorf("Bad name: %s", app.Name)
		}

		vars, err := client.ConfigVarInfo(app.Name)
		if err != nil {
			return err
		}

		if vars["FOO"] != "bar" {
			return fmt.Errorf("Bad config vars: %v", vars)
		}

		return nil
	}
}

func testAccCheckHerokuAppAttributesUpdated(app *heroku.App, appName string) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		client := testAccProvider.Meta().(*heroku.Service)

		if app.Name != appName {
			return fmt.Errorf("Bad name: %s", app.Name)
		}

		vars, err := client.ConfigVarInfo(app.Name)
		if err != nil {
			return err
		}

		// Make sure we kept the old one
		if vars["FOO"] != "bing" {
			return fmt.Errorf("Bad config vars: %v", vars)
		}

		if vars["BAZ"] != "bar" {
			return fmt.Errorf("Bad config vars: %v", vars)
		}

		return nil

	}
}

func testAccCheckHerokuAppAttributesNoVars(app *heroku.App, appName string) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		client := testAccProvider.Meta().(*heroku.Service)

		if app.Name != appName {
			return fmt.Errorf("Bad name: %s", app.Name)
		}

		vars, err := client.ConfigVarInfo(app.Name)
		if err != nil {
			return err
		}

		if len(vars) != 0 {
			return fmt.Errorf("vars exist: %v", vars)
		}

		return nil
	}
}

func testAccCheckHerokuAppAttributesOrg(app *heroku.OrganizationApp, appName string, org string) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		client := testAccProvider.Meta().(*heroku.Service)

		if app.Region.Name != "us" {
			return fmt.Errorf("Bad region: %s", app.Region.Name)
		}

		if app.Stack.Name != "cedar-14" {
			return fmt.Errorf("Bad stack: %s", app.Stack.Name)
		}

		if app.Name != appName {
			return fmt.Errorf("Bad name: %s", app.Name)
		}

		if app.Organization == nil || app.Organization.Name != org {
			return fmt.Errorf("Bad org: %v", app.Organization)
		}

		vars, err := client.ConfigVarInfo(app.Name)
		if err != nil {
			return err
		}

		if vars["FOO"] != "bar" {
			return fmt.Errorf("Bad config vars: %v", vars)
		}

		return nil
	}
}

func testAccCheckHerokuAppExists(n string, app *heroku.App) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		rs, ok := s.RootModule().Resources[n]

		if !ok {
			return fmt.Errorf("Not found: %s", n)
		}

		if rs.Primary.ID == "" {
			return fmt.Errorf("No App Name is set")
		}

		client := testAccProvider.Meta().(*heroku.Service)

		foundApp, err := client.AppInfo(rs.Primary.ID)

		if err != nil {
			return err
		}

		if foundApp.Name != rs.Primary.ID {
			return fmt.Errorf("App not found")
		}

		*app = *foundApp

		return nil
	}
}

func testAccCheckHerokuAppExistsOrg(n string, app *heroku.OrganizationApp) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		rs, ok := s.RootModule().Resources[n]

		if !ok {
			return fmt.Errorf("Not found: %s", n)
		}

		if rs.Primary.ID == "" {
			return fmt.Errorf("No App Name is set")
		}

		client := testAccProvider.Meta().(*heroku.Service)

		foundApp, err := client.OrganizationAppInfo(rs.Primary.ID)

		if err != nil {
			return err
		}

		if foundApp.Name != rs.Primary.ID {
			return fmt.Errorf("App not found")
		}

		*app = *foundApp

		return nil
	}
}

func testAccCheckHerokuAppConfig_basic(appName string) string {
	return fmt.Sprintf(`
resource "heroku_app" "foobar" {
  name   = "%s"
  region = "us"

  config_vars {
    FOO = "bar"
  }
}`, appName)
}

func testAccCheckHerokuAppConfig_updated(appName string) string {
	return fmt.Sprintf(`
resource "heroku_app" "foobar" {
  name   = "%s"
  region = "us"

  config_vars {
    FOO = "bing"
    BAZ = "bar"
  }
}`, appName)
}

func testAccCheckHerokuAppConfig_no_vars(appName string) string {
	return fmt.Sprintf(`
resource "heroku_app" "foobar" {
  name   = "%s"
  region = "us"
}`, appName)
}

func testAccCheckHerokuAppConfig_organization(appName, org string) string {
	return fmt.Sprintf(`
resource "heroku_app" "foobar" {
  name   = "%s"
  region = "us"

  organization {
    name = "%s"
  }

  config_vars {
    FOO = "bar"
  }
}`, appName, org)
}
<commit_msg>provider/heroku: Fix failing acceptance test (#11374)<commit_after>package heroku

import (
	"fmt"
	"os"
	"testing"

	"github.com/cyberdelia/heroku-go/v3"
	"github.com/hashicorp/terraform/helper/acctest"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"
)

func TestAccHerokuApp_Basic(t *testing.T) {
	var app heroku.App
	appName := fmt.Sprintf("tftest-%s", acctest.RandString(10))

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckHerokuAppDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccCheckHerokuAppConfig_basic(appName),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckHerokuAppExists("heroku_app.foobar", &app),
					testAccCheckHerokuAppAttributes(&app, appName),
					resource.TestCheckResourceAttr(
						"heroku_app.foobar", "name", appName),
					resource.TestCheckResourceAttr(
						"heroku_app.foobar", "config_vars.0.FOO", "bar"),
				),
			},
		},
	})
}

func TestAccHerokuApp_NameChange(t *testing.T) {
	var app heroku.App
	appName := fmt.Sprintf("tftest-%s", acctest.RandString(10))
	appName2 := fmt.Sprintf("%s-v2", appName)

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckHerokuAppDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccCheckHerokuAppConfig_basic(appName),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckHerokuAppExists("heroku_app.foobar", &app),
					testAccCheckHerokuAppAttributes(&app, appName),
					resource.TestCheckResourceAttr(
						"heroku_app.foobar", "name", appName),
					resource.TestCheckResourceAttr(
						"heroku_app.foobar", "config_vars.0.FOO", "bar"),
				),
			},
			resource.TestStep{
				Config: testAccCheckHerokuAppConfig_updated(appName2),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckHerokuAppExists("heroku_app.foobar", &app),
					testAccCheckHerokuAppAttributesUpdated(&app, appName2),
					resource.TestCheckResourceAttr(
						"heroku_app.foobar", "name", appName2),
					resource.TestCheckResourceAttr(
						"heroku_app.foobar", "config_vars.0.FOO", "bing"),
					resource.TestCheckResourceAttr(
						"heroku_app.foobar", "config_vars.0.BAZ", "bar"),
				),
			},
		},
	})
}

func TestAccHerokuApp_NukeVars(t *testing.T) {
	var app heroku.App
	appName := fmt.Sprintf("tftest-%s", acctest.RandString(10))

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckHerokuAppDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccCheckHerokuAppConfig_basic(appName),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckHerokuAppExists("heroku_app.foobar", &app),
					testAccCheckHerokuAppAttributes(&app, appName),
					resource.TestCheckResourceAttr(
						"heroku_app.foobar", "name", appName),
					resource.TestCheckResourceAttr(
						"heroku_app.foobar", "config_vars.0.FOO", "bar"),
				),
			},
			resource.TestStep{
				Config: testAccCheckHerokuAppConfig_no_vars(appName),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckHerokuAppExists("heroku_app.foobar", &app),
					testAccCheckHerokuAppAttributesNoVars(&app, appName),
					resource.TestCheckResourceAttr(
						"heroku_app.foobar", "name", appName),
					resource.TestCheckNoResourceAttr(
						"heroku_app.foobar", "config_vars.0.FOO"),
				),
			},
		},
	})
}

func TestAccHerokuApp_Organization(t *testing.T) {
	var app heroku.OrganizationApp
	appName := fmt.Sprintf("tftest-%s", acctest.RandString(10))
	org := os.Getenv("HEROKU_ORGANIZATION")

	resource.Test(t, resource.TestCase{
		PreCheck: func() {
			testAccPreCheck(t)
			if org == "" {
				t.Skip("HEROKU_ORGANIZATION is not set; skipping test.")
			}
		},
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckHerokuAppDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccCheckHerokuAppConfig_organization(appName, org),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckHerokuAppExistsOrg("heroku_app.foobar", &app),
					testAccCheckHerokuAppAttributesOrg(&app, appName, org),
				),
			},
		},
	})
}

func testAccCheckHerokuAppDestroy(s *terraform.State) error {
	client := testAccProvider.Meta().(*heroku.Service)

	for _, rs := range s.RootModule().Resources {
		if rs.Type != "heroku_app" {
			continue
		}

		_, err := client.AppInfo(rs.Primary.ID)

		if err == nil {
			return fmt.Errorf("App still exists")
		}
	}

	return nil
}

func testAccCheckHerokuAppAttributes(app *heroku.App, appName string) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		client := testAccProvider.Meta().(*heroku.Service)

		if app.Region.Name != "us" {
			return fmt.Errorf("Bad region: %s", app.Region.Name)
		}

		if app.Stack.Name != "cedar-14" {
			return fmt.Errorf("Bad stack: %s", app.Stack.Name)
		}

		if app.Name != appName {
			return fmt.Errorf("Bad name: %s", app.Name)
		}

		vars, err := client.ConfigVarInfo(app.Name)
		if err != nil {
			return err
		}

		if vars["FOO"] != "bar" {
			return fmt.Errorf("Bad config vars: %v", vars)
		}

		return nil
	}
}

func testAccCheckHerokuAppAttributesUpdated(app *heroku.App, appName string) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		client := testAccProvider.Meta().(*heroku.Service)

		if app.Name != appName {
			return fmt.Errorf("Bad name: %s", app.Name)
		}

		vars, err := client.ConfigVarInfo(app.Name)
		if err != nil {
			return err
		}

		// Make sure we kept the old one
		if vars["FOO"] != "bing" {
			return fmt.Errorf("Bad config vars: %v", vars)
		}

		if vars["BAZ"] != "bar" {
			return fmt.Errorf("Bad config vars: %v", vars)
		}

		return nil

	}
}

func testAccCheckHerokuAppAttributesNoVars(app *heroku.App, appName string) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		client := testAccProvider.Meta().(*heroku.Service)

		if app.Name != appName {
			return fmt.Errorf("Bad name: %s", app.Name)
		}

		vars, err := client.ConfigVarInfo(app.Name)
		if err != nil {
			return err
		}

		if len(vars) != 0 {
			return fmt.Errorf("vars exist: %v", vars)
		}

		return nil
	}
}

func testAccCheckHerokuAppAttributesOrg(app *heroku.OrganizationApp, appName string, org string) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		client := testAccProvider.Meta().(*heroku.Service)

		if app.Region.Name != "us" {
			return fmt.Errorf("Bad region: %s", app.Region.Name)
		}

		if app.Stack.Name != "cedar-14" {
			return fmt.Errorf("Bad stack: %s", app.Stack.Name)
		}

		if app.Name != appName {
			return fmt.Errorf("Bad name: %s", app.Name)
		}

		if app.Organization == nil || app.Organization.Name != org {
			return fmt.Errorf("Bad org: %v", app.Organization)
		}

		vars, err := client.ConfigVarInfo(app.Name)
		if err != nil {
			return err
		}

		if vars["FOO"] != "bar" {
			return fmt.Errorf("Bad config vars: %v", vars)
		}

		return nil
	}
}

func testAccCheckHerokuAppExists(n string, app *heroku.App) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		rs, ok := s.RootModule().Resources[n]

		if !ok {
			return fmt.Errorf("Not found: %s", n)
		}

		if rs.Primary.ID == "" {
			return fmt.Errorf("No App Name is set")
		}

		client := testAccProvider.Meta().(*heroku.Service)

		foundApp, err := client.AppInfo(rs.Primary.ID)

		if err != nil {
			return err
		}

		if foundApp.Name != rs.Primary.ID {
			return fmt.Errorf("App not found")
		}

		*app = *foundApp

		return nil
	}
}

func testAccCheckHerokuAppExistsOrg(n string, app *heroku.OrganizationApp) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		rs, ok := s.RootModule().Resources[n]

		if !ok {
			return fmt.Errorf("Not found: %s", n)
		}

		if rs.Primary.ID == "" {
			return fmt.Errorf("No App Name is set")
		}

		client := testAccProvider.Meta().(*heroku.Service)

		foundApp, err := client.OrganizationAppInfo(rs.Primary.ID)

		if err != nil {
			return err
		}

		if foundApp.Name != rs.Primary.ID {
			return fmt.Errorf("App not found")
		}

		*app = *foundApp

		return nil
	}
}

func testAccCheckHerokuAppConfig_basic(appName string) string {
	return fmt.Sprintf(`
resource "heroku_app" "foobar" {
  name   = "%s"
  region = "us"

  config_vars {
    FOO = "bar"
  }
}`, appName)
}

func testAccCheckHerokuAppConfig_updated(appName string) string {
	return fmt.Sprintf(`
resource "heroku_app" "foobar" {
  name   = "%s"
  region = "us"

  config_vars {
    FOO = "bing"
    BAZ = "bar"
  }
}`, appName)
}

func testAccCheckHerokuAppConfig_no_vars(appName string) string {
	return fmt.Sprintf(`
resource "heroku_app" "foobar" {
  name   = "%s"
  region = "us"
}`, appName)
}

func testAccCheckHerokuAppConfig_organization(appName, org string) string {
	return fmt.Sprintf(`
resource "heroku_app" "foobar" {
  name   = "%s"
  region = "us"

  organization {
    name = "%s"
  }

  config_vars {
    FOO = "bar"
  }
}`, appName, org)
}
<|endoftext|>


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

package nanomsg

import (
	"testing"
	"time"
)

type creqTest struct {
	cur   uint32
	tot   uint32
	ok    bool
	debug bool
	addr  string
        sock  *Socket
	done  chan struct{}
	t     *testing.T
}

type crepTest struct {
	cur   uint32
	tot   uint32
	ok    bool
	debug bool
        addr  string
        sock  *Socket
	done  chan struct{}
	t     *testing.T
}

// For now, we take a very simple pairwise approach to req/rep.  We should
// consider additional tests for raw mode multiple responders.

func (rt *creqTest) Init(t *testing.T, addr string, num uint32) bool {
	var e error
	if rt.sock, e = NewSocket(AF_SP, REQ); e != nil {
		t.Errorf("NewSocket(): %v", e)
		return false
	}
	if e = rt.sock.SetSendTimeout(time.Second); e != nil {
		t.Errorf("Failed SetSendTimeout: %s", e)
		return false
	}
	if e = rt.sock.SetRecvTimeout(time.Second); e != nil {
		t.Errorf("Failed SetRecvTimeout: %s", e)
		return false
	}
	rt.t = t
	rt.cur = 0
	rt.tot = num
	rt.addr = addr
	rt.done = make(chan struct{})
	return true
}

func (rt *creqTest) Finish() {
	rt.sock.Close()
	rt.ok = rt.cur == rt.tot
	close(rt.done)
}

func (rt *creqTest) DoTest() bool {
	defer rt.Finish()
	if _, err := rt.sock.Connect(rt.addr); err != nil {
		rt.t.Fatalf("Failed to connect: %s", err)
	}
	for rt.cur < rt.tot {
		var e error
		var n int
		m := make([]byte, 1)
		m[0] = byte(rt.cur)

		if rt.debug {
			rt.t.Logf("Send request %d", rt.cur)
		}
		if n, e = rt.sock.Send(m, 0); n != 1 || e != nil {
			rt.t.Errorf("Failed to send, %d sent, err %s", n, e)
			return false
		}
		if rt.debug {
			rt.t.Logf("Sent request %d", rt.cur)
		}

		m, e = rt.sock.Recv(0)
		if e != nil {
			rt.t.Errorf("Failed to recv reply: %s", e)
			return false
		}
		if len(m) != 1 {
			rt.t.Errorf("Got wrong length: %d != 1", len(m))
			return false
		}
		if m[0] != byte(rt.cur) {
			rt.t.Errorf("Got wrong reply: %d != %d", m[0], byte(rt.cur))
			return false
		}
		if rt.debug {
			rt.t.Logf("Got good reply %d", rt.cur)
		}
		rt.cur++
	}
	return true
}

func (rt *crepTest) Init(t *testing.T, addr string, num uint32) bool {
	var e error
	if rt.sock, e = NewSocket(AF_SP, REP); e != nil {
		t.Errorf("NewSocket(): %v", e)
		return false
	}
	if e = rt.sock.SetSendTimeout(time.Second); e != nil {
		t.Errorf("Failed SetSendTimeout: %s", e)
		return false
	}
	if e = rt.sock.SetRecvTimeout(time.Second); e != nil {
		t.Errorf("Failed SetRecvTimeout: %s", e)
		return false
	}
	rt.t = t
	rt.cur = 0
	rt.tot = num
	rt.addr = addr
	rt.done = make(chan struct{})
	return true
}

func (rt *crepTest) Finish() {
	rt.sock.Close()
	rt.ok = rt.cur == rt.tot
	if !rt.ok {
		close(rt.done)
	}
}

func (rt *crepTest) DoTest() bool {
	defer rt.Finish()
	if _, err := rt.sock.Bind(rt.addr); err != nil {
		rt.t.Errorf("Failed Bind: %s", err)
		return false
	}

	for rt.cur < rt.tot {
		var m []byte
		var e error
		var n int

		if rt.debug {
			rt.t.Logf("Wait for request %d", rt.cur)
		}
		if m, e = rt.sock.Recv(0); e != nil {
			rt.t.Errorf("Failed to recv request: %s", e)
			return false
		}
		if len(m) != 1 {
			rt.t.Errorf("Got wrong length: %d != 1", len(m))
			return false
		}
		if m[0] != byte(rt.cur) {
			rt.t.Errorf("Got wrong request: %d != %d", m[0], byte(rt.cur))
			return false
		}
		if rt.debug {
			rt.t.Logf("Got good request %d", rt.cur)
		}

		if n, e = rt.sock.Send(m, 0); e != nil || n != 1 {
			rt.t.Errorf("Failed to send reply: %v", e)
			return false
		}
		if rt.debug {
			rt.t.Logf("Sent reply %d", rt.cur)
		}
		rt.cur++
	}
	return true
}

func ReqRepCompat(t *testing.T, addr string, num uint32) {
	req := &creqTest{}
	rep := &crepTest{}
	req.Init(t, addr, num)
	rep.Init(t, addr, num)

	t.Logf("Doing %d exchanges", num)

	go func() {
		rep.ok = rep.DoTest()
	}()

	go func() {
		req.ok = req.DoTest()
	}()

	t.Logf("Waiting for tests to complete")

	select {
	case <-req.done:
		t.Logf("Req complete")
		break
	case <-rep.done:
		t.Logf("Rep complete")
		break
	}

	req.sock.Close()
	rep.sock.Close()
}

func TestCompatTCP(t *testing.T) {
	addr := "tcp://127.0.0.1:39093"
	ReqRepCompat(t, addr, 50000)
}

func TestCompatInp(t *testing.T) {
	addr := "inproc:///SOMENAME"
	ReqRepCompat(t, addr, 500000)
}
<commit_msg>fixes #59 compat broken (fix test conflict in Travis CI)<commit_after>// Copyright 2014 The Mangos Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use file except in compliance with the License.
// You may obtain a copy of the license at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package nanomsg

import (
	"testing"
	"time"
)

type creqTest struct {
	cur   uint32
	tot   uint32
	ok    bool
	debug bool
	addr  string
        sock  *Socket
	done  chan struct{}
	t     *testing.T
}

type crepTest struct {
	cur   uint32
	tot   uint32
	ok    bool
	debug bool
        addr  string
        sock  *Socket
	done  chan struct{}
	t     *testing.T
}

// For now, we take a very simple pairwise approach to req/rep.  We should
// consider additional tests for raw mode multiple responders.

func (rt *creqTest) Init(t *testing.T, addr string, num uint32) bool {
	var e error
	if rt.sock, e = NewSocket(AF_SP, REQ); e != nil {
		t.Errorf("NewSocket(): %v", e)
		return false
	}
	if e = rt.sock.SetSendTimeout(time.Second); e != nil {
		t.Errorf("Failed SetSendTimeout: %s", e)
		return false
	}
	if e = rt.sock.SetRecvTimeout(time.Second); e != nil {
		t.Errorf("Failed SetRecvTimeout: %s", e)
		return false
	}
	rt.t = t
	rt.cur = 0
	rt.tot = num
	rt.addr = addr
	rt.done = make(chan struct{})
	return true
}

func (rt *creqTest) Finish() {
	rt.sock.Close()
	rt.ok = rt.cur == rt.tot
	close(rt.done)
}

func (rt *creqTest) DoTest() bool {
	defer rt.Finish()
	if _, err := rt.sock.Connect(rt.addr); err != nil {
		rt.t.Fatalf("Failed to connect: %s", err)
	}
	for rt.cur < rt.tot {
		var e error
		var n int
		m := make([]byte, 1)
		m[0] = byte(rt.cur)

		if rt.debug {
			rt.t.Logf("Send request %d", rt.cur)
		}
		if n, e = rt.sock.Send(m, 0); n != 1 || e != nil {
			rt.t.Errorf("Failed to send, %d sent, err %s", n, e)
			return false
		}
		if rt.debug {
			rt.t.Logf("Sent request %d", rt.cur)
		}

		m, e = rt.sock.Recv(0)
		if e != nil {
			rt.t.Errorf("Failed to recv reply: %s", e)
			return false
		}
		if len(m) != 1 {
			rt.t.Errorf("Got wrong length: %d != 1", len(m))
			return false
		}
		if m[0] != byte(rt.cur) {
			rt.t.Errorf("Got wrong reply: %d != %d", m[0], byte(rt.cur))
			return false
		}
		if rt.debug {
			rt.t.Logf("Got good reply %d", rt.cur)
		}
		rt.cur++
	}
	return true
}

func (rt *crepTest) Init(t *testing.T, addr string, num uint32) bool {
	var e error
	if rt.sock, e = NewSocket(AF_SP, REP); e != nil {
		t.Errorf("NewSocket(): %v", e)
		return false
	}
	if e = rt.sock.SetSendTimeout(time.Second); e != nil {
		t.Errorf("Failed SetSendTimeout: %s", e)
		return false
	}
	if e = rt.sock.SetRecvTimeout(time.Second); e != nil {
		t.Errorf("Failed SetRecvTimeout: %s", e)
		return false
	}
	rt.t = t
	rt.cur = 0
	rt.tot = num
	rt.addr = addr
	rt.done = make(chan struct{})
	return true
}

func (rt *crepTest) Finish() {
	rt.sock.Close()
	rt.ok = rt.cur == rt.tot
	if !rt.ok {
		close(rt.done)
	}
}

func (rt *crepTest) DoTest() bool {
	defer rt.Finish()
	if _, err := rt.sock.Bind(rt.addr); err != nil {
		rt.t.Errorf("Failed Bind: %s", err)
		return false
	}

	for rt.cur < rt.tot {
		var m []byte
		var e error
		var n int

		if rt.debug {
			rt.t.Logf("Wait for request %d", rt.cur)
		}
		if m, e = rt.sock.Recv(0); e != nil {
			rt.t.Errorf("Failed to recv request: %s", e)
			return false
		}
		if len(m) != 1 {
			rt.t.Errorf("Got wrong length: %d != 1", len(m))
			return false
		}
		if m[0] != byte(rt.cur) {
			rt.t.Errorf("Got wrong request: %d != %d", m[0], byte(rt.cur))
			return false
		}
		if rt.debug {
			rt.t.Logf("Got good request %d", rt.cur)
		}

		if n, e = rt.sock.Send(m, 0); e != nil || n != 1 {
			rt.t.Errorf("Failed to send reply: %v", e)
			return false
		}
		if rt.debug {
			rt.t.Logf("Sent reply %d", rt.cur)
		}
		rt.cur++
	}
	return true
}

func ReqRepCompat(t *testing.T, addr string, num uint32) {
	req := &creqTest{}
	rep := &crepTest{}
	req.Init(t, addr, num)
	rep.Init(t, addr, num)

	t.Logf("Doing %d exchanges", num)

	go func() {
		rep.ok = rep.DoTest()
	}()

	go func() {
		req.ok = req.DoTest()
	}()

	t.Logf("Waiting for tests to complete")

	select {
	case <-req.done:
		t.Logf("Req complete")
		break
	case <-rep.done:
		t.Logf("Rep complete")
		break
	}

	req.sock.Close()
	rep.sock.Close()
}

func TestCompatTCP(t *testing.T) {
	addr := "tcp://127.0.0.1:34444"
	ReqRepCompat(t, addr, 50000)
}

func TestCompatInp(t *testing.T) {
	addr := "inproc:///SOMENAME"
	ReqRepCompat(t, addr, 500000)
}
<|endoftext|>


<commit_before>package sokudoku

import (
	"bufio"
	"fmt"
	"math"
	"os"
	"time"

	"github.com/mattn/go-tty"
)

func Run(wait int) error {
	p, err := phraseInit()
	if err != nil {
		return err
	}
	defer p.Destroy()

	// Get a line from stdin.
	reader := bufio.NewScanner(os.Stdin)
	line := make(chan string, 1024)
	go func() {
		for reader.Scan() {
			line <- reader.Text()
		}
		close(line)
	}()

	// Parse a line.
	word := make(chan string, 1024)
	go func() {
		for {
			l, ok := <-line
			if !ok {
				break
			}
			res, err := p.Parse(l)
			if err != nil {
				break
			}
			for _, w := range res {
				word <- w
			}
		}
		close(word)
	}()

	// Output a word.
	oerr := outputWord(word, wait)
	if oerr != nil {
		return oerr
	}

	return reader.Err()
}

func outputWord(word <-chan string, wait int) error {
	if DEBUG {
		//-tags debug
		for {
			w, ok := <-word
			if !ok {
				break
			}
			fmt.Println("   ", w)
			time.Sleep(time.Duration(wait) * time.Millisecond)
		}
	} else {
		tty, err := tty.Open()
		if err != nil {
			return err
		}
		defer func() {
			for {
				fmt.Println("Please ENTER.")
				r, _ := tty.ReadRune()
				if r == 13 {
					break
				}
			}
			tty.Close()
		}()

		key_queue := make(chan rune)
		go func() {
			for {
				r, _ := tty.ReadRune()
				key_queue <- r
			}
		}()

		// 停止フラグ
		stop := false
	loop:
		for {
			if stop {
        // in pause
				r := <-key_queue
				if r == 32 {
          // pressed Space
					stop = false
				}
			} else {
				select {
				case r := <-key_queue:
					switch r {
					case 3: // Ctrl-C
						break loop
					case 91: // [
						wait = int(math.Max(float64(wait)*0.9, 10))
					case 93: // ]
						wait = int(math.Min(float64(wait)*1.1, 2000))
					case 32: // Space
						// TODO puase
						stop = true
					}
				case w, ok := <-word:
					if !ok {
						break loop
					}
					fmt.Println("...", w)
					time.Sleep(time.Duration(wait) * time.Millisecond)
				}
			}
		}
	}
	return nil
}
<commit_msg>formated source<commit_after>package sokudoku

import (
	"bufio"
	"fmt"
	"math"
	"os"
	"time"

	"github.com/mattn/go-tty"
)

func Run(wait int) error {
	p, err := phraseInit()
	if err != nil {
		return err
	}
	defer p.Destroy()

	// Get a line from stdin.
	reader := bufio.NewScanner(os.Stdin)
	line := make(chan string, 1024)
	go func() {
		for reader.Scan() {
			line <- reader.Text()
		}
		close(line)
	}()

	// Parse a line.
	word := make(chan string, 1024)
	go func() {
		for {
			l, ok := <-line
			if !ok {
				break
			}
			res, err := p.Parse(l)
			if err != nil {
				break
			}
			for _, w := range res {
				word <- w
			}
		}
		close(word)
	}()

	// Output a word.
	oerr := outputWord(word, wait)
	if oerr != nil {
		return oerr
	}

	return reader.Err()
}

func outputWord(word <-chan string, wait int) error {
	if DEBUG {
		//-tags debug
		for {
			w, ok := <-word
			if !ok {
				break
			}
			fmt.Println("   ", w)
			time.Sleep(time.Duration(wait) * time.Millisecond)
		}
	} else {
		tty, err := tty.Open()
		if err != nil {
			return err
		}
		defer func() {
			for {
				fmt.Println("\n\n  Exit. Please press ENTER.")
				r, _ := tty.ReadRune()
				if r == 13 {
					break
				}
			}
			tty.Close()
		}()

		key_queue := make(chan rune)
		go func() {
			for {
				r, _ := tty.ReadRune()
				key_queue <- r
			}
		}()

		fmt.Println("    .")

		// 停止フラグ
		stop := false
	loop:
		for {
			if stop {
				// in pause
				r := <-key_queue
				if r == 32 {
					// pressed Space
					stop = false
				}
			} else {
				select {
				case r := <-key_queue:
					switch r {
					case 3: // Ctrl-C
						break loop
					case 91: // [
						wait = int(math.Max(float64(wait)*0.9, 10))
					case 93: // ]
						wait = int(math.Min(float64(wait)*1.1, 2000))
					case 32: // Space
						// TODO puase
						stop = true
					}
				case w, ok := <-word:
					if !ok {
						break loop
					}
					fmt.Printf("\r%s                        ", w)
					time.Sleep(time.Duration(wait) * time.Millisecond)
				}
			}
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package compiler2

import (
	"errors"
	"fmt"
	"sort"
	"syscall"

	"github.com/twtiger/gosecco/constants"
	"github.com/twtiger/gosecco/tree"

	"golang.org/x/sys/unix"
)

// This compiler runs in three stages
// - generate base code
// - do peephole optimization
// - resolve all labels and jumps

// TODO: handle boolean literal at top level (check todo in visitor)
// TODO: Fixup peephole optimization
// TODO: Fixup jumps
// TODO: handle full compile of rules, not just the expression
// TODO: put together more than one rule
// TODO: add the prefix and postfix
// TODO: fix all potential errors (no panics, we should check for errors)
// TODO: compare go-seccomp and gosecco policy evaluation

// Compile will take a parsed policy and generate an optimized sock filter for that policy
// The policy is assumed to have been unified and simplified before compilation starts -
// no unresolved variables or calls should exist in the policy.
func Compile(policy tree.Policy) ([]unix.SockFilter, error) {
	c := createCompilerContext()
	return c.compile(policy.Rules)
}

type label string

var noLabel = label("noLabel")

type compilerContext struct {
	result          []unix.SockFilter
	currentlyLoaded int
	stackTop        uint32
	// TODO we will need an unconditional jumps map as well.
	// these need to be fixed up if there is an unconditional jump inserted after.
	// these need to be fixed up if there is an unconditional jump inserted after.
	jts          map[label][]int
	jfs          map[label][]int
	uconds       map[label][]int
	labels       map[label]int
	labelCounter int
	// this will always be 0xFF in production, but it is injectable for testing.
	actions                      map[string]label
	maxJumpSize                  int
	currentlyCompilingSyscall    string
	currentlyCompilingExpression tree.Expression
}

func createCompilerContext() *compilerContext {
	return &compilerContext{
		jts:             make(map[label][]int),
		jfs:             make(map[label][]int),
		uconds:          make(map[label][]int),
		labels:          make(map[label]int),
		actions:         make(map[string]label),
		maxJumpSize:     255,
		currentlyLoaded: -1,
	}
}

func (c *compilerContext) compile(rules []tree.Rule) ([]unix.SockFilter, error) {
	for _, r := range rules {
		c.compileRule(r)
	}

	// TODO: use default policy here instead of kill
	c.unconditionalJumpTo(c.actions["kill"])

	actionOrder := []string{}
	for k := range c.actions {
		actionOrder = append(actionOrder, k)
	}
	sort.Strings(actionOrder)

	for _, k := range actionOrder {
		c.labelHere(c.actions[k])
		switch k {
		case "allow":
			c.op(OP_RET_K, SECCOMP_RET_ALLOW)
		case "kill":
			c.op(OP_RET_K, SECCOMP_RET_KILL)
		case "trace":
			c.op(OP_RET_K, SECCOMP_RET_TRACE)
		}
	}

	c.fixupJumps()

	return c.result, nil
}

func (c *compilerContext) loadAt(pos uint32) {
	if c.currentlyLoaded != int(pos) {
		c.op(OP_LOAD, pos)
		c.currentlyLoaded = int(pos)
	}
}

func (c *compilerContext) loadLiteral(lit uint32) {
	c.op(OP_LOAD_VAL, lit)
	c.currentlyLoaded = -1
}

const syscallNameIndex = 0

func (c *compilerContext) loadCurrentSyscall() {
	c.loadAt(syscallNameIndex)
}

func (c *compilerContext) checkCorrectSyscall(name string, next label) {
	sys, ok := constants.GetSyscall(name)
	if !ok {
		panic("This shouldn't happen - analyzer should have caught it before compiler tries to compile it")
	}

	c.loadCurrentSyscall()
	goesNowhere := c.newLabel()
	c.opWithJumps(OP_JEQ_K, sys, goesNowhere, next)
	c.labelHere(goesNowhere)
}

func (c *compilerContext) compileRule(r tree.Rule) {
	next := c.newLabel()

	pos, neg := c.compileActions(r.PositiveAction, r.NegativeAction)

	c.checkCorrectSyscall(r.Name, next) // set JT flag to final ret_allow only if the rule is a boolean literal

	// These are useful for debugging and helpful error messages
	c.currentlyCompilingSyscall = r.Name
	c.currentlyCompilingExpression = r.Body

	c.compileExpression(r.Body, pos, neg)

	c.labelHere(next)
}

func (c *compilerContext) compileActions(positiveAction string, negativeAction string) (label, label) {
	if positiveAction == "" {
		positiveAction = "allow"
	}

	if negativeAction == "" {
		negativeAction = "kill"
	}

	posActionLabel, positiveActionExists := c.actions[positiveAction]
	negActionLabel, negativeActionExists := c.actions[negativeAction]

	if !positiveActionExists {
		posActionLabel = c.newLabel()
		c.actions[positiveAction] = posActionLabel
	}

	if !negativeActionExists {
		negActionLabel = c.newLabel()
		c.actions[negativeAction] = negActionLabel
	}

	return posActionLabel, negActionLabel
}

func (c *compilerContext) op(code uint16, k uint32) {
	c.result = append(c.result, unix.SockFilter{
		Code: code,
		Jt:   0,
		Jf:   0,
		K:    k,
	})
}

func (c *compilerContext) compileExpression(x tree.Expression, pos, neg label) {
	// Returns error
	isTopLevel := true
	compileBoolean(c, x, isTopLevel, pos, neg)
}

func (c *compilerContext) newLabel() label {
	result := fmt.Sprintf("generatedLabel%03d", c.labelCounter)
	c.labelCounter++
	return label(result)
}

func (c *compilerContext) registerJumps(index int, jt, jf label) {
	c.jts[jt] = append(c.jts[jt], index)
	c.jfs[jf] = append(c.jfs[jf], index)
}

func (c *compilerContext) fixMaxJumps(l label, elems []int, isPos bool) {
	to := len(c.result)
	for _, from := range elems {
		if (to-from)-1 > c.maxJumpSize {
			c.longJump(from, isPos, l)
		}
	}
}

func (c *compilerContext) labelHere(l label) {
	jts, jfs := c.jts[l], c.jfs[l]

	c.fixMaxJumps(l, jts, true)
	c.fixMaxJumps(l, jfs, false)
	c.labels[l] = len(c.result)
}

func (c *compilerContext) unconditionalJumpTo(to label) {
	index := len(c.result)
	c.result = append(c.result, unix.SockFilter{
		Code: OP_JMP_K,
		Jt:   0,
		Jf:   0,
		K:    0,
	})
	c.uconds[to] = append(c.uconds[to], index)
}

func (c *compilerContext) opWithJumps(code uint16, k uint32, jt, jf label) {
	index := len(c.result)
	c.registerJumps(index, jt, jf)
	c.result = append(c.result, unix.SockFilter{
		Code: code,
		Jt:   0,
		Jf:   0,
		K:    k,
	})
}

func (c *compilerContext) jumpOnEq(val uint32, jt, jf label) {
	c.opWithJumps(OP_JEQ_K, val, jt, jf)
}

func (c *compilerContext) pushAToStack() error {
	if c.stackTop >= syscall.BPF_MEMWORDS {
		return errors.New("the expression is too complicated to compile. Please refer to the language documentation")
	}

	c.op(OP_STORE, c.stackTop)
	c.stackTop++
	return nil
}

func (c *compilerContext) popStackToX() error {
	if c.stackTop == 0 {
		return errors.New("popping from empty stack - this is likely a programmer error")
	}
	c.stackTop--
	c.op(OP_LOAD_MEM_X, c.stackTop)
	return nil
}
<commit_msg>Remove unused label<commit_after>package compiler2

import (
	"errors"
	"fmt"
	"sort"
	"syscall"

	"github.com/twtiger/gosecco/constants"
	"github.com/twtiger/gosecco/tree"

	"golang.org/x/sys/unix"
)

// This compiler runs in three stages
// - generate base code
// - do peephole optimization
// - resolve all labels and jumps

// TODO: handle boolean literal at top level (check todo in visitor)
// TODO: Fixup peephole optimization
// TODO: Fixup jumps
// TODO: handle full compile of rules, not just the expression
// TODO: put together more than one rule
// TODO: add the prefix and postfix
// TODO: fix all potential errors (no panics, we should check for errors)
// TODO: compare go-seccomp and gosecco policy evaluation

// Compile will take a parsed policy and generate an optimized sock filter for that policy
// The policy is assumed to have been unified and simplified before compilation starts -
// no unresolved variables or calls should exist in the policy.
func Compile(policy tree.Policy) ([]unix.SockFilter, error) {
	c := createCompilerContext()
	return c.compile(policy.Rules)
}

type label string

type compilerContext struct {
	result          []unix.SockFilter
	currentlyLoaded int
	stackTop        uint32
	// TODO we will need an unconditional jumps map as well.
	// these need to be fixed up if there is an unconditional jump inserted after.
	// these need to be fixed up if there is an unconditional jump inserted after.
	jts          map[label][]int
	jfs          map[label][]int
	uconds       map[label][]int
	labels       map[label]int
	labelCounter int
	// this will always be 0xFF in production, but it is injectable for testing.
	actions                      map[string]label
	maxJumpSize                  int
	currentlyCompilingSyscall    string
	currentlyCompilingExpression tree.Expression
}

func createCompilerContext() *compilerContext {
	return &compilerContext{
		jts:             make(map[label][]int),
		jfs:             make(map[label][]int),
		uconds:          make(map[label][]int),
		labels:          make(map[label]int),
		actions:         make(map[string]label),
		maxJumpSize:     255,
		currentlyLoaded: -1,
	}
}

func (c *compilerContext) compile(rules []tree.Rule) ([]unix.SockFilter, error) {
	for _, r := range rules {
		c.compileRule(r)
	}

	// TODO: use default policy here instead of kill
	c.unconditionalJumpTo(c.actions["kill"])

	actionOrder := []string{}
	for k := range c.actions {
		actionOrder = append(actionOrder, k)
	}
	sort.Strings(actionOrder)

	for _, k := range actionOrder {
		c.labelHere(c.actions[k])
		switch k {
		case "allow":
			c.op(OP_RET_K, SECCOMP_RET_ALLOW)
		case "kill":
			c.op(OP_RET_K, SECCOMP_RET_KILL)
		case "trace":
			c.op(OP_RET_K, SECCOMP_RET_TRACE)
		}
	}

	c.fixupJumps()

	return c.result, nil
}

func (c *compilerContext) loadAt(pos uint32) {
	if c.currentlyLoaded != int(pos) {
		c.op(OP_LOAD, pos)
		c.currentlyLoaded = int(pos)
	}
}

func (c *compilerContext) loadLiteral(lit uint32) {
	c.op(OP_LOAD_VAL, lit)
	c.currentlyLoaded = -1
}

const syscallNameIndex = 0

func (c *compilerContext) loadCurrentSyscall() {
	c.loadAt(syscallNameIndex)
}

func (c *compilerContext) checkCorrectSyscall(name string, next label) {
	sys, ok := constants.GetSyscall(name)
	if !ok {
		panic("This shouldn't happen - analyzer should have caught it before compiler tries to compile it")
	}

	c.loadCurrentSyscall()
	goesNowhere := c.newLabel()
	c.opWithJumps(OP_JEQ_K, sys, goesNowhere, next)
	c.labelHere(goesNowhere)
}

func (c *compilerContext) compileRule(r tree.Rule) {
	next := c.newLabel()

	pos, neg := c.compileActions(r.PositiveAction, r.NegativeAction)

	c.checkCorrectSyscall(r.Name, next) // set JT flag to final ret_allow only if the rule is a boolean literal

	// These are useful for debugging and helpful error messages
	c.currentlyCompilingSyscall = r.Name
	c.currentlyCompilingExpression = r.Body

	c.compileExpression(r.Body, pos, neg)

	c.labelHere(next)
}

func (c *compilerContext) compileActions(positiveAction string, negativeAction string) (label, label) {
	if positiveAction == "" {
		positiveAction = "allow"
	}

	if negativeAction == "" {
		negativeAction = "kill"
	}

	posActionLabel, positiveActionExists := c.actions[positiveAction]
	negActionLabel, negativeActionExists := c.actions[negativeAction]

	if !positiveActionExists {
		posActionLabel = c.newLabel()
		c.actions[positiveAction] = posActionLabel
	}

	if !negativeActionExists {
		negActionLabel = c.newLabel()
		c.actions[negativeAction] = negActionLabel
	}

	return posActionLabel, negActionLabel
}

func (c *compilerContext) op(code uint16, k uint32) {
	c.result = append(c.result, unix.SockFilter{
		Code: code,
		Jt:   0,
		Jf:   0,
		K:    k,
	})
}

func (c *compilerContext) compileExpression(x tree.Expression, pos, neg label) {
	// Returns error
	isTopLevel := true
	compileBoolean(c, x, isTopLevel, pos, neg)
}

func (c *compilerContext) newLabel() label {
	result := fmt.Sprintf("generatedLabel%03d", c.labelCounter)
	c.labelCounter++
	return label(result)
}

func (c *compilerContext) registerJumps(index int, jt, jf label) {
	c.jts[jt] = append(c.jts[jt], index)
	c.jfs[jf] = append(c.jfs[jf], index)
}

func (c *compilerContext) fixMaxJumps(l label, elems []int, isPos bool) {
	to := len(c.result)
	for _, from := range elems {
		if (to-from)-1 > c.maxJumpSize {
			c.longJump(from, isPos, l)
		}
	}
}

func (c *compilerContext) labelHere(l label) {
	jts, jfs := c.jts[l], c.jfs[l]

	c.fixMaxJumps(l, jts, true)
	c.fixMaxJumps(l, jfs, false)
	c.labels[l] = len(c.result)
}

func (c *compilerContext) unconditionalJumpTo(to label) {
	index := len(c.result)
	c.result = append(c.result, unix.SockFilter{
		Code: OP_JMP_K,
		Jt:   0,
		Jf:   0,
		K:    0,
	})
	c.uconds[to] = append(c.uconds[to], index)
}

func (c *compilerContext) opWithJumps(code uint16, k uint32, jt, jf label) {
	index := len(c.result)
	c.registerJumps(index, jt, jf)
	c.result = append(c.result, unix.SockFilter{
		Code: code,
		Jt:   0,
		Jf:   0,
		K:    k,
	})
}

func (c *compilerContext) jumpOnEq(val uint32, jt, jf label) {
	c.opWithJumps(OP_JEQ_K, val, jt, jf)
}

func (c *compilerContext) pushAToStack() error {
	if c.stackTop >= syscall.BPF_MEMWORDS {
		return errors.New("the expression is too complicated to compile. Please refer to the language documentation")
	}

	c.op(OP_STORE, c.stackTop)
	c.stackTop++
	return nil
}

func (c *compilerContext) popStackToX() error {
	if c.stackTop == 0 {
		return errors.New("popping from empty stack - this is likely a programmer error")
	}
	c.stackTop--
	c.op(OP_LOAD_MEM_X, c.stackTop)
	return nil
}
<|endoftext|>