<commit_before>package repo_manager

import (
	"context"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/url"
	"path"
	"path/filepath"
	"strings"
	"testing"

	assert "github.com/stretchr/testify/require"
	"go.skia.org/infra/autoroll/go/strategy"
	"go.skia.org/infra/go/autoroll"
	"go.skia.org/infra/go/exec"
	git_testutils "go.skia.org/infra/go/git/testutils"
	"go.skia.org/infra/go/mockhttpclient"
	"go.skia.org/infra/go/recipe_cfg"
	"go.skia.org/infra/go/testutils"
)

const (
	afdoRevPrev = "chromeos-chrome-amd64-66.0.3336.3_rc-r0.afdo.bz2"
	afdoRevBase = "chromeos-chrome-amd64-66.0.3336.3_rc-r1.afdo.bz2"
	afdoRevNext = "chromeos-chrome-amd64-66.0.3337.3_rc-r1.afdo.bz2"

	afdoTimePrev = "2009-11-10T23:00:00Z"
	afdoTimeBase = "2009-11-10T23:01:00Z"
	afdoTimeNext = "2009-11-10T23:02:00Z"
)

func afdoCfg() *AFDORepoManagerConfig {
	return &AFDORepoManagerConfig{
		DepotToolsRepoManagerConfig: DepotToolsRepoManagerConfig{
			CommonRepoManagerConfig: CommonRepoManagerConfig{
				ChildBranch:  "master",
				ChildPath:    "unused/by/afdo/repomanager",
				ParentBranch: "master",
			},
		},
	}
}

func setupAfdo(t *testing.T) (context.Context, string, *git_testutils.GitBuilder, *exec.CommandCollector, *mockhttpclient.URLMock, func()) {
	wd, err := ioutil.TempDir("", "")
	assert.NoError(t, err)

	// Create child and parent repos.
	parent := git_testutils.GitInit(t, context.Background())
	parent.Add(context.Background(), AFDO_VERSION_FILE_PATH, afdoRevBase)
	parent.Commit(context.Background())

	mockRun := &exec.CommandCollector{}
	mockRun.SetDelegateRun(func(cmd *exec.Command) error {
		if cmd.Name == "git" && cmd.Args[0] == "cl" {
			if cmd.Args[1] == "upload" {
				return nil
			} else if cmd.Args[1] == "issue" {
				json := testutils.MarshalJSON(t, &issueJson{
					Issue:    issueNum,
					IssueUrl: "???",
				})
				f := strings.Split(cmd.Args[2], "=")[1]
				testutils.WriteFile(t, f, json)
				return nil
			}
		}
		return exec.DefaultRun(cmd)
	})
	ctx := exec.NewContext(context.Background(), mockRun.Run)
	urlmock := mockhttpclient.NewURLMock()

	cleanup := func() {
		testutils.RemoveAll(t, wd)
		parent.Cleanup()
	}

	return ctx, wd, parent, mockRun, urlmock, cleanup
}

type gsObject struct {
	Kind                    string `json:"kind"`
	Id                      string `json:"id"`
	SelfLink                string `json:"selfLink"`
	Name                    string `json:"name"`
	Bucket                  string `json:"bucket"`
	Generation              string `json:"generation"`
	Metageneration          string `json:"metageneration"`
	ContentType             string `json:"contentType"`
	TimeCreated             string `json:"timeCreated"`
	Updated                 string `json:"updated"`
	StorageClass            string `json:"storageClass"`
	TimeStorageClassUpdated string `json:"timeStorageClassUpdated"`
	Size                    string `json:"size"`
	Md5Hash                 string `json:"md5Hash"`
	MediaLink               string `json:"mediaLink"`
	Crc32c                  string `json:"crc32c"`
	Etag                    string `json:"etag"`
}

type gsObjectList struct {
	Kind  string     `json:"kind"`
	Items []gsObject `json:"items"`
}

func mockGSList(t *testing.T, urlmock *mockhttpclient.URLMock, bucket, path string, items map[string]string) {
	fakeUrl := fmt.Sprintf("https://www.googleapis.com/storage/v1/b/%s/o?alt=json&delimiter=&pageToken=&prefix=%s&projection=full&versions=false", bucket, url.PathEscape(path))
	resp := gsObjectList{
		Kind:  "storage#objects",
		Items: []gsObject{},
	}
	for item, timestamp := range items {
		resp.Items = append(resp.Items, gsObject{
			Kind:                    "storage#object",
			Id:                      bucket + path + item,
			SelfLink:                bucket + path + item,
			Name:                    item,
			Bucket:                  bucket,
			Generation:              "1",
			Metageneration:          "1",
			ContentType:             "application/octet-stream",
			TimeCreated:             timestamp,
			Updated:                 timestamp,
			StorageClass:            "MULTI_REGIONAL",
			TimeStorageClassUpdated: timestamp,
			Size:      "12345",
			Md5Hash:   "dsafkldkldsaf",
			MediaLink: fakeUrl + item,
			Crc32c:    "eiekls",
			Etag:      "lasdfklds",
		})
	}
	respBytes, err := json.MarshalIndent(resp, "", "  ")
	assert.NoError(t, err)
	urlmock.MockOnce(fakeUrl, mockhttpclient.MockGetDialogue(respBytes))
}

func TestAFDORepoManager(t *testing.T) {
	testutils.LargeTest(t)

	ctx, wd, parent, _, urlmock, cleanup := setupAfdo(t)
	defer cleanup()
	g := setupFakeGerrit(t, wd)
	recipesCfg := filepath.Join(testutils.GetRepoRoot(t), recipe_cfg.RECIPE_CFG_PATH)

	// Initial update, everything up-to-date.
	mockGSList(t, urlmock, strategy.AFDO_GS_BUCKET, strategy.AFDO_GS_PATH, map[string]string{
		afdoRevBase: afdoTimeBase,
	})
	cfg := afdoCfg()
	cfg.ParentRepo = parent.RepoUrl()
	rm, err := NewAFDORepoManager(ctx, cfg, wd, g, recipesCfg, "fake.server.com", urlmock.Client())
	assert.NoError(t, err)
	assert.NoError(t, SetStrategy(ctx, rm, strategy.ROLL_STRATEGY_AFDO))
	assert.NoError(t, rm.Update(ctx))
	assert.Equal(t, mockUser, rm.User())
	assert.Equal(t, afdoRevBase, rm.LastRollRev())
	assert.Equal(t, afdoRevBase, rm.NextRollRev())
	fch, err := rm.FullChildHash(ctx, rm.LastRollRev())
	assert.NoError(t, err)
	assert.Equal(t, fch, rm.LastRollRev())
	rolledPast, err := rm.RolledPast(ctx, afdoRevPrev)
	assert.NoError(t, err)
	assert.True(t, rolledPast)
	rolledPast, err = rm.RolledPast(ctx, afdoRevBase)
	assert.NoError(t, err)
	assert.True(t, rolledPast)
	rolledPast, err = rm.RolledPast(ctx, afdoRevNext)
	assert.NoError(t, err)
	assert.False(t, rolledPast)
	assert.Nil(t, rm.PreUploadSteps())
	assert.Equal(t, 0, rm.CommitsNotRolled())

	// There's a new version.
	mockGSList(t, urlmock, strategy.AFDO_GS_BUCKET, strategy.AFDO_GS_PATH, map[string]string{
		afdoRevBase: afdoTimeBase,
		afdoRevNext: afdoTimeNext,
	})
	assert.NoError(t, rm.Update(ctx))
	assert.Equal(t, afdoRevBase, rm.LastRollRev())
	assert.Equal(t, afdoRevNext, rm.NextRollRev())
	rolledPast, err = rm.RolledPast(ctx, afdoRevPrev)
	assert.NoError(t, err)
	assert.True(t, rolledPast)
	rolledPast, err = rm.RolledPast(ctx, afdoRevBase)
	assert.NoError(t, err)
	assert.True(t, rolledPast)
	rolledPast, err = rm.RolledPast(ctx, afdoRevNext)
	assert.NoError(t, err)
	assert.False(t, rolledPast)
	assert.Equal(t, 1, rm.CommitsNotRolled())

	// Upload a CL.
	issue, err := rm.CreateNewRoll(ctx, rm.LastRollRev(), rm.NextRollRev(), emails, cqExtraTrybots, false)
	assert.NoError(t, err)
	assert.Equal(t, issueNum, issue)
	msg, err := ioutil.ReadFile(path.Join(rm.(*afdoRepoManager).parentDir, ".git", "COMMIT_EDITMSG"))
	assert.NoError(t, err)
	from, to, err := autoroll.RollRev(strings.Split(string(msg), "\n")[0], func(h string) (string, error) {
		return rm.FullChildHash(ctx, h)
	})
	assert.NoError(t, err)
	assert.Equal(t, afdoRevBase, from)
	assert.Equal(t, afdoRevNext, to)
}

func TestChromiumAFDOConfigValidation(t *testing.T) {
	testutils.SmallTest(t)

	cfg := afdoCfg()
	cfg.ParentRepo = "dummy" // Not supplied above.
	assert.NoError(t, cfg.Validate())

	// The only fields come from the nested Configs, so exclude them and
	// verify that we fail validation.
	cfg = &AFDORepoManagerConfig{}
	assert.Error(t, cfg.Validate())
}
<commit_msg>[autoroll] Fix tests after upstream storage client change<commit_after>package repo_manager

import (
	"context"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/url"
	"path"
	"path/filepath"
	"strings"
	"testing"

	assert "github.com/stretchr/testify/require"
	"go.skia.org/infra/autoroll/go/strategy"
	"go.skia.org/infra/go/autoroll"
	"go.skia.org/infra/go/exec"
	git_testutils "go.skia.org/infra/go/git/testutils"
	"go.skia.org/infra/go/mockhttpclient"
	"go.skia.org/infra/go/recipe_cfg"
	"go.skia.org/infra/go/testutils"
)

const (
	afdoRevPrev = "chromeos-chrome-amd64-66.0.3336.3_rc-r0.afdo.bz2"
	afdoRevBase = "chromeos-chrome-amd64-66.0.3336.3_rc-r1.afdo.bz2"
	afdoRevNext = "chromeos-chrome-amd64-66.0.3337.3_rc-r1.afdo.bz2"

	afdoTimePrev = "2009-11-10T23:00:00Z"
	afdoTimeBase = "2009-11-10T23:01:00Z"
	afdoTimeNext = "2009-11-10T23:02:00Z"
)

func afdoCfg() *AFDORepoManagerConfig {
	return &AFDORepoManagerConfig{
		DepotToolsRepoManagerConfig: DepotToolsRepoManagerConfig{
			CommonRepoManagerConfig: CommonRepoManagerConfig{
				ChildBranch:  "master",
				ChildPath:    "unused/by/afdo/repomanager",
				ParentBranch: "master",
			},
		},
	}
}

func setupAfdo(t *testing.T) (context.Context, string, *git_testutils.GitBuilder, *exec.CommandCollector, *mockhttpclient.URLMock, func()) {
	wd, err := ioutil.TempDir("", "")
	assert.NoError(t, err)

	// Create child and parent repos.
	parent := git_testutils.GitInit(t, context.Background())
	parent.Add(context.Background(), AFDO_VERSION_FILE_PATH, afdoRevBase)
	parent.Commit(context.Background())

	mockRun := &exec.CommandCollector{}
	mockRun.SetDelegateRun(func(cmd *exec.Command) error {
		if cmd.Name == "git" && cmd.Args[0] == "cl" {
			if cmd.Args[1] == "upload" {
				return nil
			} else if cmd.Args[1] == "issue" {
				json := testutils.MarshalJSON(t, &issueJson{
					Issue:    issueNum,
					IssueUrl: "???",
				})
				f := strings.Split(cmd.Args[2], "=")[1]
				testutils.WriteFile(t, f, json)
				return nil
			}
		}
		return exec.DefaultRun(cmd)
	})
	ctx := exec.NewContext(context.Background(), mockRun.Run)
	urlmock := mockhttpclient.NewURLMock()

	cleanup := func() {
		testutils.RemoveAll(t, wd)
		parent.Cleanup()
	}

	return ctx, wd, parent, mockRun, urlmock, cleanup
}

type gsObject struct {
	Kind                    string `json:"kind"`
	Id                      string `json:"id"`
	SelfLink                string `json:"selfLink"`
	Name                    string `json:"name"`
	Bucket                  string `json:"bucket"`
	Generation              string `json:"generation"`
	Metageneration          string `json:"metageneration"`
	ContentType             string `json:"contentType"`
	TimeCreated             string `json:"timeCreated"`
	Updated                 string `json:"updated"`
	StorageClass            string `json:"storageClass"`
	TimeStorageClassUpdated string `json:"timeStorageClassUpdated"`
	Size                    string `json:"size"`
	Md5Hash                 string `json:"md5Hash"`
	MediaLink               string `json:"mediaLink"`
	Crc32c                  string `json:"crc32c"`
	Etag                    string `json:"etag"`
}

type gsObjectList struct {
	Kind  string     `json:"kind"`
	Items []gsObject `json:"items"`
}

func mockGSList(t *testing.T, urlmock *mockhttpclient.URLMock, bucket, path string, items map[string]string) {
	fakeUrl := fmt.Sprintf("https://www.googleapis.com/storage/v1/b/%s/o?alt=json&delimiter=&pageToken=&prefix=%s&prettyPrint=false&projection=full&versions=false", bucket, url.PathEscape(path))
	resp := gsObjectList{
		Kind:  "storage#objects",
		Items: []gsObject{},
	}
	for item, timestamp := range items {
		resp.Items = append(resp.Items, gsObject{
			Kind:                    "storage#object",
			Id:                      bucket + path + item,
			SelfLink:                bucket + path + item,
			Name:                    item,
			Bucket:                  bucket,
			Generation:              "1",
			Metageneration:          "1",
			ContentType:             "application/octet-stream",
			TimeCreated:             timestamp,
			Updated:                 timestamp,
			StorageClass:            "MULTI_REGIONAL",
			TimeStorageClassUpdated: timestamp,
			Size:      "12345",
			Md5Hash:   "dsafkldkldsaf",
			MediaLink: fakeUrl + item,
			Crc32c:    "eiekls",
			Etag:      "lasdfklds",
		})
	}
	respBytes, err := json.MarshalIndent(resp, "", "  ")
	assert.NoError(t, err)
	urlmock.MockOnce(fakeUrl, mockhttpclient.MockGetDialogue(respBytes))
}

