<commit_before>package main

import (
	"errors"
	"fmt"
	"log"
	"net/http"

	"github.com/xanzy/go-gitlab"
)

const (
	resultsPerPage = 100
)

// GitLab server endpoints
type endpoint struct {
	from, to *gitlab.Client
}

type migration struct {
	params                 *config
	endpoint               *endpoint
	srcProject, dstProject *gitlab.Project
}

func NewMigration(c *config) (*migration, error) {
	if c == nil {
		return nil, errors.New("nil params")
	}
	fromgl := gitlab.NewClient(nil, c.From.Token)
	if err := fromgl.SetBaseURL(c.From.ServerURL); err != nil {
		return nil, err
	}
	togl := gitlab.NewClient(nil, c.To.Token)
	if err := togl.SetBaseURL(c.To.ServerURL); err != nil {
		return nil, err
	}
	m := &migration{params: c, endpoint: &endpoint{fromgl, togl}}
	return m, nil
}

// Returns project by name.
func (m *migration) project(endpoint *gitlab.Client, name string) (*gitlab.Project, error) {
	proj, resp, err := endpoint.Projects.GetProject(name)
	if resp == nil {
		return nil, errors.New("network error: " + err.Error())
	}
	if resp.StatusCode == http.StatusNotFound {
		return nil, fmt.Errorf("source project '%s' not found", name)
	}
	if err != nil {
		return nil, err
	}
	return proj, nil
}

func (m *migration) sourceProject(name string) (*gitlab.Project, error) {
	p, err := m.project(m.endpoint.from, name)
	if err != nil {
		return nil, err
	}
	m.srcProject = p
	return p, nil
}

func (m *migration) destProject(name string) (*gitlab.Project, error) {
	p, err := m.project(m.endpoint.to, name)
	if err != nil {
		return nil, err
	}
	m.dstProject = p
	return p, nil
}

// Performs the issues migration.
func (m *migration) migrate() error {
	if m.srcProject == nil || m.dstProject == nil {
		return errors.New("nil project.")
	}
	fmt.Println("Migrating ...")

	source := m.endpoint.from
	target := m.endpoint.to

	srcProjectID := *m.srcProject.ID
	tarProjectID := *m.dstProject.ID

	curPage := 1
	opts := &gitlab.ListProjectIssuesOptions{ListOptions: gitlab.ListOptions{PerPage: resultsPerPage, Page: curPage}}
	issues, _, err := source.Issues.ListProjectIssues(srcProjectID, opts)
	if err != nil {
		return err
	}
	if len(issues) > 0 {
		skipIssue := false
		for _, issue := range issues {
			tis, _, err := target.Issues.ListProjectIssues(tarProjectID, nil)
			if err != nil {
				log.Printf("target: can't fetch issues, skipping...")
				continue
			}
			skipIssue = false
			for _, t := range tis {
				if issue.Title == t.Title {
					// Target issue already exists, let's skip this one
					skipIssue = true
					log.Printf("target: issue '%s' already exists, skipping...", issue.Title)
					break
				}
			}
			if skipIssue {
				continue
			}
			//MAT fmt.Printf("Assignee: %+v\n", issue.Assignee)
			iopts := &gitlab.CreateIssueOptions{
				Title:       issue.Title,
				Description: issue.Description,
			}
			if issue.Assignee.Username != "" {
				// Assigned, does target user exist?
				// User may have a different ID on target
				users, _, err := target.Users.ListUsers(nil)
				if err == nil {
					for _, u := range users {
						if u.Username == issue.Assignee.Username {
							iopts.AssigneeID = u.ID
							break
						}
					}
				} else {
					log.Printf("target: error fetching users: %s", err.Error())
				}
			}
			if issue.Milestone.Title != "" {
				miles, _, err := target.Milestones.ListMilestones(tarProjectID, nil)
				if err == nil {
					found := false
					for _, mi := range miles {
						found = false
						if mi.Title == issue.Milestone.Title {
							found = true
							iopts.MilestoneID = mi.ID
							break
						}
					}
					if !found {
						// Create target milestone
						cmopts := &gitlab.CreateMilestoneOptions{
							Title:       issue.Milestone.Title,
							Description: issue.Milestone.Description,
							DueDate:     issue.Milestone.DueDate,
						}
						mi, _, err := target.Milestones.CreateMilestone(tarProjectID, cmopts)
						if err == nil {
							iopts.MilestoneID = mi.ID
						} else {
							log.Printf("target: error creating milestone '%s': %s", issue.Milestone.Title, err.Error())
						}
					}
				}
			}
			if len(issue.Labels) > 0 {
				lbls, _, err := target.Labels.ListLabels(tarProjectID)
				targetLabels := make([]string, 0)
				if err == nil {
					found := false
					for _, label := range issue.Labels {
						found = false
						for _, l := range lbls {
							if l.Name == label {
								found = true
								break
							}
						}
						if !found {
							// Create target label
							// FIXME: label color
							clopts := &gitlab.CreateLabelOptions{Name: label, Color: "#329557"}
							_, _, err := target.Labels.CreateLabel(tarProjectID, clopts)
							if err == nil {
								targetLabels = append(targetLabels, label)
							} else {
								log.Printf("target: error creating label '%s': %s", label, err.Error())
							}
						} else {
							targetLabels = append(targetLabels, label)
						}
					}
				} else {
					log.Printf("target: error fetching labels: %s", err.Error())
				}
				iopts.Labels = targetLabels
			}
			// Create target issue if not existing (same name)
			ni, _, err := target.Issues.CreateIssue(tarProjectID, iopts)
			if err != nil {
				log.Printf("target: error creating issue: %s", err.Error())
			}
			if issue.State == "closed" {
				_, _, err := target.Issues.UpdateIssue(tarProjectID, ni.ID, &gitlab.UpdateIssueOptions{StateEvent: "close"})
				if err != nil {
					log.Printf("target: error closing issue #%d: %s", ni.IID, err.Error())
				}
			}
			fmt.Printf("target: created issue #%d: %s [%s]\n", ni.IID, ni.Title, ni.State)
		}
	}
	return nil
}
<commit_msg>Fix typo<commit_after>package main

import (
	"errors"
	"fmt"
	"log"
	"net/http"

	"github.com/xanzy/go-gitlab"
)

const (
	resultsPerPage = 100
)

// GitLab server endpoints
type endpoint struct {
	from, to *gitlab.Client
}

type migration struct {
	params                 *config
	endpoint               *endpoint
	srcProject, dstProject *gitlab.Project
}

func NewMigration(c *config) (*migration, error) {
	if c == nil {
		return nil, errors.New("nil params")
	}
	fromgl := gitlab.NewClient(nil, c.From.Token)
	if err := fromgl.SetBaseURL(c.From.ServerURL); err != nil {
		return nil, err
	}
	togl := gitlab.NewClient(nil, c.To.Token)
	if err := togl.SetBaseURL(c.To.ServerURL); err != nil {
		return nil, err
	}
	m := &migration{params: c, endpoint: &endpoint{fromgl, togl}}
	return m, nil
}

// Returns project by name.
func (m *migration) project(endpoint *gitlab.Client, name string) (*gitlab.Project, error) {
	proj, resp, err := endpoint.Projects.GetProject(name)
	if resp == nil {
		return nil, errors.New("network error: " + err.Error())
	}
	if resp.StatusCode == http.StatusNotFound {
		return nil, fmt.Errorf("source project '%s' not found", name)
	}
	if err != nil {
		return nil, err
	}
	return proj, nil
}

func (m *migration) sourceProject(name string) (*gitlab.Project, error) {
	p, err := m.project(m.endpoint.from, name)
	if err != nil {
		return nil, err
	}
	m.srcProject = p
	return p, nil
}

func (m *migration) destProject(name string) (*gitlab.Project, error) {
	p, err := m.project(m.endpoint.to, name)
	if err != nil {
		return nil, err
	}
	m.dstProject = p
	return p, nil
}