func TestAFDORepoManager(t *testing.T) {
	testutils.LargeTest(t)

	ctx, wd, parent, _, urlmock, cleanup := setupAfdo(t)
	defer cleanup()
	g := setupFakeGerrit(t, wd)
	recipesCfg := filepath.Join(testutils.GetRepoRoot(t), recipe_cfg.RECIPE_CFG_PATH)

	// Initial update, everything up-to-date.
	mockGSList(t, urlmock, strategy.AFDO_GS_BUCKET, strategy.AFDO_GS_PATH, map[string]string{
		afdoRevBase: afdoTimeBase,
	})
	cfg := afdoCfg()
	cfg.ParentRepo = parent.RepoUrl()
	rm, err := NewAFDORepoManager(ctx, cfg, wd, g, recipesCfg, "fake.server.com", urlmock.Client())
	assert.NoError(t, err)
	assert.NoError(t, SetStrategy(ctx, rm, strategy.ROLL_STRATEGY_AFDO))
	assert.NoError(t, rm.Update(ctx))
	assert.Equal(t, mockUser, rm.User())
	assert.Equal(t, afdoRevBase, rm.LastRollRev())
	assert.Equal(t, afdoRevBase, rm.NextRollRev())
	fch, err := rm.FullChildHash(ctx, rm.LastRollRev())
	assert.NoError(t, err)
	assert.Equal(t, fch, rm.LastRollRev())
	rolledPast, err := rm.RolledPast(ctx, afdoRevPrev)
	assert.NoError(t, err)
	assert.True(t, rolledPast)
	rolledPast, err = rm.RolledPast(ctx, afdoRevBase)
	assert.NoError(t, err)
	assert.True(t, rolledPast)
	rolledPast, err = rm.RolledPast(ctx, afdoRevNext)
	assert.NoError(t, err)
	assert.False(t, rolledPast)
	assert.Nil(t, rm.PreUploadSteps())
	assert.Equal(t, 0, rm.CommitsNotRolled())

	// There's a new version.
	mockGSList(t, urlmock, strategy.AFDO_GS_BUCKET, strategy.AFDO_GS_PATH, map[string]string{
		afdoRevBase: afdoTimeBase,
		afdoRevNext: afdoTimeNext,
	})
	assert.NoError(t, rm.Update(ctx))
	assert.Equal(t, afdoRevBase, rm.LastRollRev())
	assert.Equal(t, afdoRevNext, rm.NextRollRev())
	rolledPast, err = rm.RolledPast(ctx, afdoRevPrev)
	assert.NoError(t, err)
	assert.True(t, rolledPast)
	rolledPast, err = rm.RolledPast(ctx, afdoRevBase)
	assert.NoError(t, err)
	assert.True(t, rolledPast)
	rolledPast, err = rm.RolledPast(ctx, afdoRevNext)
	assert.NoError(t, err)
	assert.False(t, rolledPast)
	assert.Equal(t, 1, rm.CommitsNotRolled())

	// Upload a CL.
	issue, err := rm.CreateNewRoll(ctx, rm.LastRollRev(), rm.NextRollRev(), emails, cqExtraTrybots, false)
	assert.NoError(t, err)
	assert.Equal(t, issueNum, issue)
	msg, err := ioutil.ReadFile(path.Join(rm.(*afdoRepoManager).parentDir, ".git", "COMMIT_EDITMSG"))
	assert.NoError(t, err)
	from, to, err := autoroll.RollRev(strings.Split(string(msg), "\n")[0], func(h string) (string, error) {
		return rm.FullChildHash(ctx, h)
	})
	assert.NoError(t, err)
	assert.Equal(t, afdoRevBase, from)
	assert.Equal(t, afdoRevNext, to)
}

func TestChromiumAFDOConfigValidation(t *testing.T) {
	testutils.SmallTest(t)

	cfg := afdoCfg()
	cfg.ParentRepo = "dummy" // Not supplied above.
	assert.NoError(t, cfg.Validate())

	// The only fields come from the nested Configs, so exclude them and
	// verify that we fail validation.
	cfg = &AFDORepoManagerConfig{}
	assert.Error(t, cfg.Validate())
}
<|endoftext|>


<commit_before>package grafana

import (
	"regexp"
	"strings"

	"encoding/json"

	cmodel "github.com/Cepave/open-falcon-backend/common/model"
	"github.com/Cepave/open-falcon-backend/modules/query/gin_http/computeFunc"
	"github.com/Cepave/open-falcon-backend/modules/query/gin_http/openFalcon"
	"github.com/Cepave/open-falcon-backend/modules/query/model"
	"github.com/Jeffail/gabs"
	log "github.com/Sirupsen/logrus"
	"github.com/emirpasic/gods/sets/hashset"
	"github.com/gin-gonic/gin"
	"github.com/robertkrimen/otto"
	_ "github.com/robertkrimen/otto/underscore"
)

type GrafanaResp struct {
	Expandable bool   `json:"expandable"`
	Text       string `json:"text"`
}

func ResultGen(alist []string) (result []GrafanaResp) {
	result = []GrafanaResp{}
	for _, enp := range alist {
		result = append(result, GrafanaResp{true, enp})
	}
	return
}

func parseTager(query string) (endpoints []string, counter string, ldfunction string) {
	log.Debugf("got query string: %s ", query)
	parseRgex := "^([^#]+)#(.+)"
	if strings.Contains(query, "@owl@") {
		parseRgex = "^([^#]+)#(.+)@owl@(.+)"
	}
	r := regexp.MustCompile(parseRgex)
	matched := r.FindStringSubmatch(query)
	endpointstr := matched[1]
	counter = matched[2]
	ldfunction = "null"
	if len(matched) > 3 {
		ldfunction = matched[3]
	}
	repx := regexp.MustCompile("(^{|}$)")
	endpointstr = repx.ReplaceAllString(endpointstr, "")
	endpoints = strings.Split(endpointstr, ",")
	log.Debugf("counter: %s, endpoints: %v, ldfunction: %v", counter, endpoints, ldfunction)
	return
}

func GrafanaMain(c *gin.Context) {
	query := c.DefaultQuery("query", ".+")
	log.Debugf("got query string: %s, find keyword? %v", query, strings.Contains(query, "#"))
	if strings.Contains(query, "#") {
		endpoints, counter, _ := parseTager(query)
		endpid := model.EndpointIdQuery(endpoints)
		if len(endpid) == 0 {
			c.JSON(300, gin.H{"error": "can not find any endpoint id, please check your database."})
		}
		catchAll := false
		if strings.Contains(counter, "%") {
			catchAll = true
		}
		counter = strings.Replace(counter, ".*", "%", 1)
		counter = strings.Replace(counter, "#", ".", -1)
		counters := model.FindMatchedCounters(endpid, counter)
		result := []GrafanaResp{}
		perfix := strings.Replace(counter, "%", "", 1)
		tset := hashset.New()
		if perfix == "" {
			for _, c := range counters {
				keys := strings.Split(c, ".")
				if !tset.Contains(keys[0]) {
					expandable := true
					if len(keys) == 0 {
						expandable = false
					}
					result = append(result, GrafanaResp{
						expandable,
						keys[0],
					})
					tset.Add(keys[0])
				}
			}
		} else if catchAll {
			result = []GrafanaResp{GrafanaResp{false, "renderAll"}}
		} else {
			for _, c := range counters {
				skey := strings.Replace(c, perfix, "", 1)
				if skey == "" {
					result = append(result, GrafanaResp{false, c})
				} else {
					keys := strings.Split(skey, ".")
					if !tset.Contains(keys[0]) {
						expandable := true
						if len(keys) == 0 {
							expandable = false
						}
						result = append(result, GrafanaResp{expandable, keys[0]})
						tset.Add(keys[0])
					}
				}
			}
		}
		c.JSON(200, result)
		return
	}
	endpoints := model.EndpointQuery(query)
	var resp []GrafanaResp
	resp = ResultGen(endpoints)
	c.JSON(200, resp)
	return
}

//{"function":"sumAll","aliasName":"sumAll"}
func parseFunc(funjs string) (string, map[string]string) {
	parsedjson, err := gabs.ParseJSON([]byte(funjs))
	if err != nil {
		log.Errorf("during parse UDF got error with -> %s", err.Error())
	}
	funName := parsedjson.Search("function").Data().(string)
	c := computeFunc.GetFuncSetup(funName)
	gotKey := map[string]string{}
	for _, pa := range c.Params {
		pramArr := strings.Split(pa, ":")
		pname := pramArr[0]
		// ptype := pramArr[1]
		if parsedjson.Exists(pname) {
			gotKey[pname] = parsedjson.Search(pname).Data().(string)
		}
	}
	log.Debugf("got http map: %v, funName: %s", gotKey, funName)
	return funName, gotKey
}

type GrafanaPostPrams struct {
	Format        string   `form:"format" json:"format"`
	From          int64    `form:"from" json:"from"`
	MaxDataPoints int      `form:"maxDataPoints" json:"maxDataPoints"`
	Targets       []string `form:"targets" json:"targets"`
	Until         int64    `form:"until" json:"until"`
}

func GetQueryTargets(c *gin.Context) {
	// x := []string{"target", "from", "until", "format", "maxDataPoints", "ldfunction"}
	// for _, s := range x {
	// 	log.Debugf("params: %v", c.DefaultPostForm(s, "null"))
	// }
	var params GrafanaPostPrams
	err := c.Bind(&params)
	if err != nil {
		log.Error(err.Error())
	}
	mtarget := params.Targets
	var resResp []*cmodel.GraphQueryResponse
	for _, target := range mtarget {
		endpoints, counter, ldfunction := parseTager(target)
		endpid := model.EndpointIdQuery(endpoints)
		log.Debugf("got endpoints : %d itmes", len(endpid))
		counter = strings.Replace(counter, ".*", "%", 1)
		counter = strings.Replace(counter, "#", ".", -1)
		counters := model.FindMatchedCounters(endpid, counter)
		startTs := params.From
		endTs := params.Until
		result := []*cmodel.GraphQueryResponse{}
		log.Debugf("got counter : %d itmes", len(counters))
		for _, c := range counters {
			rrds := openFalcon.QueryOnce(startTs, endTs, "AVERAGE", 60, c, endpoints)
			if len(rrds) != 0 {
				for _, s := range rrds {
					result = append(result, s)
				}
			}
		}
		// ldfunction := c.DefaultPostForm("ldfunction", "null")
		if ldfunction == "null" || len(result) == 0 {
			for _, rs := range result {
				resResp = append(resResp, rs)
			}
		} else {
			vm := otto.New()
			funcName, tmpparams := parseFunc(ldfunction)
			funcInstance := computeFunc.GetFuncSetup(funcName)
			err := vm.Set("input", result)
			if err != nil {
				log.Debug(err.Error)
			}
			vm = computeFunc.SetParamsToJSVM(tmpparams, funcInstance.Params, vm)
			vm.Run(funcInstance.Codes)
			output, err := vm.Get("output")
			if err != nil {
				log.Error(err.Error())
				c.JSON(400, gin.H{
					"msg": err.Error(),
				})
				return
			}
			var res []*cmodel.GraphQueryResponse
			json.Unmarshal([]byte(output.String()), &res)
			for _, rs := range res {
				resResp = append(resResp, rs)
			}
			log.Debugf("outputStr: %v", output.String())
		}
	}
	c.JSON(200, resResp)
	return
}
<commit_msg>changed separate string<commit_after>package grafana

import (
	"regexp"
	"strings"

	"encoding/json"

	cmodel "github.com/Cepave/open-falcon-backend/common/model"
	"github.com/Cepave/open-falcon-backend/modules/query/gin_http/computeFunc"
	"github.com/Cepave/open-falcon-backend/modules/query/gin_http/openFalcon"
	"github.com/Cepave/open-falcon-backend/modules/query/model"
	"github.com/Jeffail/gabs"
	log "github.com/Sirupsen/logrus"
	"github.com/emirpasic/gods/sets/hashset"
	"github.com/gin-gonic/gin"
	"github.com/robertkrimen/otto"
	_ "github.com/robertkrimen/otto/underscore"
)

type GrafanaResp struct {
	Expandable bool   `json:"expandable"`
	Text       string `json:"text"`
}

func ResultGen(alist []string) (result []GrafanaResp) {
	result = []GrafanaResp{}
	for _, enp := range alist {
		result = append(result, GrafanaResp{true, enp})
	}
	return
}

func parseTager(query string) (endpoints []string, counter string, ldfunction string) {
	log.Debugf("got query string: %s ", query)
	parseRgex := "^([^#]+)#(.+)"
	if strings.Contains(query, "#{") {
		parseRgex = "^([^#]+)#(.+)#({.+)"
	}
	r := regexp.MustCompile(parseRgex)
	matched := r.FindStringSubmatch(query)
	endpointstr := matched[1]
	counter = matched[2]
	ldfunction = "null"
	if len(matched) > 3 {
		ldfunction = matched[3]
	}
	repx := regexp.MustCompile("(^{|}$)")
	endpointstr = repx.ReplaceAllString(endpointstr, "")
	endpoints = strings.Split(endpointstr, ",")
	log.Debugf("counter: %s, endpoints: %v, ldfunction: %v", counter, endpoints, ldfunction)
	return
}

func GrafanaMain(c *gin.Context) {
	query := c.DefaultQuery("query", ".+")
	log.Debugf("got query string: %s, find keyword? %v", query, strings.Contains(query, "#"))
	if strings.Contains(query, "#") {
		endpoints, counter, _ := parseTager(query)
		endpid := model.EndpointIdQuery(endpoints)
		if len(endpid) == 0 {
			c.JSON(300, gin.H{"error": "can not find any endpoint id, please check your database."})
		}
		catchAll := false
		if strings.Contains(counter, "%") {
			catchAll = true
		}
		counter = strings.Replace(counter, ".*", "%", 1)
		counter = strings.Replace(counter, "#", ".", -1)
		counters := model.FindMatchedCounters(endpid, counter)
		result := []GrafanaResp{}
		perfix := strings.Replace(counter, "%", "", 1)
		tset := hashset.New()
		if perfix == "" {
			for _, c := range counters {
				keys := strings.Split(c, ".")
				if !tset.Contains(keys[0]) {
					expandable := true
					if len(keys) == 0 {
						expandable = false
					}
					result = append(result, GrafanaResp{
						expandable,
						keys[0],
					})
					tset.Add(keys[0])
				}
			}
		} else if catchAll {
			result = []GrafanaResp{GrafanaResp{false, "renderAll"}}
		} else {
			for _, c := range counters {
				skey := strings.Replace(c, perfix, "", 1)
				if skey == "" {
					result = append(result, GrafanaResp{false, c})
				} else {
					keys := strings.Split(skey, ".")
					if !tset.Contains(keys[0]) {
						expandable := true
						if len(keys) == 0 {
							expandable = false
						}
						result = append(result, GrafanaResp{expandable, keys[0]})
						tset.Add(keys[0])
					}
				}
			}
		}
		c.JSON(200, result)
		return
	}
	endpoints := model.EndpointQuery(query)
	var resp []GrafanaResp
	resp = ResultGen(endpoints)
	c.JSON(200, resp)
	return
}

//{"function":"sumAll","aliasName":"sumAll"}
func parseFunc(funjs string) (string, map[string]string) {
	parsedjson, err := gabs.ParseJSON([]byte(funjs))
	if err != nil {
		log.Errorf("during parse UDF got error with -> %s", err.Error())
	}
	funName := parsedjson.Search("function").Data().(string)
	c := computeFunc.GetFuncSetup(funName)
	gotKey := map[string]string{}
	for _, pa := range c.Params {
		pramArr := strings.Split(pa, ":")
		pname := pramArr[0]
		// ptype := pramArr[1]
		if parsedjson.Exists(pname) {
			gotKey[pname] = parsedjson.Search(pname).Data().(string)
		}
	}
	log.Debugf("got http map: %v, funName: %s", gotKey, funName)
	return funName, gotKey
}

type GrafanaPostPrams struct {
	Format        string   `form:"format" json:"format"`
	From          int64    `form:"from" json:"from"`
	MaxDataPoints int      `form:"maxDataPoints" json:"maxDataPoints"`
	Targets       []string `form:"targets" json:"targets"`
	Until         int64    `form:"until" json:"until"`
}

func GetQueryTargets(c *gin.Context) {
	// x := []string{"target", "from", "until", "format", "maxDataPoints", "ldfunction"}
	// for _, s := range x {
	// 	log.Debugf("params: %v", c.DefaultPostForm(s, "null"))
	// }
	var params GrafanaPostPrams
	err := c.Bind(&params)
	if err != nil {
		log.Error(err.Error())
	}
	mtarget := params.Targets
	var resResp []*cmodel.GraphQueryResponse
	for _, target := range mtarget {
		endpoints, counter, ldfunction := parseTager(target)
		endpid := model.EndpointIdQuery(endpoints)
		log.Debugf("got endpoints : %d itmes", len(endpid))
		counter = strings.Replace(counter, ".*", "%", 1)
		counter = strings.Replace(counter, "#", ".", -1)
		counters := model.FindMatchedCounters(endpid, counter)
		startTs := params.From
		endTs := params.Until
		result := []*cmodel.GraphQueryResponse{}
		log.Debugf("got counter : %d itmes", len(counters))
		for _, c := range counters {
			rrds := openFalcon.QueryOnce(startTs, endTs, "AVERAGE", 60, c, endpoints)
			if len(rrds) != 0 {
				for _, s := range rrds {
					result = append(result, s)
				}
			}
		}
		// ldfunction := c.DefaultPostForm("ldfunction", "null")
		if ldfunction == "null" || len(result) == 0 {
			for _, rs := range result {
				resResp = append(resResp, rs)
			}
		} else {
			vm := otto.New()
			funcName, tmpparams := parseFunc(ldfunction)
			funcInstance := computeFunc.GetFuncSetup(funcName)
			err := vm.Set("input", result)
			if err != nil {
				log.Debug(err.Error)
			}
			vm = computeFunc.SetParamsToJSVM(tmpparams, funcInstance.Params, vm)
			vm.Run(funcInstance.Codes)
			output, err := vm.Get("output")
			if err != nil {
				log.Error(err.Error())
				c.JSON(400, gin.H{
					"msg": err.Error(),
				})
				return
			}
			var res []*cmodel.GraphQueryResponse
			json.Unmarshal([]byte(output.String()), &res)
			for _, rs := range res {
				resResp = append(resResp, rs)
			}
			log.Debugf("outputStr: %v", output.String())
		}
	}
	c.JSON(200, resResp)
	return
}
<|endoftext|>


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

package constants

// Version number string.
const Version = "0.1.1"
<commit_msg>Version 0.2.0<commit_after>// +-------------------------------------------------------------------------
// | Copyright (C) 2016 Yunify, Inc.
// +-------------------------------------------------------------------------
// | Licensed under the Apache License, Version 2.0 (the "License");
// | you may not use this work except in compliance with the License.
// | You may obtain a copy of the License in the LICENSE file, or at:
// |
// | http://www.apache.org/licenses/LICENSE-2.0
// |
// | Unless required by applicable law or agreed to in writing, software
// | distributed under the License is distributed on an "AS IS" BASIS,
// | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// | See the License for the specific language governing permissions and
// | limitations under the License.
// +-------------------------------------------------------------------------

package constants

// Version number string.
const Version = "0.2.0"
<|endoftext|>


<commit_before>package btrfs

import (
	"bufio"
	"errors"
	"fmt"
	"os"
	"os/exec"
	"path"
	"strings"
	"syscall"
)

type FsMagic uint64

const (
	FsMagicBtrfs = FsMagic(0x9123683E)
)

var (
	ErrPrerequisites = errors.New("prerequisites for driver not satisfied (wrong filesystem?)")
)

func Init(home string) (*Driver, error) {
	rootdir := path.Dir(home + "/")

	var buf syscall.Statfs_t
	if err := syscall.Statfs(rootdir, &buf); err != nil {
		return nil, err
	}

	if FsMagic(buf.Type) != FsMagicBtrfs {
		return nil, ErrPrerequisites
	}

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

	return &Driver{
		home: home,
	}, nil
}

type Driver struct {
	home string
}

func (d *Driver) Snapshot(from, to string, readonly bool) error {
	fromPath := fmt.Sprintf("%s/%s", d.home, from)
	toPath := fmt.Sprintf("%s/%s", d.home, to)

	if !d.Exists(from) {
		return fmt.Errorf("Volume does not exist: %s", fromPath)
	}
	if d.Exists(to) {
		return fmt.Errorf("Snapshot already exists: %s", toPath)
	}

	var cmd *exec.Cmd

	if readonly {
		cmd = raw("subvolume", "snapshot", "-r", fromPath, toPath)
	} else {
		cmd = raw("subvolume", "snapshot", fromPath, toPath)
	}
	if err := cmd.Run(); err != nil {
		return err
	}

	// create recursive snapshots.
	subvolumes, err := d.ListSubSubvolumes(from)
	if err != nil {
		return err
	}

	for _, subvol := range subvolumes {
		subvolFrom := fmt.Sprintf("%s/%s", from, subvol)
		subvolTo := fmt.Sprintf("%s/%s", to, subvol)

		// delete empty directory
		if d.Exists(subvolTo) {
			if err := os.Remove(fmt.Sprintf("%s/%s", d.home, subvolTo)); err != nil {
				return err
			}
		}

		err = d.Snapshot(subvolFrom, subvolTo, readonly)
		if err != nil {
			return err
		}
	}
	return nil
}

func (d *Driver) Subvolume(vol string) error {
	volPath := fmt.Sprintf("%s/%s", d.home, vol)
	if _, err := os.Stat(volPath); err == nil {
		return fmt.Errorf("Subvolume already exists: %s", volPath)
	}

	return raw("subvolume", "create", volPath).Run()
}

func (d *Driver) Exists(vol string) bool {
	volPath := fmt.Sprintf("%s/%s", d.home, vol)
	_, err := os.Stat(volPath)
	if err == nil {
		return true
	} else {
		// check os.IsNotExist(err) ?
		return false
	}
}

func (d *Driver) GetSubvolumeDetail(vol, detail string) (string, error) {
	volPath := fmt.Sprintf("%s/%s", d.home, vol)

	o, _ := raw("subvolume", "show", volPath).Output()

	output := string(o)
	lines := strings.Split(output, "\n")

	for _, line := range lines {
		fields := strings.Split(line, ":")
		if len(fields) > 1 {
			key, val := strings.Trim(fields[0], " \t"), strings.Trim(fields[1], " \t")
			if strings.EqualFold(key, detail) {
				return val, nil
			}
		}
	}
	return "", fmt.Errorf("Subvolume detail %s not found", detail)
}

func (d *Driver) GetSubvolumeParentUuid(vol string) (string, error) {
	return d.GetSubvolumeDetail(vol, "Parent uuid")

}

func (d *Driver) GetSubvolumeUuid(vol string) (string, error) {
	return d.GetSubvolumeDetail(vol, "uuid")
}

func (d *Driver) ListSubvolumes() ([]string, error) {
	var volumes []string

	// find sub-subvolumes
	cmd := raw("subvolume", "list", "-o", d.home, "-u")

	output, err := cmd.StdoutPipe()
	if err != nil {
		return volumes, fmt.Errorf("Can't access subvolume list of %s: %v", d.home, err)
	}
	defer output.Close()
	err = cmd.Start()
	if err != nil {
		return volumes, err
	}

	scanner := bufio.NewScanner(output)
	for scanner.Scan() {
		line := scanner.Text()
		if strings.Contains(line, "__active") {
			line = strings.Replace(line, "__active/", "", 1)
		}
		volumes = append(volumes, line)
	}
	return volumes, nil
}

func (d *Driver) GetLayerByUuid(uuid string) (string, error) {
	layers, err := d.ListSubvolumes()
	if err != nil {
		return "", err
	}

	replaceHome := strings.Replace(d.home, "/", "", 1) + "/"
	for _, layer := range layers {
		if strings.Contains(layer, fmt.Sprintf(" uuid %s ", uuid)) {
			layerDetails := strings.Split(layer, " ")
			if len(layerDetails) > 10 {
				return strings.Replace(layerDetails[10], replaceHome, "", 1), nil
			}
		}
	}
	return "", fmt.Errorf("No layer found")
}

func (d *Driver) ListSubSubvolumes(vol string) ([]string, error) {
	var volumes []string

	volPath := fmt.Sprintf("%s/%s", d.home, vol)

	if !d.Exists(vol) {
		return volumes, fmt.Errorf("Volume does not exist: %s", volPath)
	}

	// find sub-subvolumes
	cmd := raw("subvolume", "list", "-o", volPath)

	output, err := cmd.StdoutPipe()
	if err != nil {
		return volumes, fmt.Errorf("Can't access subvolume list of %s: %v", volPath, err)
	}
	defer output.Close()
	err = cmd.Start()
	if err != nil {
		return volumes, err
	}

	scanner := bufio.NewScanner(output)
	for scanner.Scan() {
		line := strings.Split(scanner.Text(), " ")
		if len(line) > 8 {
			subvol := strings.Join(line[8:], " ")
			// remove beginning of volume path - relative to conair home
			if strings.Contains(subvol, "__active") {
				subvol = strings.Replace(subvol, "__active/", "", 1)
			}

			if strings.HasPrefix(subvol, volPath) {
				volumes = append(volumes, strings.Replace(subvol, fmt.Sprintf("%s/", strings.Replace(volPath, "/", "", 1)), "", 1))
			}

			if strings.HasPrefix(subvol, vol) {
				volumes = append(volumes, strings.Replace(subvol, fmt.Sprintf("%s/", vol), "", 1))
			}
		}
	}
	err = scanner.Err()
	if err != nil {
		return volumes, fmt.Errorf("Can't read subvolume list of %s: %v", volPath, err)
	}
	return volumes, nil
}

func (d *Driver) Remove(vol string) error {
	volPath := fmt.Sprintf("%s/%s", d.home, vol)

	if !d.Exists(vol) {
		return fmt.Errorf("Volume does not exist: %s", volPath)
	}

	subvolumes, err := d.ListSubSubvolumes(vol)
	if err != nil {
		return err
	}

	for _, subvol := range subvolumes {
		if err := d.Remove(fmt.Sprintf("%s/%s", vol, subvol)); err != nil {
			return err
		}
	}

	return raw("subvolume", "delete", volPath).Run()
}

func raw(args ...string) *exec.Cmd {
	return exec.Command("btrfs", args...)
}
<commit_msg>fix 32-bit (raspberrypi) btrfs check<commit_after>package btrfs

import (
	"bufio"
	"errors"
	"fmt"
	"os"
	"os/exec"
	"path"
	"strings"
	"syscall"
)

type FsMagic int64

const (
	FsMagicBtrfs      = FsMagic(0x9123683E)
	FsMagicBtrfs32Bit = FsMagic(-1859950530)
)

var (
	ErrPrerequisites = errors.New("prerequisites for driver not satisfied (wrong filesystem?)")
)

func Init(home string) (*Driver, error) {
	rootdir := path.Dir(home + "/")

	var buf syscall.Statfs_t
	if err := syscall.Statfs(rootdir, &buf); err != nil {
		return nil, err
	}

	if !(FsMagic(buf.Type) == FsMagicBtrfs || FsMagic(buf.Type) == FsMagicBtrfs32Bit) {
		return nil, ErrPrerequisites
	}

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

	return &Driver{
		home: home,
	}, nil
}

type Driver struct {
	home string
}