// Performs the issues migration.
func (m *migration) migrate() error {
	if m.srcProject == nil || m.dstProject == nil {
		return errors.New("nil project.")
	}
	fmt.Println("Migrating ...")

	source := m.endpoint.from
	target := m.endpoint.to

	srcProjectID := *m.srcProject.ID
	tarProjectID := *m.dstProject.ID

	curPage := 1
	opts := &gitlab.ListProjectIssuesOptions{ListOptions: gitlab.ListOptions{PerPage: resultsPerPage, Page: curPage}}
	issues, _, err := source.Issues.ListProjectIssues(srcProjectID, opts)
	if err != nil {
		return err
	}
	if len(issues) > 0 {
		skipIssue := false
		for _, issue := range issues {
			tis, _, err := target.Issues.ListProjectIssues(tarProjectID, nil)
			if err != nil {
				log.Printf("target: can't fetch issues, skipping...")
				continue
			}
			skipIssue = false
			for _, t := range tis {
				if issue.Title == t.Title {
					// Target issue already exists, let's skip this one
					skipIssue = true
					log.Printf("target: issue '%s' already exists, skipping...", issue.Title)
					break
				}
			}
			if skipIssue {
				continue
			}
			//MAT fmt.Printf("Assignee: %+v\n", issue.Assignee)
			iopts := &gitlab.CreateIssueOptions{
				Title:       issue.Title,
				Description: issue.Description,
			}
			if issue.Assignee.Username != "" {
				// Assigned, does target user exist?
				// User may have a different ID on target
				users, _, err := target.Users.ListUsers(nil)
				if err == nil {
					for _, u := range users {
						if u.Username == issue.Assignee.Username {
							iopts.AssigneeID = u.ID
							break
						}
					}
				} else {
					log.Printf("target: error fetching users: %s", err.Error())
				}
			}
			if issue.Milestone.Title != "" {
				miles, _, err := target.Milestones.ListMilestones(tarProjectID, nil)
				if err == nil {
					found := false
					for _, mi := range miles {
						found = false
						if mi.Title == issue.Milestone.Title {
							found = true
							iopts.MilestoneID = mi.ID
							break
						}
					}
					if !found {
						// Create target milestone
						cmopts := &gitlab.CreateMilestoneOptions{
							Title:       issue.Milestone.Title,
							Description: issue.Milestone.Description,
							DueDate:     issue.Milestone.DueDate,
						}
						mi, _, err := target.Milestones.CreateMilestone(tarProjectID, cmopts)
						if err == nil {
							iopts.MilestoneID = mi.ID
						} else {
							log.Printf("target: error creating milestone '%s': %s", issue.Milestone.Title, err.Error())
						}
					}
				}
			}
			if len(issue.Labels) > 0 {
				lbls, _, err := target.Labels.ListLabels(tarProjectID)
				targetLabels := make([]string, 0)
				if err == nil {
					found := false
					for _, label := range issue.Labels {
						found = false
						for _, l := range lbls {
							if l.Name == label {
								found = true
								break
							}
						}
						if !found {
							// Create target label
							// FIXME: label color
							clopts := &gitlab.CreateLabelOptions{Name: label, Color: "#329557"}
							_, _, err := target.Labels.CreateLabel(tarProjectID, clopts)
							if err == nil {
								targetLabels = append(targetLabels, label)
							} else {
								log.Printf("target: error creating label '%s': %s", label, err.Error())
							}
						} else {
							targetLabels = append(targetLabels, label)
						}
					}
				} else {
					log.Printf("target: error fetching labels: %s", err.Error())
				}
				iopts.Labels = targetLabels
			}
			// Create target issue if not existing (same name)
			ni, _, err := target.Issues.CreateIssue(tarProjectID, iopts)
			if err != nil {
				log.Printf("target: error creating issue: %s", err.Error())
			}
			if issue.State == "closed" {
				_, _, err := target.Issues.UpdateIssue(tarProjectID, ni.ID, &gitlab.UpdateIssueOptions{StateEvent: "close"})
				if err != nil {
					log.Printf("target: error closing issue #%d: %s", ni.IID, err.Error())
				}
			}
			fmt.Printf("target: created issue #%d: %s [%s]\n", ni.IID, ni.Title, issue.State)

			// TODO: now copy related notes (comments)
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package command

import (
	"errors"
	"flag"
	"fmt"
	"os"
	"runtime"
	"runtime/pprof"

	"github.com/simulated-reality/laboratory/src/internal/config"
)

var (
	configFile  = flag.String("c", "", "a configuration file (required)")
	profileFile = flag.String("p", "", "an output file for profiling information")
	verbose     = flag.Bool("v", false, "a flag for displaying diagnostic information")
)

func Run(function func(*config.Config) error) {
	flag.Usage = usage
	flag.Parse()

	if len(*profileFile) > 0 {
		profile, err := os.Create(*profileFile)
		if err != nil {
			fail(errors.New("cannot enable profiling"))
		}
		pprof.StartCPUProfile(profile)
		defer pprof.StopCPUProfile()
	}

	runtime.GOMAXPROCS(runtime.NumCPU())

	if len(*configFile) == 0 {
		fail(errors.New("expected a filename"))
	}
	config, err := config.New(*configFile)
	if err != nil {
		fail(err)
	}
	if *verbose {
		config.Verbose = true
	}

	if err = function(config); err != nil {
		fail(err)
	}
}

func fail(err error) {
	fmt.Printf("Error: %s.\n", err)
	os.Exit(1)
}

func usage() {
	fmt.Printf("Usage: %s [options]\n\n", os.Args[0])
	fmt.Printf("Options:\n")
	flag.PrintDefaults()
	os.Exit(1)
}
<commit_msg>Do not set GOMAXPROCS<commit_after>package command

import (
	"errors"
	"flag"
	"fmt"
	"os"
	"runtime/pprof"

	"github.com/simulated-reality/laboratory/src/internal/config"
)

var (
	configFile  = flag.String("c", "", "a configuration file (required)")
	profileFile = flag.String("p", "", "an output file for profiling information")
	verbose     = flag.Bool("v", false, "a flag for displaying diagnostic information")
)

func Run(function func(*config.Config) error) {
	flag.Usage = usage
	flag.Parse()

	if len(*profileFile) > 0 {
		profile, err := os.Create(*profileFile)
		if err != nil {
			fail(errors.New("cannot enable profiling"))
		}
		pprof.StartCPUProfile(profile)
		defer pprof.StopCPUProfile()
	}

	if len(*configFile) == 0 {
		fail(errors.New("expected a filename"))
	}
	config, err := config.New(*configFile)
	if err != nil {
		fail(err)
	}
	if *verbose {
		config.Verbose = true
	}

	if err = function(config); err != nil {
		fail(err)
	}
}

func fail(err error) {
	fmt.Printf("Error: %s.\n", err)
	os.Exit(1)
}

func usage() {
	fmt.Printf("Usage: %s [options]\n\n", os.Args[0])
	fmt.Printf("Options:\n")
	flag.PrintDefaults()
	os.Exit(1)
}
<|endoftext|>


<commit_before>package horizon

import (
	"encoding/json"
	. "github.com/smartystreets/goconvey/convey"
	"github.com/stellar/go-horizon/test"
	"github.com/zenazn/goji/web"
	"net/http"
	"net/http/httptest"
	"testing"
)

func TestLedgerActions(t *testing.T) {

	Convey("Ledger Actions:", t, func() {
		Convey("GET /ledgers/1", func() {
			test.LoadScenario("base")
			app := NewTestApp()

			r, _ := http.NewRequest("GET", "/ledgers/1", nil)
			w := httptest.NewRecorder()
			c := web.C{
				Env: map[interface{}]interface{}{},
			}

			app.web.router.ServeHTTPC(c, w, r)
			So(w.Code, ShouldEqual, 200)

			var result ledgerResource
			err := json.Unmarshal(w.Body.Bytes(), &result)
			So(err, ShouldBeNil)
			So(result.Sequence, ShouldEqual, 1)
		})

		Convey("GET /ledgers/100", func() {
			test.LoadScenario("base")
			app := NewTestApp()

			r, _ := http.NewRequest("GET", "/ledgers/100", nil)
			w := httptest.NewRecorder()
			c := web.C{
				Env: map[interface{}]interface{}{},
			}

			app.web.router.ServeHTTPC(c, w, r)

			So(w.Code, ShouldEqual, 404)
		})

		Convey("GET /ledgers", func() {
			test.LoadScenario("base")
			app := NewTestApp()
			rh := NewRequestHelper(app)

			w := rh.Get("/ledgers", test.RequestHelperNoop)

			var result map[string]interface{}
			err := json.Unmarshal(w.Body.Bytes(), &result)
			So(err, ShouldBeNil)
			So(w.Code, ShouldEqual, 200)

			embedded := result["_embedded"].(map[string]interface{})
			records := embedded["records"].([]interface{})

			So(len(records), ShouldEqual, 4)
		})
	})
}
<commit_msg>Convert other tests to RequestHelper<commit_after>package horizon

import (
	"encoding/json"
	. "github.com/smartystreets/goconvey/convey"
	"github.com/stellar/go-horizon/test"
	"testing"
)

func TestLedgerActions(t *testing.T) {

	Convey("Ledger Actions:", t, func() {
		test.LoadScenario("base")
		app := NewTestApp()
		rh := NewRequestHelper(app)

		Convey("GET /ledgers/1", func() {
			w := rh.Get("/ledgers/1", test.RequestHelperNoop)

			So(w.Code, ShouldEqual, 200)

			var result ledgerResource
			err := json.Unmarshal(w.Body.Bytes(), &result)
			So(err, ShouldBeNil)
			So(result.Sequence, ShouldEqual, 1)
		})

		Convey("GET /ledgers/100", func() {
			w := rh.Get("/ledgers/100", test.RequestHelperNoop)

			So(w.Code, ShouldEqual, 404)
		})

		Convey("GET /ledgers", func() {

			w := rh.Get("/ledgers", test.RequestHelperNoop)

			var result map[string]interface{}
			err := json.Unmarshal(w.Body.Bytes(), &result)
			So(err, ShouldBeNil)
			So(w.Code, ShouldEqual, 200)

			embedded := result["_embedded"].(map[string]interface{})
			records := embedded["records"].([]interface{})

			So(len(records), ShouldEqual, 4)
		})
	})
}
<|endoftext|>


<commit_before>package copper

import (
	"reflect"
	"testing"
)

func makebuffer(data []byte, off int, size int) buffer {
	var b buffer
	b.buf = make([]byte, len(data))
	copy(b.buf, data)
	b.off = off
	b.buf = b.buf[:size]
	return b
}

type bufferReadTestCase struct {
	data     []byte
	off      int
	size     int
	readsize int
	expected []byte
	newoff   int
	newsize  int
}

var bufferReadTestCases = []bufferReadTestCase{
	{[]byte{0, 1, 2, 3}, 0, 2, 0, []byte{}, 0, 2},
	{[]byte{0, 1, 2, 3}, 0, 2, 1, []byte{0}, 1, 1},
	{[]byte{0, 1, 2, 3}, 0, 2, 2, []byte{0, 1}, 0, 0},
	{[]byte{0, 1, 2, 3}, 0, 2, 3, []byte{0, 1}, 0, 0},

	{[]byte{0, 1, 2, 3}, 0, 4, 0, []byte{}, 0, 4},
	{[]byte{0, 1, 2, 3}, 0, 4, 1, []byte{0}, 1, 3},
	{[]byte{0, 1, 2, 3}, 0, 4, 2, []byte{0, 1}, 2, 2},
	{[]byte{0, 1, 2, 3}, 0, 4, 3, []byte{0, 1, 2}, 3, 1},
	{[]byte{0, 1, 2, 3}, 0, 4, 4, []byte{0, 1, 2, 3}, 0, 0},
	{[]byte{0, 1, 2, 3}, 0, 4, 5, []byte{0, 1, 2, 3}, 0, 0},

	{[]byte{0, 1, 2, 3}, 2, 2, 0, []byte{}, 2, 2},
	{[]byte{0, 1, 2, 3}, 2, 2, 1, []byte{2}, 3, 1},
	{[]byte{0, 1, 2, 3}, 2, 2, 2, []byte{2, 3}, 0, 0},
	{[]byte{0, 1, 2, 3}, 2, 2, 3, []byte{2, 3}, 0, 0},

	{[]byte{0, 1, 2, 3}, 2, 3, 0, []byte{}, 2, 3},
	{[]byte{0, 1, 2, 3}, 2, 3, 1, []byte{2}, 3, 2},
	{[]byte{0, 1, 2, 3}, 2, 3, 2, []byte{2, 3}, 0, 1},
	{[]byte{0, 1, 2, 3}, 2, 3, 3, []byte{2, 3, 0}, 0, 0},
	{[]byte{0, 1, 2, 3}, 2, 3, 4, []byte{2, 3, 0}, 0, 0},

	{[]byte{0, 1, 2, 3}, 2, 4, 0, []byte{}, 2, 4},
	{[]byte{0, 1, 2, 3}, 2, 4, 1, []byte{2}, 3, 3},
	{[]byte{0, 1, 2, 3}, 2, 4, 2, []byte{2, 3}, 0, 2},
	{[]byte{0, 1, 2, 3}, 2, 4, 3, []byte{2, 3, 0}, 1, 1},
	{[]byte{0, 1, 2, 3}, 2, 4, 4, []byte{2, 3, 0, 1}, 0, 0},
	{[]byte{0, 1, 2, 3}, 2, 4, 5, []byte{2, 3, 0, 1}, 0, 0},
}

func TestBufferRead(t *testing.T) {
	var b buffer
	for index, c := range bufferReadTestCases {
		b = makebuffer(c.data, c.off, c.size)
		data := make([]byte, c.readsize)
		taken := b.read(data)
		if taken != len(c.expected) {
			t.Errorf("read case %d: read returned %d (expected %d)", index, taken, len(c.expected))
			continue
		}
		data = data[:taken]
		if !reflect.DeepEqual(data, c.expected) {
			t.Errorf("read case %d: read returned %v (expected %v)", index, data, c.expected)
			continue
		}
		if b.off != c.newoff {
			t.Errorf("read case %d: new offset = %d (expected %d)", index, b.off, c.newoff)
		}
		if b.len() != c.newsize {
			t.Errorf("read case %d: new size = %d (expected %d)", index, b.len(), c.newsize)
		}
	}
}

type bufferWriteTestCase struct {
	data     []byte
	off      int
	size     int
	src      []byte
	newoff   int
	newsize  int
	expected []byte
}

var bufferWriteTestCases = []bufferWriteTestCase{
	{[]byte{}, 0, 0, []byte{}, 0, 0, []byte{}},
	{[]byte{}, 0, 0, []byte{1}, 0, 1, []byte{1}},
	{[]byte{}, 0, 0, []byte{1, 2}, 0, 2, []byte{1, 2}},
	{[]byte{}, 0, 0, []byte{1, 2, 3}, 0, 3, []byte{1, 2, 3, 0}},

	{[]byte{0, 1, 2, 3}, 0, 2, []byte{}, 0, 2, []byte{0, 1, 2, 3}},
	{[]byte{0, 1, 2, 3}, 0, 2, []byte{4}, 0, 3, []byte{0, 1, 4, 3}},
	{[]byte{0, 1, 2, 3}, 0, 2, []byte{4, 5}, 0, 4, []byte{0, 1, 4, 5}},
	{[]byte{0, 1, 2, 3}, 0, 2, []byte{4, 5, 6}, 0, 5, []byte{0, 1, 4, 5, 6, 0, 0, 0}},

	{[]byte{0, 1, 2, 3}, 1, 2, []byte{}, 1, 2, []byte{0, 1, 2, 3}},
	{[]byte{0, 1, 2, 3}, 1, 2, []byte{4}, 1, 3, []byte{0, 1, 2, 4}},
	{[]byte{0, 1, 2, 3}, 1, 2, []byte{4, 5}, 1, 4, []byte{5, 1, 2, 4}},
	{[]byte{0, 1, 2, 3}, 1, 2, []byte{4, 5, 6}, 0, 5, []byte{1, 2, 4, 5, 6, 0, 0, 0}},

	{[]byte{0, 1, 2, 3}, 2, 2, []byte{}, 2, 2, []byte{0, 1, 2, 3}},
	{[]byte{0, 1, 2, 3}, 2, 2, []byte{4}, 2, 3, []byte{4, 1, 2, 3}},
	{[]byte{0, 1, 2, 3}, 2, 2, []byte{4, 5}, 2, 4, []byte{4, 5, 2, 3}},
	{[]byte{0, 1, 2, 3}, 2, 2, []byte{4, 5, 6}, 0, 5, []byte{2, 3, 4, 5, 6, 0, 0, 0}},

	{[]byte{0, 1, 2, 3}, 2, 3, []byte{}, 2, 3, []byte{0, 1, 2, 3}},
	{[]byte{0, 1, 2, 3}, 2, 3, []byte{4}, 2, 4, []byte{0, 4, 2, 3}},
	{[]byte{0, 1, 2, 3}, 2, 3, []byte{4, 5}, 0, 5, []byte{2, 3, 0, 4, 5, 0, 0, 0}},
}

func TestBufferWrite(t *testing.T) {
	var b buffer
	for index, c := range bufferWriteTestCases {
		b = makebuffer(c.data, c.off, c.size)
		b.write(c.src)
		if b.off != c.newoff {
			t.Errorf("write case %d: new offset = %d (expected %d)", index, b.off, c.newoff)
		}
		if b.len() != c.newsize {
			t.Errorf("write case %d: new size = %d (expected %d)", index, b.len(), c.newsize)
		}
		data := b.buf[:cap(b.buf)]
		if !reflect.DeepEqual(data, c.expected) {
			t.Errorf("write case %d: new data = %v (expected %v)", index, data, c.expected)
		}
		b.clear()
		if b.buf != nil || b.off != 0 {
			t.Errorf("write case %d: clear failed", index)
		}
	}
}
<commit_msg>Test buffer.peek together with buffer.read<commit_after>package copper

import (
	"reflect"
	"testing"
)

func makebuffer(data []byte, off int, size int) buffer {
	var b buffer
	b.buf = make([]byte, len(data))
	copy(b.buf, data)
	b.off = off
	b.buf = b.buf[:size]
	return b
}

type bufferReadTestCase struct {
	data     []byte
	off      int
	size     int
	readsize int
	expected []byte
	newoff   int
	newsize  int
}

var bufferReadTestCases = []bufferReadTestCase{
	{[]byte{0, 1, 2, 3}, 0, 2, 0, []byte{}, 0, 2},
	{[]byte{0, 1, 2, 3}, 0, 2, 1, []byte{0}, 1, 1},
	{[]byte{0, 1, 2, 3}, 0, 2, 2, []byte{0, 1}, 0, 0},
	{[]byte{0, 1, 2, 3}, 0, 2, 3, []byte{0, 1}, 0, 0},

	{[]byte{0, 1, 2, 3}, 0, 4, 0, []byte{}, 0, 4},
	{[]byte{0, 1, 2, 3}, 0, 4, 1, []byte{0}, 1, 3},
	{[]byte{0, 1, 2, 3}, 0, 4, 2, []byte{0, 1}, 2, 2},
	{[]byte{0, 1, 2, 3}, 0, 4, 3, []byte{0, 1, 2}, 3, 1},
	{[]byte{0, 1, 2, 3}, 0, 4, 4, []byte{0, 1, 2, 3}, 0, 0},
	{[]byte{0, 1, 2, 3}, 0, 4, 5, []byte{0, 1, 2, 3}, 0, 0},

	{[]byte{0, 1, 2, 3}, 2, 2, 0, []byte{}, 2, 2},
	{[]byte{0, 1, 2, 3}, 2, 2, 1, []byte{2}, 3, 1},
	{[]byte{0, 1, 2, 3}, 2, 2, 2, []byte{2, 3}, 0, 0},
	{[]byte{0, 1, 2, 3}, 2, 2, 3, []byte{2, 3}, 0, 0},

	{[]byte{0, 1, 2, 3}, 2, 3, 0, []byte{}, 2, 3},
	{[]byte{0, 1, 2, 3}, 2, 3, 1, []byte{2}, 3, 2},
	{[]byte{0, 1, 2, 3}, 2, 3, 2, []byte{2, 3}, 0, 1},
	{[]byte{0, 1, 2, 3}, 2, 3, 3, []byte{2, 3, 0}, 0, 0},
	{[]byte{0, 1, 2, 3}, 2, 3, 4, []byte{2, 3, 0}, 0, 0},

	{[]byte{0, 1, 2, 3}, 2, 4, 0, []byte{}, 2, 4},
	{[]byte{0, 1, 2, 3}, 2, 4, 1, []byte{2}, 3, 3},
	{[]byte{0, 1, 2, 3}, 2, 4, 2, []byte{2, 3}, 0, 2},
	{[]byte{0, 1, 2, 3}, 2, 4, 3, []byte{2, 3, 0}, 1, 1},
	{[]byte{0, 1, 2, 3}, 2, 4, 4, []byte{2, 3, 0, 1}, 0, 0},
	{[]byte{0, 1, 2, 3}, 2, 4, 5, []byte{2, 3, 0, 1}, 0, 0},
}

func TestBufferRead(t *testing.T) {
	var b buffer
	for index, c := range bufferReadTestCases {
		b = makebuffer(c.data, c.off, c.size)
		data := make([]byte, c.readsize)
		// call peek() first
		{
			taken := b.peek(data)
			if taken != len(c.expected) {
				t.Errorf("read case %d: read returned %d (expected %d)", index, taken, len(c.expected))
				continue
			}
			result := data[:taken]
			if !reflect.DeepEqual(result, c.expected) {
				t.Errorf("read case %d: read returned %v (expected %v)", index, result, c.expected)
				continue
			}
		}
		// call read() to consume the data
		{
			taken := b.read(data)
			if taken != len(c.expected) {
				t.Errorf("read case %d: read returned %d (expected %d)", index, taken, len(c.expected))
				continue
			}
			result := data[:taken]
			if !reflect.DeepEqual(result, c.expected) {
				t.Errorf("read case %d: read returned %v (expected %v)", index, result, c.expected)
				continue
			}
		}
		if b.off != c.newoff {
			t.Errorf("read case %d: new offset = %d (expected %d)", index, b.off, c.newoff)
		}
		if b.len() != c.newsize {
			t.Errorf("read case %d: new size = %d (expected %d)", index, b.len(), c.newsize)
		}
	}
}

type bufferWriteTestCase struct {
	data     []byte
	off      int
	size     int
	src      []byte
	newoff   int
	newsize  int
	expected []byte
}

var bufferWriteTestCases = []bufferWriteTestCase{
	{[]byte{}, 0, 0, []byte{}, 0, 0, []byte{}},
	{[]byte{}, 0, 0, []byte{1}, 0, 1, []byte{1}},
	{[]byte{}, 0, 0, []byte{1, 2}, 0, 2, []byte{1, 2}},
	{[]byte{}, 0, 0, []byte{1, 2, 3}, 0, 3, []byte{1, 2, 3, 0}},

	{[]byte{0, 1, 2, 3}, 0, 2, []byte{}, 0, 2, []byte{0, 1, 2, 3}},
	{[]byte{0, 1, 2, 3}, 0, 2, []byte{4}, 0, 3, []byte{0, 1, 4, 3}},
	{[]byte{0, 1, 2, 3}, 0, 2, []byte{4, 5}, 0, 4, []byte{0, 1, 4, 5}},
	{[]byte{0, 1, 2, 3}, 0, 2, []byte{4, 5, 6}, 0, 5, []byte{0, 1, 4, 5, 6, 0, 0, 0}},

	{[]byte{0, 1, 2, 3}, 1, 2, []byte{}, 1, 2, []byte{0, 1, 2, 3}},
	{[]byte{0, 1, 2, 3}, 1, 2, []byte{4}, 1, 3, []byte{0, 1, 2, 4}},
	{[]byte{0, 1, 2, 3}, 1, 2, []byte{4, 5}, 1, 4, []byte{5, 1, 2, 4}},
	{[]byte{0, 1, 2, 3}, 1, 2, []byte{4, 5, 6}, 0, 5, []byte{1, 2, 4, 5, 6, 0, 0, 0}},

	{[]byte{0, 1, 2, 3}, 2, 2, []byte{}, 2, 2, []byte{0, 1, 2, 3}},
	{[]byte{0, 1, 2, 3}, 2, 2, []byte{4}, 2, 3, []byte{4, 1, 2, 3}},
	{[]byte{0, 1, 2, 3}, 2, 2, []byte{4, 5}, 2, 4, []byte{4, 5, 2, 3}},
	{[]byte{0, 1, 2, 3}, 2, 2, []byte{4, 5, 6}, 0, 5, []byte{2, 3, 4, 5, 6, 0, 0, 0}},

	{[]byte{0, 1, 2, 3}, 2, 3, []byte{}, 2, 3, []byte{0, 1, 2, 3}},
	{[]byte{0, 1, 2, 3}, 2, 3, []byte{4}, 2, 4, []byte{0, 4, 2, 3}},
	{[]byte{0, 1, 2, 3}, 2, 3, []byte{4, 5}, 0, 5, []byte{2, 3, 0, 4, 5, 0, 0, 0}},
}

func TestBufferWrite(t *testing.T) {
	var b buffer
	for index, c := range bufferWriteTestCases {
		b = makebuffer(c.data, c.off, c.size)
		b.write(c.src)
		if b.off != c.newoff {
			t.Errorf("write case %d: new offset = %d (expected %d)", index, b.off, c.newoff)
		}
		if b.len() != c.newsize {
			t.Errorf("write case %d: new size = %d (expected %d)", index, b.len(), c.newsize)
		}
		data := b.buf[:cap(b.buf)]
		if !reflect.DeepEqual(data, c.expected) {
			t.Errorf("write case %d: new data = %v (expected %v)", index, data, c.expected)
		}
		b.clear()
		if b.buf != nil || b.off != 0 {
			t.Errorf("write case %d: clear failed", index)
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 Christian Gärtner. All rights reserved.
// Use of this source code is governed by a MIT license
// that can be found in the LICENSE file.

package build

import (
	"fmt"
	"github.com/achtern/kluver/lexer"
)

type Shader struct {
	version  string
	vertex   Tokens
	fragment Tokens
	global   Tokens
	compiled GLSL
}

type GLSL struct {
	vertex   string
	fragment string
}

type Tokens []lexer.Token

func (s *Shader) String() string {
	return fmt.Sprintf("Shader(%s, vertex=%q, fragment=%q, global=%q)", s.version, s.vertex, s.fragment, s.global)
}

func Build(tokenStream <-chan lexer.Token) string {
	global := make(Tokens, 0)
	vertex := make(Tokens, 0)
	fragment := make(Tokens, 0)

	shader := Shader{}

	// phase 0 : global
	// phase 1 : vertex
	// phase 2 : fragment
	phase := 0
	for token := range tokenStream {
		switch token.Typ {
		case lexer.TokenVertex:
			phase = 1
			continue
		case lexer.TokenFragment:
			phase = 2
			continue
		case lexer.TokenEnd:
			phase = 0
			continue
		case lexer.TokenVoid:
			continue
		}

		if token.Typ == lexer.TokenVersionNumber {
			shader.version = token.Val
			continue
		}

		switch phase {
		case 0:
			global = append(global, token)
		case 1:
			vertex = append(vertex, token)
		case 2:
			fragment = append(fragment, token)
		default:
			panic("unknow phase")
		}
	}

	shader.global = global
	shader.vertex = vertex
	shader.fragment = fragment

	s, _ := shader.buildVertex()
	return s
}

func (shader *Shader) buildHead() string {
	return "#version " + shader.version + "\n"
}

func (shader *Shader) buildVertex() (string, error) {

	var sb StringBuffer
	sb.append(shader.buildHead())

	for _, token := range shader.vertex {
		sb.append(token.Val)
	}

	return sb.String(), nil
}

func (shader *Shader) buildFragment() (string, error) {

	var sb StringBuffer
	sb.append(shader.buildHead())

	for _, token := range shader.fragment {
		sb.append(token.Val)
	}

	return sb.String(), nil
}

func generateRequire(action, typ, name lexer.Token) string {
	return fmt.Sprintf("uniform %s %s;", typ.Val, name.Val)
}<commit_msg>basic vertex shader generation working, providers and lib support missing<commit_after>// Copyright 2015 Christian Gärtner. All rights reserved.
// Use of this source code is governed by a MIT license
// that can be found in the LICENSE file.

package build

import (
	"fmt"
	"github.com/achtern/kluver/lexer"
)

type Shader struct {
	version  string
	vertex   Tokens
	fragment Tokens
	global   Tokens
	compiled GLSL
}

type GLSL struct {
	vertex   string
	fragment string
}

type varDef struct {
	typ  string
	name string
}

type Tokens []lexer.Token

func (s *Shader) String() string {
	return fmt.Sprintf("Shader(%s, vertex=%q, fragment=%q, global=%q)", s.version, s.vertex, s.fragment, s.global)
}

func Build(tokenStream <-chan lexer.Token) string {
	global := make(Tokens, 0)
	vertex := make(Tokens, 0)
	fragment := make(Tokens, 0)

	shader := Shader{}

	// phase 0 : global
	// phase 1 : vertex
	// phase 2 : fragment
	phase := 0
	for token := range tokenStream {
		switch token.Typ {
		case lexer.TokenVertex:
			phase = 1
			continue
		case lexer.TokenFragment:
			phase = 2
			continue
		case lexer.TokenEnd:
			phase = 0
			continue
		case lexer.TokenVoid:
			continue
		}

		if token.Typ == lexer.TokenVersionNumber {
			shader.version = token.Val
			continue
		}

		if token.Typ == lexer.TokenAction {
			// we do need the action tokens after lexing
			continue
		}

		switch phase {
		case 0:
			global = append(global, token)
		case 1:
			vertex = append(vertex, token)
		case 2:
			fragment = append(fragment, token)
		default:
			panic("unknow phase")
		}
	}

	shader.global = global
	shader.vertex = vertex
	shader.fragment = fragment

	s, _ := shader.buildVertex()
	return s
}

func (shader *Shader) buildHead() string {
	return "#version " + shader.version + "\n"
}

func (shader *Shader) buildVertex() (string, error) {

	var sb StringBuffer
	sb.append(shader.buildHead())

	provides := make([]Tokens, 0)

	for i := 0; i < len(shader.vertex); i++ {
		token := shader.vertex[i]
		switch token.Typ {
		case lexer.TokenRequire:
			sb.append(generateRequire(token, shader.vertex[i + 1], shader.vertex[i + 2]))
			i += 2
		case lexer.TokenProvide:
			provides = append(provides, Tokens{shader.vertex[i + 1], shader.vertex[i + 2]})
			sb.append(generateProvideSetting(shader.vertex[i + 1], shader.vertex[i + 2], shader.vertex[i + 3], shader.vertex[i + 4]))
			i += 4
		default:
			sb.append(token.Val)
		}
	}

	return sb.String(), nil
}

func (shader *Shader) buildFragment() (string, error) {

	var sb StringBuffer
	sb.append(shader.buildHead())

	for _, token := range shader.fragment {
		sb.append(token.Val)
	}

	return sb.String(), nil
}

func generateRequire(action, typ, name lexer.Token) string {
	return fmt.Sprintf("uniform %s %s", typ.Val, name.Val)
}

func generateProvideSetting(typ, name, assign, glslAction lexer.Token) string {
	return fmt.Sprintf("%s %s %s %s", typ.Val, name.Val, assign.Val, glslAction.Val)
}
<|endoftext|>


<commit_before>package build

import (
	"fmt"
	"github.com/c4s4/neon/util"
	"gopkg.in/yaml.v2"
	"net"
	"os"
	"path/filepath"
	"runtime"
	"time"
)

const (
	// DefaultRepository is local repository root directory
	DefaultRepository = "~/.neon"
	// RegexpPlugin is regexp for a plugin name
	RegexpPlugin = `[\w-]+/[\w-]+`
)

// Fields is the list of possible root fields for a build file
var Fields = []string{"doc", "default", "extends", "repository", "context", "singleton",
	"shell", "properties", "configuration", "environment", "targets", "version"}

// Build structure
type Build struct {
	File        string
	Dir         string
	Here        string
	Default     []string
	Doc         string
	Repository  string
	Singleton   string
	Shell       map[string][]string
	Scripts     []string
	Extends     []string
	Config      []string
	Properties  util.Object
	Environment map[string]string
	Targets     map[string]*Target
	Parents     []*Build
	Version     string
	Template    bool
}

// NewBuild makes a build from a build file
// - file: path of the build file
// - base: base of the build
// - repo: repository location
// Return:
// - Pointer to the build
// - error if something went wrong
func NewBuild(file, base, repo string, template bool) (*Build, error) {
	object, build, err := parseBuildFile(file)
	if err != nil {
		return nil, err
	}
	if err := setDirectories(build, base); err != nil {
		return nil, err
	}
	if err := object.CheckFields(Fields); err != nil {
		return nil, fmt.Errorf("parsing build file: %v", err)
	}
	if err := ParseFields(object, build, repo); err != nil {
		return nil, err
	}
	build.Parents, err = build.GetParents()
	if err != nil {
		return nil, err
	}
	build.Properties = build.GetProperties()
	build.Environment = build.GetEnvironment()
	build.SetDir(build.Dir)
	build.Template = template
	return build, nil
}

// ParseFields parses build file fields:
// - object: the build as an object.
// - build: the build object.
// - repo: the repository.
// Return: an error if something went wrong.
func ParseFields(object util.Object, build *Build, repo string) error {
	if err := ParseSingleton(object, build); err != nil {
		return err
	}
	if err := ParseShell(object, build); err != nil {
		return err
	}
	if err := ParseDefault(object, build); err != nil {
		return err
	}
	if err := ParseDoc(object, build); err != nil {
		return err
	}
	if err := ParseRepository(object, build, repo); err != nil {
		return err
	}
	if err := ParseContext(object, build); err != nil {
		return err
	}
	if err := ParseExtends(object, build); err != nil {
		return err
	}
	if err := ParseProperties(object, build); err != nil {
		return err
	}
	if err := ParseConfiguration(object, build); err != nil {
		return err
	}
	if err := ParseEnvironment(object, build); err != nil {
		return err
	}
	if err := ParseTargets(object, build); err != nil {
		return err
	}
	return ParseVersion(object, build)
}

func parseBuildFile(file string) (util.Object, *Build, error) {
	build := &Build{}
	file = util.ExpandUserHome(file)
	build.File = filepath.Base(file)
	source, err := util.ReadFile(file)
	if err != nil {
		return nil, nil, fmt.Errorf("loading build file '%s': %v", file, err)
	}
	var object util.Object
	if err = yaml.Unmarshal(source, &object); err != nil {
		return nil, nil, fmt.Errorf("build must be a map with string keys: %v", err)
	}
	return object, build, nil
}

func setDirectories(build *Build, base string) error {
	build.Dir = base
	here, err := os.Getwd()
	if err != nil {
		return fmt.Errorf("getting build file directory: %v", err)
	}
	build.Here = here
	return nil
}

// GetParents returns parent build objects.
// Return list of build objects and an error if any.
func (build *Build) GetParents() ([]*Build, error) {
	var parents []*Build
	for _, extend := range build.Extends {
		file, err := build.ParentPath(extend)
		if err != nil {
			return nil, fmt.Errorf("searching parent build file '%s': %v", extend, err)
		}
		parent, err := NewBuild(file, filepath.Dir(file), build.Repository, build.Template)
		if err != nil {
			return nil, fmt.Errorf("loading parent build file '%s': %v", extend, err)
		}
		parents = append(parents, parent)
	}
	return parents, nil
}

// GetProperties returns build properties, including those inherited from
// parents
// Return: build properties as an Object
func (build *Build) GetProperties() util.Object {
	var properties = make(map[string]interface{})
	for _, parent := range build.Parents {
		for name, value := range parent.GetProperties() {
			properties[name] = value
		}
	}
	for name, value := range build.Properties {
		properties[name] = value
	}
	return properties
}

// GetEnvironment returns the build environment, including the environment
// inherited from parents
// Return: environment as a map with string keys and values
func (build *Build) GetEnvironment() map[string]string {
	var environment = make(map[string]string)
	for _, parent := range build.Parents {
		for name, value := range parent.GetEnvironment() {
			environment[name] = value
		}
	}
	for name, value := range build.Environment {
		environment[name] = value
	}
	return environment
}

// GetTargets returns build targets, including those inherited from parents
// Return: targets as a map of targets with their name as keys
func (build *Build) GetTargets() map[string]*Target {
	var targets = make(map[string]*Target)
	for _, parent := range build.Parents {
		for name, target := range parent.GetTargets() {
			targets[name] = target
		}
	}
	for name, target := range build.Targets {
		targets[name] = target
	}
	return targets
}

// GetTargetByName return target with given name. If not defined in build,
// return target inherited from parent
// - name: the target name as a string
// Return: found target
func (build *Build) GetTargetByName(name string) *Target {
	target, found := build.Targets[name]
	if found {
		return target
	}
	for _, parent := range build.Parents {
		target = parent.GetTargetByName(name)
		if target != nil {
			return target
		}
	}
	return nil
}

// SetDir sets the build directory, propagating to parents
// - dir: build directory as a string
func (build *Build) SetDir(dir string) {
	build.Dir = dir
	for _, parent := range build.Parents {
		parent.SetDir(dir)
	}
}

// SetCommandLineProperties defines properties passed on command line in the
// context. These properties overwrite those define in the build file.
// - props: properties as a YAML map
// Return: error if something went wrong
func (build *Build) SetCommandLineProperties(props string) error {
	var object util.Object
	err := yaml.Unmarshal([]byte(props), &object)
	if err != nil {
		return fmt.Errorf("parsing command line properties: properties must be a map with string keys")
	}
	for name, value := range object {
		build.Properties[name] = value
	}
	return nil
}

// GetDefault returns default targets. If none is defined in build, return
// those from parent build files.
// Return: default targets a slice of strings
func (build *Build) GetDefault() []string {
	if len(build.Default) > 0 {
		return build.Default
	}
	for _, parent := range build.Parents {
		if len(parent.Default) > 0 {
			return parent.Default
		}
	}
	for _, parent := range build.Parents {
		parentDefault := parent.GetDefault()
		if len(parentDefault) > 0 {
			return parentDefault
		}
	}
	return build.Default
}

// GetScripts return a list of context scripts to run.
// Return: the list of context scripts
func (build *Build) GetScripts() []string {
	var scripts []string
	for _, parent := range build.Parents {
		scripts = append(scripts, parent.GetScripts()...)
	}
	scripts = append(scripts, build.Scripts...)
	return scripts
}

// Run runs given targets in a build context. If no target is given, runs
// default one.
// - context: the context to run into
// - targets: targets to run as a slice of strings
// Return: error if something went wrong
func (build *Build) Run(context *Context, targets []string) error {
	if err := build.CheckVersion(context); err != nil {
		return err
	}
	var listener net.Listener
	var err error
	if listener, err = build.EnsureSingle(context); err != nil {
		return err
	}
	if listener != nil {
		defer listener.Close()
	}
	if len(targets) == 0 {
		targets = build.GetDefault()
		if len(targets) == 0 {
			return fmt.Errorf("no default target")
		}
	}
	for _, target := range targets {
		context.Stack = NewStack()
		err := build.RunTarget(context, target)
		if err != nil {
			return err
		}
	}
	return nil
}

// RunTarget runs given target in a build context.
// - context: build context
// - name: name of the target to run as a string
// Return: an error if something went wrong
func (build *Build) RunTarget(context *Context, name string) error {
	target := build.GetTargetByName(name)
	if target == nil {
		return fmt.Errorf("target '%s' not found", name)
	}
	err := target.Run(context)
	if err != nil {
		return fmt.Errorf("running target '%s': %v", name, err)
	}
	return nil
}

// RunParentTarget runs parent target with given name in a build context.
// - context: build context
// - name: the name of the target to run
// Return:
// - boolean: that tells if parent target was found
// - error: if something went wrong
func (build *Build) RunParentTarget(context *Context, name string) (bool, error) {
	for _, parent := range build.Parents {
		target := parent.GetTargetByName(name)
		if target != nil {
			err := context.Stack.Push(target)
			if err != nil {
				return false, err
			}
			err = target.Steps.Run(context)
			if err != nil {
				return true, fmt.Errorf("running target '%s': %v", name, err)
			}
			return true, nil
		}
	}
	return false, nil
}

// GetShell return shell for current os.
// Return:
// - shell as a slice of strings (such as ["sh", "-c"])
// - error if something went wrong
func (build *Build) GetShell() ([]string, error) {
	for system, shell := range build.Shell {
		if system != "default" && system == runtime.GOOS {
			return shell, nil
		}
	}
	shell, ok := build.Shell["default"]
	if !ok {
		return nil, fmt.Errorf("no shell found for '%s'", runtime.GOOS)
	}
	return shell, nil
}

// EnsureSingle runs a TCP server on given port to ensure that a single
// instance is running on a machine. Fails if another instance is already
// running on same port.
// - context: build context
// Return: a listener and an error if another instance is running on same port
func (build *Build) EnsureSingle(context *Context) (net.Listener, error) {
	if build.Singleton == "" {
		return nil, nil
	}
	expression := build.Singleton
	if IsExpression(expression) {
		expression = expression[1:]
	}
	singleton, err := context.EvaluateExpression(expression)
	if err != nil {
		return nil, fmt.Errorf("evaluating singleton port expression '%s': %v", expression, err)
	}
	port, ok := singleton.(int64)
	if !ok {
		portInt, ok := singleton.(int)
		if !ok {
			return nil, fmt.Errorf("singleton port expression '%s' must return an integer", expression)
		}
		port = int64(portInt)
	}
	return ListenPort(int(port))
}

// ListenPort listens given port:
// - port: port to listen.
// Return: listener and error if any
func ListenPort(port int) (net.Listener, error) {
	if port < 0 || port > 65535 {
		return nil, fmt.Errorf("singleton port port must be between 0 and 65535")
	}
	listener, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
	if err != nil {
		return nil, fmt.Errorf("listening singleton port: %v", err)
	}
	go func() {
		for {
			listener.Accept()
			time.Sleep(100 * time.Millisecond)
		}
	}()
	return listener, nil
}

// CheckVersion checks evaluates version expression to check that NeON version is OK
func (build *Build) CheckVersion(context *Context) error {
	if build.Version == "" {
		return nil
	}
	result, err := context.EvaluateExpression(build.Version)
	if err != nil {
		return fmt.Errorf("evaluating version expression: %v", err)
	}
	versionOK, ok := result.(bool)
	if !ok {
		return fmt.Errorf("version expression should return a boolean")
	}
	if !versionOK {
		return fmt.Errorf("neon version '%s' doesn't meet requirements in version field", NeonVersion)
	}
	return nil
}
<commit_msg>Fixed parent evaluation order<commit_after>package build

import (
	"fmt"
	"github.com/c4s4/neon/util"
	"gopkg.in/yaml.v2"
	"net"
	"os"
	"path/filepath"
	"runtime"
	"time"
)

const (
	// DefaultRepository is local repository root directory
	DefaultRepository = "~/.neon"
	// RegexpPlugin is regexp for a plugin name
	RegexpPlugin = `[\w-]+/[\w-]+`
)

// Fields is the list of possible root fields for a build file
var Fields = []string{"doc", "default", "extends", "repository", "context", "singleton",
	"shell", "properties", "configuration", "environment", "targets", "version"}

// Build structure
type Build struct {
	File        string
	Dir         string
	Here        string
	Default     []string
	Doc         string
	Repository  string
	Singleton   string
	Shell       map[string][]string
	Scripts     []string
	Extends     []string
	Config      []string
	Properties  util.Object
	Environment map[string]string
	Targets     map[string]*Target
	Parents     []*Build
	Version     string
	Template    bool
}

// NewBuild makes a build from a build file
// - file: path of the build file
// - base: base of the build
// - repo: repository location
// Return:
// - Pointer to the build
// - error if something went wrong
func NewBuild(file, base, repo string, template bool) (*Build, error) {
	object, build, err := parseBuildFile(file)
	if err != nil {
		return nil, err
	}
	if err := setDirectories(build, base); err != nil {
		return nil, err
	}
	if err := object.CheckFields(Fields); err != nil {
		return nil, fmt.Errorf("parsing build file: %v", err)
	}
	if err := ParseFields(object, build, repo); err != nil {
		return nil, err
	}
	build.Parents, err = build.GetParents()
	if err != nil {
		return nil, err
	}
	build.Properties = build.GetProperties()
	build.Environment = build.GetEnvironment()
	build.SetDir(build.Dir)
	build.Template = template
	return build, nil
}

// ParseFields parses build file fields:
// - object: the build as an object.
// - build: the build object.
// - repo: the repository.
// Return: an error if something went wrong.
func ParseFields(object util.Object, build *Build, repo string) error {
	if err := ParseSingleton(object, build); err != nil {
		return err
	}
	if err := ParseShell(object, build); err != nil {
		return err
	}
	if err := ParseDefault(object, build); err != nil {
		return err
	}
	if err := ParseDoc(object, build); err != nil {
		return err
	}
	if err := ParseRepository(object, build, repo); err != nil {
		return err
	}
	if err := ParseContext(object, build); err != nil {
		return err
	}
	if err := ParseExtends(object, build); err != nil {
		return err
	}
	if err := ParseProperties(object, build); err != nil {
		return err
	}
	if err := ParseConfiguration(object, build); err != nil {
		return err
	}
	if err := ParseEnvironment(object, build); err != nil {
		return err
	}
	if err := ParseTargets(object, build); err != nil {
		return err
	}
	return ParseVersion(object, build)
}

func parseBuildFile(file string) (util.Object, *Build, error) {
	build := &Build{}
	file = util.ExpandUserHome(file)
	build.File = filepath.Base(file)
	source, err := util.ReadFile(file)
	if err != nil {
		return nil, nil, fmt.Errorf("loading build file '%s': %v", file, err)
	}
	var object util.Object
	if err = yaml.Unmarshal(source, &object); err != nil {
		return nil, nil, fmt.Errorf("build must be a map with string keys: %v", err)
	}
	return object, build, nil
}

func setDirectories(build *Build, base string) error {
	build.Dir = base
	here, err := os.Getwd()
	if err != nil {
		return fmt.Errorf("getting build file directory: %v", err)
	}
	build.Here = here
	return nil
}

// GetParents returns parent build objects.
// Return list of build objects and an error if any.
func (build *Build) GetParents() ([]*Build, error) {
	var parents []*Build
	for _, extend := range build.Extends {
		file, err := build.ParentPath(extend)
		if err != nil {
			return nil, fmt.Errorf("searching parent build file '%s': %v", extend, err)
		}
		parent, err := NewBuild(file, filepath.Dir(file), build.Repository, build.Template)
		if err != nil {
			return nil, fmt.Errorf("loading parent build file '%s': %v", extend, err)
		}
		parents = append(parents, parent)
	}
	return parents, nil
}

// GetProperties returns build properties, including those inherited from
// parents
// Return: build properties as an Object
func (build *Build) GetProperties() util.Object {
	var properties = make(map[string]interface{})
	for _, parent := range build.Parents {
		for name, value := range parent.GetProperties() {
			properties[name] = value
		}
	}
	for name, value := range build.Properties {
		properties[name] = value
	}
	return properties
}

// GetEnvironment returns the build environment, including the environment
// inherited from parents
// Return: environment as a map with string keys and values
func (build *Build) GetEnvironment() map[string]string {
	var environment = make(map[string]string)
	for _, parent := range build.Parents {
		for name, value := range parent.GetEnvironment() {
			environment[name] = value
		}
	}
	for name, value := range build.Environment {
		environment[name] = value
	}
	return environment
}

// GetTargets returns build targets, including those inherited from parents
// Return: targets as a map of targets with their name as keys
func (build *Build) GetTargets() map[string]*Target {
	var targets = make(map[string]*Target)
	for i := len(build.Parents)-1; i >= 0; i-- {
		parent := build.Parents[i]
		for name, target := range parent.GetTargets() {
			targets[name] = target
		}
	}
	for name, target := range build.Targets {
		targets[name] = target
	}
	return targets
}

// GetTargetByName return target with given name. If not defined in build,
// return target inherited from parent
// - name: the target name as a string
// Return: found target
func (build *Build) GetTargetByName(name string) *Target {
	target, found := build.Targets[name]
	if found {
		return target
	}
	for i := len(build.Parents)-1; i >= 0; i-- {
		parent := build.Parents[i]
		target = parent.GetTargetByName(name)
		if target != nil {
			return target
		}
	}
	return nil
}

// SetDir sets the build directory, propagating to parents
// - dir: build directory as a string
func (build *Build) SetDir(dir string) {
	build.Dir = dir
	for _, parent := range build.Parents {
		parent.SetDir(dir)
	}
}

// SetCommandLineProperties defines properties passed on command line in the
// context. These properties overwrite those define in the build file.
// - props: properties as a YAML map
// Return: error if something went wrong
func (build *Build) SetCommandLineProperties(props string) error {
	var object util.Object
	err := yaml.Unmarshal([]byte(props), &object)
	if err != nil {
		return fmt.Errorf("parsing command line properties: properties must be a map with string keys")
	}
	for name, value := range object {
		build.Properties[name] = value
	}
	return nil
}

// GetDefault returns default targets. If none is defined in build, return
// those from parent build files.
// Return: default targets a slice of strings
func (build *Build) GetDefault() []string {
	if len(build.Default) > 0 {
		return build.Default
	}
	for _, parent := range build.Parents {
		if len(parent.Default) > 0 {
			return parent.Default
		}
	}
	for _, parent := range build.Parents {
		parentDefault := parent.GetDefault()
		if len(parentDefault) > 0 {
			return parentDefault
		}
	}
	return build.Default
}

// GetScripts return a list of context scripts to run.
// Return: the list of context scripts
func (build *Build) GetScripts() []string {
	var scripts []string
	for _, parent := range build.Parents {
		scripts = append(scripts, parent.GetScripts()...)
	}
	scripts = append(scripts, build.Scripts...)
	return scripts
}

// Run runs given targets in a build context. If no target is given, runs
// default one.
// - context: the context to run into
// - targets: targets to run as a slice of strings
// Return: error if something went wrong
func (build *Build) Run(context *Context, targets []string) error {
	if err := build.CheckVersion(context); err != nil {
		return err
	}
	var listener net.Listener
	var err error
	if listener, err = build.EnsureSingle(context); err != nil {
		return err
	}
	if listener != nil {
		defer listener.Close()
	}
	if len(targets) == 0 {
		targets = build.GetDefault()
		if len(targets) == 0 {
			return fmt.Errorf("no default target")
		}
	}
	for _, target := range targets {
		context.Stack = NewStack()
		err := build.RunTarget(context, target)
		if err != nil {
			return err
		}
	}
	return nil
}

// RunTarget runs given target in a build context.
// - context: build context
// - name: name of the target to run as a string
// Return: an error if something went wrong
func (build *Build) RunTarget(context *Context, name string) error {
	target := build.GetTargetByName(name)
	if target == nil {
		return fmt.Errorf("target '%s' not found", name)
	}
	err := target.Run(context)
	if err != nil {
		return fmt.Errorf("running target '%s': %v", name, err)
	}
	return nil
}

// RunParentTarget runs parent target with given name in a build context.
// - context: build context
// - name: the name of the target to run
// Return:
// - boolean: that tells if parent target was found
// - error: if something went wrong
func (build *Build) RunParentTarget(context *Context, name string) (bool, error) {
	for _, parent := range build.Parents {
		target := parent.GetTargetByName(name)
		if target != nil {
			err := context.Stack.Push(target)
			if err != nil {
				return false, err
			}
			err = target.Steps.Run(context)
			if err != nil {
				return true, fmt.Errorf("running target '%s': %v", name, err)
			}
			return true, nil
		}
	}
	return false, nil
}

// GetShell return shell for current os.
// Return:
// - shell as a slice of strings (such as ["sh", "-c"])
// - error if something went wrong
func (build *Build) GetShell() ([]string, error) {
	for system, shell := range build.Shell {
		if system != "default" && system == runtime.GOOS {
			return shell, nil
		}
	}
	shell, ok := build.Shell["default"]
	if !ok {
		return nil, fmt.Errorf("no shell found for '%s'", runtime.GOOS)
	}
	return shell, nil
}

// EnsureSingle runs a TCP server on given port to ensure that a single
// instance is running on a machine. Fails if another instance is already
// running on same port.
// - context: build context
// Return: a listener and an error if another instance is running on same port
func (build *Build) EnsureSingle(context *Context) (net.Listener, error) {
	if build.Singleton == "" {
		return nil, nil
	}
	expression := build.Singleton
	if IsExpression(expression) {
		expression = expression[1:]
	}
	singleton, err := context.EvaluateExpression(expression)
	if err != nil {
		return nil, fmt.Errorf("evaluating singleton port expression '%s': %v", expression, err)
	}
	port, ok := singleton.(int64)
	if !ok {
		portInt, ok := singleton.(int)
		if !ok {
			return nil, fmt.Errorf("singleton port expression '%s' must return an integer", expression)
		}
		port = int64(portInt)
	}
	return ListenPort(int(port))
}

// ListenPort listens given port:
// - port: port to listen.
// Return: listener and error if any
func ListenPort(port int) (net.Listener, error) {
	if port < 0 || port > 65535 {
		return nil, fmt.Errorf("singleton port port must be between 0 and 65535")
	}
	listener, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
	if err != nil {
		return nil, fmt.Errorf("listening singleton port: %v", err)
	}
	go func() {
		for {
			listener.Accept()
			time.Sleep(100 * time.Millisecond)
		}
	}()
	return listener, nil
}

// CheckVersion checks evaluates version expression to check that NeON version is OK
func (build *Build) CheckVersion(context *Context) error {
	if build.Version == "" {
		return nil
	}
	result, err := context.EvaluateExpression(build.Version)
	if err != nil {
		return fmt.Errorf("evaluating version expression: %v", err)
	}
	versionOK, ok := result.(bool)
	if !ok {
		return fmt.Errorf("version expression should return a boolean")
	}
	if !versionOK {
		return fmt.Errorf("neon version '%s' doesn't meet requirements in version field", NeonVersion)
	}
	return nil
}
<|endoftext|>


<commit_before>package builder

import (
	"errors"
	"github.com/appc/spec/discovery"
	"github.com/appc/spec/schema/types"
	"github.com/blablacar/cnt/log"
	"github.com/blablacar/cnt/spec"
	"github.com/blablacar/cnt/utils"
	"github.com/ghodss/yaml"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"regexp"
	"strings"
)

const EXEC_FILES = `
execute_files() {
  fdir=$1
  [ -d "$fdir" ] || return 0

  for file in $fdir/*; do
    [ -e "$file" ] && {
     	[ -x "$file" ] || /cnt/bin/busybox chmod +x "$file"
     	echo -e "\e[1m\e[32mRunning script -> $file\e[0m"
     	$file
    }
  done
}`

const BUILD_SCRIPT = `#!/cnt/bin/busybox sh
set -x
set -e
export TARGET=$( dirname $0 )
export ROOTFS=%%ROOTFS%%
export TERM=xterm

` + EXEC_FILES + `

execute_files "$ROOTFS/cnt/runlevels/inherit-build-early"
execute_files "$TARGET/runlevels/build"
`

const BUILD_SCRIPT_LATE = `#!/cnt/bin/busybox sh
set -x
set -e
export TARGET=$( dirname $0 )
export ROOTFS=%%ROOTFS%%
export TERM=xterm

` + EXEC_FILES + `

execute_files "$TARGET/runlevels/build-late"
execute_files "$ROOTFS/cnt/runlevels/inherit-build-late"
`

const PRESTART = `#!/cnt/bin/busybox sh
set -x
set -e

BASEDIR=${0%/*}
CNT_PATH=/cnt

` + EXEC_FILES + `

execute_files ${CNT_PATH}/runlevels/prestart-early

if [ -d ${CNT_PATH}/attributes ]; then
    ${BASEDIR}/attributes-merger -i ${CNT_PATH}/attributes -e CONFD_OVERRIDE
    export CONFD_DATA=$(cat attributes.json)
fi
${BASEDIR}/confd -onetime -config-file=${CNT_PATH}/prestart/confd.toml

execute_files ${CNT_PATH}/runlevels/prestart-late
`
const PATH_BIN = "/bin"
const PATH_TESTS = "/tests"
const PATH_INSTALLED = "/installed"
const PATH_MANIFEST = "/manifest"
const PATH_IMAGE_ACI = "/image.aci"
const PATH_IMAGE_ACI_ZIP = "/image-zip.aci"
const PATH_ROOTFS = "/rootfs"
const PATH_TARGET = "/target"
const PATH_CNT = "/cnt"
const PATH_CNT_MANIFEST = "/cnt-manifest.yml"
const PATH_RUNLEVELS = "/runlevels"
const PATH_PRESTART_EARLY = "/prestart-early"
const PATH_PRESTART_LATE = "/prestart-late"
const PATH_INHERIT_BUILD_LATE = "/inherit-build-late"
const PATH_INHERIT_BUILD_EARLY = "/inherit-build-early"
const PATH_ATTRIBUTES = "/attributes"
const PATH_FILES = "/files"
const PATH_CONFD = "/confd"
const PATH_BUILD_LATE = "/build-late"
const PATH_BUILD_SETUP = "/build-setup"
const PATH_BUILD = "/build"
const PATH_CONFDOTD = "/conf.d"
const PATH_TEMPLATES = "/templates"

type Img struct {
	path     string
	target   string
	rootfs   string
	PodName  *spec.ACFullname
	manifest spec.AciManifest
	args     BuildArgs
}

func Version(nameAndVersion string) string {
	split := strings.Split(nameAndVersion, ":")
	if len(split) == 1 {
		return ""
	}
	return split[1]
}

func ShortNameId(name types.ACIdentifier) string {
	return strings.Split(string(name), "/")[1]
}

func ShortName(nameAndVersion string) string {
	return strings.Split(Name(nameAndVersion), "/")[1]
}

func Name(nameAndVersion string) string {
	return strings.Split(nameAndVersion, ":")[0]
}

////////////////////////////////////////////

func NewAciWithManifest(path string, args BuildArgs, manifest spec.AciManifest) (*Img, error) {
	log.Get().Debug("New aci", path, args, manifest)
	cnt, err := PrepAci(path, args)
	if err != nil {
		return nil, err
	}
	cnt.manifest = manifest

	cnt.checkLatestVersions()

	return cnt, nil
}

func NewAci(path string, args BuildArgs) (*Img, error) {
	manifest, err := readManifest(path + PATH_CNT_MANIFEST)
	if err != nil {
		log.Get().Debug(path, PATH_CNT_MANIFEST+" does not exists")
		return nil, err
	}
	return NewAciWithManifest(path, args, *manifest)
}

func PrepAci(aciPath string, args BuildArgs) (*Img, error) {
	cnt := new(Img)
	cnt.args = args

	if fullPath, err := filepath.Abs(aciPath); err != nil {
		log.Get().Panic("Cannot get fullpath of project", err)
	} else {
		cnt.path = fullPath
		cnt.target = cnt.path + PATH_TARGET
		if args.TargetPath != "" {
			currentAbsDir, err := filepath.Abs(args.TargetPath + "/" + cnt.manifest.NameAndVersion.ShortName())
			if err != nil {
				log.Get().Panic("invalid target path")
			}
			cnt.target = currentAbsDir
		}
		cnt.rootfs = cnt.target + PATH_ROOTFS
	}
	return cnt, nil
}

//////////////////////////////////////////////////////////////////

func readManifest(manifestPath string) (*spec.AciManifest, error) {
	manifest := spec.AciManifest{Aci: spec.AciDefinition{}}

	source, err := ioutil.ReadFile(manifestPath)
	if err != nil {
		return nil, err
	}
	err = yaml.Unmarshal([]byte(source), &manifest)
	if err != nil {
		log.Get().Panic(err)
	}

	return &manifest, nil
}

func (cnt *Img) tarAci(zip bool) {
	target := PATH_IMAGE_ACI[1:]
	if zip {
		target = PATH_IMAGE_ACI_ZIP[1:]
	}
	dir, _ := os.Getwd()
	log.Get().Debug("chdir to", cnt.target)
	os.Chdir(cnt.target)
	utils.Tar(zip, target, PATH_MANIFEST[1:], PATH_ROOTFS[1:])
	log.Get().Debug("chdir to", dir)
	os.Chdir(dir)
}

func (cnt *Img) checkLatestVersions() {
	if cnt.manifest.From != "" {
		version := getLatestVersion(cnt.manifest.From)
		log.Get().Debug("latest version of from : " + cnt.manifest.NameAndVersion.Name() + ":" + version)
		if version != "" && utils.Version(cnt.manifest.From.Version()).LessThan(utils.Version(version)) {
			log.Get().Warn("---------------------------------")
			log.Get().Warn("From has newer version : " + cnt.manifest.From.Name() + ":" + version)
			log.Get().Warn("---------------------------------")
		}
	}
	for _, dep := range cnt.manifest.Aci.Dependencies {
		version := getLatestVersion(dep)
		if version != "" && utils.Version(dep.Version()).LessThan(utils.Version(version)) {
			log.Get().Warn("---------------------------------")
			log.Get().Warn("Newer dependency version : " + dep.Name() + ":" + version)
			log.Get().Warn("---------------------------------")
		}
	}
}

func getLatestVersion(name spec.ACFullname) string {
	app, err := discovery.NewAppFromString(name.Name() + ":latest")
	if app.Labels["os"] == "" {
		app.Labels["os"] = "linux"
	}
	if app.Labels["arch"] == "" {
		app.Labels["arch"] = "amd64"
	}

	endpoint, _, err := discovery.DiscoverEndpoints(*app, false)
	if err != nil {
		return ""
	}

	r, _ := regexp.Compile(`^(\d+\.)?(\d+\.)?(\*|\d+)$`)

	url := getRedirectForLatest(endpoint.ACIEndpoints[0].ACI)
	log.Get().Debug("latest version url is ", url)

	for _, part := range strings.Split(url, "/") {
		if r.Match([]byte(part)) {
			return part
		}
	}
	return ""
}

func getRedirectForLatest(url string) string {
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return ""
	}
	transport := http.DefaultTransport
	//	if insecureSkipVerify {
	//		transport = &http.Transport{
	//			TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	//		}
	//	}
	client := &http.Client{Transport: transport}
	myurl := ""
	client.CheckRedirect = func(req *http.Request, via []*http.Request) error {
		myurl = req.URL.Path
		return errors.New("do not want to get the file")
	}
	_, err2 := client.Do(req)
	if err2 != nil {
		if myurl != "" {
			return myurl
		}
		return ""
	}
	return myurl
}
<commit_msg>check version in go routine<commit_after>package builder

import (
	"errors"
	"github.com/appc/spec/discovery"
	"github.com/appc/spec/schema/types"
	"github.com/blablacar/cnt/log"
	"github.com/blablacar/cnt/spec"
	"github.com/blablacar/cnt/utils"
	"github.com/ghodss/yaml"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"regexp"
	"strings"
)

const EXEC_FILES = `
execute_files() {
  fdir=$1
  [ -d "$fdir" ] || return 0

  for file in $fdir/*; do
    [ -e "$file" ] && {
     	[ -x "$file" ] || /cnt/bin/busybox chmod +x "$file"
     	echo -e "\e[1m\e[32mRunning script -> $file\e[0m"
     	$file
    }
  done
}`

const BUILD_SCRIPT = `#!/cnt/bin/busybox sh
set -x
set -e
export TARGET=$( dirname $0 )
export ROOTFS=%%ROOTFS%%
export TERM=xterm

` + EXEC_FILES + `

execute_files "$ROOTFS/cnt/runlevels/inherit-build-early"
execute_files "$TARGET/runlevels/build"
`

const BUILD_SCRIPT_LATE = `#!/cnt/bin/busybox sh
set -x
set -e
export TARGET=$( dirname $0 )
export ROOTFS=%%ROOTFS%%
export TERM=xterm

` + EXEC_FILES + `

execute_files "$TARGET/runlevels/build-late"
execute_files "$ROOTFS/cnt/runlevels/inherit-build-late"
`

const PRESTART = `#!/cnt/bin/busybox sh
set -x
set -e

BASEDIR=${0%/*}
CNT_PATH=/cnt

` + EXEC_FILES + `

execute_files ${CNT_PATH}/runlevels/prestart-early

if [ -d ${CNT_PATH}/attributes ]; then
    ${BASEDIR}/attributes-merger -i ${CNT_PATH}/attributes -e CONFD_OVERRIDE
    export CONFD_DATA=$(cat attributes.json)
fi
${BASEDIR}/confd -onetime -config-file=${CNT_PATH}/prestart/confd.toml

execute_files ${CNT_PATH}/runlevels/prestart-late
`
const PATH_BIN = "/bin"
const PATH_TESTS = "/tests"
const PATH_INSTALLED = "/installed"
const PATH_MANIFEST = "/manifest"
const PATH_IMAGE_ACI = "/image.aci"
const PATH_IMAGE_ACI_ZIP = "/image-zip.aci"
const PATH_ROOTFS = "/rootfs"
const PATH_TARGET = "/target"
const PATH_CNT = "/cnt"
const PATH_CNT_MANIFEST = "/cnt-manifest.yml"
const PATH_RUNLEVELS = "/runlevels"
const PATH_PRESTART_EARLY = "/prestart-early"
const PATH_PRESTART_LATE = "/prestart-late"
const PATH_INHERIT_BUILD_LATE = "/inherit-build-late"
const PATH_INHERIT_BUILD_EARLY = "/inherit-build-early"
const PATH_ATTRIBUTES = "/attributes"
const PATH_FILES = "/files"
const PATH_CONFD = "/confd"
const PATH_BUILD_LATE = "/build-late"
const PATH_BUILD_SETUP = "/build-setup"
const PATH_BUILD = "/build"
const PATH_CONFDOTD = "/conf.d"
const PATH_TEMPLATES = "/templates"

type Img struct {
	path     string
	target   string
	rootfs   string
	PodName  *spec.ACFullname
	manifest spec.AciManifest
	args     BuildArgs
}

func Version(nameAndVersion string) string {
	split := strings.Split(nameAndVersion, ":")
	if len(split) == 1 {
		return ""
	}
	return split[1]
}

func ShortNameId(name types.ACIdentifier) string {
	return strings.Split(string(name), "/")[1]
}

func ShortName(nameAndVersion string) string {
	return strings.Split(Name(nameAndVersion), "/")[1]
}

func Name(nameAndVersion string) string {
	return strings.Split(nameAndVersion, ":")[0]
}

////////////////////////////////////////////

func NewAciWithManifest(path string, args BuildArgs, manifest spec.AciManifest) (*Img, error) {
	log.Get().Debug("New aci", path, args, manifest)
	cnt, err := PrepAci(path, args)
	if err != nil {
		return nil, err
	}
	cnt.manifest = manifest

	go cnt.checkLatestVersions()

	return cnt, nil
}

func NewAci(path string, args BuildArgs) (*Img, error) {
	manifest, err := readManifest(path + PATH_CNT_MANIFEST)
	if err != nil {
		log.Get().Debug(path, PATH_CNT_MANIFEST+" does not exists")
		return nil, err
	}
	return NewAciWithManifest(path, args, *manifest)
}

func PrepAci(aciPath string, args BuildArgs) (*Img, error) {
	cnt := new(Img)
	cnt.args = args

	if fullPath, err := filepath.Abs(aciPath); err != nil {
		log.Get().Panic("Cannot get fullpath of project", err)
	} else {
		cnt.path = fullPath
		cnt.target = cnt.path + PATH_TARGET
		if args.TargetPath != "" {
			currentAbsDir, err := filepath.Abs(args.TargetPath + "/" + cnt.manifest.NameAndVersion.ShortName())
			if err != nil {
				log.Get().Panic("invalid target path")
			}
			cnt.target = currentAbsDir
		}
		cnt.rootfs = cnt.target + PATH_ROOTFS
	}
	return cnt, nil
}

//////////////////////////////////////////////////////////////////

func readManifest(manifestPath string) (*spec.AciManifest, error) {
	manifest := spec.AciManifest{Aci: spec.AciDefinition{}}

	source, err := ioutil.ReadFile(manifestPath)
	if err != nil {
		return nil, err
	}
	err = yaml.Unmarshal([]byte(source), &manifest)
	if err != nil {
		log.Get().Panic(err)
	}

	return &manifest, nil
}

func (cnt *Img) tarAci(zip bool) {
	target := PATH_IMAGE_ACI[1:]
	if zip {
		target = PATH_IMAGE_ACI_ZIP[1:]
	}
	dir, _ := os.Getwd()
	log.Get().Debug("chdir to", cnt.target)
	os.Chdir(cnt.target)
	utils.Tar(zip, target, PATH_MANIFEST[1:], PATH_ROOTFS[1:])
	log.Get().Debug("chdir to", dir)
	os.Chdir(dir)
}

func (cnt *Img) checkLatestVersions() {
	if cnt.manifest.From != "" {
		version := getLatestVersion(cnt.manifest.From)
		log.Get().Debug("latest version of from : " + cnt.manifest.NameAndVersion.Name() + ":" + version)
		if version != "" && utils.Version(cnt.manifest.From.Version()).LessThan(utils.Version(version)) {
			log.Get().Warn("---------------------------------")
			log.Get().Warn("From has newer version : " + cnt.manifest.From.Name() + ":" + version)
			log.Get().Warn("---------------------------------")
		}
	}
	for _, dep := range cnt.manifest.Aci.Dependencies {
		version := getLatestVersion(dep)
		if version != "" && utils.Version(dep.Version()).LessThan(utils.Version(version)) {
			log.Get().Warn("---------------------------------")
			log.Get().Warn("Newer dependency version : " + dep.Name() + ":" + version)
			log.Get().Warn("---------------------------------")
		}
	}
}

func getLatestVersion(name spec.ACFullname) string {
	app, err := discovery.NewAppFromString(name.Name() + ":latest")
	if app.Labels["os"] == "" {
		app.Labels["os"] = "linux"
	}
	if app.Labels["arch"] == "" {
		app.Labels["arch"] = "amd64"
	}

	endpoint, _, err := discovery.DiscoverEndpoints(*app, false)
	if err != nil {
		return ""
	}

	r, _ := regexp.Compile(`^(\d+\.)?(\d+\.)?(\*|\d+)$`)

	url := getRedirectForLatest(endpoint.ACIEndpoints[0].ACI)
	log.Get().Debug("latest version url is ", url)

	for _, part := range strings.Split(url, "/") {
		if r.Match([]byte(part)) {
			return part
		}
	}
	return ""
}

func getRedirectForLatest(url string) string {
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return ""
	}
	transport := http.DefaultTransport
	//	if insecureSkipVerify {
	//		transport = &http.Transport{
	//			TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	//		}
	//	}
	client := &http.Client{Transport: transport}
	myurl := ""
	client.CheckRedirect = func(req *http.Request, via []*http.Request) error {
		myurl = req.URL.Path
		return errors.New("do not want to get the file")
	}
	_, err2 := client.Do(req)
	if err2 != nil {
		if myurl != "" {
			return myurl
		}
		return ""
	}
	return myurl
}
<|endoftext|>


<commit_before>package main

import "log"

func main() {
    slice := make([]byte, 10)
    log.Printf("slice: %d", len(slice))

    str := "Hello, 世界"
    log.Printf("string: %d", len(str))

    m := make(map[string]int)
    m["hello"] = 1
    log.Printf("map: %d", len(m))

    channel := make(chan int, 5)
    log.Printf("channel: %d", len(channel))
    channel <- 1
    log.Printf("channel: %d", len(channel))

    var pointer *[5]byte
    log.Printf("pointer: %d", len(pointer))
}
<commit_msg>Use greek for len, since it gives the desired output, but doesn't break in the book.<commit_after>package main

import "log"

func main() {
    slice := make([]byte, 10)
    log.Printf("slice: %d", len(slice))

    str := "γειά σου κόσμε"
    log.Printf("string: %d", len(str))

    m := make(map[string]int)
    m["hello"] = 1
    log.Printf("map: %d", len(m))

    channel := make(chan int, 5)
    log.Printf("channel: %d", len(channel))
    channel <- 1
    log.Printf("channel: %d", len(channel))

    var pointer *[5]byte
    log.Printf("pointer: %d", len(pointer))
}
<|endoftext|>


<commit_before>package logx

import (
	"sync"
	"io"
	"unsafe"
)

type bytesBuffer struct {
	B []byte
}

//no bb
var bbFree = sync.Pool{
	New: func() interface{} { return new(bytesBuffer) },
}

func (b *bytesBuffer) WriteTo(w io.Writer) (int64, error) {
	n, err := w.Write(b.B)
	return int64(n), err
}

func (b *bytesBuffer) Bytes() []byte {
	return b.B
}

func (b *bytesBuffer) Write(p []byte) (int, error) {
	b.B = append(b.B, p...)
	return len(p), nil
}

func (b *bytesBuffer) WriteByte(c byte) error {
	b.B = append(b.B, c)
	return nil
}

func (b *bytesBuffer) WriteString(s string) (int, error) {
	b.B = append(b.B, s...)
	return len(s), nil
}

func (b *bytesBuffer) Set(p []byte) {
	b.B = append(b.B[:0], p...)
}

func (b *bytesBuffer) SetString(s string) {
	b.B = append(b.B[:0], s...)
}

func (b *bytesBuffer) String() string {
	return b2s(b.B)
}

func (b *bytesBuffer) Reset() {
	b.B = b.B[:0]
}

func s2b(s string) []byte {
	return *(*[]byte)(unsafe.Pointer(&s))
}

func b2s(b []byte) string {
	return *(*string)(unsafe.Pointer(&b))
}
<commit_msg>update<commit_after>package logx

import (
	"sync"
	"io"
	"unsafe"
)
//pool 4 bytesbuffer
type bytesBuffer struct {
	B []byte
}

//no bb
var bbFree = sync.Pool{
	New: func() interface{} { return new(bytesBuffer) },
}

func (b *bytesBuffer) WriteTo(w io.Writer) (int64, error) {
	n, err := w.Write(b.B)
	return int64(n), err
}

func (b *bytesBuffer) Bytes() []byte {
	return b.B
}

func (b *bytesBuffer) Write(p []byte) (int, error) {
	b.B = append(b.B, p...)
	return len(p), nil
}

func (b *bytesBuffer) WriteByte(c byte) error {
	b.B = append(b.B, c)
	return nil
}

func (b *bytesBuffer) WriteString(s string) (int, error) {
	b.B = append(b.B, s...)
	return len(s), nil
}

func (b *bytesBuffer) Set(p []byte) {
	b.B = append(b.B[:0], p...)
}

func (b *bytesBuffer) SetString(s string) {
	b.B = append(b.B[:0], s...)
}

func (b *bytesBuffer) String() string {
	return b2s(b.B)
}

func (b *bytesBuffer) Reset() {
	b.B = b.B[:0]
}

func s2b(s string) []byte {
	return *(*[]byte)(unsafe.Pointer(&s))
}

func b2s(b []byte) string {
	return *(*string)(unsafe.Pointer(&b))
}
<|endoftext|>


<commit_before>package check

import (
	"fmt"
	"plaid/parser"
	"plaid/scope"
	"plaid/types"
	"plaid/vm"
)

type binopsLUT map[string]map[types.Type]map[types.Type]types.Type
type doubleLUT map[types.Type]map[types.Type]types.Type
type singleLUT map[types.Type]types.Type

var defaultBinopsLUT = binopsLUT{
	"+": doubleLUT{
		types.Int: singleLUT{types.Int: types.Int},
		types.Str: singleLUT{types.Str: types.Str},
	},
	"-": doubleLUT{
		types.Int: singleLUT{types.Int: types.Int},
	},
	"*": doubleLUT{
		types.Int: singleLUT{types.Int: types.Int},
	},
	"<": doubleLUT{
		types.Int: singleLUT{types.Int: types.Bool},
	},
	"<=": doubleLUT{
		types.Int: singleLUT{types.Int: types.Bool},
	},
	">": doubleLUT{
		types.Int: singleLUT{types.Int: types.Bool},
	},
	">=": doubleLUT{
		types.Int: singleLUT{types.Int: types.Bool},
	},
	"[": doubleLUT{
		types.Str: singleLUT{types.Int: types.TypeOptional{Child: types.Str}},
	},
}

// Check takes an existing abstract syntax tree and performs type checks and
// other correctness checks. It returns a list of any errors that were
// discovered inside the AST
func Check(prog *parser.Program, libraries ...vm.Library) *scope.GlobalScope {
	global := scope.MakeGlobalScope()

	for _, library := range libraries {
		for name, builtin := range library {
			global.NewVariable(name, builtin.Type)
		}
	}

	checkProgram(global, prog)
	return global
}

func checkProgram(s scope.Scope, prog *parser.Program) {
	for _, stmt := range prog.Stmts {
		checkStmt(s, stmt)
	}
}

func checkStmt(s scope.Scope, stmt parser.Stmt) {
	switch stmt := stmt.(type) {
	case *parser.IfStmt:
		checkIfStmt(s, stmt)
		break
	case *parser.DeclarationStmt:
		checkDeclarationStmt(s, stmt)
		break
	case *parser.ReturnStmt:
		checkReturnStmt(s, stmt)
		break
	case *parser.ExprStmt:
		checkExprAllowVoid(s, stmt.Expr)
		break
	}
}

func checkStmtBlock(s scope.Scope, block *parser.StmtBlock) {
	for _, stmt := range block.Stmts {
		checkStmt(s, stmt)
	}
}

func checkIfStmt(s scope.Scope, stmt *parser.IfStmt) {
	typ := checkExpr(s, stmt.Cond)
	if typ.Equals(types.Bool) == false {
		s.NewError(fmt.Errorf("condition must resolve to a boolean"))
	}

	checkStmtBlock(s, stmt.Clause)
}

func checkDeclarationStmt(s scope.Scope, stmt *parser.DeclarationStmt) {
	name := stmt.Name.Name
	typ := checkExpr(s, stmt.Expr)
	s.NewVariable(name, typ)
}

func checkReturnStmt(s scope.Scope, stmt *parser.ReturnStmt) {
	var ret types.Type = types.TypeVoid{}
	if stmt.Expr != nil {
		ret = checkExpr(s, stmt.Expr)
	}

	if s.HasSelfReference() == false {
		s.NewError(fmt.Errorf("return statements must be inside a function"))
		return
	}

	if s.GetSelfReference().Ret.Equals(ret) || ret.IsError() {
		return
	}

	if s.GetSelfReference().Ret.Equals(types.TypeVoid{}) {
		s.NewError(fmt.Errorf("expected to return nothing, got '%s'", ret))
		return
	}

	if ret.Equals(types.TypeVoid{}) {
		s.NewError(fmt.Errorf("expected a return type of '%s', got nothing", s.GetSelfReference().Ret))
	}

	s.NewError(fmt.Errorf("expected to return '%s', got '%s'", s.GetSelfReference().Ret, ret))
}

func checkExprAllowVoid(s scope.Scope, expr parser.Expr) types.Type {
	var typ types.Type = types.TypeError{}
	switch expr := expr.(type) {
	case *parser.FunctionExpr:
		typ = checkFunctionExpr(s, expr)
	case *parser.DispatchExpr:
		typ = checkDispatchExpr(s, expr)
	case *parser.AssignExpr:
		typ = checkAssignExpr(s, expr)
	case *parser.BinaryExpr:
		typ = checkBinaryExpr(s, expr, defaultBinopsLUT)
	case *parser.ListExpr:
		typ = checkListExpr(s, expr)
	case *parser.SubscriptExpr:
		typ = checkSubscriptExpr(s, expr, defaultBinopsLUT)
	case *parser.SelfExpr:
		typ = checkSelfExpr(s, expr)
	case *parser.IdentExpr:
		typ = checkIdentExpr(s, expr)
	case *parser.NumberExpr:
		typ = checkNumberExpr(s, expr)
	case *parser.StringExpr:
		typ = checkStringExpr(s, expr)
	case *parser.BooleanExpr:
		typ = checkBooleanExpr(s, expr)
	default:
		s.NewError(fmt.Errorf("unknown expression type"))
	}

	return typ
}

func checkExpr(s scope.Scope, expr parser.Expr) types.Type {
	typ := checkExprAllowVoid(s, expr)

	if typ.Equals(types.TypeVoid{}) {
		s.NewError(fmt.Errorf("cannot use void types in an expression"))
		return types.TypeError{}
	}

	return typ
}

func checkFunctionExpr(s scope.Scope, expr *parser.FunctionExpr) types.Type {
	ret := ConvertTypeNote(expr.Ret)
	params := []types.Type{}
	for _, param := range expr.Params {
		params = append(params, ConvertTypeNote(param.Note))
	}
	tuple := types.TypeTuple{Children: params}
	self := types.TypeFunction{Params: tuple, Ret: ret}

	childScope := scope.MakeLocalScope(s, self)

	for _, param := range expr.Params {
		paramName := param.Name.Name
		paramType := ConvertTypeNote(param.Note)
		childScope.NewVariable(paramName, paramType)
	}

	checkStmtBlock(childScope, expr.Block)
	return self
}

func checkDispatchExpr(s scope.Scope, expr *parser.DispatchExpr) types.Type {
	// Resolve arguments to types
	argTypes := []types.Type{}
	for _, argExpr := range expr.Args {
		argTypes = append(argTypes, checkExpr(s, argExpr))
	}

	// Resolve callee to type
	calleeType := checkExpr(s, expr.Callee)
	calleeFunc, ok := calleeType.(types.TypeFunction)
	if ok == false {
		if calleeType.IsError() == false {
			s.NewError(fmt.Errorf("cannot call function on type '%s'", calleeType))
		}

		return types.TypeError{}
	}

	// Resolve return type
	retType := calleeFunc.Ret

	// Check that the given argument types match the expected parameter types
	totalArgs := len(argTypes)
	totalParams := len(calleeFunc.Params.Children)
	if totalArgs == totalParams {
		for i := 0; i < totalArgs; i++ {
			argType := argTypes[i]
			paramType := calleeFunc.Params.Children[i]

			if argType.IsError() {
				retType = types.TypeError{}
			} else if argType.Equals(paramType) == false {
				s.NewError(fmt.Errorf("expected '%s', got '%s'", paramType, argType))
				retType = types.TypeError{}
			}
		}
	} else {
		s.NewError(fmt.Errorf("expected %d arguments, got %d", totalParams, totalArgs))
		retType = types.TypeError{}
	}

	return retType
}

func checkAssignExpr(s scope.Scope, expr *parser.AssignExpr) types.Type {
	name := expr.Left.Name
	leftType := s.GetVariableType(name)
	rightType := checkExpr(s, expr.Right)

	if leftType == nil {
		s.NewError(fmt.Errorf("'%s' cannot be assigned before it is declared", name))
		return types.TypeError{}
	}

	if leftType.IsError() || rightType.IsError() {
		return types.TypeError{}
	}

	if leftType.Equals(rightType) == false {
		s.NewError(fmt.Errorf("'%s' cannot be assigned type '%s'", leftType, rightType))
		return types.TypeError{}
	}

	return leftType
}

func checkBinaryExpr(s scope.Scope, expr *parser.BinaryExpr, lut binopsLUT) types.Type {
	leftType := checkExpr(s, expr.Left)
	rightType := checkExpr(s, expr.Right)

	if leftType.IsError() || rightType.IsError() {
		return types.TypeError{}
	}

	if operLUT, ok := lut[expr.Oper]; ok {
		if leftLUT, ok := operLUT[leftType]; ok {
			if retType, ok := leftLUT[rightType]; ok {
				return retType
			}
		}

		s.NewError(fmt.Errorf("operator '%s' does not support %s and %s", expr.Oper, leftType, rightType))
		return types.TypeError{}
	}

	s.NewError(fmt.Errorf("unknown infix operator '%s'", expr.Oper))
	return types.TypeError{}
}

func checkListExpr(s scope.Scope, expr *parser.ListExpr) types.Type {
	var elemTypes []types.Type
	for _, elem := range expr.Elements {
		elemTypes = append(elemTypes, checkExpr(s, elem))
	}

	if len(elemTypes) == 0 {
		s.NewError(fmt.Errorf("cannot determine type from empty list"))
		return types.TypeError{}
	}

	for _, typ := range elemTypes {
		if typ.IsError() {
			return types.TypeError{}
		}
	}

	var listType types.Type
	for _, typ := range elemTypes {
		if listType == nil {
			listType = typ
			continue
		}

		if listType.Equals(typ) == false {
			s.NewError(fmt.Errorf("element type %s is not compatible with type %s", typ, listType))
			return types.TypeError{}
		}
	}

	return types.TypeList{Child: listType}
}

func checkSubscriptExpr(s scope.Scope, expr *parser.SubscriptExpr, lut binopsLUT) types.Type {
	listType := checkExpr(s, expr.ListLike)
	indexType := checkExpr(s, expr.Index)

	if listType.IsError() || indexType.IsError() {
		return types.TypeError{}
	}

	if listType, ok := listType.(types.TypeList); ok {
		return types.TypeOptional{Child: listType.Child}
	}

	if subscriptLUT, ok := lut["["]; ok {
		if listLUT, ok := subscriptLUT[listType]; ok {
			if retType, ok := listLUT[indexType]; ok {
				return retType
			}
		}

		s.NewError(fmt.Errorf("subscript operator does not support %s[%s]", listType, indexType))
		return types.TypeError{}
	}

	s.NewError(fmt.Errorf("unknown infix operator '['"))
	return types.TypeError{}
}

func checkSelfExpr(s scope.Scope, expr *parser.SelfExpr) types.Type {
	if s.HasSelfReference() == false {
		s.NewError(fmt.Errorf("self references must be inside a function"))
		return types.TypeError{}
	}

	return s.GetSelfReference()
}

func checkIdentExpr(s scope.Scope, expr *parser.IdentExpr) types.Type {
	if s.HasVariable(expr.Name) {
		return s.GetVariableType(expr.Name)
	}

	s.NewError(fmt.Errorf("variable '%s' was used before it was declared", expr.Name))
	return types.TypeError{}
}

func checkNumberExpr(s scope.Scope, expr *parser.NumberExpr) types.Type {
	return types.Int
}

func checkStringExpr(s scope.Scope, expr *parser.StringExpr) types.Type {
	return types.Str
}

func checkBooleanExpr(s scope.Scope, expr *parser.BooleanExpr) types.Type {
	return types.Bool
}
<commit_msg>bind local scope to FunctionExpr AST node<commit_after>package check

import (
	"fmt"
	"plaid/parser"
	"plaid/scope"
	"plaid/types"
	"plaid/vm"
)

type binopsLUT map[string]map[types.Type]map[types.Type]types.Type
type doubleLUT map[types.Type]map[types.Type]types.Type
type singleLUT map[types.Type]types.Type

var defaultBinopsLUT = binopsLUT{
	"+": doubleLUT{
		types.Int: singleLUT{types.Int: types.Int},
		types.Str: singleLUT{types.Str: types.Str},
	},
	"-": doubleLUT{
		types.Int: singleLUT{types.Int: types.Int},
	},
	"*": doubleLUT{
		types.Int: singleLUT{types.Int: types.Int},
	},
	"<": doubleLUT{
		types.Int: singleLUT{types.Int: types.Bool},
	},
	"<=": doubleLUT{
		types.Int: singleLUT{types.Int: types.Bool},
	},
	">": doubleLUT{
		types.Int: singleLUT{types.Int: types.Bool},
	},
	">=": doubleLUT{
		types.Int: singleLUT{types.Int: types.Bool},
	},
	"[": doubleLUT{
		types.Str: singleLUT{types.Int: types.TypeOptional{Child: types.Str}},
	},
}

// Check takes an existing abstract syntax tree and performs type checks and
// other correctness checks. It returns a list of any errors that were
// discovered inside the AST
func Check(prog *parser.Program, libraries ...vm.Library) *scope.GlobalScope {
	global := scope.MakeGlobalScope()

	for _, library := range libraries {
		for name, builtin := range library {
			global.NewVariable(name, builtin.Type)
		}
	}

	checkProgram(global, prog)
	return global
}

func checkProgram(s scope.Scope, prog *parser.Program) {
	for _, stmt := range prog.Stmts {
		checkStmt(s, stmt)
	}
}

func checkStmt(s scope.Scope, stmt parser.Stmt) {
	switch stmt := stmt.(type) {
	case *parser.IfStmt:
		checkIfStmt(s, stmt)
		break
	case *parser.DeclarationStmt:
		checkDeclarationStmt(s, stmt)
		break
	case *parser.ReturnStmt:
		checkReturnStmt(s, stmt)
		break
	case *parser.ExprStmt:
		checkExprAllowVoid(s, stmt.Expr)
		break
	}
}

func checkStmtBlock(s scope.Scope, block *parser.StmtBlock) {
	for _, stmt := range block.Stmts {
		checkStmt(s, stmt)
	}
}

func checkIfStmt(s scope.Scope, stmt *parser.IfStmt) {
	typ := checkExpr(s, stmt.Cond)
	if typ.Equals(types.Bool) == false {
		s.NewError(fmt.Errorf("condition must resolve to a boolean"))
	}

	checkStmtBlock(s, stmt.Clause)
}

func checkDeclarationStmt(s scope.Scope, stmt *parser.DeclarationStmt) {
	name := stmt.Name.Name
	typ := checkExpr(s, stmt.Expr)
	s.NewVariable(name, typ)
}

func checkReturnStmt(s scope.Scope, stmt *parser.ReturnStmt) {
	var ret types.Type = types.TypeVoid{}
	if stmt.Expr != nil {
		ret = checkExpr(s, stmt.Expr)
	}

	if s.HasSelfReference() == false {
		s.NewError(fmt.Errorf("return statements must be inside a function"))
		return
	}

	if s.GetSelfReference().Ret.Equals(ret) || ret.IsError() {
		return
	}

	if s.GetSelfReference().Ret.Equals(types.TypeVoid{}) {
		s.NewError(fmt.Errorf("expected to return nothing, got '%s'", ret))
		return
	}

	if ret.Equals(types.TypeVoid{}) {
		s.NewError(fmt.Errorf("expected a return type of '%s', got nothing", s.GetSelfReference().Ret))
	}

	s.NewError(fmt.Errorf("expected to return '%s', got '%s'", s.GetSelfReference().Ret, ret))
}

func checkExprAllowVoid(s scope.Scope, expr parser.Expr) types.Type {
	var typ types.Type = types.TypeError{}
	switch expr := expr.(type) {
	case *parser.FunctionExpr:
		typ = checkFunctionExpr(s, expr)
	case *parser.DispatchExpr:
		typ = checkDispatchExpr(s, expr)
	case *parser.AssignExpr:
		typ = checkAssignExpr(s, expr)
	case *parser.BinaryExpr:
		typ = checkBinaryExpr(s, expr, defaultBinopsLUT)
	case *parser.ListExpr:
		typ = checkListExpr(s, expr)
	case *parser.SubscriptExpr:
		typ = checkSubscriptExpr(s, expr, defaultBinopsLUT)
	case *parser.SelfExpr:
		typ = checkSelfExpr(s, expr)
	case *parser.IdentExpr:
		typ = checkIdentExpr(s, expr)
	case *parser.NumberExpr:
		typ = checkNumberExpr(s, expr)
	case *parser.StringExpr:
		typ = checkStringExpr(s, expr)
	case *parser.BooleanExpr:
		typ = checkBooleanExpr(s, expr)
	default:
		s.NewError(fmt.Errorf("unknown expression type"))
	}

	return typ
}

func checkExpr(s scope.Scope, expr parser.Expr) types.Type {
	typ := checkExprAllowVoid(s, expr)

	if typ.Equals(types.TypeVoid{}) {
		s.NewError(fmt.Errorf("cannot use void types in an expression"))
		return types.TypeError{}
	}

	return typ
}

func checkFunctionExpr(s scope.Scope, expr *parser.FunctionExpr) types.Type {
	ret := ConvertTypeNote(expr.Ret)
	params := []types.Type{}
	for _, param := range expr.Params {
		params = append(params, ConvertTypeNote(param.Note))
	}
	tuple := types.TypeTuple{Children: params}
	self := types.TypeFunction{Params: tuple, Ret: ret}

	childScope := scope.MakeLocalScope(s, self)

	for _, param := range expr.Params {
		paramName := param.Name.Name
		paramType := ConvertTypeNote(param.Note)
		childScope.NewVariable(paramName, paramType)
	}

	checkStmtBlock(childScope, expr.Block)
	expr.Scope = childScope
	return self
}

func checkDispatchExpr(s scope.Scope, expr *parser.DispatchExpr) types.Type {
	// Resolve arguments to types
	argTypes := []types.Type{}
	for _, argExpr := range expr.Args {
		argTypes = append(argTypes, checkExpr(s, argExpr))
	}

	// Resolve callee to type
	calleeType := checkExpr(s, expr.Callee)
	calleeFunc, ok := calleeType.(types.TypeFunction)
	if ok == false {
		if calleeType.IsError() == false {
			s.NewError(fmt.Errorf("cannot call function on type '%s'", calleeType))
		}

		return types.TypeError{}
	}

	// Resolve return type
	retType := calleeFunc.Ret

	// Check that the given argument types match the expected parameter types
	totalArgs := len(argTypes)
	totalParams := len(calleeFunc.Params.Children)
	if totalArgs == totalParams {
		for i := 0; i < totalArgs; i++ {
			argType := argTypes[i]
			paramType := calleeFunc.Params.Children[i]

			if argType.IsError() {
				retType = types.TypeError{}
			} else if argType.Equals(paramType) == false {
				s.NewError(fmt.Errorf("expected '%s', got '%s'", paramType, argType))
				retType = types.TypeError{}
			}
		}
	} else {
		s.NewError(fmt.Errorf("expected %d arguments, got %d", totalParams, totalArgs))
		retType = types.TypeError{}
	}

	return retType
}

func checkAssignExpr(s scope.Scope, expr *parser.AssignExpr) types.Type {
	name := expr.Left.Name
	leftType := s.GetVariableType(name)
	rightType := checkExpr(s, expr.Right)

	if leftType == nil {
		s.NewError(fmt.Errorf("'%s' cannot be assigned before it is declared", name))
		return types.TypeError{}
	}

	if leftType.IsError() || rightType.IsError() {
		return types.TypeError{}
	}

	if leftType.Equals(rightType) == false {
		s.NewError(fmt.Errorf("'%s' cannot be assigned type '%s'", leftType, rightType))
		return types.TypeError{}
	}

	return leftType
}

func checkBinaryExpr(s scope.Scope, expr *parser.BinaryExpr, lut binopsLUT) types.Type {
	leftType := checkExpr(s, expr.Left)
	rightType := checkExpr(s, expr.Right)

	if leftType.IsError() || rightType.IsError() {
		return types.TypeError{}
	}

	if operLUT, ok := lut[expr.Oper]; ok {
		if leftLUT, ok := operLUT[leftType]; ok {
			if retType, ok := leftLUT[rightType]; ok {
				return retType
			}
		}

		s.NewError(fmt.Errorf("operator '%s' does not support %s and %s", expr.Oper, leftType, rightType))
		return types.TypeError{}
	}

	s.NewError(fmt.Errorf("unknown infix operator '%s'", expr.Oper))
	return types.TypeError{}
}

func checkListExpr(s scope.Scope, expr *parser.ListExpr) types.Type {
	var elemTypes []types.Type
	for _, elem := range expr.Elements {
		elemTypes = append(elemTypes, checkExpr(s, elem))
	}

	if len(elemTypes) == 0 {
		s.NewError(fmt.Errorf("cannot determine type from empty list"))
		return types.TypeError{}
	}

	for _, typ := range elemTypes {
		if typ.IsError() {
			return types.TypeError{}
		}
	}

	var listType types.Type
	for _, typ := range elemTypes {
		if listType == nil {
			listType = typ
			continue
		}

		if listType.Equals(typ) == false {
			s.NewError(fmt.Errorf("element type %s is not compatible with type %s", typ, listType))
			return types.TypeError{}
		}
	}

	return types.TypeList{Child: listType}
}

func checkSubscriptExpr(s scope.Scope, expr *parser.SubscriptExpr, lut binopsLUT) types.Type {
	listType := checkExpr(s, expr.ListLike)
	indexType := checkExpr(s, expr.Index)

	if listType.IsError() || indexType.IsError() {
		return types.TypeError{}
	}

	if listType, ok := listType.(types.TypeList); ok {
		return types.TypeOptional{Child: listType.Child}
	}

	if subscriptLUT, ok := lut["["]; ok {
		if listLUT, ok := subscriptLUT[listType]; ok {
			if retType, ok := listLUT[indexType]; ok {
				return retType
			}
		}

		s.NewError(fmt.Errorf("subscript operator does not support %s[%s]", listType, indexType))
		return types.TypeError{}
	}

	s.NewError(fmt.Errorf("unknown infix operator '['"))
	return types.TypeError{}
}

func checkSelfExpr(s scope.Scope, expr *parser.SelfExpr) types.Type {
	if s.HasSelfReference() == false {
		s.NewError(fmt.Errorf("self references must be inside a function"))
		return types.TypeError{}
	}

	return s.GetSelfReference()
}

func checkIdentExpr(s scope.Scope, expr *parser.IdentExpr) types.Type {
	if s.HasVariable(expr.Name) {
		return s.GetVariableType(expr.Name)
	}

	s.NewError(fmt.Errorf("variable '%s' was used before it was declared", expr.Name))
	return types.TypeError{}
}

func checkNumberExpr(s scope.Scope, expr *parser.NumberExpr) types.Type {
	return types.Int
}

func checkStringExpr(s scope.Scope, expr *parser.StringExpr) types.Type {
	return types.Str
}

func checkBooleanExpr(s scope.Scope, expr *parser.BooleanExpr) types.Type {
	return types.Bool
}
<|endoftext|>


<commit_before>package nodeman

import (
	"bufio"
	"errors"
	"fmt"
	"io"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"sync"
	"syscall"
	"time"
)

type Client struct {
	mutex   *sync.Mutex
	runCmd  *exec.Cmd
}

func New() *Client {
	return &Client{mutex: &sync.Mutex{}}
}

func (client *Client) Running() bool {
	return client.runCmd != nil
}

func (client *Client) Stop() (err error) {

	client.mutex.Lock()
	defer client.mutex.Unlock()

	if client.runCmd != nil {
		if err = client.runCmd.Process.Signal(syscall.SIGINT); err != nil {
			err = fmt.Errorf("nodeman: failed to send sigint. %s", err.Error())
		}
		waitOnStop(client.runCmd)
	} else {
		err = errors.New("nodeman: cannot stop as not running")
	}

	if err != nil {
		log.Println(err.Error())
	}
	client.runCmd = nil
	return err
}

func (client *Client) Start() (err error) {

	client.mutex.Lock()
	defer client.mutex.Unlock()

	if client.runCmd != nil {
		return errors.New("obnodeman: cannot start as already running")
	}
	if err = checkWorkingDir(); err != nil {
		log.Println(err.Error())
		return err
	}

	args := []string{
		"openbazaard.py",
		"start",
		"-a",
		"0.0.0.0",
	}

	if err = client.runAndWriteToLog(exec.Command("python", args...)); err != nil {
		err = fmt.Errorf("nodeman: failed to start. %s", err.Error())
	}

	if err != nil {
		log.Println(err.Error())
	}
	return err
}

func waitOnStop(cmd *exec.Cmd) {
	done := make(chan error, 1)
	go func() {
		done <- cmd.Wait()
	}()
	select {
	case <-time.After(10 * time.Second):
		if err := cmd.Process.Kill(); err != nil {
			log.Printf("nodeman: attempted, but failed to kill ob process as it did not shut down within the alloted time. Error: %s", err.Error())
		} else {
			log.Println("nodeman: killed ob process as it did not shut down within the alloted time")
		}
	case err := <-done:
		if err != nil {
			log.Println("nodeman: ob process exited with error = %v", err)
		} else {
			log.Println("nodeman: ob process exited gracefully")
		}
	}
}
func checkWorkingDir() error {
	workingDir, err := os.Getwd()
	if err != nil {
		return fmt.Errorf("nodeman: failed to read working dir: %s", err.Error())
	}
	filename := "openbazaard.py"
	fullname := filepath.Join(workingDir, filename)
	if _, err := os.Stat(fullname); os.IsNotExist(err) {
		return fmt.Errorf("nodeman: %s not found in working dir %s", filename, workingDir)
	}
	return nil
}

func (client *Client) runAndWriteToLog(cmd *exec.Cmd) error {

	/*    stdout, err := cmd.StdoutPipe()
	      if err != nil {
	          return err
	      }
	      stderr, err := cmd.StderrPipe()
	      if err != nil {
	          return err
	      }*/

	// start the command after having set up the pipe
	if err := cmd.Start(); err != nil {
		return err
	}
	client.runCmd = cmd

	//    go asyncScan(stdout)
	//    go asyncScan(stderr)

	return nil
}

// TODO: delete below?
func asyncScan(read io.ReadCloser) {

	// read command's stdout line by line
	in := bufio.NewScanner(read)

	for in.Scan() {
		log.Printf(in.Text()) // write each line to your log, or anything you need
	}
	if err := in.Err(); err != nil {
		log.Printf("error: %s", err)
	}
}
<commit_msg>Code cleanup - remove unused code<commit_after>package nodeman

import (
	"errors"
	"fmt"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"sync"
	"syscall"
	"time"
)

type Client struct {
	mutex  *sync.Mutex
	runCmd *exec.Cmd
}

func New() *Client {
	return &Client{mutex: &sync.Mutex{}}
}

func (client *Client) Running() bool {
	return client.runCmd != nil
}

func (client *Client) Stop() (err error) {

	client.mutex.Lock()
	defer client.mutex.Unlock()

	if client.runCmd != nil {
		if err = client.runCmd.Process.Signal(syscall.SIGINT); err != nil {
			err = fmt.Errorf("nodeman: failed to send sigint. %s", err.Error())
		}
		waitOnStop(client.runCmd)
	} else {
		err = errors.New("nodeman: cannot stop as not running")
	}

	if err != nil {
		log.Println(err.Error())
	}
	client.runCmd = nil
	return err
}

func (client *Client) Start() (err error) {

	client.mutex.Lock()
	defer client.mutex.Unlock()

	if client.runCmd != nil {
		return errors.New("obnodeman: cannot start as already running")
	}
	if err = checkWorkingDir(); err != nil {
		log.Println(err.Error())
		return err
	}

	args := []string{
		"openbazaard.py",
		"start",
		"-a",
		"0.0.0.0",
	}

	if err = client.startCmd(exec.Command("python", args...)); err != nil {
		err = fmt.Errorf("nodeman: failed to start. %s", err.Error())
	}

	if err != nil {
		log.Println(err.Error())
	}
	return err
}

func waitOnStop(cmd *exec.Cmd) {
	done := make(chan error, 1)
	go func() {
		done <- cmd.Wait()
	}()
	select {
	case <-time.After(10 * time.Second):
		if err := cmd.Process.Kill(); err != nil {
			log.Printf("nodeman: attempted, but failed to kill ob process as it did not shut down within the alloted time. Error: %s", err.Error())
		} else {
			log.Println("nodeman: killed ob process as it did not shut down within the alloted time")
		}
	case err := <-done:
		if err != nil {
			log.Printf("nodeman: ob process exited with error = %v", err)
		} else {
			log.Println("nodeman: ob process exited gracefully")
		}
	}
}
func checkWorkingDir() error {
	workingDir, err := os.Getwd()
	if err != nil {
		return fmt.Errorf("nodeman: failed to read working dir: %s", err.Error())
	}
	filename := "openbazaard.py"
	fullname := filepath.Join(workingDir, filename)
	if _, err := os.Stat(fullname); os.IsNotExist(err) {
		return fmt.Errorf("nodeman: %s not found in working dir %s", filename, workingDir)
	}
	return nil
}

func (client *Client) startCmd(cmd *exec.Cmd) error {

	if err := cmd.Start(); err != nil {
		return err
	}
	client.runCmd = cmd
	return nil
}
<|endoftext|>