func (d *Driver) Snapshot(from, to string, readonly bool) error {
	fromPath := fmt.Sprintf("%s/%s", d.home, from)
	toPath := fmt.Sprintf("%s/%s", d.home, to)

	if !d.Exists(from) {
		return fmt.Errorf("Volume does not exist: %s", fromPath)
	}
	if d.Exists(to) {
		return fmt.Errorf("Snapshot already exists: %s", toPath)
	}

	var cmd *exec.Cmd

	if readonly {
		cmd = raw("subvolume", "snapshot", "-r", fromPath, toPath)
	} else {
		cmd = raw("subvolume", "snapshot", fromPath, toPath)
	}
	if err := cmd.Run(); err != nil {
		return err
	}

	// create recursive snapshots.
	subvolumes, err := d.ListSubSubvolumes(from)
	if err != nil {
		return err
	}

	for _, subvol := range subvolumes {
		subvolFrom := fmt.Sprintf("%s/%s", from, subvol)
		subvolTo := fmt.Sprintf("%s/%s", to, subvol)

		// delete empty directory
		if d.Exists(subvolTo) {
			if err := os.Remove(fmt.Sprintf("%s/%s", d.home, subvolTo)); err != nil {
				return err
			}
		}

		err = d.Snapshot(subvolFrom, subvolTo, readonly)
		if err != nil {
			return err
		}
	}
	return nil
}

func (d *Driver) Subvolume(vol string) error {
	volPath := fmt.Sprintf("%s/%s", d.home, vol)
	if _, err := os.Stat(volPath); err == nil {
		return fmt.Errorf("Subvolume already exists: %s", volPath)
	}

	return raw("subvolume", "create", volPath).Run()
}

func (d *Driver) Exists(vol string) bool {
	volPath := fmt.Sprintf("%s/%s", d.home, vol)
	_, err := os.Stat(volPath)
	if err == nil {
		return true
	} else {
		// check os.IsNotExist(err) ?
		return false
	}
}

func (d *Driver) GetSubvolumeDetail(vol, detail string) (string, error) {
	volPath := fmt.Sprintf("%s/%s", d.home, vol)

	o, _ := raw("subvolume", "show", volPath).Output()

	output := string(o)
	lines := strings.Split(output, "\n")

	for _, line := range lines {
		fields := strings.Split(line, ":")
		if len(fields) > 1 {
			key, val := strings.Trim(fields[0], " \t"), strings.Trim(fields[1], " \t")
			if strings.EqualFold(key, detail) {
				return val, nil
			}
		}
	}
	return "", fmt.Errorf("Subvolume detail %s not found", detail)
}

func (d *Driver) GetSubvolumeParentUuid(vol string) (string, error) {
	return d.GetSubvolumeDetail(vol, "Parent uuid")

}

func (d *Driver) GetSubvolumeUuid(vol string) (string, error) {
	return d.GetSubvolumeDetail(vol, "uuid")
}

func (d *Driver) ListSubvolumes() ([]string, error) {
	var volumes []string

	// find sub-subvolumes
	cmd := raw("subvolume", "list", "-o", d.home, "-u")

	output, err := cmd.StdoutPipe()
	if err != nil {
		return volumes, fmt.Errorf("Can't access subvolume list of %s: %v", d.home, err)
	}
	defer output.Close()
	err = cmd.Start()
	if err != nil {
		return volumes, err
	}

	scanner := bufio.NewScanner(output)
	for scanner.Scan() {
		line := scanner.Text()
		if strings.Contains(line, "__active") {
			line = strings.Replace(line, "__active/", "", 1)
		}
		volumes = append(volumes, line)
	}
	return volumes, nil
}

func (d *Driver) GetLayerByUuid(uuid string) (string, error) {
	layers, err := d.ListSubvolumes()
	if err != nil {
		return "", err
	}

	replaceHome := strings.Replace(d.home, "/", "", 1) + "/"
	for _, layer := range layers {
		if strings.Contains(layer, fmt.Sprintf(" uuid %s ", uuid)) {
			layerDetails := strings.Split(layer, " ")
			if len(layerDetails) > 10 {
				return strings.Replace(layerDetails[10], replaceHome, "", 1), nil
			}
		}
	}
	return "", fmt.Errorf("No layer found")
}

func (d *Driver) ListSubSubvolumes(vol string) ([]string, error) {
	var volumes []string

	volPath := fmt.Sprintf("%s/%s", d.home, vol)

	if !d.Exists(vol) {
		return volumes, fmt.Errorf("Volume does not exist: %s", volPath)
	}

	// find sub-subvolumes
	cmd := raw("subvolume", "list", "-o", volPath)

	output, err := cmd.StdoutPipe()
	if err != nil {
		return volumes, fmt.Errorf("Can't access subvolume list of %s: %v", volPath, err)
	}
	defer output.Close()
	err = cmd.Start()
	if err != nil {
		return volumes, err
	}

	scanner := bufio.NewScanner(output)
	for scanner.Scan() {
		line := strings.Split(scanner.Text(), " ")
		if len(line) > 8 {
			subvol := strings.Join(line[8:], " ")
			// remove beginning of volume path - relative to conair home
			if strings.Contains(subvol, "__active") {
				subvol = strings.Replace(subvol, "__active/", "", 1)
			}

			if strings.HasPrefix(subvol, volPath) {
				volumes = append(volumes, strings.Replace(subvol, fmt.Sprintf("%s/", strings.Replace(volPath, "/", "", 1)), "", 1))
			}

			if strings.HasPrefix(subvol, vol) {
				volumes = append(volumes, strings.Replace(subvol, fmt.Sprintf("%s/", vol), "", 1))
			}
		}
	}
	err = scanner.Err()
	if err != nil {
		return volumes, fmt.Errorf("Can't read subvolume list of %s: %v", volPath, err)
	}
	return volumes, nil
}

func (d *Driver) Remove(vol string) error {
	volPath := fmt.Sprintf("%s/%s", d.home, vol)

	if !d.Exists(vol) {
		return fmt.Errorf("Volume does not exist: %s", volPath)
	}

	subvolumes, err := d.ListSubSubvolumes(vol)
	if err != nil {
		return err
	}

	for _, subvol := range subvolumes {
		if err := d.Remove(fmt.Sprintf("%s/%s", vol, subvol)); err != nil {
			return err
		}
	}

	return raw("subvolume", "delete", volPath).Run()
}

func raw(args ...string) *exec.Cmd {
	return exec.Command("btrfs", args...)
}
<|endoftext|>


<commit_before>package echo

import (
	"io"
	"mime/multipart"
	"os"
	"path/filepath"
	"strconv"
	"strings"

	"github.com/webx-top/echo/engine"
	"github.com/webx-top/echo/param"
)

// Request returns *http.Request.
func (c *xContext) Request() engine.Request {
	return c.request
}

// Path returns the registered path for the handler.
func (c *xContext) Path() string {
	return c.path
}

// P returns path parameter by index.
func (c *xContext) P(i int, defaults ...string) (value string) {
	l := len(c.pnames)
	if i < l {
		value = c.pvalues[i]
	}
	if len(value) == 0 && len(defaults) > 0 {
		return defaults[0]
	}
	return
}

func (c *xContext) Px(n int, defaults ...string) param.String {
	return param.String(c.P(n, defaults...))
}

// Param returns path parameter by name.
func (c *xContext) Param(name string, defaults ...string) (value string) {
	l := len(c.pnames)
	for i, n := range c.pnames {
		if n == name && i < l {
			value = c.pvalues[i]
			break
		}
	}

	if len(value) == 0 && len(defaults) > 0 {
		return defaults[0]
	}
	return
}

func (c *xContext) Paramx(name string, defaults ...string) param.String {
	return param.String(c.Param(name, defaults...))
}

func (c *xContext) ParamNames() []string {
	return c.pnames
}

func (c *xContext) ParamValues() []string {
	return c.pvalues
}

func (c *xContext) SetParamValues(values ...string) {
	c.pvalues = values
}

// Query returns query parameter by name.
func (c *xContext) Query(name string, defaults ...string) (value string) {
	value = c.request.URL().QueryValue(name)
	if len(value) == 0 && len(defaults) > 0 {
		return defaults[0]
	}
	return
}

func (c *xContext) Queryx(name string, defaults ...string) param.String {
	return param.String(c.Query(name, defaults...))
}

func (c *xContext) QueryValues(name string) []string {
	return c.request.URL().QueryValues(name)
}

func (c *xContext) QueryxValues(name string) param.StringSlice {
	return param.StringSlice(c.request.URL().QueryValues(name))
}

func (c *xContext) Queries() map[string][]string {
	return c.request.URL().Query()
}

// Form returns form parameter by name.
func (c *xContext) Form(name string, defaults ...string) (value string) {
	value = c.request.FormValue(name)
	if len(value) == 0 && len(defaults) > 0 {
		return defaults[0]
	}
	return
}

func (c *xContext) Formx(name string, defaults ...string) param.String {
	return param.String(c.Form(name, defaults...))
}

func (c *xContext) FormValues(name string) []string {
	return c.request.Form().Gets(name)
}

func (c *xContext) FormxValues(name string) param.StringSlice {
	return param.StringSlice(c.request.Form().Gets(name))
}

func (c *xContext) Forms() map[string][]string {
	return c.request.Form().All()
}

// Bind binds the request body into specified type `i`. The default binder does
// it based on Content-Type header.
func (c *xContext) Bind(i interface{}, filter ...FormDataFilter) error {
	return c.echo.binder.Bind(i, c, filter...)
}

func (c *xContext) MustBind(i interface{}, filter ...FormDataFilter) error {
	return c.echo.binder.MustBind(i, c, filter...)
}

func (c *xContext) Header(name string) string {
	return c.Request().Header().Get(name)
}

func (c *xContext) IsAjax() bool {
	return c.Header(`X-Requested-With`) == `XMLHttpRequest`
}

func (c *xContext) IsPjax() bool {
	return len(c.Header(`X-PJAX`)) > 0
}

func (c *xContext) PjaxContainer() string {
	container := c.Header(`X-PJAX-Container`)
	if len(container) > 0 {
		return container
	}
	return c.Query(`_pjax`)
}

func (c *xContext) Method() string {
	return c.Request().Method()
}

func (c *xContext) Format() string {
	if len(c.format) == 0 {
		c.format = c.ResolveFormat()
	}
	return c.format
}

// IsPost CREATE：在服务器新建一个资源
func (c *xContext) IsPost() bool {
	return c.Method() == POST
}

// IsGet SELECT：从服务器取出资源（一项或多项）
func (c *xContext) IsGet() bool {
	return c.Method() == GET
}

// IsPut UPDATE：在服务器更新资源（客户端提供改变后的完整资源）
func (c *xContext) IsPut() bool {
	return c.Method() == PUT
}

// IsDel DELETE：从服务器删除资源
func (c *xContext) IsDel() bool {
	return c.Method() == DELETE
}

// IsHead 获取资源的元数据
func (c *xContext) IsHead() bool {
	return c.Method() == HEAD
}

//IsPatch UPDATE：在服务器更新资源（客户端提供改变的属性）
func (c *xContext) IsPatch() bool {
	return c.Method() == PATCH
}

// IsOptions 获取信息，关于资源的哪些属性是客户端可以改变的
func (c *xContext) IsOptions() bool {
	return c.Method() == OPTIONS
}

func (c *xContext) IsSecure() bool {
	return c.Scheme() == `https`
}

// IsWebsocket returns boolean of this request is in webSocket.
func (c *xContext) IsWebsocket() bool {
	upgrade := c.Header(`Upgrade`)
	return upgrade == `websocket` || upgrade == `Websocket`
}

// IsUpload returns boolean of whether file uploads in this request or not..
func (c *xContext) IsUpload() bool {
	return c.ResolveContentType() == MIMEMultipartForm
}

// ResolveContentType Get the content type.
// e.g. From `multipart/form-data; boundary=--` to `multipart/form-data`
// If none is specified, returns `text/html` by default.
func (c *xContext) ResolveContentType() string {
	contentType := c.Header(HeaderContentType)
	if len(contentType) == 0 {
		return `text/html`
	}
	return strings.ToLower(strings.TrimSpace(strings.SplitN(contentType, `;`, 2)[0]))
}

// ResolveFormat maps the request's Accept MIME type declaration to
// a Request.Format attribute, specifically `html`, `xml`, `json`, or `txt`,
// returning a default of `html` when Accept header cannot be mapped to a
// value above.
func (c *xContext) ResolveFormat() string {
	if format := c.Query(`format`); len(format) > 0 {
		return format
	}
	if c.withFormatExtension {
		urlPath := c.Request().URL().Path()
		if pos := strings.LastIndex(urlPath, `.`); pos > -1 {
			return strings.ToLower(urlPath[pos+1:])
		}
	}

	info := c.Accept()
	for _, accept := range info.Type {
		if format, ok := c.echo.acceptFormats[accept.Mime]; ok {
			return format
		}
	}
	if format, ok := c.echo.acceptFormats[`*`]; ok {
		return format
	}
	return `html`
}

func (c *xContext) Accept() *Accepts {
	if c.accept != nil {
		return c.accept
	}
	c.accept = NewAccepts(c.Header(HeaderAccept)).Simple(2)
	return c.accept
}

// Protocol returns request protocol name, such as HTTP/1.1 .
func (c *xContext) Protocol() string {
	return c.Request().Proto()
}

// Site returns base site url as scheme://domain/ type.
func (c *xContext) Site() string {
	return c.Scheme() + `://` + c.Request().Host() + `/`
}

// Scheme returns request scheme as `http` or `https`.
func (c *xContext) Scheme() string {
	scheme := c.Request().Scheme()
	if len(scheme) > 0 {
		return scheme
	}
	if c.Request().IsTLS() == false {
		return `http`
	}
	return `https`
}

// Domain returns host name.
// Alias of Host method.
func (c *xContext) Domain() string {
	return c.Host()
}

// Host returns host name.
// if no host info in request, return localhost.
func (c *xContext) Host() string {
	host := c.Request().Host()
	if len(host) > 0 {
		delim := `:`
		if host[0] == '[' {
			host = strings.TrimPrefix(host, `[`)
			delim = `]:`
		}
		hostParts := strings.SplitN(host, delim, 2)
		if len(hostParts) > 0 {
			return hostParts[0]
		}
		return host
	}
	return `localhost`
}

// Proxy returns proxy client ips slice.
func (c *xContext) Proxy() []string {
	if ips := c.Header(`X-Forwarded-For`); len(ips) > 0 {
		return strings.Split(ips, `,`)
	}
	return []string{}
}

// Referer returns http referer header.
func (c *xContext) Referer() string {
	return c.Header(`Referer`)
}

func (c *xContext) RealIP() string {
	return c.Request().RealIP()
}

// Port returns request client port.
// when error or empty, return 80.
func (c *xContext) Port() int {
	host := c.Request().Host()
	delim := `:`
	if len(host) > 0 && host[0] == '[' {
		delim = `]:`
	}
	parts := strings.SplitN(host, delim, 2)
	if len(parts) > 1 {
		port, _ := strconv.Atoi(parts[1])
		return port
	}
	return 80
}

// MapForm 映射表单数据到结构体
// ParseStruct mapping forms' name and values to struct's field
// For example:
//		<form>
//			<input name=`user.id`/>
//			<input name=`user.name`/>
//			<input name=`user.age`/>
//		</form>
//
//		type User struct {
//			Id int64
//			Name string
//			Age string
//		}
//
//		var user User
//		err := c.MapForm(&user,`user`)
//
func (c *xContext) MapForm(i interface{}, names ...string) error {
	return c.MapData(i, c.Request().Form().All(), names...)
}

func (c *xContext) SaveUploadedFile(fieldName string, saveAbsPath string, saveFileName ...string) (*multipart.FileHeader, error) {
	fileSrc, fileHdr, err := c.Request().FormFile(fieldName)
	if err != nil {
		return fileHdr, err
	}
	defer fileSrc.Close()

	// Destination
	fileName := fileHdr.Filename
	if len(saveFileName) > 0 {
		fileName = saveFileName[0]
	}
	fileDst, err := os.Create(filepath.Join(saveAbsPath, fileName))
	if err != nil {
		return fileHdr, err
	}
	defer fileDst.Close()

	// Copy
	if _, err = io.Copy(fileDst, fileSrc); err != nil {
		return fileHdr, err
	}
	return fileHdr, nil
}

func (c *xContext) SaveUploadedFileToWriter(fieldName string, writer io.Writer) (*multipart.FileHeader, error) {
	fileSrc, fileHdr, err := c.Request().FormFile(fieldName)
	if err != nil {
		return fileHdr, err
	}
	defer fileSrc.Close()
	if _, err = io.Copy(writer, fileSrc); err != nil {
		return fileHdr, err
	}
	return fileHdr, nil
}

func (c *xContext) SaveUploadedFiles(fieldName string, savePath func(*multipart.FileHeader) string) error {
	m := c.Request().MultipartForm()
	files := m.File[fieldName]
	for _, fileHdr := range files {
		//for each fileheader, get a handle to the actual file
		file, err := fileHdr.Open()
		defer file.Close()
		if err != nil {
			return err
		}

		//create destination file making sure the path is writeable.
		dst, err := os.Create(savePath(fileHdr))
		defer dst.Close()
		if err != nil {
			return err
		}
		//copy the uploaded file to the destination file
		if _, err := io.Copy(dst, file); err != nil {
			return err
		}
	}
	return nil
}

func (c *xContext) SaveUploadedFilesToWriter(fieldName string, writer func(*multipart.FileHeader) io.Writer) error {
	m := c.Request().MultipartForm()
	files := m.File[fieldName]
	for _, fileHdr := range files {
		//for each fileheader, get a handle to the actual file
		file, err := fileHdr.Open()
		defer file.Close()
		if err != nil {
			return err
		}
		w := writer(fileHdr)
		if v, ok := w.(Closer); ok {
			defer v.Close()
		}
		//copy the uploaded file to the destination file
		if _, err := io.Copy(w, file); err != nil {
			return err
		}
	}
	return nil
}

// HasAnyRequest 是否提交了参数
func (c *xContext) HasAnyRequest() bool {
	return len(c.Request().Form().All()) > 0
}
<commit_msg>update<commit_after>package echo

import (
	"io"
	"mime/multipart"
	"os"
	"path/filepath"
	"strconv"
	"strings"

	"github.com/webx-top/echo/engine"
	"github.com/webx-top/echo/param"
)

// Request returns *http.Request.
func (c *xContext) Request() engine.Request {
	return c.request
}

// Path returns the registered path for the handler.
func (c *xContext) Path() string {
	return c.path
}

// P returns path parameter by index.
func (c *xContext) P(i int, defaults ...string) (value string) {
	l := len(c.pnames)
	if i < l {
		value = c.pvalues[i]
	}
	if len(value) == 0 && len(defaults) > 0 {
		return defaults[0]
	}
	return
}

func (c *xContext) Px(n int, defaults ...string) param.String {
	return param.String(c.P(n, defaults...))
}

// Param returns path parameter by name.
func (c *xContext) Param(name string, defaults ...string) (value string) {
	l := len(c.pnames)
	for i, n := range c.pnames {
		if n == name && i < l {
			value = c.pvalues[i]
			break
		}
	}

	if len(value) == 0 && len(defaults) > 0 {
		return defaults[0]
	}
	return
}

func (c *xContext) Paramx(name string, defaults ...string) param.String {
	return param.String(c.Param(name, defaults...))
}

func (c *xContext) ParamNames() []string {
	return c.pnames
}

func (c *xContext) ParamValues() []string {
	return c.pvalues
}

func (c *xContext) SetParamValues(values ...string) {
	c.pvalues = values
}

// Query returns query parameter by name.
func (c *xContext) Query(name string, defaults ...string) (value string) {
	value = c.request.URL().QueryValue(name)
	if len(value) == 0 && len(defaults) > 0 {
		return defaults[0]
	}
	return
}

func (c *xContext) Queryx(name string, defaults ...string) param.String {
	return param.String(c.Query(name, defaults...))
}

func (c *xContext) QueryValues(name string) []string {
	return c.request.URL().QueryValues(name)
}

func (c *xContext) QueryxValues(name string) param.StringSlice {
	return param.StringSlice(c.request.URL().QueryValues(name))
}

func (c *xContext) Queries() map[string][]string {
	return c.request.URL().Query()
}

// Form returns form parameter by name.
func (c *xContext) Form(name string, defaults ...string) (value string) {
	value = c.request.FormValue(name)
	if len(value) == 0 && len(defaults) > 0 {
		return defaults[0]
	}
	return
}

func (c *xContext) Formx(name string, defaults ...string) param.String {
	return param.String(c.Form(name, defaults...))
}

func (c *xContext) FormValues(name string) []string {
	return c.request.Form().Gets(name)
}

func (c *xContext) FormxValues(name string) param.StringSlice {
	return param.StringSlice(c.request.Form().Gets(name))
}

func (c *xContext) Forms() map[string][]string {
	return c.request.Form().All()
}

// Bind binds the request body into specified type `i`. The default binder does
// it based on Content-Type header.
func (c *xContext) Bind(i interface{}, filter ...FormDataFilter) error {
	return c.echo.binder.Bind(i, c, filter...)
}

func (c *xContext) MustBind(i interface{}, filter ...FormDataFilter) error {
	return c.echo.binder.MustBind(i, c, filter...)
}

func (c *xContext) Header(name string) string {
	return c.Request().Header().Get(name)
}

func (c *xContext) IsAjax() bool {
	return c.Header(`X-Requested-With`) == `XMLHttpRequest`
}

func (c *xContext) IsPjax() bool {
	return len(c.Header(`X-PJAX`)) > 0
}

func (c *xContext) PjaxContainer() string {
	container := c.Header(`X-PJAX-Container`)
	if len(container) > 0 {
		return container
	}
	return c.Query(`_pjax`)
}

func (c *xContext) Method() string {
	return c.Request().Method()
}

func (c *xContext) Format() string {
	if len(c.format) == 0 {
		c.format = c.ResolveFormat()
	}
	return c.format
}

// IsPost CREATE：在服务器新建一个资源
func (c *xContext) IsPost() bool {
	return c.Method() == POST
}

// IsGet SELECT：从服务器取出资源（一项或多项）
func (c *xContext) IsGet() bool {
	return c.Method() == GET
}

// IsPut UPDATE：在服务器更新资源（客户端提供改变后的完整资源）
func (c *xContext) IsPut() bool {
	return c.Method() == PUT
}

// IsDel DELETE：从服务器删除资源
func (c *xContext) IsDel() bool {
	return c.Method() == DELETE
}

// IsHead 获取资源的元数据
func (c *xContext) IsHead() bool {
	return c.Method() == HEAD
}

//IsPatch UPDATE：在服务器更新资源（客户端提供改变的属性）
func (c *xContext) IsPatch() bool {
	return c.Method() == PATCH
}

// IsOptions 获取信息，关于资源的哪些属性是客户端可以改变的
func (c *xContext) IsOptions() bool {
	return c.Method() == OPTIONS
}

func (c *xContext) IsSecure() bool {
	return c.Scheme() == `https`
}

// IsWebsocket returns boolean of this request is in webSocket.
func (c *xContext) IsWebsocket() bool {
	upgrade := c.Header(`Upgrade`)
	return upgrade == `websocket` || upgrade == `Websocket`
}

// IsUpload returns boolean of whether file uploads in this request or not..
func (c *xContext) IsUpload() bool {
	return c.ResolveContentType() == MIMEMultipartForm
}

// ResolveContentType Get the content type.
// e.g. From `multipart/form-data; boundary=--` to `multipart/form-data`
// If none is specified, returns `text/html` by default.
func (c *xContext) ResolveContentType() string {
	contentType := c.Header(HeaderContentType)
	if len(contentType) == 0 {
		return `text/html`
	}
	return strings.ToLower(strings.TrimSpace(strings.SplitN(contentType, `;`, 2)[0]))
}

// ResolveFormat maps the request's Accept MIME type declaration to
// a Request.Format attribute, specifically `html`, `xml`, `json`, or `txt`,
// returning a default of `html` when Accept header cannot be mapped to a
// value above.
func (c *xContext) ResolveFormat() string {
	if format := c.Query(`format`); len(format) > 0 {
		return format
	}
	if c.withFormatExtension {
		urlPath := c.Request().URL().Path()
		if pos := strings.LastIndex(urlPath, `.`); pos > -1 {
			return strings.ToLower(urlPath[pos+1:])
		}
	}

	info := c.Accept()
	for _, accept := range info.Type {
		if format, ok := c.echo.acceptFormats[accept.Mime]; ok {
			return format
		}
	}
	if format, ok := c.echo.acceptFormats[`*`]; ok {
		return format
	}
	return `html`
}

func (c *xContext) Accept() *Accepts {
	if c.accept != nil {
		return c.accept
	}
	c.accept = NewAccepts(c.Header(HeaderAccept)).Simple(3)
	return c.accept
}

// Protocol returns request protocol name, such as HTTP/1.1 .
func (c *xContext) Protocol() string {
	return c.Request().Proto()
}

// Site returns base site url as scheme://domain/ type.
func (c *xContext) Site() string {
	return c.Scheme() + `://` + c.Request().Host() + `/`
}

// Scheme returns request scheme as `http` or `https`.
func (c *xContext) Scheme() string {
	scheme := c.Request().Scheme()
	if len(scheme) > 0 {
		return scheme
	}
	if c.Request().IsTLS() == false {
		return `http`
	}
	return `https`
}

// Domain returns host name.
// Alias of Host method.
func (c *xContext) Domain() string {
	return c.Host()
}

// Host returns host name.
// if no host info in request, return localhost.
func (c *xContext) Host() string {
	host := c.Request().Host()
	if len(host) > 0 {
		delim := `:`
		if host[0] == '[' {
			host = strings.TrimPrefix(host, `[`)
			delim = `]:`
		}
		hostParts := strings.SplitN(host, delim, 2)
		if len(hostParts) > 0 {
			return hostParts[0]
		}
		return host
	}
	return `localhost`
}

// Proxy returns proxy client ips slice.
func (c *xContext) Proxy() []string {
	if ips := c.Header(`X-Forwarded-For`); len(ips) > 0 {
		return strings.Split(ips, `,`)
	}
	return []string{}
}

// Referer returns http referer header.
func (c *xContext) Referer() string {
	return c.Header(`Referer`)
}

func (c *xContext) RealIP() string {
	return c.Request().RealIP()
}

// Port returns request client port.
// when error or empty, return 80.
func (c *xContext) Port() int {
	host := c.Request().Host()
	delim := `:`
	if len(host) > 0 && host[0] == '[' {
		delim = `]:`
	}
	parts := strings.SplitN(host, delim, 2)
	if len(parts) > 1 {
		port, _ := strconv.Atoi(parts[1])
		return port
	}
	return 80
}

// MapForm 映射表单数据到结构体
// ParseStruct mapping forms' name and values to struct's field
// For example:
//		<form>
//			<input name=`user.id`/>
//			<input name=`user.name`/>
//			<input name=`user.age`/>
//		</form>
//
//		type User struct {
//			Id int64
//			Name string
//			Age string
//		}
//
//		var user User
//		err := c.MapForm(&user,`user`)
//
func (c *xContext) MapForm(i interface{}, names ...string) error {
	return c.MapData(i, c.Request().Form().All(), names...)
}

func (c *xContext) SaveUploadedFile(fieldName string, saveAbsPath string, saveFileName ...string) (*multipart.FileHeader, error) {
	fileSrc, fileHdr, err := c.Request().FormFile(fieldName)
	if err != nil {
		return fileHdr, err
	}
	defer fileSrc.Close()

	// Destination
	fileName := fileHdr.Filename
	if len(saveFileName) > 0 {
		fileName = saveFileName[0]
	}
	fileDst, err := os.Create(filepath.Join(saveAbsPath, fileName))
	if err != nil {
		return fileHdr, err
	}
	defer fileDst.Close()

	// Copy
	if _, err = io.Copy(fileDst, fileSrc); err != nil {
		return fileHdr, err
	}
	return fileHdr, nil
}

func (c *xContext) SaveUploadedFileToWriter(fieldName string, writer io.Writer) (*multipart.FileHeader, error) {
	fileSrc, fileHdr, err := c.Request().FormFile(fieldName)
	if err != nil {
		return fileHdr, err
	}
	defer fileSrc.Close()
	if _, err = io.Copy(writer, fileSrc); err != nil {
		return fileHdr, err
	}
	return fileHdr, nil
}

func (c *xContext) SaveUploadedFiles(fieldName string, savePath func(*multipart.FileHeader) string) error {
	m := c.Request().MultipartForm()
	files := m.File[fieldName]
	for _, fileHdr := range files {
		//for each fileheader, get a handle to the actual file
		file, err := fileHdr.Open()
		defer file.Close()
		if err != nil {
			return err
		}

		//create destination file making sure the path is writeable.
		dst, err := os.Create(savePath(fileHdr))
		defer dst.Close()
		if err != nil {
			return err
		}
		//copy the uploaded file to the destination file
		if _, err := io.Copy(dst, file); err != nil {
			return err
		}
	}
	return nil
}

func (c *xContext) SaveUploadedFilesToWriter(fieldName string, writer func(*multipart.FileHeader) io.Writer) error {
	m := c.Request().MultipartForm()
	files := m.File[fieldName]
	for _, fileHdr := range files {
		//for each fileheader, get a handle to the actual file
		file, err := fileHdr.Open()
		defer file.Close()
		if err != nil {
			return err
		}
		w := writer(fileHdr)
		if v, ok := w.(Closer); ok {
			defer v.Close()
		}
		//copy the uploaded file to the destination file
		if _, err := io.Copy(w, file); err != nil {
			return err
		}
	}
	return nil
}

// HasAnyRequest 是否提交了参数
func (c *xContext) HasAnyRequest() bool {
	return len(c.Request().Form().All()) > 0
}
<|endoftext|>


<commit_before>package main

import (
	"delay"
	"fmt"
	"rtos"

	"stm32/hal/dma"
	"stm32/hal/gpio"
	"stm32/hal/irq"
	"stm32/hal/spi"
	"stm32/hal/system"
	"stm32/hal/system/timer/systick"
)

type ILI9341 struct {
	SPI *spi.Driver

	ctrport       *gpio.Port
	reset, cs, dc gpio.Pins
}

func (ili *ILI9341) Reset() {
	ili.ctrport.SetPins(ili.reset | ili.cs)
	delay.Millisec(1)
	ili.ctrport.ClearPins(ili.reset)
	delay.Millisec(1)
	ili.ctrport.SetPins(ili.reset)
}

func (ili *ILI9341) Select() {
	ili.ctrport.ClearPins(ili.cs)
}

func (ili *ILI9341) Deselect() {
	ili.ctrport.SetPins(ili.cs)
}

func (ili *ILI9341) Cmd(cmd byte) {
	delay.Millisec(1)
	ili.ctrport.ClearPins(ili.dc)
	ili.SPI.WriteReadByte(cmd)
	delay.Millisec(1)
	ili.ctrport.SetPins(ili.dc)
}

func (ili *ILI9341) WriteByte(b byte) {
	ili.SPI.WriteReadByte(b)
}

func (ili *ILI9341) Write(data []byte) {
	ili.SPI.WriteRead(data, nil)
}

var ili ILI9341

func init() {
	system.Setup168(8)
	systick.Setup()

	// GPIO

	gpio.A.EnableClock(true)
	ili.ctrport = gpio.A
	ili.reset, ili.cs, ili.dc = gpio.Pin0, gpio.Pin1, gpio.Pin4
	spiport, sck, miso, mosi := gpio.A, gpio.Pin5, gpio.Pin6, gpio.Pin7

	// SPI

	spiport.Setup(sck|mosi, &gpio.Config{Mode: gpio.Alt, Speed: gpio.High})
	spiport.Setup(miso, &gpio.Config{Mode: gpio.AltIn})
	spiport.SetAltFunc(sck|miso|mosi, gpio.SPI1)
	d := dma.DMA2
	d.EnableClock(true)
	ili.SPI = spi.NewDriver(spi.SPI1, d.Channel(2, 3), d.Channel(3, 3))
	ili.SPI.P.EnableClock(true)
	ili.SPI.P.SetConf(
		spi.Master | spi.MSBF | spi.CPOL0 | spi.CPHA0 |
			ili.SPI.P.BR(21e6) | // 21 MHz max.
			spi.SoftSS | spi.ISSHigh,
	)
	ili.SPI.P.Enable()
	rtos.IRQ(irq.SPI1).Enable()
	rtos.IRQ(irq.DMA2_Stream2).Enable()
	rtos.IRQ(irq.DMA2_Stream3).Enable()

	// Controll

	ili.ctrport.Setup(
		ili.reset|ili.cs|ili.dc,
		&gpio.Config{Mode: gpio.Out, Speed: gpio.High},
	)
}

const (
	ILI9341_SLPOUT = 0x11
	ILI9341_DISPON = 0x29
	ILI9341_RAMWR  = 0x2C
	ILI9341_MADCTL = 0x36
	ILI9341_PIXFMT = 0x3A
)

func main() {
	ili.Reset()
	delay.Millisec(10)
	ili.Select()
	ili.Cmd(ILI9341_SLPOUT)
	delay.Millisec(120)
	ili.Cmd(ILI9341_DISPON)

	spibus := ili.SPI.P.Bus()
	fmt.Printf(
		"\nSPI on %s (%d MHz). SPI speed: %d Hz.\n\n",
		spibus, spibus.Clock()/1e6, ili.SPI.P.Baudrate(ili.SPI.P.Conf()),
	)

	ili.Cmd(ILI9341_PIXFMT)
	ili.WriteByte(0x55) // 16 bit 565 format.

	ili.Cmd(ILI9341_MADCTL)
	ili.WriteByte(0x48) // Screen orientation.

	ili.Cmd(ILI9341_RAMWR)

	line := make([]byte, 240*2)
	for i := 0; i < 320; i++ {
		for k := range line {
			x := i
			if k == x || k == x+1 {
				line[k] = 0xff
			} else {
				line[k] = 0
			}
		}
		ili.Write(line)
	}
}

func iliSPIISR() {
	ili.SPI.ISR()
}

func iliRxDMAISR() {
	ili.SPI.DMAISR(ili.SPI.RxDMA)
}

func iliTxDMAISR() {
	ili.SPI.DMAISR(ili.SPI.TxDMA)
}

//emgo:const
//c:__attribute__((section(".ISRs")))
var ISRs = [...]func(){
	irq.SPI1:         iliSPIISR,
	irq.DMA2_Stream2: iliRxDMAISR,
	irq.DMA2_Stream3: iliTxDMAISR,
}
<commit_msg>examples/f4-discovery/ili9341: Add short description.<commit_after>// This is test program that tries to communicate with ILI9341 controller using
// raw SPI (without any display library). There are more useful examples (for
// other boards) that use display/ili9341 package.
package main

import (
	"delay"
	"fmt"
	"rtos"

	"stm32/hal/dma"
	"stm32/hal/gpio"
	"stm32/hal/irq"
	"stm32/hal/spi"
	"stm32/hal/system"
	"stm32/hal/system/timer/systick"
)

type ILI9341 struct {
	SPI *spi.Driver

	ctrport       *gpio.Port
	reset, cs, dc gpio.Pins
}

func (ili *ILI9341) Reset() {
	ili.ctrport.SetPins(ili.reset | ili.cs)
	delay.Millisec(1)
	ili.ctrport.ClearPins(ili.reset)
	delay.Millisec(1)
	ili.ctrport.SetPins(ili.reset)
}

func (ili *ILI9341) Select() {
	ili.ctrport.ClearPins(ili.cs)
}

func (ili *ILI9341) Deselect() {
	ili.ctrport.SetPins(ili.cs)
}

func (ili *ILI9341) Cmd(cmd byte) {
	delay.Millisec(1)
	ili.ctrport.ClearPins(ili.dc)
	ili.SPI.WriteReadByte(cmd)
	delay.Millisec(1)
	ili.ctrport.SetPins(ili.dc)
}

func (ili *ILI9341) WriteByte(b byte) {
	ili.SPI.WriteReadByte(b)
}

func (ili *ILI9341) Write(data []byte) {
	ili.SPI.WriteRead(data, nil)
}

var ili ILI9341

func init() {
	system.Setup168(8)
	systick.Setup()

	// GPIO

	gpio.A.EnableClock(true)
	ili.ctrport = gpio.A
	ili.reset, ili.cs, ili.dc = gpio.Pin0, gpio.Pin1, gpio.Pin4
	spiport, sck, miso, mosi := gpio.A, gpio.Pin5, gpio.Pin6, gpio.Pin7

	// SPI

	spiport.Setup(sck|mosi, &gpio.Config{Mode: gpio.Alt, Speed: gpio.High})
	spiport.Setup(miso, &gpio.Config{Mode: gpio.AltIn})
	spiport.SetAltFunc(sck|miso|mosi, gpio.SPI1)
	d := dma.DMA2
	d.EnableClock(true)
	ili.SPI = spi.NewDriver(spi.SPI1, d.Channel(2, 3), d.Channel(3, 3))
	ili.SPI.P.EnableClock(true)
	ili.SPI.P.SetConf(
		spi.Master | spi.MSBF | spi.CPOL0 | spi.CPHA0 |
			ili.SPI.P.BR(21e6) | // 21 MHz max.
			spi.SoftSS | spi.ISSHigh,
	)
	ili.SPI.P.Enable()
	rtos.IRQ(irq.SPI1).Enable()
	rtos.IRQ(irq.DMA2_Stream2).Enable()
	rtos.IRQ(irq.DMA2_Stream3).Enable()

	// Controll

	ili.ctrport.Setup(
		ili.reset|ili.cs|ili.dc,
		&gpio.Config{Mode: gpio.Out, Speed: gpio.High},
	)
}

const (
	ILI9341_SLPOUT = 0x11
	ILI9341_DISPON = 0x29
	ILI9341_RAMWR  = 0x2C
	ILI9341_MADCTL = 0x36
	ILI9341_PIXFMT = 0x3A
)

func main() {
	ili.Reset()
	delay.Millisec(10)
	ili.Select()
	ili.Cmd(ILI9341_SLPOUT)
	delay.Millisec(120)
	ili.Cmd(ILI9341_DISPON)

	spibus := ili.SPI.P.Bus()
	fmt.Printf(
		"\nSPI on %s (%d MHz). SPI speed: %d Hz.\n\n",
		spibus, spibus.Clock()/1e6, ili.SPI.P.Baudrate(ili.SPI.P.Conf()),
	)

	ili.Cmd(ILI9341_PIXFMT)
	ili.WriteByte(0x55) // 16 bit 565 format.

	ili.Cmd(ILI9341_MADCTL)
	ili.WriteByte(0x48) // Screen orientation.

	ili.Cmd(ILI9341_RAMWR)

	line := make([]byte, 240*2)
	for i := 0; i < 320; i++ {
		for k := range line {
			x := i
			if k == x || k == x+1 {
				line[k] = 0xff
			} else {
				line[k] = 0
			}
		}
		ili.Write(line)
	}
}

func iliSPIISR() {
	ili.SPI.ISR()
}

func iliRxDMAISR() {
	ili.SPI.DMAISR(ili.SPI.RxDMA)
}

func iliTxDMAISR() {
	ili.SPI.DMAISR(ili.SPI.TxDMA)
}

//emgo:const
//c:__attribute__((section(".ISRs")))
var ISRs = [...]func(){
	irq.SPI1:         iliSPIISR,
	irq.DMA2_Stream2: iliRxDMAISR,
	irq.DMA2_Stream3: iliTxDMAISR,
}
<|endoftext|>


<commit_before>package controllers

import (
	"bytes"
	"github.com/aphistic/gomol"
	"github.com/quakkels/goshipit/slack"
	"net/http"
)

func slash(w http.ResponseWriter, req *http.Request) {
	if req.Method == "POST" {
		slashCommand := slack.NewSlashCommandModel(req)
		gomol.Infof("slash command received: %f", slashCommand)

		w.Header().Add("Content Type", "text/plain")
		b := bytes.NewBufferString("Slash command received.")

		b.WriteTo(w)
	}
}
<commit_msg>list categories from slash command<commit_after>package controllers

import (
	"bytes"
	"github.com/aphistic/gomol"
	"github.com/quakkels/goshipit/images"
	"github.com/quakkels/goshipit/slack"
	"net/http"
	"strconv"
)

func slash(w http.ResponseWriter, req *http.Request) {
	if req.Method == "POST" {
		slashCommand := slack.NewSlashCommandModel(req)
		gomol.Infof("slash command received: %f", slashCommand)

		w.Header().Add("Content Type", "text/plain")

		if slashCommand.Text == "categories" {
			cats := images.Images.GetCategories()
			var catBuffer bytes.Buffer
			for key, count := range cats {
				catBuffer.WriteString(key +
					" has " +
					strconv.Itoa(count) +
					" shipit squirrels.\n")
			}

			catBuffer.WriteTo(w)
		} else {
			b := bytes.NewBufferString("Command not recognized.")
			b.WriteTo(w)
		}
	}
}
<|endoftext|>


<commit_before>package commands

import (
	"errors"
	"fmt"
	"io"

	bstore "github.com/ipfs/go-ipfs/blocks/blockstore"
	blockservice "github.com/ipfs/go-ipfs/blockservice"
	cmds "github.com/ipfs/go-ipfs/commands"
	files "github.com/ipfs/go-ipfs/commands/files"
	core "github.com/ipfs/go-ipfs/core"
	"github.com/ipfs/go-ipfs/core/coreunix"
	offline "github.com/ipfs/go-ipfs/exchange/offline"
	dag "github.com/ipfs/go-ipfs/merkledag"
	dagtest "github.com/ipfs/go-ipfs/merkledag/test"
	mfs "github.com/ipfs/go-ipfs/mfs"
	ft "github.com/ipfs/go-ipfs/unixfs"

	u "gx/ipfs/QmWbjfz3u6HkAdPh34dgPchGbQjob6LXLhAeCGii2TX69n/go-ipfs-util"
	"gx/ipfs/QmeWjRodbcZFKe5tMN7poEx3izym6osrLSnTLf9UjJZBbs/pb"
)

// Error indicating the max depth has been exceded.
var ErrDepthLimitExceeded = fmt.Errorf("depth limit exceeded")

const (
	quietOptionName       = "quiet"
	quieterOptionName     = "quieter"
	silentOptionName      = "silent"
	progressOptionName    = "progress"
	trickleOptionName     = "trickle"
	wrapOptionName        = "wrap-with-directory"
	hiddenOptionName      = "hidden"
	onlyHashOptionName    = "only-hash"
	chunkerOptionName     = "chunker"
	pinOptionName         = "pin"
	rawLeavesOptionName   = "raw-leaves"
	noCopyOptionName      = "nocopy"
	fstoreCacheOptionName = "fscache"
	cidVersionOptionName  = "cid-version"
)

const adderOutChanSize = 8

var AddCmd = &cmds.Command{
	Helptext: cmds.HelpText{
		Tagline: "Add a file or directory to ipfs.",
		ShortDescription: `
Adds contents of <path> to ipfs. Use -r to add directories (recursively).
`,
		LongDescription: `
Adds contents of <path> to ipfs. Use -r to add directories.
Note that directories are added recursively, to form the ipfs
MerkleDAG.

The wrap option, '-w', wraps the file (or files, if using the
recursive option) in a directory. This directory contains only
the files which have been added, and means that the file retains
its filename. For example:

  > ipfs add example.jpg
  added QmbFMke1KXqnYyBBWxB74N4c5SBnJMVAiMNRcGu6x1AwQH example.jpg
  > ipfs add example.jpg -w
  added QmbFMke1KXqnYyBBWxB74N4c5SBnJMVAiMNRcGu6x1AwQH example.jpg
  added QmaG4FuMqEBnQNn3C8XJ5bpW8kLs7zq2ZXgHptJHbKDDVx

You can now refer to the added file in a gateway, like so:

  /ipfs/QmaG4FuMqEBnQNn3C8XJ5bpW8kLs7zq2ZXgHptJHbKDDVx/example.jpg
`,
	},

	Arguments: []cmds.Argument{
		cmds.FileArg("path", true, true, "The path to a file to be added to ipfs.").EnableRecursive().EnableStdin(),
	},
	Options: []cmds.Option{
		cmds.OptionRecursivePath, // a builtin option that allows recursive paths (-r, --recursive)
		cmds.BoolOption(quietOptionName, "q", "Write minimal output."),
		cmds.BoolOption(quieterOptionName, "Q", "Write only final hash."),
		cmds.BoolOption(silentOptionName, "Write no output."),
		cmds.BoolOption(progressOptionName, "p", "Stream progress data."),
		cmds.BoolOption(trickleOptionName, "t", "Use trickle-dag format for dag generation."),
		cmds.BoolOption(onlyHashOptionName, "n", "Only chunk and hash - do not write to disk."),
		cmds.BoolOption(wrapOptionName, "w", "Wrap files with a directory object."),
		cmds.BoolOption(hiddenOptionName, "H", "Include files that are hidden. Only takes effect on recursive add."),
		cmds.StringOption(chunkerOptionName, "s", "Chunking algorithm to use."),
		cmds.BoolOption(pinOptionName, "Pin this object when adding.").Default(true),
		cmds.BoolOption(rawLeavesOptionName, "Use raw blocks for leaf nodes. (experimental)"),
		cmds.BoolOption(noCopyOptionName, "Add the file using filestore. (experimental)"),
		cmds.BoolOption(fstoreCacheOptionName, "Check the filestore for pre-existing blocks. (experimental)"),
		cmds.IntOption(cidVersionOptionName, "Cid version. Non-zero value will change default of 'raw-leaves' to true. (experimental)").Default(0),
	},
	PreRun: func(req cmds.Request) error {
		quiet, _, _ := req.Option(quietOptionName).Bool()
		quieter, _, _ := req.Option(quieterOptionName).Bool()
		quiet = quiet || quieter

		silent, _, _ := req.Option(silentOptionName).Bool()

		if quiet || silent {
			return nil
		}

		// ipfs cli progress bar defaults to true unless quiet or silent is used
		_, found, _ := req.Option(progressOptionName).Bool()
		if !found {
			req.SetOption(progressOptionName, true)
		}

		sizeFile, ok := req.Files().(files.SizeFile)
		if !ok {
			// we don't need to error, the progress bar just won't know how big the files are
			log.Warning("cannnot determine size of input file")
			return nil
		}

		sizeCh := make(chan int64, 1)
		req.Values()["size"] = sizeCh

		go func() {
			size, err := sizeFile.Size()
			if err != nil {
				log.Warningf("error getting files size: %s", err)
				// see comment above
				return
			}

			log.Debugf("Total size of file being added: %v\n", size)
			sizeCh <- size
		}()

		return nil
	},
	Run: func(req cmds.Request, res cmds.Response) {
		n, err := req.InvocContext().GetNode()
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}

		cfg, err := n.Repo.Config()
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}
		// check if repo will exceed storage limit if added
		// TODO: this doesn't handle the case if the hashed file is already in blocks (deduplicated)
		// TODO: conditional GC is disabled due to it is somehow not possible to pass the size to the daemon
		//if err := corerepo.ConditionalGC(req.Context(), n, uint64(size)); err != nil {
		//	res.SetError(err, cmds.ErrNormal)
		//	return
		//}

		progress, _, _ := req.Option(progressOptionName).Bool()
		trickle, _, _ := req.Option(trickleOptionName).Bool()
		wrap, _, _ := req.Option(wrapOptionName).Bool()
		hash, _, _ := req.Option(onlyHashOptionName).Bool()
		hidden, _, _ := req.Option(hiddenOptionName).Bool()
		silent, _, _ := req.Option(silentOptionName).Bool()
		chunker, _, _ := req.Option(chunkerOptionName).String()
		dopin, _, _ := req.Option(pinOptionName).Bool()
		rawblks, rbset, _ := req.Option(rawLeavesOptionName).Bool()
		nocopy, _, _ := req.Option(noCopyOptionName).Bool()
		fscache, _, _ := req.Option(fstoreCacheOptionName).Bool()
		cidVer, _, _ := req.Option(cidVersionOptionName).Int()

		if nocopy && !cfg.Experimental.FilestoreEnabled {
			res.SetError(errors.New("filestore is not enabled, see https://git.io/vy4XN"),
				cmds.ErrClient)
			return
		}

		if nocopy && !rbset {
			rawblks = true
		}

		if nocopy && !rawblks {
			res.SetError(fmt.Errorf("nocopy option requires '--raw-leaves' to be enabled as well"), cmds.ErrNormal)
			return
		}

		if cidVer >= 1 && !rbset {
			rawblks = true
		}

		prefix, err := dag.PrefixForCidVersion(cidVer)
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}

		if hash {
			nilnode, err := core.NewNode(n.Context(), &core.BuildCfg{
				//TODO: need this to be true or all files
				// hashed will be stored in memory!
				NilRepo: true,
			})
			if err != nil {
				res.SetError(err, cmds.ErrNormal)
				return
			}
			n = nilnode
		}

		addblockstore := n.Blockstore
		if !(fscache || nocopy) {
			addblockstore = bstore.NewGCBlockstore(n.BaseBlocks, n.GCLocker)
		}

		exch := n.Exchange
		local, _, _ := req.Option("local").Bool()
		if local {
			exch = offline.Exchange(addblockstore)
		}

		bserv := blockservice.New(addblockstore, exch)
		dserv := dag.NewDAGService(bserv)

		fileAdder, err := coreunix.NewAdder(req.Context(), n.Pinning, n.Blockstore, dserv)
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}

		outChan := make(chan interface{}, adderOutChanSize)
		res.SetOutput((<-chan interface{})(outChan))

		fileAdder.Out = outChan
		fileAdder.Chunker = chunker
		fileAdder.Progress = progress
		fileAdder.Hidden = hidden
		fileAdder.Trickle = trickle
		fileAdder.Wrap = wrap
		fileAdder.Pin = dopin
		fileAdder.Silent = silent
		fileAdder.RawLeaves = rawblks
		fileAdder.NoCopy = nocopy
		fileAdder.Prefix = &prefix

		if hash {
			md := dagtest.Mock()
			mr, err := mfs.NewRoot(req.Context(), md, ft.EmptyDirNode(), nil)
			if err != nil {
				res.SetError(err, cmds.ErrNormal)
				return
			}

			fileAdder.SetMfsRoot(mr)
		}

		addAllAndPin := func(f files.File) error {
			// Iterate over each top-level file and add individually. Otherwise the
			// single files.File f is treated as a directory, affecting hidden file
			// semantics.
			for {
				file, err := f.NextFile()
				if err == io.EOF {
					// Finished the list of files.
					break
				} else if err != nil {
					return err
				}
				if err := fileAdder.AddFile(file); err != nil {
					return err
				}
			}

			// copy intermediary nodes from editor to our actual dagservice
			_, err := fileAdder.Finalize()
			if err != nil {
				return err
			}

			if hash {
				return nil
			}

			return fileAdder.PinRoot()
		}

		go func() {
			defer close(outChan)
			if err := addAllAndPin(req.Files()); err != nil {
				res.SetError(err, cmds.ErrNormal)
				return
			}

		}()
	},
	PostRun: func(req cmds.Request, res cmds.Response) {
		if res.Error() != nil {
			return
		}
		outChan, ok := res.Output().(<-chan interface{})
		if !ok {
			res.SetError(u.ErrCast(), cmds.ErrNormal)
			return
		}
		res.SetOutput(nil)

		quiet, _, _ := req.Option(quietOptionName).Bool()
		quieter, _, _ := req.Option(quieterOptionName).Bool()
		quiet = quiet || quieter

		progress, _, _ := req.Option(progressOptionName).Bool()

		var bar *pb.ProgressBar
		if progress {
			bar = pb.New64(0).SetUnits(pb.U_BYTES)
			bar.ManualUpdate = true
			bar.ShowTimeLeft = false
			bar.ShowPercent = false
			bar.Output = res.Stderr()
			bar.Start()
		}

		var sizeChan chan int64
		s, found := req.Values()["size"]
		if found {
			sizeChan = s.(chan int64)
		}

		lastFile := ""
		lastHash := ""
		var totalProgress, prevFiles, lastBytes int64

	LOOP:
		for {
			select {
			case out, ok := <-outChan:
				if !ok {
					if quieter {
						fmt.Fprintln(res.Stdout(), lastHash)
					}
					break LOOP
				}
				output := out.(*coreunix.AddedObject)
				if len(output.Hash) > 0 {
					lastHash = output.Hash
					if quieter {
						continue
					}

					if progress {
						// clear progress bar line before we print "added x" output
						fmt.Fprintf(res.Stderr(), "\033[2K\r")
					}
					if quiet {
						fmt.Fprintf(res.Stdout(), "%s\n", output.Hash)
					} else {
						fmt.Fprintf(res.Stdout(), "added %s %s\n", output.Hash, output.Name)
					}
				} else {
					log.Debugf("add progress: %v %v\n", output.Name, output.Bytes)

					if !progress {
						continue
					}

					if len(lastFile) == 0 {
						lastFile = output.Name
					}
					if output.Name != lastFile || output.Bytes < lastBytes {
						prevFiles += lastBytes
						lastFile = output.Name
					}
					lastBytes = output.Bytes
					delta := prevFiles + lastBytes - totalProgress
					totalProgress = bar.Add64(delta)
				}

				if progress {
					bar.Update()
				}
			case size := <-sizeChan:
				if progress {
					bar.Total = size
					bar.ShowPercent = true
					bar.ShowBar = true
					bar.ShowTimeLeft = true
				}
			case <-req.Context().Done():
				res.SetError(req.Context().Err(), cmds.ErrNormal)
				return
			}
		}
	},
	Type: coreunix.AddedObject{},
}
<commit_msg>Fix typo in message when file is not determined<commit_after>package commands

import (
	"errors"
	"fmt"
	"io"

	bstore "github.com/ipfs/go-ipfs/blocks/blockstore"
	blockservice "github.com/ipfs/go-ipfs/blockservice"
	cmds "github.com/ipfs/go-ipfs/commands"
	files "github.com/ipfs/go-ipfs/commands/files"
	core "github.com/ipfs/go-ipfs/core"
	"github.com/ipfs/go-ipfs/core/coreunix"
	offline "github.com/ipfs/go-ipfs/exchange/offline"
	dag "github.com/ipfs/go-ipfs/merkledag"
	dagtest "github.com/ipfs/go-ipfs/merkledag/test"
	mfs "github.com/ipfs/go-ipfs/mfs"
	ft "github.com/ipfs/go-ipfs/unixfs"

	u "gx/ipfs/QmWbjfz3u6HkAdPh34dgPchGbQjob6LXLhAeCGii2TX69n/go-ipfs-util"
	"gx/ipfs/QmeWjRodbcZFKe5tMN7poEx3izym6osrLSnTLf9UjJZBbs/pb"
)

// Error indicating the max depth has been exceded.
var ErrDepthLimitExceeded = fmt.Errorf("depth limit exceeded")

const (
	quietOptionName       = "quiet"
	quieterOptionName     = "quieter"
	silentOptionName      = "silent"
	progressOptionName    = "progress"
	trickleOptionName     = "trickle"
	wrapOptionName        = "wrap-with-directory"
	hiddenOptionName      = "hidden"
	onlyHashOptionName    = "only-hash"
	chunkerOptionName     = "chunker"
	pinOptionName         = "pin"
	rawLeavesOptionName   = "raw-leaves"
	noCopyOptionName      = "nocopy"
	fstoreCacheOptionName = "fscache"
	cidVersionOptionName  = "cid-version"
)

const adderOutChanSize = 8

var AddCmd = &cmds.Command{
	Helptext: cmds.HelpText{
		Tagline: "Add a file or directory to ipfs.",
		ShortDescription: `
Adds contents of <path> to ipfs. Use -r to add directories (recursively).
`,
		LongDescription: `
Adds contents of <path> to ipfs. Use -r to add directories.
Note that directories are added recursively, to form the ipfs
MerkleDAG.

The wrap option, '-w', wraps the file (or files, if using the
recursive option) in a directory. This directory contains only
the files which have been added, and means that the file retains
its filename. For example:

  > ipfs add example.jpg
  added QmbFMke1KXqnYyBBWxB74N4c5SBnJMVAiMNRcGu6x1AwQH example.jpg
  > ipfs add example.jpg -w
  added QmbFMke1KXqnYyBBWxB74N4c5SBnJMVAiMNRcGu6x1AwQH example.jpg
  added QmaG4FuMqEBnQNn3C8XJ5bpW8kLs7zq2ZXgHptJHbKDDVx

You can now refer to the added file in a gateway, like so:

  /ipfs/QmaG4FuMqEBnQNn3C8XJ5bpW8kLs7zq2ZXgHptJHbKDDVx/example.jpg
`,
	},

	Arguments: []cmds.Argument{
		cmds.FileArg("path", true, true, "The path to a file to be added to ipfs.").EnableRecursive().EnableStdin(),
	},
	Options: []cmds.Option{
		cmds.OptionRecursivePath, // a builtin option that allows recursive paths (-r, --recursive)
		cmds.BoolOption(quietOptionName, "q", "Write minimal output."),
		cmds.BoolOption(quieterOptionName, "Q", "Write only final hash."),
		cmds.BoolOption(silentOptionName, "Write no output."),
		cmds.BoolOption(progressOptionName, "p", "Stream progress data."),
		cmds.BoolOption(trickleOptionName, "t", "Use trickle-dag format for dag generation."),
		cmds.BoolOption(onlyHashOptionName, "n", "Only chunk and hash - do not write to disk."),
		cmds.BoolOption(wrapOptionName, "w", "Wrap files with a directory object."),
		cmds.BoolOption(hiddenOptionName, "H", "Include files that are hidden. Only takes effect on recursive add."),
		cmds.StringOption(chunkerOptionName, "s", "Chunking algorithm to use."),
		cmds.BoolOption(pinOptionName, "Pin this object when adding.").Default(true),
		cmds.BoolOption(rawLeavesOptionName, "Use raw blocks for leaf nodes. (experimental)"),
		cmds.BoolOption(noCopyOptionName, "Add the file using filestore. (experimental)"),
		cmds.BoolOption(fstoreCacheOptionName, "Check the filestore for pre-existing blocks. (experimental)"),
		cmds.IntOption(cidVersionOptionName, "Cid version. Non-zero value will change default of 'raw-leaves' to true. (experimental)").Default(0),
	},
	PreRun: func(req cmds.Request) error {
		quiet, _, _ := req.Option(quietOptionName).Bool()
		quieter, _, _ := req.Option(quieterOptionName).Bool()
		quiet = quiet || quieter

		silent, _, _ := req.Option(silentOptionName).Bool()

		if quiet || silent {
			return nil
		}

		// ipfs cli progress bar defaults to true unless quiet or silent is used
		_, found, _ := req.Option(progressOptionName).Bool()
		if !found {
			req.SetOption(progressOptionName, true)
		}

		sizeFile, ok := req.Files().(files.SizeFile)
		if !ok {
			// we don't need to error, the progress bar just won't know how big the files are
			log.Warning("cannot determine size of input file")
			return nil
		}

		sizeCh := make(chan int64, 1)
		req.Values()["size"] = sizeCh

		go func() {
			size, err := sizeFile.Size()
			if err != nil {
				log.Warningf("error getting files size: %s", err)
				// see comment above
				return
			}

			log.Debugf("Total size of file being added: %v\n", size)
			sizeCh <- size
		}()

		return nil
	},
	Run: func(req cmds.Request, res cmds.Response) {
		n, err := req.InvocContext().GetNode()
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}

		cfg, err := n.Repo.Config()
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}
		// check if repo will exceed storage limit if added
		// TODO: this doesn't handle the case if the hashed file is already in blocks (deduplicated)
		// TODO: conditional GC is disabled due to it is somehow not possible to pass the size to the daemon
		//if err := corerepo.ConditionalGC(req.Context(), n, uint64(size)); err != nil {
		//	res.SetError(err, cmds.ErrNormal)
		//	return
		//}

		progress, _, _ := req.Option(progressOptionName).Bool()
		trickle, _, _ := req.Option(trickleOptionName).Bool()
		wrap, _, _ := req.Option(wrapOptionName).Bool()
		hash, _, _ := req.Option(onlyHashOptionName).Bool()
		hidden, _, _ := req.Option(hiddenOptionName).Bool()
		silent, _, _ := req.Option(silentOptionName).Bool()
		chunker, _, _ := req.Option(chunkerOptionName).String()
		dopin, _, _ := req.Option(pinOptionName).Bool()
		rawblks, rbset, _ := req.Option(rawLeavesOptionName).Bool()
		nocopy, _, _ := req.Option(noCopyOptionName).Bool()
		fscache, _, _ := req.Option(fstoreCacheOptionName).Bool()
		cidVer, _, _ := req.Option(cidVersionOptionName).Int()

		if nocopy && !cfg.Experimental.FilestoreEnabled {
			res.SetError(errors.New("filestore is not enabled, see https://git.io/vy4XN"),
				cmds.ErrClient)
			return
		}

		if nocopy && !rbset {
			rawblks = true
		}

		if nocopy && !rawblks {
			res.SetError(fmt.Errorf("nocopy option requires '--raw-leaves' to be enabled as well"), cmds.ErrNormal)
			return
		}

		if cidVer >= 1 && !rbset {
			rawblks = true
		}

		prefix, err := dag.PrefixForCidVersion(cidVer)
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}

		if hash {
			nilnode, err := core.NewNode(n.Context(), &core.BuildCfg{
				//TODO: need this to be true or all files
				// hashed will be stored in memory!
				NilRepo: true,
			})
			if err != nil {
				res.SetError(err, cmds.ErrNormal)
				return
			}
			n = nilnode
		}

		addblockstore := n.Blockstore
		if !(fscache || nocopy) {
			addblockstore = bstore.NewGCBlockstore(n.BaseBlocks, n.GCLocker)
		}

		exch := n.Exchange
		local, _, _ := req.Option("local").Bool()
		if local {
			exch = offline.Exchange(addblockstore)
		}

		bserv := blockservice.New(addblockstore, exch)
		dserv := dag.NewDAGService(bserv)

		fileAdder, err := coreunix.NewAdder(req.Context(), n.Pinning, n.Blockstore, dserv)
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}

		outChan := make(chan interface{}, adderOutChanSize)
		res.SetOutput((<-chan interface{})(outChan))

		fileAdder.Out = outChan
		fileAdder.Chunker = chunker
		fileAdder.Progress = progress
		fileAdder.Hidden = hidden
		fileAdder.Trickle = trickle
		fileAdder.Wrap = wrap
		fileAdder.Pin = dopin
		fileAdder.Silent = silent
		fileAdder.RawLeaves = rawblks
		fileAdder.NoCopy = nocopy
		fileAdder.Prefix = &prefix

		if hash {
			md := dagtest.Mock()
			mr, err := mfs.NewRoot(req.Context(), md, ft.EmptyDirNode(), nil)
			if err != nil {
				res.SetError(err, cmds.ErrNormal)
				return
			}

			fileAdder.SetMfsRoot(mr)
		}

		addAllAndPin := func(f files.File) error {
			// Iterate over each top-level file and add individually. Otherwise the
			// single files.File f is treated as a directory, affecting hidden file
			// semantics.
			for {
				file, err := f.NextFile()
				if err == io.EOF {
					// Finished the list of files.
					break
				} else if err != nil {
					return err
				}
				if err := fileAdder.AddFile(file); err != nil {
					return err
				}
			}

			// copy intermediary nodes from editor to our actual dagservice
			_, err := fileAdder.Finalize()
			if err != nil {
				return err
			}

			if hash {
				return nil
			}

			return fileAdder.PinRoot()
		}

		go func() {
			defer close(outChan)
			if err := addAllAndPin(req.Files()); err != nil {
				res.SetError(err, cmds.ErrNormal)
				return
			}

		}()
	},
	PostRun: func(req cmds.Request, res cmds.Response) {
		if res.Error() != nil {
			return
		}
		outChan, ok := res.Output().(<-chan interface{})
		if !ok {
			res.SetError(u.ErrCast(), cmds.ErrNormal)
			return
		}
		res.SetOutput(nil)

		quiet, _, _ := req.Option(quietOptionName).Bool()
		quieter, _, _ := req.Option(quieterOptionName).Bool()
		quiet = quiet || quieter

		progress, _, _ := req.Option(progressOptionName).Bool()

		var bar *pb.ProgressBar
		if progress {
			bar = pb.New64(0).SetUnits(pb.U_BYTES)
			bar.ManualUpdate = true
			bar.ShowTimeLeft = false
			bar.ShowPercent = false
			bar.Output = res.Stderr()
			bar.Start()
		}

		var sizeChan chan int64
		s, found := req.Values()["size"]
		if found {
			sizeChan = s.(chan int64)
		}

		lastFile := ""
		lastHash := ""
		var totalProgress, prevFiles, lastBytes int64

	LOOP:
		for {
			select {
			case out, ok := <-outChan:
				if !ok {
					if quieter {
						fmt.Fprintln(res.Stdout(), lastHash)
					}
					break LOOP
				}
				output := out.(*coreunix.AddedObject)
				if len(output.Hash) > 0 {
					lastHash = output.Hash
					if quieter {
						continue
					}

					if progress {
						// clear progress bar line before we print "added x" output
						fmt.Fprintf(res.Stderr(), "\033[2K\r")
					}
					if quiet {
						fmt.Fprintf(res.Stdout(), "%s\n", output.Hash)
					} else {
						fmt.Fprintf(res.Stdout(), "added %s %s\n", output.Hash, output.Name)
					}
				} else {
					log.Debugf("add progress: %v %v\n", output.Name, output.Bytes)

					if !progress {
						continue
					}

					if len(lastFile) == 0 {
						lastFile = output.Name
					}
					if output.Name != lastFile || output.Bytes < lastBytes {
						prevFiles += lastBytes
						lastFile = output.Name
					}
					lastBytes = output.Bytes
					delta := prevFiles + lastBytes - totalProgress
					totalProgress = bar.Add64(delta)
				}

				if progress {
					bar.Update()
				}
			case size := <-sizeChan:
				if progress {
					bar.Total = size
					bar.ShowPercent = true
					bar.ShowBar = true
					bar.ShowTimeLeft = true
				}
			case <-req.Context().Done():
				res.SetError(req.Context().Err(), cmds.ErrNormal)
				return
			}
		}
	},
	Type: coreunix.AddedObject{},
}
<|endoftext|>


<commit_before>package commands

import (
	"fmt"

	cmds "github.com/jbenet/go-ipfs/commands"
)

type Link struct {
	Name, Hash string
	Size       uint64
}

var ls = &cmds.Command{
	Help: "TODO",
	Run: func(res cmds.Response, req cmds.Request) {
		node := req.Context().Node
		output := make(map[string][]Link, len(req.Arguments()))

		for _, path := range req.Arguments() {
			dagnode, err := node.Resolver.ResolvePath(path)
			if err != nil {
				res.SetError(err, cmds.ErrNormal)
				return
			}

			output[path] = make([]Link, len(dagnode.Links))
			for i, link := range dagnode.Links {
				output[path][i] = Link{
					Name: link.Name,
					Hash: link.Hash.B58String(),
					Size: link.Size,
				}
			}
		}

		res.SetValue(output)
	},
	Format: func(res cmds.Response) (string, error) {
		s := ""
		output := res.Value().(*map[string][]Link)

		for path, links := range *output {
			if len(*output) > 1 {
				s += fmt.Sprintf("%s:\n", path)
			}

			for _, link := range links {
				s += fmt.Sprintf("-> %s %s (%v bytes)\n", link.Name, link.Hash, link.Size)
			}

			if len(*output) > 1 {
				s += "\n"
			}
		}

		return s, nil
	},
	Type: &map[string][]Link{},
}
<commit_msg>core/command2: Fixed ls output for XML marshalling<commit_after>package commands

import (
	"fmt"

	cmds "github.com/jbenet/go-ipfs/commands"
)

type Link struct {
	Name, Hash string
	Size       uint64
}

type Object struct {
	Hash  string
	Links []Link
}

type LsOutput struct {
	Objects []Object
}

var ls = &cmds.Command{
	Help: "TODO",
	Run: func(res cmds.Response, req cmds.Request) {
		node := req.Context().Node
		output := make([]Object, len(req.Arguments()))

		for i, path := range req.Arguments() {
			dagnode, err := node.Resolver.ResolvePath(path)
			if err != nil {
				res.SetError(err, cmds.ErrNormal)
				return
			}

			output[i] = Object{
				Hash:  path,
				Links: make([]Link, len(dagnode.Links)),
			}
			for j, link := range dagnode.Links {
				output[i].Links[j] = Link{
					Name: link.Name,
					Hash: link.Hash.B58String(),
					Size: link.Size,
				}
			}
		}

		res.SetValue(&LsOutput{output})
	},
	Format: func(res cmds.Response) (string, error) {
		s := ""
		output := res.Value().(*LsOutput).Objects

		for _, object := range output {
			if len(output) > 1 {
				s += fmt.Sprintf("%s:\n", object.Hash)
			}

			for _, link := range object.Links {
				s += fmt.Sprintf("-> %s %s (%v bytes)\n", link.Name, link.Hash, link.Size)
			}

			if len(output) > 1 {
				s += "\n"
			}
		}

		return s, nil
	},
	Type: &LsOutput{},
}
<|endoftext|>