<commit_before>package controller

import (
	. "eaciit/wfdemo-git/library/core"
	. "eaciit/wfdemo-git/library/models"
	"eaciit/wfdemo-git/web/helper"

	"time"

	"github.com/eaciit/dbox"
	"github.com/eaciit/knot/knot.v1"
	tk "github.com/eaciit/toolkit"
)

type AnalyticPerformanceIndexController struct {
	App
}

func CreateAnalyticPerformanceIndexController() *AnalyticPerformanceIndexController {
	var controller = new(AnalyticPerformanceIndexController)
	return controller
}

func (m *AnalyticPerformanceIndexController) GetPerformanceIndex(k *knot.WebContext) interface{} {
	k.Config.OutputType = knot.OutputJson

	type PerformanceDetail struct {
		Turbine                     string
		PerformanceIndex            float64
		PerformanceIndexLast24Hours float64
		PerformanceIndexLastWeek    float64
		PerformanceIndexMTD         float64
		PerformanceIndexYTD         float64
		Production                  float64
		ProductionLast24Hours       float64
		ProductionLastWeek          float64
		ProductionMTD               float64
		ProductionYTD               float64
		Power                       float64
		PowerLast24Hours            float64
		PowerLastWeek               float64
		PowerMTD                    float64
		PowerYTD                    float64
		StartDate                   time.Time
		EndDate                     time.Time
	}

	type Performance struct {
		Project                     string
		PerformanceIndex            float64
		PerformanceIndexLast24Hours float64
		PerformanceIndexLastWeek    float64
		PerformanceIndexMTD         float64
		PerformanceIndexYTD         float64
		Production                  float64
		ProductionLast24Hours       float64
		ProductionLastWeek          float64
		ProductionMTD               float64
		ProductionYTD               float64
		Power                       float64
		PowerLast24Hours            float64
		PowerLastWeek               float64
		PowerMTD                    float64
		PowerYTD                    float64
		StartDate                   time.Time
		EndDate                     time.Time
		Details                     []PerformanceDetail
	}

	p := new(PayloadAnalytic)
	e := k.GetPayload(&p)
	if e != nil {
		return helper.CreateResult(false, nil, e.Error())
	}
	// filter, _ := p.ParseFilter()

	tStart, tEnd, e := helper.GetStartEndDate(k, p.Period, p.DateStart, p.DateEnd)
	if e != nil {
		return helper.CreateResult(false, nil, e.Error())
	}

	turbine := p.Turbine
	project := p.Project

	results := make([]Performance, 0)

	aggrData := []tk.M{}

	for i := 0; i < 5; i++ {
		var filter []*dbox.Filter

		switch i {
		case 3:
			// last24hours
			filter = append(filter, dbox.Gte("dateinfo.dateid", tEnd.Add(time.Hour*24*(-1))))
			break
		case 2:
			// lastweek
			filter = append(filter, dbox.Gte("dateinfo.dateid", tEnd.Add(time.Hour*24*(-7))))
			break
		case 1:
			// mtd
			filter = append(filter, dbox.Gte("dateinfo.dateid", time.Date(tEnd.Year(), tEnd.Month(), 1, 0, 0, 0, 0, tEnd.Location())))
			break
		case 0:
			// ytd
			filter = append(filter, dbox.Gte("dateinfo.dateid", time.Date(tEnd.Year(), 1, 1, 0, 0, 0, 0, tEnd.Location())))
			break
		default:
			// period
			filter = append(filter, dbox.Gte("dateinfo.dateid", tStart))
			break
		}

		filter = append(filter, dbox.Lte("dateinfo.dateid", tEnd))

		if project != "" {
			filter = append(filter, dbox.Eq("projectname", project))
		}

		if len(turbine) != 0 {
			filter = append(filter, dbox.In("turbine", turbine...))
		}

		queryAggr := DB().Connection.NewQuery().From(new(ScadaData).TableName()).
			Aggr(dbox.AggrSum, "$energy", "totalProduction").
			Aggr(dbox.AggrSum, "$power", "totalPower").
			Aggr(dbox.AggrSum, "$denpower", "totaldenPower").
			Group("projectname").Where(dbox.And(filter...))

		caggr, e := queryAggr.Cursor(nil)
		if e != nil {
			return helper.CreateResult(false, nil, e.Error())
		}
		defer caggr.Close()
		e = caggr.Fetch(&aggrData, 0, false)
		if e != nil {
			return helper.CreateResult(false, nil, e.Error())
		}

		var resulttemp Performance

		for _, val := range aggrData {
			switch i {
			case 3:
				// last24hours
				results[len(results)-1].PerformanceIndexLast24Hours = val.GetFloat64("totalPower") / val.GetFloat64("totaldenPower") * 100
				results[len(results)-1].ProductionLast24Hours = val.GetFloat64("totalProduction")
				results[len(results)-1].PowerLast24Hours = val.GetFloat64("totalPower")
				break
			case 2:
				// lastweek
				results[len(results)-1].PerformanceIndexLastWeek = val.GetFloat64("totalPower") / val.GetFloat64("totaldenPower") * 100
				results[len(results)-1].ProductionLastWeek = val.GetFloat64("totalProduction")
				results[len(results)-1].PowerLastWeek = val.GetFloat64("totalPower")
				break
			case 1:
				// mtd
				results[len(results)-1].PerformanceIndexMTD = val.GetFloat64("totalPower") / val.GetFloat64("totaldenPower") * 100
				results[len(results)-1].ProductionMTD = val.GetFloat64("totalProduction")
				results[len(results)-1].PowerMTD = val.GetFloat64("totalPower")
				break
			case 0:
				// ytd
				results = append(results, resulttemp)
				results[len(results)-1].Project = val["_id"].(tk.M)["projectname"].(string)
				results[len(results)-1].PerformanceIndexYTD = val.GetFloat64("totalPower") / val.GetFloat64("totaldenPower") * 100
				results[len(results)-1].ProductionYTD = val.GetFloat64("totalProduction")
				results[len(results)-1].PowerYTD = val.GetFloat64("totalPower")
				results[len(results)-1].StartDate = tStart
				results[len(results)-1].EndDate = tEnd
				break
			default:
				// period
				results[len(results)-1].PerformanceIndex = val.GetFloat64("totalPower") / val.GetFloat64("totaldenPower") * 100
				results[len(results)-1].Production = val.GetFloat64("totalProduction")
				results[len(results)-1].Power = val.GetFloat64("totalPower")
				break
			}
		}
	}

	if len(turbine) == 0 {
		var filter []*dbox.Filter
		filter = append(filter, dbox.Gte("dateinfo.dateid", tStart))
		filter = append(filter, dbox.Lte("dateinfo.dateid", tEnd))

		queryAggr := DB().Connection.NewQuery().From(new(ScadaData).TableName()).
			// Aggr(dbox.AggrMax, "$energy", "energy").
			Group("turbine").Where(dbox.And(filter...))

		caggr, e := queryAggr.Cursor(nil)
		if e != nil {
			return helper.CreateResult(false, nil, e.Error())
		}
		defer caggr.Close()
		e = caggr.Fetch(&aggrData, 0, false)
		if e != nil {
			return helper.CreateResult(false, nil, e.Error())
		}

		for _, val := range aggrData {
			turbine = append(turbine, val["_id"].(tk.M)["turbine"].(string))
		}
	}

	// detail turbines
	for i := 0; i < len(results); i++ {
		for _, valturbine := range turbine {
			for j := 0; j < 5; j++ {
				var filter []*dbox.Filter

				switch j {
				case 3:
					// last24hours
					filter = append(filter, dbox.Gte("dateinfo.dateid", tEnd.Add(time.Hour*24*(-1))))
					break
				case 2:
					// lastweek
					filter = append(filter, dbox.Gte("dateinfo.dateid", tEnd.Add(time.Hour*24*(-7))))
					break
				case 1:
					// mtd
					filter = append(filter, dbox.Gte("dateinfo.dateid", time.Date(tEnd.Year(), tEnd.Month(), 1, 0, 0, 0, 0, tEnd.Location())))
					break
				case 0:
					// ytd
					filter = append(filter, dbox.Gte("dateinfo.dateid", time.Date(tEnd.Year(), 1, 1, 0, 0, 0, 0, tEnd.Location())))
					break
				default:
					// period
					filter = append(filter, dbox.Gte("dateinfo.dateid", tStart))
					break
				}

				filter = append(filter, dbox.Lte("dateinfo.dateid", tEnd))

				// if project != "" {
				filter = append(filter, dbox.Eq("projectname", results[i].Project))
				// }

				// if len(turbine) != 0 {
				filter = append(filter, dbox.In("turbine", valturbine))
				// }

				queryAggr := DB().Connection.NewQuery().From(new(ScadaData).TableName()).
					Aggr(dbox.AggrSum, "$energy", "totalProduction").
					Aggr(dbox.AggrSum, "$power", "totalPower").
					Aggr(dbox.AggrSum, "$denpower", "totaldenPower").
					Group("turbine").Where(dbox.And(filter...))

				caggr, e := queryAggr.Cursor(nil)
				if e != nil {
					return helper.CreateResult(false, nil, e.Error())
				}
				defer caggr.Close()
				e = caggr.Fetch(&aggrData, 0, false)
				if e != nil {
					return helper.CreateResult(false, nil, e.Error())
				}

				// fmt.Println(aggrData)

				var resultdetailtemp PerformanceDetail

				for _, val := range aggrData {
					switch j {
					case 3:
						// last24hours
						results[i].Details[len(results[i].Details)-1].PerformanceIndexLast24Hours = val.GetFloat64("totalPower") / val.GetFloat64("totaldenPower") * 100
						results[i].Details[len(results[i].Details)-1].ProductionLast24Hours = val.GetFloat64("totalProduction")
						results[i].Details[len(results[i].Details)-1].PowerLast24Hours = val.GetFloat64("totalPower")
						break
					case 2:
						// lastweek
						results[i].Details[len(results[i].Details)-1].PerformanceIndexLastWeek = val.GetFloat64("totalPower") / val.GetFloat64("totaldenPower") * 100
						results[i].Details[len(results[i].Details)-1].ProductionLastWeek = val.GetFloat64("totalProduction")
						results[i].Details[len(results[i].Details)-1].PowerLastWeek = val.GetFloat64("totalPower")
						break
					case 1:
						// mtd
						results[i].Details[len(results[i].Details)-1].PerformanceIndexMTD = val.GetFloat64("totalPower") / val.GetFloat64("totaldenPower") * 100
						results[i].Details[len(results[i].Details)-1].ProductionMTD = val.GetFloat64("totalProduction")
						results[i].Details[len(results[i].Details)-1].PowerMTD = val.GetFloat64("totalPower")
						break
					case 0:
						// ytd
						results[i].Details = append(results[i].Details, resultdetailtemp)
						results[i].Details[len(results[i].Details)-1].Turbine = val["_id"].(tk.M)["turbine"].(string)
						results[i].Details[len(results[i].Details)-1].PerformanceIndexYTD = val.GetFloat64("totalPower") / val.GetFloat64("totaldenPower") * 100
						results[i].Details[len(results[i].Details)-1].ProductionYTD = val.GetFloat64("totalProduction")
						results[i].Details[len(results[i].Details)-1].PowerYTD = val.GetFloat64("totalPower")
						results[i].Details[len(results[i].Details)-1].StartDate = tStart
						results[i].Details[len(results[i].Details)-1].EndDate = tEnd
						break
					default:
						// period
						results[i].Details[len(results[i].Details)-1].PerformanceIndex = val.GetFloat64("totalPower") / val.GetFloat64("totaldenPower") * 100
						results[i].Details[len(results[i].Details)-1].Production = val.GetFloat64("totalProduction")
						results[i].Details[len(results[i].Details)-1].Power = val.GetFloat64("totalPower")
						break
					}
				}
			}
		}
	}

	data := struct {
		Data []Performance
	}{
		Data: results,
	}

	return helper.CreateResult(true, data, "success")
}
<commit_msg>Change to average<commit_after>package controller

import (
	. "eaciit/wfdemo-git/library/core"
	. "eaciit/wfdemo-git/library/models"
	"eaciit/wfdemo-git/web/helper"

	"time"

	"github.com/eaciit/dbox"
	"github.com/eaciit/knot/knot.v1"
	tk "github.com/eaciit/toolkit"
)

type AnalyticPerformanceIndexController struct {
	App
}

func CreateAnalyticPerformanceIndexController() *AnalyticPerformanceIndexController {
	var controller = new(AnalyticPerformanceIndexController)
	return controller
}

func (m *AnalyticPerformanceIndexController) GetPerformanceIndex(k *knot.WebContext) interface{} {
	k.Config.OutputType = knot.OutputJson

	type PerformanceDetail struct {
		Turbine                     string
		PerformanceIndex            float64
		PerformanceIndexLast24Hours float64
		PerformanceIndexLastWeek    float64
		PerformanceIndexMTD         float64
		PerformanceIndexYTD         float64
		Production                  float64
		ProductionLast24Hours       float64
		ProductionLastWeek          float64
		ProductionMTD               float64
		ProductionYTD               float64
		Power                       float64
		PowerLast24Hours            float64
		PowerLastWeek               float64
		PowerMTD                    float64
		PowerYTD                    float64
		StartDate                   time.Time
		EndDate                     time.Time
	}

	type Performance struct {
		Project                     string
		PerformanceIndex            float64
		PerformanceIndexLast24Hours float64
		PerformanceIndexLastWeek    float64
		PerformanceIndexMTD         float64
		PerformanceIndexYTD         float64
		Production                  float64
		ProductionLast24Hours       float64
		ProductionLastWeek          float64
		ProductionMTD               float64
		ProductionYTD               float64
		Power                       float64
		PowerLast24Hours            float64
		PowerLastWeek               float64
		PowerMTD                    float64
		PowerYTD                    float64
		StartDate                   time.Time
		EndDate                     time.Time
		Details                     []PerformanceDetail
	}

	p := new(PayloadAnalytic)
	e := k.GetPayload(&p)
	if e != nil {
		return helper.CreateResult(false, nil, e.Error())
	}
	// filter, _ := p.ParseFilter()

	tStart, tEnd, e := helper.GetStartEndDate(k, p.Period, p.DateStart, p.DateEnd)
	if e != nil {
		return helper.CreateResult(false, nil, e.Error())
	}

	turbine := p.Turbine
	project := p.Project

	results := make([]Performance, 0)

	aggrData := []tk.M{}

	for i := 0; i < 5; i++ {
		var filter []*dbox.Filter

		switch i {
		case 3:
			// last24hours
			filter = append(filter, dbox.Gte("dateinfo.dateid", tEnd.Add(time.Hour*24*(-1))))
			break
		case 2:
			// lastweek
			filter = append(filter, dbox.Gte("dateinfo.dateid", tEnd.Add(time.Hour*24*(-7))))
			break
		case 1:
			// mtd
			filter = append(filter, dbox.Gte("dateinfo.dateid", time.Date(tEnd.Year(), tEnd.Month(), 1, 0, 0, 0, 0, tEnd.Location())))
			break
		case 0:
			// ytd
			filter = append(filter, dbox.Gte("dateinfo.dateid", time.Date(tEnd.Year(), 1, 1, 0, 0, 0, 0, tEnd.Location())))
			break
		default:
			// period
			filter = append(filter, dbox.Gte("dateinfo.dateid", tStart))
			break
		}

		filter = append(filter, dbox.Lte("dateinfo.dateid", tEnd))

		if project != "" {
			filter = append(filter, dbox.Eq("projectname", project))
		}

		if len(turbine) != 0 {
			filter = append(filter, dbox.In("turbine", turbine...))
		}

		queryAggr := DB().Connection.NewQuery().From(new(ScadaData).TableName()).
			Aggr(dbox.AggrAvr, "$energy", "totalProduction").
			Aggr(dbox.AggrAvr, "$power", "totalPower").
			Aggr(dbox.AggrAvr, "$denpower", "totaldenPower").
			Group("projectname").Where(dbox.And(filter...))

		caggr, e := queryAggr.Cursor(nil)
		if e != nil {
			return helper.CreateResult(false, nil, e.Error())
		}
		defer caggr.Close()
		e = caggr.Fetch(&aggrData, 0, false)
		if e != nil {
			return helper.CreateResult(false, nil, e.Error())
		}

		var resulttemp Performance

		for _, val := range aggrData {
			switch i {
			case 3:
				// last24hours
				results[len(results)-1].PerformanceIndexLast24Hours = val.GetFloat64("totalPower") / val.GetFloat64("totaldenPower") * 100
				results[len(results)-1].ProductionLast24Hours = val.GetFloat64("totalProduction")
				results[len(results)-1].PowerLast24Hours = val.GetFloat64("totalPower")
				break
			case 2:
				// lastweek
				results[len(results)-1].PerformanceIndexLastWeek = val.GetFloat64("totalPower") / val.GetFloat64("totaldenPower") * 100
				results[len(results)-1].ProductionLastWeek = val.GetFloat64("totalProduction")
				results[len(results)-1].PowerLastWeek = val.GetFloat64("totalPower")
				break
			case 1:
				// mtd
				results[len(results)-1].PerformanceIndexMTD = val.GetFloat64("totalPower") / val.GetFloat64("totaldenPower") * 100
				results[len(results)-1].ProductionMTD = val.GetFloat64("totalProduction")
				results[len(results)-1].PowerMTD = val.GetFloat64("totalPower")
				break
			case 0:
				// ytd
				results = append(results, resulttemp)
				results[len(results)-1].Project = val["_id"].(tk.M)["projectname"].(string)
				results[len(results)-1].PerformanceIndexYTD = val.GetFloat64("totalPower") / val.GetFloat64("totaldenPower") * 100
				results[len(results)-1].ProductionYTD = val.GetFloat64("totalProduction")
				results[len(results)-1].PowerYTD = val.GetFloat64("totalPower")
				results[len(results)-1].StartDate = tStart
				results[len(results)-1].EndDate = tEnd
				break
			default:
				// period
				results[len(results)-1].PerformanceIndex = val.GetFloat64("totalPower") / val.GetFloat64("totaldenPower") * 100
				results[len(results)-1].Production = val.GetFloat64("totalProduction")
				results[len(results)-1].Power = val.GetFloat64("totalPower")
				break
			}
		}
	}

	if len(turbine) == 0 {
		var filter []*dbox.Filter
		filter = append(filter, dbox.Gte("dateinfo.dateid", tStart))
		filter = append(filter, dbox.Lte("dateinfo.dateid", tEnd))

		queryAggr := DB().Connection.NewQuery().From(new(ScadaData).TableName()).
			// Aggr(dbox.AggrMax, "$energy", "energy").
			Group("turbine").Where(dbox.And(filter...))

		caggr, e := queryAggr.Cursor(nil)
		if e != nil {
			return helper.CreateResult(false, nil, e.Error())
		}
		defer caggr.Close()
		e = caggr.Fetch(&aggrData, 0, false)
		if e != nil {
			return helper.CreateResult(false, nil, e.Error())
		}

		for _, val := range aggrData {
			turbine = append(turbine, val["_id"].(tk.M)["turbine"].(string))
		}
	}

	// detail turbines
	for i := 0; i < len(results); i++ {
		for _, valturbine := range turbine {
			for j := 0; j < 5; j++ {
				var filter []*dbox.Filter

				switch j {
				case 3:
					// last24hours
					filter = append(filter, dbox.Gte("dateinfo.dateid", tEnd.Add(time.Hour*24*(-1))))
					break
				case 2:
					// lastweek
					filter = append(filter, dbox.Gte("dateinfo.dateid", tEnd.Add(time.Hour*24*(-7))))
					break
				case 1:
					// mtd
					filter = append(filter, dbox.Gte("dateinfo.dateid", time.Date(tEnd.Year(), tEnd.Month(), 1, 0, 0, 0, 0, tEnd.Location())))
					break
				case 0:
					// ytd
					filter = append(filter, dbox.Gte("dateinfo.dateid", time.Date(tEnd.Year(), 1, 1, 0, 0, 0, 0, tEnd.Location())))
					break
				default:
					// period
					filter = append(filter, dbox.Gte("dateinfo.dateid", tStart))
					break
				}

				filter = append(filter, dbox.Lte("dateinfo.dateid", tEnd))

				// if project != "" {
				filter = append(filter, dbox.Eq("projectname", results[i].Project))
				// }

				// if len(turbine) != 0 {
				filter = append(filter, dbox.In("turbine", valturbine))
				// }

				queryAggr := DB().Connection.NewQuery().From(new(ScadaData).TableName()).
					Aggr(dbox.AggrAvr, "$energy", "totalProduction").
					Aggr(dbox.AggrAvr, "$power", "totalPower").
					Aggr(dbox.AggrAvr, "$denpower", "totaldenPower").
					Group("turbine").Where(dbox.And(filter...))

				caggr, e := queryAggr.Cursor(nil)
				if e != nil {
					return helper.CreateResult(false, nil, e.Error())
				}
				defer caggr.Close()
				e = caggr.Fetch(&aggrData, 0, false)
				if e != nil {
					return helper.CreateResult(false, nil, e.Error())
				}

				// fmt.Println(aggrData)

				var resultdetailtemp PerformanceDetail

				for _, val := range aggrData {
					switch j {
					case 3:
						// last24hours
						results[i].Details[len(results[i].Details)-1].PerformanceIndexLast24Hours = val.GetFloat64("totalPower") / val.GetFloat64("totaldenPower") * 100
						results[i].Details[len(results[i].Details)-1].ProductionLast24Hours = val.GetFloat64("totalProduction")
						results[i].Details[len(results[i].Details)-1].PowerLast24Hours = val.GetFloat64("totalPower")
						break
					case 2:
						// lastweek
						results[i].Details[len(results[i].Details)-1].PerformanceIndexLastWeek = val.GetFloat64("totalPower") / val.GetFloat64("totaldenPower") * 100
						results[i].Details[len(results[i].Details)-1].ProductionLastWeek = val.GetFloat64("totalProduction")
						results[i].Details[len(results[i].Details)-1].PowerLastWeek = val.GetFloat64("totalPower")
						break
					case 1:
						// mtd
						results[i].Details[len(results[i].Details)-1].PerformanceIndexMTD = val.GetFloat64("totalPower") / val.GetFloat64("totaldenPower") * 100
						results[i].Details[len(results[i].Details)-1].ProductionMTD = val.GetFloat64("totalProduction")
						results[i].Details[len(results[i].Details)-1].PowerMTD = val.GetFloat64("totalPower")
						break
					case 0:
						// ytd
						results[i].Details = append(results[i].Details, resultdetailtemp)
						results[i].Details[len(results[i].Details)-1].Turbine = val["_id"].(tk.M)["turbine"].(string)
						results[i].Details[len(results[i].Details)-1].PerformanceIndexYTD = val.GetFloat64("totalPower") / val.GetFloat64("totaldenPower") * 100
						results[i].Details[len(results[i].Details)-1].ProductionYTD = val.GetFloat64("totalProduction")
						results[i].Details[len(results[i].Details)-1].PowerYTD = val.GetFloat64("totalPower")
						results[i].Details[len(results[i].Details)-1].StartDate = tStart
						results[i].Details[len(results[i].Details)-1].EndDate = tEnd
						break
					default:
						// period
						results[i].Details[len(results[i].Details)-1].PerformanceIndex = val.GetFloat64("totalPower") / val.GetFloat64("totaldenPower") * 100
						results[i].Details[len(results[i].Details)-1].Production = val.GetFloat64("totalProduction")
						results[i].Details[len(results[i].Details)-1].Power = val.GetFloat64("totalPower")
						break
					}
				}
			}
		}
	}

	data := struct {
		Data []Performance
	}{
		Data: results,
	}

	return helper.CreateResult(true, data, "success")
}
<|endoftext|>


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

// +build !windows

package procfs

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"regexp"
	"strings"

	"github.com/prometheus/procfs/internal/util"
)

// Zoneinfo holds info parsed from /proc/zoneinfo.
type Zoneinfo struct {
	Node                       string
	Zone                       string
	NrFreePages                *int64
	Min                        *int64
	Low                        *int64
	High                       *int64
	Scanned                    *int64
	Spanned                    *int64
	Present                    *int64
	Managed                    *int64
	NrActiveAnon               *int64
	NrInactiveAnon             *int64
	NrIsolatedAnon             *int64
	NrAnonPages                *int64
	NrAnonTransparentHugepages *int64
	NrActiveFile               *int64
	NrInactiveFile             *int64
	NrIsolatedFile             *int64
	NrFilePages                *int64
	NrSlabReclaimable          *int64
	NrSlabUnreclaimable        *int64
	NrMlockStack               *int64
	NrKernelStack              *int64
	NrMapped                   *int64
	NrDirty                    *int64
	NrWriteback                *int64
	NrUnevictable              *int64
	NrShmem                    *int64
	NrDirtied                  *int64
	NrWritten                  *int64
	NumaHit                    *int64
	NumaMiss                   *int64
	NumaForeign                *int64
	NumaInterleave             *int64
	NumaLocal                  *int64
	NumaOther                  *int64
	Protection                 []*int64
}

// Zoneinfo parses an zoneinfo-file (/proc/zoneinfo) and returns a slice of
// structs containing the relevant info.  More information available here:
// https://github.com/torvalds/linux/blob/master/Documentation/sysctl/vm.txt
func (fs FS) Zoneinfo() ([]Zoneinfo, error) {
	data, err := ioutil.ReadFile(fs.proc.Path("zoneinfo"))
	if err != nil {
		return nil, fmt.Errorf("error parsing zoneinfo %s: %s", fs.proc.Path("zoneinfo"), err)
	}
	zoneinfo, err := parseZoneinfo(data)
	if err != nil {
		return nil, fmt.Errorf("error parsing zoneinfo %s: %s", fs.proc.Path("zoneinfo"), err)
	}
	return zoneinfo, nil
}

func parseZoneinfo(zoneinfoData []byte) ([]Zoneinfo, error) {
	var nodeZoneRE = regexp.MustCompile(`Node (\d+), zone\s+(\w+)`)

	zoneinfo := []Zoneinfo{}

	cryptoBlocks := bytes.Split(zoneinfoData, []byte("\nNode"))
	for _, block := range cryptoBlocks {
		var zoneinfoElement Zoneinfo
		blockComplete := []byte("Node")
		blockComplete = append(blockComplete, block...)
		lines := strings.Split(string(blockComplete), "\n")
		for _, line := range lines {

			if nodeZone := nodeZoneRE.FindStringSubmatch(line); nodeZone != nil {
				zoneinfoElement.Node = nodeZone[1]
				zoneinfoElement.Zone = nodeZone[2]
				continue
			}
			if strings.HasPrefix(strings.TrimSpace(line), "per-node stats") {
				zoneinfoElement.Zone = ""
				continue
			}
			parts := strings.Fields(strings.TrimSpace(line))
			if len(parts) < 2 {
				continue
			}
			vp := util.NewValueParser(parts[1])
			switch parts[0] {
			case "nr_free_pages":
				zoneinfoElement.NrFreePages = vp.PInt64()
			case "min":
				zoneinfoElement.Min = vp.PInt64()
			case "low":
				zoneinfoElement.Low = vp.PInt64()
			case "high":
				zoneinfoElement.High = vp.PInt64()
			case "scanned":
				zoneinfoElement.Scanned = vp.PInt64()
			case "spanned":
				zoneinfoElement.Spanned = vp.PInt64()
			case "present":
				zoneinfoElement.Present = vp.PInt64()
			case "managed":
				zoneinfoElement.Managed = vp.PInt64()
			case "nr_active_anon":
				zoneinfoElement.NrActiveAnon = vp.PInt64()
			case "nr_inactive_anon":
				zoneinfoElement.NrInactiveAnon = vp.PInt64()
			case "nr_isolated_anon":
				zoneinfoElement.NrIsolatedAnon = vp.PInt64()
			case "nr_anon_pages":
				zoneinfoElement.NrAnonPages = vp.PInt64()
			case "nr_anon_transparent_hugepages":
				zoneinfoElement.NrAnonTransparentHugepages = vp.PInt64()
			case "nr_active_file":
				zoneinfoElement.NrActiveFile = vp.PInt64()
			case "nr_inactive_file":
				zoneinfoElement.NrInactiveFile = vp.PInt64()
			case "nr_isolated_file":
				zoneinfoElement.NrIsolatedFile = vp.PInt64()
			case "nr_file_pages":
				zoneinfoElement.NrFilePages = vp.PInt64()
			case "nr_slab_reclaimable":
				zoneinfoElement.NrSlabReclaimable = vp.PInt64()
			case "nr_slab_unreclaimable":
				zoneinfoElement.NrSlabUnreclaimable = vp.PInt64()
			case "nr_mlock_stack":
				zoneinfoElement.NrMlockStack = vp.PInt64()
			case "nr_kernel_stack":
				zoneinfoElement.NrKernelStack = vp.PInt64()
			case "nr_mapped":
				zoneinfoElement.NrMapped = vp.PInt64()
			case "nr_dirty":
				zoneinfoElement.NrDirty = vp.PInt64()
			case "nr_writeback":
				zoneinfoElement.NrWriteback = vp.PInt64()
			case "nr_unevictable":
				zoneinfoElement.NrUnevictable = vp.PInt64()
			case "nr_shmem":
				zoneinfoElement.NrShmem = vp.PInt64()
			case "nr_dirtied":
				zoneinfoElement.NrDirtied = vp.PInt64()
			case "nr_written":
				zoneinfoElement.NrWritten = vp.PInt64()
			case "numa_hit":
				zoneinfoElement.NumaHit = vp.PInt64()
			case "numa_miss":
				zoneinfoElement.NumaMiss = vp.PInt64()
			case "numa_foreign":
				zoneinfoElement.NumaForeign = vp.PInt64()
			case "numa_interleave":
				zoneinfoElement.NumaInterleave = vp.PInt64()
			case "numa_local":
				zoneinfoElement.NumaLocal = vp.PInt64()
			case "numa_other":
				zoneinfoElement.NumaOther = vp.PInt64()
			case "protection:":
				protectionParts := strings.Split(line, ":")
				protectionValues := strings.Replace(protectionParts[1], "(", "", 1)
				protectionValues = strings.Replace(protectionValues, ")", "", 1)
				protectionValues = strings.TrimSpace(protectionValues)
				protectionStringMap := strings.Split(protectionValues, ", ")
				val, err := util.ParsePInt64s(protectionStringMap)
				if err == nil {
					zoneinfoElement.Protection = val
				}
			}

		}

		zoneinfo = append(zoneinfo, zoneinfoElement)
	}
	return zoneinfo, nil
}
<commit_msg>address review on !195<commit_after>// Copyright 2019 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// +build !windows

package procfs

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"regexp"
	"strings"

	"github.com/prometheus/procfs/internal/util"
)

// Zoneinfo holds info parsed from /proc/zoneinfo.
type Zoneinfo struct {
	Node                       string
	Zone                       string
	NrFreePages                *int64
	Min                        *int64
	Low                        *int64
	High                       *int64
	Scanned                    *int64
	Spanned                    *int64
	Present                    *int64
	Managed                    *int64
	NrActiveAnon               *int64
	NrInactiveAnon             *int64
	NrIsolatedAnon             *int64
	NrAnonPages                *int64
	NrAnonTransparentHugepages *int64
	NrActiveFile               *int64
	NrInactiveFile             *int64
	NrIsolatedFile             *int64
	NrFilePages                *int64
	NrSlabReclaimable          *int64
	NrSlabUnreclaimable        *int64
	NrMlockStack               *int64
	NrKernelStack              *int64
	NrMapped                   *int64
	NrDirty                    *int64
	NrWriteback                *int64
	NrUnevictable              *int64
	NrShmem                    *int64
	NrDirtied                  *int64
	NrWritten                  *int64
	NumaHit                    *int64
	NumaMiss                   *int64
	NumaForeign                *int64
	NumaInterleave             *int64
	NumaLocal                  *int64
	NumaOther                  *int64
	Protection                 []*int64
}

var nodeZoneRE = regexp.MustCompile(`(\d+), zone\s+(\w+)`)

// Zoneinfo parses an zoneinfo-file (/proc/zoneinfo) and returns a slice of
// structs containing the relevant info.  More information available here:
// https://www.kernel.org/doc/Documentation/sysctl/vm.txt
func (fs FS) Zoneinfo() ([]Zoneinfo, error) {
	data, err := ioutil.ReadFile(fs.proc.Path("zoneinfo"))
	if err != nil {
		return nil, fmt.Errorf("error reading zoneinfo %s: %s", fs.proc.Path("zoneinfo"), err)
	}
	zoneinfo, err := parseZoneinfo(data)
	if err != nil {
		return nil, fmt.Errorf("error parsing zoneinfo %s: %s", fs.proc.Path("zoneinfo"), err)
	}
	return zoneinfo, nil
}

func parseZoneinfo(zoneinfoData []byte) ([]Zoneinfo, error) {

	zoneinfo := []Zoneinfo{}

	zoneinfoBlocks := bytes.Split(zoneinfoData, []byte("\nNode"))
	for _, block := range zoneinfoBlocks {
		var zoneinfoElement Zoneinfo
		lines := strings.Split(string(block), "\n")
		for _, line := range lines {

			if nodeZone := nodeZoneRE.FindStringSubmatch(line); nodeZone != nil {
				zoneinfoElement.Node = nodeZone[1]
				zoneinfoElement.Zone = nodeZone[2]
				continue
			}
			if strings.HasPrefix(strings.TrimSpace(line), "per-node stats") {
				zoneinfoElement.Zone = ""
				continue
			}
			parts := strings.Fields(strings.TrimSpace(line))
			if len(parts) < 2 {
				continue
			}
			vp := util.NewValueParser(parts[1])
			switch parts[0] {
			case "nr_free_pages":
				zoneinfoElement.NrFreePages = vp.PInt64()
			case "min":
				zoneinfoElement.Min = vp.PInt64()
			case "low":
				zoneinfoElement.Low = vp.PInt64()
			case "high":
				zoneinfoElement.High = vp.PInt64()
			case "scanned":
				zoneinfoElement.Scanned = vp.PInt64()
			case "spanned":
				zoneinfoElement.Spanned = vp.PInt64()
			case "present":
				zoneinfoElement.Present = vp.PInt64()
			case "managed":
				zoneinfoElement.Managed = vp.PInt64()
			case "nr_active_anon":
				zoneinfoElement.NrActiveAnon = vp.PInt64()
			case "nr_inactive_anon":
				zoneinfoElement.NrInactiveAnon = vp.PInt64()
			case "nr_isolated_anon":
				zoneinfoElement.NrIsolatedAnon = vp.PInt64()
			case "nr_anon_pages":
				zoneinfoElement.NrAnonPages = vp.PInt64()
			case "nr_anon_transparent_hugepages":
				zoneinfoElement.NrAnonTransparentHugepages = vp.PInt64()
			case "nr_active_file":
				zoneinfoElement.NrActiveFile = vp.PInt64()
			case "nr_inactive_file":
				zoneinfoElement.NrInactiveFile = vp.PInt64()
			case "nr_isolated_file":
				zoneinfoElement.NrIsolatedFile = vp.PInt64()
			case "nr_file_pages":
				zoneinfoElement.NrFilePages = vp.PInt64()
			case "nr_slab_reclaimable":
				zoneinfoElement.NrSlabReclaimable = vp.PInt64()
			case "nr_slab_unreclaimable":
				zoneinfoElement.NrSlabUnreclaimable = vp.PInt64()
			case "nr_mlock_stack":
				zoneinfoElement.NrMlockStack = vp.PInt64()
			case "nr_kernel_stack":
				zoneinfoElement.NrKernelStack = vp.PInt64()
			case "nr_mapped":
				zoneinfoElement.NrMapped = vp.PInt64()
			case "nr_dirty":
				zoneinfoElement.NrDirty = vp.PInt64()
			case "nr_writeback":
				zoneinfoElement.NrWriteback = vp.PInt64()
			case "nr_unevictable":
				zoneinfoElement.NrUnevictable = vp.PInt64()
			case "nr_shmem":
				zoneinfoElement.NrShmem = vp.PInt64()
			case "nr_dirtied":
				zoneinfoElement.NrDirtied = vp.PInt64()
			case "nr_written":
				zoneinfoElement.NrWritten = vp.PInt64()
			case "numa_hit":
				zoneinfoElement.NumaHit = vp.PInt64()
			case "numa_miss":
				zoneinfoElement.NumaMiss = vp.PInt64()
			case "numa_foreign":
				zoneinfoElement.NumaForeign = vp.PInt64()
			case "numa_interleave":
				zoneinfoElement.NumaInterleave = vp.PInt64()
			case "numa_local":
				zoneinfoElement.NumaLocal = vp.PInt64()
			case "numa_other":
				zoneinfoElement.NumaOther = vp.PInt64()
			case "protection:":
				protectionParts := strings.Split(line, ":")
				protectionValues := strings.Replace(protectionParts[1], "(", "", 1)
				protectionValues = strings.Replace(protectionValues, ")", "", 1)
				protectionValues = strings.TrimSpace(protectionValues)
				protectionStringMap := strings.Split(protectionValues, ", ")
				val, err := util.ParsePInt64s(protectionStringMap)
				if err == nil {
					zoneinfoElement.Protection = val
				}
			}

		}

		zoneinfo = append(zoneinfo, zoneinfoElement)
	}
	return zoneinfo, nil
}
<|endoftext|>


<commit_before>package docker

import (
	"fmt"
	"io"
	"io/ioutil"
	"strings"
	"testing"
	"time"
)

func TestStart(t *testing.T) {
	docker, err := newTestDocker()
	if err != nil {
		t.Fatal(err)
	}
	container, err := docker.Create(
		"start_test",
		"ls",
		[]string{"-al"},
		[]string{"/var/lib/docker/images/ubuntu"},
		&Config{
			Ram: 33554432,
		},
	)
	if err != nil {
		t.Fatal(err)
	}
	defer docker.Destroy(container)

	if container.State.Running {
		t.Errorf("Container shouldn't be running")
	}
	if err := container.Start(); err != nil {
		t.Fatal(err)
	}
	container.Wait()
	if container.State.Running {
		t.Errorf("Container shouldn't be running")
	}
	// We should be able to call Wait again
	container.Wait()
	if container.State.Running {
		t.Errorf("Container shouldn't be running")
	}
}

func TestRun(t *testing.T) {
	docker, err := newTestDocker()
	if err != nil {
		t.Fatal(err)
	}
	container, err := docker.Create(
		"run_test",
		"ls",
		[]string{"-al"},
		[]string{"/var/lib/docker/images/ubuntu"},
		&Config{
			Ram: 33554432,
		},
	)
	if err != nil {
		t.Fatal(err)
	}
	defer docker.Destroy(container)

	if container.State.Running {
		t.Errorf("Container shouldn't be running")
	}
	if err := container.Run(); err != nil {
		t.Fatal(err)
	}
	if container.State.Running {
		t.Errorf("Container shouldn't be running")
	}
}

func TestOutput(t *testing.T) {
	docker, err := newTestDocker()
	if err != nil {
		t.Fatal(err)
	}
	container, err := docker.Create(
		"output_test",
		"echo",
		[]string{"-n", "foobar"},
		[]string{"/var/lib/docker/images/ubuntu"},
		&Config{},
	)
	if err != nil {
		t.Fatal(err)
	}
	defer docker.Destroy(container)
	output, err := container.Output()
	if err != nil {
		t.Fatal(err)
	}
	if string(output) != "foobar" {
		t.Error(string(output))
	}
}

func TestKill(t *testing.T) {
	docker, err := newTestDocker()
	if err != nil {
		t.Fatal(err)
	}
	container, err := docker.Create(
		"stop_test",
		"cat",
		[]string{"/dev/zero"},
		[]string{"/var/lib/docker/images/ubuntu"},
		&Config{},
	)
	if err != nil {
		t.Fatal(err)
	}
	defer docker.Destroy(container)

	if container.State.Running {
		t.Errorf("Container shouldn't be running")
	}
	if err := container.Start(); err != nil {
		t.Fatal(err)
	}
	if !container.State.Running {
		t.Errorf("Container should be running")
	}
	if err := container.Kill(); err != nil {
		t.Fatal(err)
	}
	if container.State.Running {
		t.Errorf("Container shouldn't be running")
	}
	container.Wait()
	if container.State.Running {
		t.Errorf("Container shouldn't be running")
	}
	// Try stopping twice
	if err := container.Kill(); err != nil {
		t.Fatal(err)
	}
}

func TestExitCode(t *testing.T) {
	docker, err := newTestDocker()
	if err != nil {
		t.Fatal(err)
	}

	trueContainer, err := docker.Create(
		"exit_test_1",
		"/bin/true",
		[]string{""},
		[]string{"/var/lib/docker/images/ubuntu"},
		&Config{},
	)
	if err != nil {
		t.Fatal(err)
	}
	defer docker.Destroy(trueContainer)
	if err := trueContainer.Run(); err != nil {
		t.Fatal(err)
	}

	falseContainer, err := docker.Create(
		"exit_test_2",
		"/bin/false",
		[]string{""},
		[]string{"/var/lib/docker/images/ubuntu"},
		&Config{},
	)
	if err != nil {
		t.Fatal(err)
	}
	defer docker.Destroy(falseContainer)
	if err := falseContainer.Run(); err != nil {
		t.Fatal(err)
	}

	if trueContainer.State.ExitCode != 0 {
		t.Errorf("Unexpected exit code %v", trueContainer.State.ExitCode)
	}

	if falseContainer.State.ExitCode != 1 {
		t.Errorf("Unexpected exit code %v", falseContainer.State.ExitCode)
	}
}

func TestUser(t *testing.T) {
	docker, err := newTestDocker()
	if err != nil {
		t.Fatal(err)
	}

	// Default user must be root
	container, err := docker.Create(
		"user_default",
		"id",
		[]string{},
		[]string{"/var/lib/docker/images/ubuntu"},
		&Config{},
	)
	if err != nil {
		t.Fatal(err)
	}
	defer docker.Destroy(container)
	output, err := container.Output()
	if err != nil {
		t.Fatal(err)
	}
	if !strings.Contains(string(output), "uid=0(root) gid=0(root)") {
		t.Error(string(output))
	}

	// Set a username
	container, err = docker.Create(
		"user_root",
		"id",
		[]string{},
		[]string{"/var/lib/docker/images/ubuntu"},
		&Config{
			User: "root",
		},
	)
	if err != nil {
		t.Fatal(err)
	}
	defer docker.Destroy(container)
	output, err = container.Output()
	if err != nil {
		t.Fatal(err)
	}
	if !strings.Contains(string(output), "uid=0(root) gid=0(root)") {
		t.Error(string(output))
	}

	// Set a UID
	container, err = docker.Create(
		"user_uid0",
		"id",
		[]string{},
		[]string{"/var/lib/docker/images/ubuntu"},
		&Config{
			User: "0",
		},
	)
	if err != nil {
		t.Fatal(err)
	}
	defer docker.Destroy(container)
	output, err = container.Output()
	if err != nil {
		t.Fatal(err)
	}
	if !strings.Contains(string(output), "uid=0(root) gid=0(root)") {
		t.Error(string(output))
	}

	// Set a different user by uid
	container, err = docker.Create(
		"user_uid1",
		"id",
		[]string{},
		[]string{"/var/lib/docker/images/ubuntu"},
		&Config{
			User: "1",
		},
	)
	if err != nil {
		t.Fatal(err)
	}
	defer docker.Destroy(container)
	output, err = container.Output()
	if err != nil {
		t.Fatal(err)
	}
	if !strings.Contains(string(output), "uid=1(daemon) gid=1(daemon)") {
		t.Error(string(output))
	}

	// Set a different user by username
	container, err = docker.Create(
		"user_daemon",
		"id",
		[]string{},
		[]string{"/var/lib/docker/images/ubuntu"},
		&Config{
			User: "daemon",
		},
	)
	if err != nil {
		t.Fatal(err)
	}
	defer docker.Destroy(container)
	output, err = container.Output()
	if err != nil {
		t.Fatal(err)
	}
	if !strings.Contains(string(output), "uid=1(daemon) gid=1(daemon)") {
		t.Error(string(output))
	}
}

func TestMultipleContainers(t *testing.T) {
	docker, err := newTestDocker()
	if err != nil {
		t.Fatal(err)
	}

	container1, err := docker.Create(
		"container1",
		"cat",
		[]string{"/dev/zero"},
		[]string{"/var/lib/docker/images/ubuntu"},
		&Config{},
	)
	if err != nil {
		t.Fatal(err)
	}
	defer docker.Destroy(container1)

	container2, err := docker.Create(
		"container2",
		"cat",
		[]string{"/dev/zero"},
		[]string{"/var/lib/docker/images/ubuntu"},
		&Config{},
	)
	if err != nil {
		t.Fatal(err)
	}
	defer docker.Destroy(container2)

	// Start both containers
	if err := container1.Start(); err != nil {
		t.Fatal(err)
	}
	if err := container2.Start(); err != nil {
		t.Fatal(err)
	}

	// If we are here, both containers should be running
	if !container1.State.Running {
		t.Fatal("Container not running")
	}
	if !container2.State.Running {
		t.Fatal("Container not running")
	}

	// Kill them
	if err := container1.Kill(); err != nil {
		t.Fatal(err)
	}

	if err := container2.Kill(); err != nil {
		t.Fatal(err)
	}
}

func TestStdin(t *testing.T) {
	docker, err := newTestDocker()
	if err != nil {
		t.Fatal(err)
	}
	container, err := docker.Create(
		"stdin_test",
		"cat",
		[]string{},
		[]string{"/var/lib/docker/images/ubuntu"},
		&Config{
			OpenStdin: true,
		},
	)
	if err != nil {
		t.Fatal(err)
	}
	defer docker.Destroy(container)

	stdin, err := container.StdinPipe()
	stdout, err := container.StdoutPipe()
	defer stdin.Close()
	defer stdout.Close()
	if err := container.Start(); err != nil {
		t.Fatal(err)
	}
	io.WriteString(stdin, "hello world")
	stdin.Close()
	container.Wait()
	output, err := ioutil.ReadAll(stdout)
	if string(output) != "hello world" {
		t.Fatal(string(output))
	}
}

func TestTty(t *testing.T) {
	docker, err := newTestDocker()
	if err != nil {
		t.Fatal(err)
	}
	container, err := docker.Create(
		"tty_test",
		"cat",
		[]string{},
		[]string{"/var/lib/docker/images/ubuntu"},
		&Config{
			OpenStdin: true,
		},
	)
	if err != nil {
		t.Fatal(err)
	}
	defer docker.Destroy(container)

	stdin, err := container.StdinPipe()
	stdout, err := container.StdoutPipe()
	defer stdin.Close()
	defer stdout.Close()
	if err := container.Start(); err != nil {
		t.Fatal(err)
	}
	io.WriteString(stdin, "hello world")
	stdin.Close()
	container.Wait()
	output, err := ioutil.ReadAll(stdout)
	if string(output) != "hello world" {
		t.Fatal(string(output))
	}
}

func BenchmarkRunSequencial(b *testing.B) {
	docker, err := newTestDocker()
	if err != nil {
		b.Fatal(err)
	}
	for i := 0; i < b.N; i++ {
		container, err := docker.Create(
			fmt.Sprintf("bench_%v", i),
			"echo",
			[]string{"-n", "foo"},
			[]string{"/var/lib/docker/images/ubuntu"},
			&Config{},
		)
		if err != nil {
			b.Fatal(err)
		}
		defer docker.Destroy(container)
		output, err := container.Output()
		if err != nil {
			b.Fatal(err)
		}
		if string(output) != "foo" {
			b.Fatalf("Unexecpted output: %v", string(output))
		}
		if err := docker.Destroy(container); err != nil {
			b.Fatal(err)
		}
	}
}

func BenchmarkRunParallel(b *testing.B) {
	docker, err := newTestDocker()
	if err != nil {
		b.Fatal(err)
	}

	var tasks []chan error

	for i := 0; i < b.N; i++ {
		complete := make(chan error)
		tasks = append(tasks, complete)
		go func(i int, complete chan error) {
			container, err := docker.Create(
				fmt.Sprintf("bench_%v", i),
				"echo",
				[]string{"-n", "foo"},
				[]string{"/var/lib/docker/images/ubuntu"},
				&Config{},
			)
			if err != nil {
				complete <- err
				return
			}
			defer docker.Destroy(container)
			if err := container.Start(); err != nil {
				complete <- err
				return
			}
			if err := container.WaitTimeout(15 * time.Second); err != nil {
				complete <- err
				return
			}
			// if string(output) != "foo" {
			// 	complete <- fmt.Errorf("Unexecpted output: %v", string(output))
			// }
			if err := docker.Destroy(container); err != nil {
				complete <- err
				return
			}
			complete <- nil
		}(i, complete)
	}
	var errors []error
	for _, task := range tasks {
		err := <-task
		if err != nil {
			errors = append(errors, err)
		}
	}
	if len(errors) > 0 {
		b.Fatal(errors)
	}
}
<commit_msg>Added a restart test to ensure a container can be successfully run twice<commit_after>package docker

import (
	"fmt"
	"io"
	"io/ioutil"
	"strings"
	"testing"
	"time"
)

func TestStart(t *testing.T) {
	docker, err := newTestDocker()
	if err != nil {
		t.Fatal(err)
	}
	container, err := docker.Create(
		"start_test",
		"ls",
		[]string{"-al"},
		[]string{"/var/lib/docker/images/ubuntu"},
		&Config{
			Ram: 33554432,
		},
	)
	if err != nil {
		t.Fatal(err)
	}
	defer docker.Destroy(container)

	if container.State.Running {
		t.Errorf("Container shouldn't be running")
	}
	if err := container.Start(); err != nil {
		t.Fatal(err)
	}
	container.Wait()
	if container.State.Running {
		t.Errorf("Container shouldn't be running")
	}
	// We should be able to call Wait again
	container.Wait()
	if container.State.Running {
		t.Errorf("Container shouldn't be running")
	}
}

func TestRun(t *testing.T) {
	docker, err := newTestDocker()
	if err != nil {
		t.Fatal(err)
	}
	container, err := docker.Create(
		"run_test",
		"ls",
		[]string{"-al"},
		[]string{"/var/lib/docker/images/ubuntu"},
		&Config{
			Ram: 33554432,
		},
	)
	if err != nil {
		t.Fatal(err)
	}
	defer docker.Destroy(container)

	if container.State.Running {
		t.Errorf("Container shouldn't be running")
	}
	if err := container.Run(); err != nil {
		t.Fatal(err)
	}
	if container.State.Running {
		t.Errorf("Container shouldn't be running")
	}
}

func TestOutput(t *testing.T) {
	docker, err := newTestDocker()
	if err != nil {
		t.Fatal(err)
	}
	container, err := docker.Create(
		"output_test",
		"echo",
		[]string{"-n", "foobar"},
		[]string{"/var/lib/docker/images/ubuntu"},
		&Config{},
	)
	if err != nil {
		t.Fatal(err)
	}
	defer docker.Destroy(container)
	output, err := container.Output()
	if err != nil {
		t.Fatal(err)
	}
	if string(output) != "foobar" {
		t.Error(string(output))
	}
}

func TestKill(t *testing.T) {
	docker, err := newTestDocker()
	if err != nil {
		t.Fatal(err)
	}
	container, err := docker.Create(
		"stop_test",
		"cat",
		[]string{"/dev/zero"},
		[]string{"/var/lib/docker/images/ubuntu"},
		&Config{},
	)
	if err != nil {
		t.Fatal(err)
	}
	defer docker.Destroy(container)

	if container.State.Running {
		t.Errorf("Container shouldn't be running")
	}
	if err := container.Start(); err != nil {
		t.Fatal(err)
	}
	if !container.State.Running {
		t.Errorf("Container should be running")
	}
	if err := container.Kill(); err != nil {
		t.Fatal(err)
	}
	if container.State.Running {
		t.Errorf("Container shouldn't be running")
	}
	container.Wait()
	if container.State.Running {
		t.Errorf("Container shouldn't be running")
	}
	// Try stopping twice
	if err := container.Kill(); err != nil {
		t.Fatal(err)
	}
}

func TestExitCode(t *testing.T) {
	docker, err := newTestDocker()
	if err != nil {
		t.Fatal(err)
	}

	trueContainer, err := docker.Create(
		"exit_test_1",
		"/bin/true",
		[]string{""},
		[]string{"/var/lib/docker/images/ubuntu"},
		&Config{},
	)
	if err != nil {
		t.Fatal(err)
	}
	defer docker.Destroy(trueContainer)
	if err := trueContainer.Run(); err != nil {
		t.Fatal(err)
	}

	falseContainer, err := docker.Create(
		"exit_test_2",
		"/bin/false",
		[]string{""},
		[]string{"/var/lib/docker/images/ubuntu"},
		&Config{},
	)
	if err != nil {
		t.Fatal(err)
	}
	defer docker.Destroy(falseContainer)
	if err := falseContainer.Run(); err != nil {
		t.Fatal(err)
	}

	if trueContainer.State.ExitCode != 0 {
		t.Errorf("Unexpected exit code %v", trueContainer.State.ExitCode)
	}

	if falseContainer.State.ExitCode != 1 {
		t.Errorf("Unexpected exit code %v", falseContainer.State.ExitCode)
	}
}

func TestRestart(t *testing.T) {
	docker, err := newTestDocker()
	if err != nil {
		t.Fatal(err)
	}
	container, err := docker.Create(
		"restart_test",
		"echo",
		[]string{"-n", "foobar"},
		[]string{"/var/lib/docker/images/ubuntu"},
		&Config{},
	)
	if err != nil {
		t.Fatal(err)
	}
	defer docker.Destroy(container)
	output, err := container.Output()
	if err != nil {
		t.Fatal(err)
	}
	if string(output) != "foobar" {
		t.Error(string(output))
	}

	// Run the container again and check the output
	output, err = container.Output()
	if err != nil {
		t.Fatal(err)
	}
	if string(output) != "foobar" {
		t.Error(string(output))
	}
}

func TestUser(t *testing.T) {
	docker, err := newTestDocker()
	if err != nil {
		t.Fatal(err)
	}

	// Default user must be root
	container, err := docker.Create(
		"user_default",
		"id",
		[]string{},
		[]string{"/var/lib/docker/images/ubuntu"},
		&Config{},
	)
	if err != nil {
		t.Fatal(err)
	}
	defer docker.Destroy(container)
	output, err := container.Output()
	if err != nil {
		t.Fatal(err)
	}
	if !strings.Contains(string(output), "uid=0(root) gid=0(root)") {
		t.Error(string(output))
	}

	// Set a username
	container, err = docker.Create(
		"user_root",
		"id",
		[]string{},
		[]string{"/var/lib/docker/images/ubuntu"},
		&Config{
			User: "root",
		},
	)
	if err != nil {
		t.Fatal(err)
	}
	defer docker.Destroy(container)
	output, err = container.Output()
	if err != nil {
		t.Fatal(err)
	}
	if !strings.Contains(string(output), "uid=0(root) gid=0(root)") {
		t.Error(string(output))
	}

	// Set a UID
	container, err = docker.Create(
		"user_uid0",
		"id",
		[]string{},
		[]string{"/var/lib/docker/images/ubuntu"},
		&Config{
			User: "0",
		},
	)
	if err != nil {
		t.Fatal(err)
	}
	defer docker.Destroy(container)
	output, err = container.Output()
	if err != nil {
		t.Fatal(err)
	}
	if !strings.Contains(string(output), "uid=0(root) gid=0(root)") {
		t.Error(string(output))
	}

	// Set a different user by uid
	container, err = docker.Create(
		"user_uid1",
		"id",
		[]string{},
		[]string{"/var/lib/docker/images/ubuntu"},
		&Config{
			User: "1",
		},
	)
	if err != nil {
		t.Fatal(err)
	}
	defer docker.Destroy(container)
	output, err = container.Output()
	if err != nil {
		t.Fatal(err)
	}
	if !strings.Contains(string(output), "uid=1(daemon) gid=1(daemon)") {
		t.Error(string(output))
	}

	// Set a different user by username
	container, err = docker.Create(
		"user_daemon",
		"id",
		[]string{},
		[]string{"/var/lib/docker/images/ubuntu"},
		&Config{
			User: "daemon",
		},
	)
	if err != nil {
		t.Fatal(err)
	}
	defer docker.Destroy(container)
	output, err = container.Output()
	if err != nil {
		t.Fatal(err)
	}
	if !strings.Contains(string(output), "uid=1(daemon) gid=1(daemon)") {
		t.Error(string(output))
	}
}

func TestMultipleContainers(t *testing.T) {
	docker, err := newTestDocker()
	if err != nil {
		t.Fatal(err)
	}

	container1, err := docker.Create(
		"container1",
		"cat",
		[]string{"/dev/zero"},
		[]string{"/var/lib/docker/images/ubuntu"},
		&Config{},
	)
	if err != nil {
		t.Fatal(err)
	}
	defer docker.Destroy(container1)

	container2, err := docker.Create(
		"container2",
		"cat",
		[]string{"/dev/zero"},
		[]string{"/var/lib/docker/images/ubuntu"},
		&Config{},
	)
	if err != nil {
		t.Fatal(err)
	}
	defer docker.Destroy(container2)

	// Start both containers
	if err := container1.Start(); err != nil {
		t.Fatal(err)
	}
	if err := container2.Start(); err != nil {
		t.Fatal(err)
	}

	// If we are here, both containers should be running
	if !container1.State.Running {
		t.Fatal("Container not running")
	}
	if !container2.State.Running {
		t.Fatal("Container not running")
	}

	// Kill them
	if err := container1.Kill(); err != nil {
		t.Fatal(err)
	}

	if err := container2.Kill(); err != nil {
		t.Fatal(err)
	}
}

func TestStdin(t *testing.T) {
	docker, err := newTestDocker()
	if err != nil {
		t.Fatal(err)
	}
	container, err := docker.Create(
		"stdin_test",
		"cat",
		[]string{},
		[]string{"/var/lib/docker/images/ubuntu"},
		&Config{
			OpenStdin: true,
		},
	)
	if err != nil {
		t.Fatal(err)
	}
	defer docker.Destroy(container)

	stdin, err := container.StdinPipe()
	stdout, err := container.StdoutPipe()
	defer stdin.Close()
	defer stdout.Close()
	if err := container.Start(); err != nil {
		t.Fatal(err)
	}
	io.WriteString(stdin, "hello world")
	stdin.Close()
	container.Wait()
	output, err := ioutil.ReadAll(stdout)
	if string(output) != "hello world" {
		t.Fatal(string(output))
	}
}

func TestTty(t *testing.T) {
	docker, err := newTestDocker()
	if err != nil {
		t.Fatal(err)
	}
	container, err := docker.Create(
		"tty_test",
		"cat",
		[]string{},
		[]string{"/var/lib/docker/images/ubuntu"},
		&Config{
			OpenStdin: true,
		},
	)
	if err != nil {
		t.Fatal(err)
	}
	defer docker.Destroy(container)

	stdin, err := container.StdinPipe()
	stdout, err := container.StdoutPipe()
	defer stdin.Close()
	defer stdout.Close()
	if err := container.Start(); err != nil {
		t.Fatal(err)
	}
	io.WriteString(stdin, "hello world")
	stdin.Close()
	container.Wait()
	output, err := ioutil.ReadAll(stdout)
	if string(output) != "hello world" {
		t.Fatal(string(output))
	}
}

func BenchmarkRunSequencial(b *testing.B) {
	docker, err := newTestDocker()
	if err != nil {
		b.Fatal(err)
	}
	for i := 0; i < b.N; i++ {
		container, err := docker.Create(
			fmt.Sprintf("bench_%v", i),
			"echo",
			[]string{"-n", "foo"},
			[]string{"/var/lib/docker/images/ubuntu"},
			&Config{},
		)
		if err != nil {
			b.Fatal(err)
		}
		defer docker.Destroy(container)
		output, err := container.Output()
		if err != nil {
			b.Fatal(err)
		}
		if string(output) != "foo" {
			b.Fatalf("Unexecpted output: %v", string(output))
		}
		if err := docker.Destroy(container); err != nil {
			b.Fatal(err)
		}
	}
}

func BenchmarkRunParallel(b *testing.B) {
	docker, err := newTestDocker()
	if err != nil {
		b.Fatal(err)
	}

	var tasks []chan error

	for i := 0; i < b.N; i++ {
		complete := make(chan error)
		tasks = append(tasks, complete)
		go func(i int, complete chan error) {
			container, err := docker.Create(
				fmt.Sprintf("bench_%v", i),
				"echo",
				[]string{"-n", "foo"},
				[]string{"/var/lib/docker/images/ubuntu"},
				&Config{},
			)
			if err != nil {
				complete <- err
				return
			}
			defer docker.Destroy(container)
			if err := container.Start(); err != nil {
				complete <- err
				return
			}
			if err := container.WaitTimeout(15 * time.Second); err != nil {
				complete <- err
				return
			}
			// if string(output) != "foo" {
			// 	complete <- fmt.Errorf("Unexecpted output: %v", string(output))
			// }
			if err := docker.Destroy(container); err != nil {
				complete <- err
				return
			}
			complete <- nil
		}(i, complete)
	}
	var errors []error
	for _, task := range tasks {
		err := <-task
		if err != nil {
			errors = append(errors, err)
		}
	}
	if len(errors) > 0 {
		b.Fatal(errors)
	}
}
<|endoftext|>


<commit_before>package auth

import "testing"

func Test_SetSessionId(t *testing.T) {
	t.FailNow()
}
<commit_msg>added another test<commit_after>package auth

import "testing"

func Test_SetSessionId(t *testing.T) {
	t.FailNow()
}

func Test_CheckCredentials(t *testing.T) {
	t.FailNow()
}
<|endoftext|>


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

// Package main is the main entry point for the app.
package main

import (
	"context"
	"time"

	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials"

	"go.chromium.org/luci/common/clock"
	"go.chromium.org/luci/common/errors"
	"go.chromium.org/luci/common/logging"
	"go.chromium.org/luci/common/tsmon"
	"go.chromium.org/luci/common/tsmon/monitor"
	"go.chromium.org/luci/common/tsmon/store"
	"go.chromium.org/luci/common/tsmon/target"
	"go.chromium.org/luci/grpc/grpcmon"
	"go.chromium.org/luci/server"
	"go.chromium.org/luci/server/auth"
	"go.chromium.org/luci/server/cron"
	"go.chromium.org/luci/server/gaeemulation"
	"go.chromium.org/luci/server/module"
	"go.chromium.org/luci/server/redisconn"
	"go.chromium.org/luci/server/secrets"

	"go.chromium.org/luci/cv/internal/aggrmetrics"
	"go.chromium.org/luci/cv/internal/common"
)

const (
	// prodXGRPCTarget is the dial target for prodx grpc service.
	prodXGRPCTarget = "prodxmon-pa.googleapis.com:443"

	// aggregateMetricsCronTimeout is the amount off time the Cron has to compute
	// and flush the aggregation metrics.
	aggregateMetricsCronTimeout = 2 * time.Minute
)

func main() {

	modules := []module.Module{
		cron.NewModuleFromFlags(),
		gaeemulation.NewModuleFromFlags(),
		redisconn.NewModuleFromFlags(),
		secrets.NewModuleFromFlags(),
	}

	server.Main(nil, modules, func(srv *server.Server) error {
		opts := srv.Options
		env := common.MakeEnv(opts)

		// Init a new tsmon.State with the default task target,
		// configured in luci/server.
		target := *tsmon.GetState(srv.Context).Store().DefaultTarget().(*target.Task)
		state := tsmon.NewState()
		state.SetStore(store.NewInMemory(&target))
		state.InhibitGlobalCallbacksOnFlush()
		ctx := tsmon.WithState(srv.Context, state)
		mon, err := newMonitor(ctx, opts.TsMonAccount)
		if err != nil {
			return errors.Annotate(err, "failed to initiate monitoring client").Err()
		}
		aggregator := aggrmetrics.New(env)

		cron.RegisterHandler("report-aggregated-metrics", func(ctx context.Context) error {
			ctx, cancel := context.WithTimeout(ctx, aggregateMetricsCronTimeout)
			defer cancel()

			start := clock.Now(ctx)
			if err := aggregator.Cron(ctx); err != nil {
				return errors.Annotate(err, "failed to compute aggregation metrics").Err()
			}
			logging.Infof(ctx, "computing aggregation metrics took %s", clock.Since(ctx, start))
			start = clock.Now(ctx)
			if err := state.ParallelFlush(ctx, mon, 8); err != nil {
				return errors.Annotate(err, "failed to flush aggregation metrics").Err()
			}
			logging.Infof(ctx, "flushing aggregation metrics took %s", clock.Since(ctx, start))
			return nil
		})

		return nil
	})
}

func newMonitor(ctx context.Context, account string) (monitor.Monitor, error) {
	cred, err := auth.GetPerRPCCredentials(
		ctx, auth.AsActor,
		auth.WithServiceAccount(account),
		auth.WithScopes(monitor.ProdxmonScopes...),
	)
	if err != nil {
		return nil, errors.Annotate(err, "failed to get per RPC credentials").Err()
	}
	conn, err := grpc.Dial(
		prodXGRPCTarget,
		grpc.WithTransportCredentials(credentials.NewTLS(nil)),
		grpc.WithPerRPCCredentials(cred),
		grpcmon.WithClientRPCStatsMonitor(),
	)
	if err != nil {
		return nil, errors.Annotate(err, "failed to dial ProdX service(%s)", prodXGRPCTarget).Err()
	}
	return monitor.NewGRPCMonitorWithChunkSize(ctx, 1024, conn), nil
}
<commit_msg>cv: override the tsmon state in the requst to report aggregation metrics<commit_after>// Copyright 2022 The LUCI Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package main is the main entry point for the app.
package main

import (
	"context"
	"time"

	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials"

	"go.chromium.org/luci/common/clock"
	"go.chromium.org/luci/common/errors"
	"go.chromium.org/luci/common/logging"
	"go.chromium.org/luci/common/tsmon"
	"go.chromium.org/luci/common/tsmon/monitor"
	"go.chromium.org/luci/common/tsmon/store"
	"go.chromium.org/luci/common/tsmon/target"
	"go.chromium.org/luci/grpc/grpcmon"
	"go.chromium.org/luci/server"
	"go.chromium.org/luci/server/auth"
	"go.chromium.org/luci/server/cron"
	"go.chromium.org/luci/server/gaeemulation"
	"go.chromium.org/luci/server/module"
	"go.chromium.org/luci/server/redisconn"
	"go.chromium.org/luci/server/secrets"

	"go.chromium.org/luci/cv/internal/aggrmetrics"
	"go.chromium.org/luci/cv/internal/common"
)

const (
	// prodXGRPCTarget is the dial target for prodx grpc service.
	prodXGRPCTarget = "prodxmon-pa.googleapis.com:443"

	// aggregateMetricsCronTimeout is the amount off time the Cron has to compute
	// and flush the aggregation metrics.
	aggregateMetricsCronTimeout = 2 * time.Minute
)

func main() {

	modules := []module.Module{
		cron.NewModuleFromFlags(),
		gaeemulation.NewModuleFromFlags(),
		redisconn.NewModuleFromFlags(),
		secrets.NewModuleFromFlags(),
	}

	server.Main(nil, modules, func(srv *server.Server) error {
		opts := srv.Options
		env := common.MakeEnv(opts)

		// Init a new tsmon.State with the default task target,
		// configured in luci/server.
		target := *tsmon.GetState(srv.Context).Store().DefaultTarget().(*target.Task)
		state := tsmon.NewState()
		state.SetStore(store.NewInMemory(&target))
		state.InhibitGlobalCallbacksOnFlush()

		mon, err := newMonitor(srv.Context, opts.TsMonAccount)
		if err != nil {
			return errors.Annotate(err, "failed to initiate monitoring client").Err()
		}

		cron.RegisterHandler("report-aggregated-metrics", func(ctx context.Context) error {
			ctx, cancel := context.WithTimeout(ctx, aggregateMetricsCronTimeout)
			defer cancel()

			// Override the state to avoid using the default state from the server.
			ctx = tsmon.WithState(ctx, state)
			aggregator := aggrmetrics.New(env)
			start := clock.Now(ctx)
			if err := aggregator.Cron(ctx); err != nil {
				return errors.Annotate(err, "failed to compute aggregation metrics").Err()
			}
			logging.Infof(ctx, "computing aggregation metrics took %s", clock.Since(ctx, start))
			start = clock.Now(ctx)
			if err := state.ParallelFlush(ctx, mon, 8); err != nil {
				return errors.Annotate(err, "failed to flush aggregation metrics").Err()
			}
			logging.Infof(ctx, "flushing aggregation metrics took %s", clock.Since(ctx, start))
			return nil
		})

		return nil
	})
}

func newMonitor(ctx context.Context, account string) (monitor.Monitor, error) {
	cred, err := auth.GetPerRPCCredentials(
		ctx, auth.AsActor,
		auth.WithServiceAccount(account),
		auth.WithScopes(monitor.ProdxmonScopes...),
	)
	if err != nil {
		return nil, errors.Annotate(err, "failed to get per RPC credentials").Err()
	}
	conn, err := grpc.Dial(
		prodXGRPCTarget,
		grpc.WithTransportCredentials(credentials.NewTLS(nil)),
		grpc.WithPerRPCCredentials(cred),
		grpcmon.WithClientRPCStatsMonitor(),
	)
	if err != nil {
		return nil, errors.Annotate(err, "failed to dial ProdX service(%s)", prodXGRPCTarget).Err()
	}
	return monitor.NewGRPCMonitorWithChunkSize(ctx, 1024, conn), nil
}
<|endoftext|>


<commit_before>// Copyright 2015-2016 Sevki <s@sevki.org>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main // import "sevki.org/build/cmd/build"

import (
	"fmt"
	"log"
	"os"
	"os/signal"
	"time"

	"runtime"

	"flag"

	"sevki.org/build/builder"
	_ "sevki.org/build/targets/apple"
	_ "sevki.org/build/targets/build"
	_ "sevki.org/build/targets/cc"
	_ "sevki.org/build/targets/harvey"
	_ "sevki.org/build/targets/js"
	_ "sevki.org/build/targets/yacc"
	"sevki.org/build/term"
	"sevki.org/lib/prettyprint"
)

var (
	build = "version"
	usage = `usage: build target

We require that you run this application inside a git project.
All the targets are relative to the git project.
If you are in a subfoler we will traverse the parent folders until we hit a .git file.
`
)
var (
	verbose = flag.Bool("v", false, "more verbose output")
)

func main() {
	flag.Parse()

	target := flag.Args()[0]
	if len(flag.Args()) < 1 {
		flag.Usage()
		printUsage()
	}
	switch target {
	case "version":
		version()
		return
	case "serve":
		target = flag.Args()[1]
		server(target)
	case "query":
		target = flag.Args()[1]
		query(target)
	case "hash":
		target = flag.Args()[1]
		hash(target)
	default:
		execute(target)
	}
}
func progress() {
	fmt.Println(runtime.NumCPU())
}
func printUsage() {
	fmt.Fprintf(os.Stderr, usage)
	os.Exit(1)

}
func version() {
	fmt.Printf("Build %s", build)
	os.Exit(0)
}
func doneMessage(s string) {
	fmt.Printf("[%s] %s\n", " OK ", s)
}
func failMessage(s string) {
	fmt.Printf("[ %s ] %s\n", "FAIL", s)

}
func hash(t string) {
	c := builder.New()

	if c.ProjectPath == "" {
		fmt.Fprintf(os.Stderr, "You need to be in a git project.\n\n")
		printUsage()
	}
	fmt.Printf("%x\n", c.Add(t).HashNode())
}

func query(t string) {

	c := builder.New()

	if c.ProjectPath == "" {
		fmt.Fprintf(os.Stderr, "You need to be in a git project.\n\n")
		printUsage()
	}
	fmt.Println(prettyprint.AsJSON(c.Add(t).Target))
}
func execute(t string) {

	c := builder.New()

	if c.ProjectPath == "" {
		fmt.Fprintf(os.Stderr, "You need to be in a git project.\n\n")
		printUsage()
	}
	c.Root = c.Add(t)
	c.Root.IsRoot = true

	if c.Root == nil {
		log.Fatal("We couldn't find the root")
	}

	cpus := int(float32(runtime.NumCPU()) * 1.25)

	done := make(chan bool)

	// If the app hangs, there is a log.
	sigs := make(chan os.Signal, 1)
	signal.Notify(sigs, os.Interrupt)
	go func() {
		<-sigs
		f, _ := os.Create("/tmp/build-crash-log.json")
		fmt.Fprintf(f, prettyprint.AsJSON(c.Root))
		os.Exit(1)
	}()

	go term.Listen(c.Updates, cpus, *verbose)
	go term.Run(done)

	go c.Execute(time.Second, cpus)
	for {
		select {
		case done := <-c.Done:
			if *verbose {
				doneMessage(done.Url.String())
			}
			if done.IsRoot {
				goto FIN
			}
		case err := <-c.Error:
			<-done
			log.Fatal(err)
			os.Exit(1)
		case <-c.Timeout:
			log.Println("your build has timed out")
		}

	}
FIN:
	term.Exit()
	<-done
	os.Exit(0)
}

func compare(a, b []byte) bool {
	if len(a) != len(b) {
		return false
	}
	for i, c := range a {
		if c != b[i] {
			return false
		}
	}
	return true
}
<commit_msg>cmd/build: fix panic on no args<commit_after>// Copyright 2015-2016 Sevki <s@sevki.org>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main // import "sevki.org/build/cmd/build"

import (
	"fmt"
	"log"
	"os"
	"os/signal"
	"time"

	"runtime"

	"flag"

	"sevki.org/build/builder"
	_ "sevki.org/build/targets/apple"
	_ "sevki.org/build/targets/build"
	_ "sevki.org/build/targets/cc"
	_ "sevki.org/build/targets/harvey"
	_ "sevki.org/build/targets/js"
	_ "sevki.org/build/targets/yacc"
	"sevki.org/build/term"
	"sevki.org/lib/prettyprint"
)

var (
	build = "version"
	usage = `usage: build target

We require that you run this application inside a git project.
All the targets are relative to the git project.
If you are in a subfoler we will traverse the parent folders until we hit a .git file.
`
)
var (
	verbose = flag.Bool("v", false, "more verbose output")
)

func main() {
	flag.Parse()

	if len(flag.Args()) < 1 {
		flag.Usage()
		printUsage()
	}
	target := flag.Args()[0]
	switch target {
	case "version":
		version()
		return
	case "serve":
		target = flag.Args()[1]
		server(target)
	case "query":
		target = flag.Args()[1]
		query(target)
	case "hash":
		target = flag.Args()[1]
		hash(target)
	default:
		execute(target)
	}
}
func progress() {
	fmt.Println(runtime.NumCPU())
}
func printUsage() {
	fmt.Fprintf(os.Stderr, usage)
	os.Exit(1)

}
func version() {
	fmt.Printf("Build %s", build)
	os.Exit(0)
}
func doneMessage(s string) {
	fmt.Printf("[%s] %s\n", " OK ", s)
}
func failMessage(s string) {
	fmt.Printf("[ %s ] %s\n", "FAIL", s)

}
func hash(t string) {
	c := builder.New()

	if c.ProjectPath == "" {
		fmt.Fprintf(os.Stderr, "You need to be in a git project.\n\n")
		printUsage()
	}
	fmt.Printf("%x\n", c.Add(t).HashNode())
}

func query(t string) {

	c := builder.New()

	if c.ProjectPath == "" {
		fmt.Fprintf(os.Stderr, "You need to be in a git project.\n\n")
		printUsage()
	}
	fmt.Println(prettyprint.AsJSON(c.Add(t).Target))
}
func execute(t string) {

	c := builder.New()

	if c.ProjectPath == "" {
		fmt.Fprintf(os.Stderr, "You need to be in a git project.\n\n")
		printUsage()
	}
	c.Root = c.Add(t)
	c.Root.IsRoot = true

	if c.Root == nil {
		log.Fatal("We couldn't find the root")
	}

	cpus := int(float32(runtime.NumCPU()) * 1.25)

	done := make(chan bool)

	// If the app hangs, there is a log.
	sigs := make(chan os.Signal, 1)
	signal.Notify(sigs, os.Interrupt)
	go func() {
		<-sigs
		f, _ := os.Create("/tmp/build-crash-log.json")
		fmt.Fprintf(f, prettyprint.AsJSON(c.Root))
		os.Exit(1)
	}()

	go term.Listen(c.Updates, cpus, *verbose)
	go term.Run(done)

	go c.Execute(time.Second, cpus)
	for {
		select {
		case done := <-c.Done:
			if *verbose {
				doneMessage(done.Url.String())
			}
			if done.IsRoot {
				goto FIN
			}
		case err := <-c.Error:
			<-done
			log.Fatal(err)
			os.Exit(1)
		case <-c.Timeout:
			log.Println("your build has timed out")
		}

	}
FIN:
	term.Exit()
	<-done
	os.Exit(0)
}

func compare(a, b []byte) bool {
	if len(a) != len(b) {
		return false
	}
	for i, c := range a {
		if c != b[i] {
			return false
		}
	}
	return true
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"math/rand"
	"runtime"
	"time"

	"github.com/ready-steady/format/mat"
	"github.com/ready-steady/numeric/interpolation/adhier"
	"github.com/ready-steady/probability"
	"github.com/ready-steady/probability/uniform"
	"github.com/ready-steady/statistics/test"

	"../internal"
)

func main() {
	internal.Run(command)
}

func command(config string, ifile *mat.File, ofile *mat.File) error {
	const (
		α = 0.05
	)

	approximations, surrogate, err := sampleSurrogate(config, ifile)
	if err != nil {
		return err
	}

	values, err := sampleOriginal(config)
	if err != nil {
		return err
	}

	passed, p := test.KolmogorovSmirnov(approximations, values, α)

	fmt.Printf("Inputs: %d, Outputs: %d, Nodes: %d, Passed: %v, P-value: %.4e\n",
		surrogate.Inputs, surrogate.Outputs, surrogate.Nodes, passed, p)

	if ofile == nil {
		return nil
	}

	oc := surrogate.Outputs
	sc := uint32(len(approximations)) / oc

	if err := ofile.PutMatrix("approximations", approximations, oc, sc); err != nil {
		return err
	}
	if err := ofile.PutMatrix("values", values, oc, sc); err != nil {
		return err
	}

	return nil
}

func sampleSurrogate(configFile string, ifile *mat.File) ([]float64, *adhier.Surrogate, error) {
	config, err := internal.NewConfig(configFile)
	if err != nil {
		return nil, nil, err
	}

	problem, err := internal.NewProblem(config)
	if err != nil {
		return nil, nil, err
	}

	target, err := internal.NewTarget(problem)
	if err != nil {
		return nil, nil, err
	}

	interpolator, err := internal.NewInterpolator(problem, target)
	if err != nil {
		return nil, nil, err
	}

	surrogate := new(adhier.Surrogate)
	if ifile == nil {
		return nil, nil, errors.New("an input file is required")
	}
	if err = ifile.Get("surrogate", surrogate); err != nil {
		return nil, nil, err
	}

	problem.Println("Processing the surrogate model...")

	problem.Println(problem)
	problem.Println(target)
	problem.Println(surrogate)

	points, err := generate(problem, target)
	if err != nil {
		return nil, nil, err
	}

	return interpolator.Evaluate(surrogate, points), surrogate, nil
}

func sampleOriginal(configFile string) ([]float64, error) {
	config, err := internal.NewConfig(configFile)
	if err != nil {
		return nil, err
	}

	config.ProbModel.VarThreshold = 42

	problem, err := internal.NewProblem(config)
	if err != nil {
		return nil, err
	}

	target, err := internal.NewTarget(problem)
	if err != nil {
		return nil, err
	}

	points, err := generate(problem, target)
	if err != nil {
		return nil, err
	}

	problem.Println("Processing the original model...")

	problem.Println(problem)
	problem.Println(target)

	return invoke(target, points), nil
}

func generate(problem *internal.Problem, target internal.Target) ([]float64, error) {
	sc := problem.Config.Samples
	if sc == 0 {
		return nil, errors.New("the number of samples is zero")
	}

	if problem.Config.Seed > 0 {
		rand.Seed(problem.Config.Seed)
	} else {
		rand.Seed(time.Now().Unix())
	}

	ic, _ := target.InputsOutputs()

	return probability.Sample(uniform.New(0, 1), sc*ic), nil
}

func invoke(target internal.Target, points []float64) []float64 {
	wc := uint32(runtime.GOMAXPROCS(0))
	ic, oc := target.InputsOutputs()
	pc := uint32(len(points)) / ic

	values := make([]float64, pc*oc)
	jobs := make(chan uint32, pc)
	done := make(chan bool, pc)

	for i := uint32(0); i < wc; i++ {
		go func() {
			for j := range jobs {
				target.Evaluate(points[j*ic:(j+1)*ic], values[j*oc:(j+1)*oc], nil)
				done <- true
			}
		}()
	}

	for i := uint32(0); i < pc; i++ {
		jobs <- i
	}
	for i := uint32(0); i < pc; i++ {
		<-done
	}

	close(jobs)

	return values
}
<commit_msg>Improved the output of cmd/check<commit_after>package main

import (
	"errors"
	"fmt"
	"math/rand"
	"runtime"
	"time"

	"github.com/ready-steady/format/mat"
	"github.com/ready-steady/numeric/interpolation/adhier"
	"github.com/ready-steady/probability"
	"github.com/ready-steady/probability/uniform"
	"github.com/ready-steady/statistics/test"

	"../internal"
)

func main() {
	internal.Run(command)
}

func command(config string, ifile *mat.File, ofile *mat.File) error {
	const (
		α = 0.05
	)

	approximations, surrogate, err := sampleSurrogate(config, ifile)
	if err != nil {
		return err
	}

	values, err := sampleOriginal(config)
	if err != nil {
		return err
	}

	rejected, p := test.KolmogorovSmirnov(approximations, values, α)

	fmt.Printf("Inputs: %d, Outputs: %d, Nodes: %d, Passed: %v (%.2f%%)\n",
		surrogate.Inputs, surrogate.Outputs, surrogate.Nodes, !rejected, 100*p)

	if ofile == nil {
		return nil
	}

	oc := surrogate.Outputs
	sc := uint32(len(approximations)) / oc

	if err := ofile.PutMatrix("approximations", approximations, oc, sc); err != nil {
		return err
	}
	if err := ofile.PutMatrix("values", values, oc, sc); err != nil {
		return err
	}

	return nil
}

func sampleSurrogate(configFile string, ifile *mat.File) ([]float64, *adhier.Surrogate, error) {
	config, err := internal.NewConfig(configFile)
	if err != nil {
		return nil, nil, err
	}

	problem, err := internal.NewProblem(config)
	if err != nil {
		return nil, nil, err
	}

	target, err := internal.NewTarget(problem)
	if err != nil {
		return nil, nil, err
	}

	interpolator, err := internal.NewInterpolator(problem, target)
	if err != nil {
		return nil, nil, err
	}

	surrogate := new(adhier.Surrogate)
	if ifile == nil {
		return nil, nil, errors.New("an input file is required")
	}
	if err = ifile.Get("surrogate", surrogate); err != nil {
		return nil, nil, err
	}

	problem.Println("Processing the surrogate model...")

	problem.Println(problem)
	problem.Println(target)
	problem.Println(surrogate)

	points, err := generate(problem, target)
	if err != nil {
		return nil, nil, err
	}

	return interpolator.Evaluate(surrogate, points), surrogate, nil
}

func sampleOriginal(configFile string) ([]float64, error) {
	config, err := internal.NewConfig(configFile)
	if err != nil {
		return nil, err
	}

	config.ProbModel.VarThreshold = 42

	problem, err := internal.NewProblem(config)
	if err != nil {
		return nil, err
	}

	target, err := internal.NewTarget(problem)
	if err != nil {
		return nil, err
	}

	points, err := generate(problem, target)
	if err != nil {
		return nil, err
	}

	problem.Println("Processing the original model...")

	problem.Println(problem)
	problem.Println(target)

	return invoke(target, points), nil
}

func generate(problem *internal.Problem, target internal.Target) ([]float64, error) {
	sc := problem.Config.Samples
	if sc == 0 {
		return nil, errors.New("the number of samples is zero")
	}

	if problem.Config.Seed > 0 {
		rand.Seed(problem.Config.Seed)
	} else {
		rand.Seed(time.Now().Unix())
	}

	ic, _ := target.InputsOutputs()

	return probability.Sample(uniform.New(0, 1), sc*ic), nil
}

func invoke(target internal.Target, points []float64) []float64 {
	wc := uint32(runtime.GOMAXPROCS(0))
	ic, oc := target.InputsOutputs()
	pc := uint32(len(points)) / ic

	values := make([]float64, pc*oc)
	jobs := make(chan uint32, pc)
	done := make(chan bool, pc)

	for i := uint32(0); i < wc; i++ {
		go func() {
			for j := range jobs {
				target.Evaluate(points[j*ic:(j+1)*ic], values[j*oc:(j+1)*oc], nil)
				done <- true
			}
		}()
	}

	for i := uint32(0); i < pc; i++ {
		jobs <- i
	}
	for i := uint32(0); i < pc; i++ {
		<-done
	}

	close(jobs)

	return values
}
<|endoftext|>


<commit_before>package cmd

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"runtime"
	"strconv"
	"strings"
	"text/template"

	"github.com/rsteube/carapace"
	"github.com/spf13/cobra"
	gitlab "github.com/xanzy/go-gitlab"
	"github.com/zaquestion/lab/internal/action"
	"github.com/zaquestion/lab/internal/git"
	lab "github.com/zaquestion/lab/internal/gitlab"
)

var issueNoteCmd = &cobra.Command{
	Use:              "note [remote] <id>[:<comment_id>]",
	Aliases:          []string{"comment", "reply"},
	Short:            "Add a note or comment to an issue on GitLab",
	Long:             ``,
	Args:             cobra.MinimumNArgs(1),
	PersistentPreRun: LabPersistentPreRun,
	Run:              NoteRunFn,
}

func NoteRunFn(cmd *cobra.Command, args []string) {

	isMR := false
	if os.Args[1] == "mr" {
		isMR = true
	}

	rn, idString, err := parseArgsRemoteAndProject(args)
	if err != nil {
		log.Fatal(err)
	}

	var (
		idNum int = 0
		reply int = 0
	)

	if strings.Contains(idString, ":") {
		ids := strings.Split(idString, ":")
		idNum, _ = strconv.Atoi(ids[0])
		reply, _ = strconv.Atoi(ids[1])
	} else {
		idNum, _ = strconv.Atoi(idString)
	}

	if isMR && idNum == 0 {
		idNum = getCurrentBranchMR(rn)
		if idNum == 0 {
			fmt.Println("Error: Cannot determine MR id.")
			os.Exit(1)
		}
	}

	msgs, err := cmd.Flags().GetStringArray("message")
	if err != nil {
		log.Fatal(err)
	}

	filename, err := cmd.Flags().GetString("file")
	if err != nil {
		log.Fatal(err)
	}

	linebreak, err := cmd.Flags().GetBool("force-linebreak")
	if err != nil {
		log.Fatal(err)
	}

	if reply != 0 {
		quote, err := cmd.Flags().GetBool("quote")
		if err != nil {
			log.Fatal(err)
		}
		replyNote(rn, isMR, int(idNum), reply, quote, false, filename, linebreak)
		return
	}

	createNote(rn, isMR, int(idNum), msgs, filename, linebreak)
}

func createNote(rn string, isMR bool, idNum int, msgs []string, filename string, linebreak bool) {

	var err error

	body := ""
	if filename != "" {
		content, err := ioutil.ReadFile(filename)
		if err != nil {
			log.Fatal(err)
		}
		body = string(content)
	} else {
		if isMR {
			mr, err := lab.MRGet(rn, idNum)
			if err != nil {
				log.Fatal(err)
			}

			state := map[string]string{
				"opened": "OPEN",
				"closed": "CLOSED",
				"merged": "MERGED",
			}[mr.State]

			body = fmt.Sprintf("\n# This comment is being applied to %s Merge Request %d.", state, idNum)
		}

		body, err = noteMsg(msgs, isMR, body)
		if err != nil {
			_, f, l, _ := runtime.Caller(0)
			log.Fatal(f+":"+strconv.Itoa(l)+" ", err)
		}
	}

	if body == "" {
		log.Fatal("aborting note due to empty note msg")
	}

	if linebreak {
		body = textToMarkdown(body)
	}

	var (
		noteURL string
	)

	if isMR {
		noteURL, err = lab.MRCreateNote(rn, idNum, &gitlab.CreateMergeRequestNoteOptions{
			Body: &body,
		})
	} else {
		noteURL, err = lab.IssueCreateNote(rn, idNum, &gitlab.CreateIssueNoteOptions{
			Body: &body,
		})
	}
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(noteURL)
}

func noteMsg(msgs []string, isMR bool, body string) (string, error) {
	if len(msgs) > 0 {
		return strings.Join(msgs[0:], "\n\n"), nil
	}

	text, err := noteText(body)
	if err != nil {
		return "", err
	}

	if isMR {
		return git.EditFile("MR_NOTE", text)
	}
	return git.EditFile("ISSUE_NOTE", text)
}

func noteText(body string) (string, error) {
	const tmpl = `{{.InitMsg}}
{{.CommentChar}} Write a message for this note. Commented lines are discarded.`

	initMsg := body
	commentChar := git.CommentChar()

	t, err := template.New("tmpl").Parse(tmpl)
	if err != nil {
		return "", err
	}

	msg := &struct {
		InitMsg     string
		CommentChar string
	}{
		InitMsg:     initMsg,
		CommentChar: commentChar,
	}

	var b bytes.Buffer
	err = t.Execute(&b, msg)
	if err != nil {
		return "", err
	}

	return b.String(), nil
}

func replyNote(rn string, isMR bool, idNum int, reply int, quote bool, update bool, filename string, linebreak bool) {

	var (
		discussions []*gitlab.Discussion
		err         error
		NoteURL     string
	)

	if isMR {
		discussions, err = lab.MRListDiscussions(rn, idNum)
	} else {
		discussions, err = lab.IssueListDiscussions(rn, idNum)
	}
	if err != nil {
		log.Fatal(err)
	}
	for _, discussion := range discussions {
		for _, note := range discussion.Notes {

			if note.System {
				continue
			}

			if note.ID != reply {
				continue
			}

			body := ""
			if filename != "" {
				content, err := ioutil.ReadFile(filename)
				if err != nil {
					log.Fatal(err)
				}
				body = string(content)
			} else {
				noteBody := ""
				if quote {
					noteBody = note.Body
					noteBody = strings.Replace(noteBody, "\n", "\n>", -1)
					if !update {
						noteBody = ">" + noteBody + "\n"
					}
				}
				body, err = noteMsg([]string{}, isMR, noteBody)
				if err != nil {
					_, f, l, _ := runtime.Caller(0)
					log.Fatal(f+":"+strconv.Itoa(l)+" ", err)
				}
			}

			if body == "" {
				log.Fatal("aborting note due to empty note msg")
			}

			if linebreak {
				body = textToMarkdown(body)
			}

			if update {
				if isMR {
					NoteURL, err = lab.UpdateMRDiscussionNote(rn, idNum, discussion.ID, note.ID, body)
				} else {
					NoteURL, err = lab.UpdateIssueDiscussionNote(rn, idNum, discussion.ID, note.ID, body)
				}
			} else {
				if isMR {
					NoteURL, err = lab.AddMRDiscussionNote(rn, idNum, discussion.ID, body)
				} else {
					NoteURL, err = lab.AddIssueDiscussionNote(rn, idNum, discussion.ID, body)
				}
			}
			if err != nil {
				log.Fatal(err)
			}
			fmt.Println(NoteURL)
		}
	}
}

func init() {
	issueNoteCmd.Flags().StringArrayP("message", "m", []string{}, "use the given <msg>; multiple -m are concatenated as separate paragraphs")
	issueNoteCmd.Flags().StringP("file", "F", "", "use the given file as the message")
	issueNoteCmd.Flags().Bool("force-linebreak", false, "append 2 spaces to the end of each line to force markdown linebreaks")
	issueNoteCmd.Flags().Bool("quote", false, "quote note in reply (used with --reply only)")

	issueCmd.AddCommand(issueNoteCmd)
	carapace.Gen(issueNoteCmd).PositionalCompletion(
		action.Remotes(),
		action.Issues(issueList),
	)
}
<commit_msg>issue note: Provide more information in comment message<commit_after>package cmd

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"runtime"
	"strconv"
	"strings"
	"text/template"

	"github.com/rsteube/carapace"
	"github.com/spf13/cobra"
	gitlab "github.com/xanzy/go-gitlab"
	"github.com/zaquestion/lab/internal/action"
	"github.com/zaquestion/lab/internal/git"
	lab "github.com/zaquestion/lab/internal/gitlab"
)

var issueNoteCmd = &cobra.Command{
	Use:              "note [remote] <id>[:<comment_id>]",
	Aliases:          []string{"comment", "reply"},
	Short:            "Add a note or comment to an issue on GitLab",
	Long:             ``,
	Args:             cobra.MinimumNArgs(1),
	PersistentPreRun: LabPersistentPreRun,
	Run:              NoteRunFn,
}

func NoteRunFn(cmd *cobra.Command, args []string) {

	isMR := false
	if os.Args[1] == "mr" {
		isMR = true
	}

	rn, idString, err := parseArgsRemoteAndProject(args)
	if err != nil {
		log.Fatal(err)
	}

	var (
		idNum int = 0
		reply int = 0
	)

	if strings.Contains(idString, ":") {
		ids := strings.Split(idString, ":")
		idNum, _ = strconv.Atoi(ids[0])
		reply, _ = strconv.Atoi(ids[1])
	} else {
		idNum, _ = strconv.Atoi(idString)
	}

	if isMR && idNum == 0 {
		idNum = getCurrentBranchMR(rn)
		if idNum == 0 {
			fmt.Println("Error: Cannot determine MR id.")
			os.Exit(1)
		}
	}

	msgs, err := cmd.Flags().GetStringArray("message")
	if err != nil {
		log.Fatal(err)
	}

	filename, err := cmd.Flags().GetString("file")
	if err != nil {
		log.Fatal(err)
	}

	linebreak, err := cmd.Flags().GetBool("force-linebreak")
	if err != nil {
		log.Fatal(err)
	}

	if reply != 0 {
		quote, err := cmd.Flags().GetBool("quote")
		if err != nil {
			log.Fatal(err)
		}
		replyNote(rn, isMR, int(idNum), reply, quote, false, filename, linebreak)
		return
	}

	createNote(rn, isMR, int(idNum), msgs, filename, linebreak)
}

func createNote(rn string, isMR bool, idNum int, msgs []string, filename string, linebreak bool) {

	var err error

	body := ""
	if filename != "" {
		content, err := ioutil.ReadFile(filename)
		if err != nil {
			log.Fatal(err)
		}
		body = string(content)
	} else {
		if isMR {
			mr, err := lab.MRGet(rn, idNum)
			if err != nil {
				log.Fatal(err)
			}

			state := map[string]string{
				"opened": "OPEN",
				"closed": "CLOSED",
				"merged": "MERGED",
			}[mr.State]

			body = fmt.Sprintf("\n# This comment is being applied to %s Merge Request %d.", state, idNum)
		} else {
			issue, err := lab.IssueGet(rn, idNum)
			if err != nil {
				log.Fatal(err)
			}

			state := map[string]string{
				"opened": "OPEN",
				"closed": "CLOSED",
			}[issue.State]

			body = fmt.Sprintf("\n# This comment is being applied to %s Issue %d.", state, idNum)
		}

		body, err = noteMsg(msgs, isMR, body)
		if err != nil {
			_, f, l, _ := runtime.Caller(0)
			log.Fatal(f+":"+strconv.Itoa(l)+" ", err)
		}
	}

	if body == "" {
		log.Fatal("aborting note due to empty note msg")
	}

	if linebreak {
		body = textToMarkdown(body)
	}

	var (
		noteURL string
	)

	if isMR {
		noteURL, err = lab.MRCreateNote(rn, idNum, &gitlab.CreateMergeRequestNoteOptions{
			Body: &body,
		})
	} else {
		noteURL, err = lab.IssueCreateNote(rn, idNum, &gitlab.CreateIssueNoteOptions{
			Body: &body,
		})
	}
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(noteURL)
}

func noteMsg(msgs []string, isMR bool, body string) (string, error) {
	if len(msgs) > 0 {
		return strings.Join(msgs[0:], "\n\n"), nil
	}

	text, err := noteText(body)
	if err != nil {
		return "", err
	}

	if isMR {
		return git.EditFile("MR_NOTE", text)
	}
	return git.EditFile("ISSUE_NOTE", text)
}

func noteText(body string) (string, error) {
	const tmpl = `{{.InitMsg}}
{{.CommentChar}} Write a message for this note. Commented lines are discarded.`

	initMsg := body
	commentChar := git.CommentChar()

	t, err := template.New("tmpl").Parse(tmpl)
	if err != nil {
		return "", err
	}

	msg := &struct {
		InitMsg     string
		CommentChar string
	}{
		InitMsg:     initMsg,
		CommentChar: commentChar,
	}

	var b bytes.Buffer
	err = t.Execute(&b, msg)
	if err != nil {
		return "", err
	}

	return b.String(), nil
}

func replyNote(rn string, isMR bool, idNum int, reply int, quote bool, update bool, filename string, linebreak bool) {

	var (
		discussions []*gitlab.Discussion
		err         error
		NoteURL     string
	)

	if isMR {
		discussions, err = lab.MRListDiscussions(rn, idNum)
	} else {
		discussions, err = lab.IssueListDiscussions(rn, idNum)
	}
	if err != nil {
		log.Fatal(err)
	}
	for _, discussion := range discussions {
		for _, note := range discussion.Notes {

			if note.System {
				continue
			}

			if note.ID != reply {
				continue
			}

			body := ""
			if filename != "" {
				content, err := ioutil.ReadFile(filename)
				if err != nil {
					log.Fatal(err)
				}
				body = string(content)
			} else {
				noteBody := ""
				if quote {
					noteBody = note.Body
					noteBody = strings.Replace(noteBody, "\n", "\n>", -1)
					if !update {
						noteBody = ">" + noteBody + "\n"
					}
				}
				body, err = noteMsg([]string{}, isMR, noteBody)
				if err != nil {
					_, f, l, _ := runtime.Caller(0)
					log.Fatal(f+":"+strconv.Itoa(l)+" ", err)
				}
			}

			if body == "" {
				log.Fatal("aborting note due to empty note msg")
			}

			if linebreak {
				body = textToMarkdown(body)
			}

			if update {
				if isMR {
					NoteURL, err = lab.UpdateMRDiscussionNote(rn, idNum, discussion.ID, note.ID, body)
				} else {
					NoteURL, err = lab.UpdateIssueDiscussionNote(rn, idNum, discussion.ID, note.ID, body)
				}
			} else {
				if isMR {
					NoteURL, err = lab.AddMRDiscussionNote(rn, idNum, discussion.ID, body)
				} else {
					NoteURL, err = lab.AddIssueDiscussionNote(rn, idNum, discussion.ID, body)
				}
			}
			if err != nil {
				log.Fatal(err)
			}
			fmt.Println(NoteURL)
		}
	}
}

func init() {
	issueNoteCmd.Flags().StringArrayP("message", "m", []string{}, "use the given <msg>; multiple -m are concatenated as separate paragraphs")
	issueNoteCmd.Flags().StringP("file", "F", "", "use the given file as the message")
	issueNoteCmd.Flags().Bool("force-linebreak", false, "append 2 spaces to the end of each line to force markdown linebreaks")
	issueNoteCmd.Flags().Bool("quote", false, "quote note in reply (used with --reply only)")

	issueCmd.AddCommand(issueNoteCmd)
	carapace.Gen(issueNoteCmd).PositionalCompletion(
		action.Remotes(),
		action.Issues(issueList),
	)
}
<|endoftext|>


<commit_before>// Copyright 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package main

import (
	"fmt"

	"launchpad.net/gnuflag"
	"launchpad.net/loggo"
	"launchpad.net/tomb"

	"launchpad.net/juju-core/cmd"
	"launchpad.net/juju-core/state"
	"launchpad.net/juju-core/state/api"
	"launchpad.net/juju-core/worker"
	"launchpad.net/juju-core/worker/uniter"
)

var agentLogger = loggo.GetLogger("juju.jujud")

// UnitAgent is a cmd.Command responsible for running a unit agent.
type UnitAgent struct {
	cmd.CommandBase
	tomb     tomb.Tomb
	Conf     AgentConf
	UnitName string
	runner   *worker.Runner
}

// Info returns usage information for the command.
func (a *UnitAgent) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "unit",
		Purpose: "run a juju unit agent",
	}
}

func (a *UnitAgent) SetFlags(f *gnuflag.FlagSet) {
	a.Conf.addFlags(f)
	f.StringVar(&a.UnitName, "unit-name", "", "name of the unit to run")
}

// Init initializes the command for running.
func (a *UnitAgent) Init(args []string) error {
	if a.UnitName == "" {
		return requiredError("unit-name")
	}
	if !state.IsUnitName(a.UnitName) {
		return fmt.Errorf(`--unit-name option expects "<service>/<n>" argument`)
	}
	if err := a.Conf.checkArgs(args); err != nil {
		return err
	}
	a.runner = worker.NewRunner(isFatal, moreImportant)
	return nil
}

// Stop stops the unit agent.
func (a *UnitAgent) Stop() error {
	a.runner.Kill()
	return a.tomb.Wait()
}

// Run runs a unit agent.
func (a *UnitAgent) Run(ctx *cmd.Context) error {
	defer a.tomb.Done()
	if err := a.Conf.read(a.Tag()); err != nil {
		return err
	}
	agentLogger.Infof("unit agent %v start", a.Tag())
	a.runner.StartWorker("toplevel", func() (worker.Worker, error) {
		// TODO(rog) go1.1: use method expression
		return a.Workers()
	})
	err := agentDone(a.runner.Wait())
	a.tomb.Kill(err)
	return err
}

// Workers returns a worker that runs the unit agent workers.
func (a *UnitAgent) Workers() (worker.Worker, error) {
	st, entity, err := openState(a.Conf.Conf, a)
	if err != nil {
		return nil, err
	}
	if err := EnsureAPIInfo(a.Conf.Conf, st, entity); err != nil {
		// We suppress this error, because it is probably more interesting
		// to see other failures, but we log it, in case it is a root cause
		agentLogger.Warningf("error while calling EnsureAPIInfo: %v", err)
	}
	unit := entity.(*state.Unit)
	dataDir := a.Conf.DataDir
	runner := worker.NewRunner(allFatal, moreImportant)
	runner.StartWorker("upgrader", func() (worker.Worker, error) {
		return upgrader.New(st, unit.Tag, dataDir), nil
	})
	runner.StartWorker("uniter", func() (worker.Worker, error) {
		return uniter.NewUniter(st, unit.Name(), dataDir), nil
	})
	return newCloseWorker(runner, st), nil
}

func (a *UnitAgent) Entity(st *state.State) (AgentState, error) {
	return st.Unit(a.UnitName)
}

func (a *UnitAgent) APIEntity(st *api.State) (AgentAPIState, error) {
	return nil, fmt.Errorf("not implemented yet")
}

func (a *UnitAgent) Tag() string {
	return state.UnitTag(a.UnitName)
}
<commit_msg>revert premature cmd/jujud change<commit_after>// Copyright 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package main

import (
	"fmt"

	"launchpad.net/gnuflag"
	"launchpad.net/loggo"
	"launchpad.net/tomb"

	"launchpad.net/juju-core/cmd"
	"launchpad.net/juju-core/state"
	"launchpad.net/juju-core/state/api"
	"launchpad.net/juju-core/worker"
	"launchpad.net/juju-core/worker/uniter"
)

var agentLogger = loggo.GetLogger("juju.jujud")

// UnitAgent is a cmd.Command responsible for running a unit agent.
type UnitAgent struct {
	cmd.CommandBase
	tomb     tomb.Tomb
	Conf     AgentConf
	UnitName string
	runner   *worker.Runner
}

// Info returns usage information for the command.
func (a *UnitAgent) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "unit",
		Purpose: "run a juju unit agent",
	}
}

func (a *UnitAgent) SetFlags(f *gnuflag.FlagSet) {
	a.Conf.addFlags(f)
	f.StringVar(&a.UnitName, "unit-name", "", "name of the unit to run")
}

// Init initializes the command for running.
func (a *UnitAgent) Init(args []string) error {
	if a.UnitName == "" {
		return requiredError("unit-name")
	}
	if !state.IsUnitName(a.UnitName) {
		return fmt.Errorf(`--unit-name option expects "<service>/<n>" argument`)
	}
	if err := a.Conf.checkArgs(args); err != nil {
		return err
	}
	a.runner = worker.NewRunner(isFatal, moreImportant)
	return nil
}

// Stop stops the unit agent.
func (a *UnitAgent) Stop() error {
	a.runner.Kill()
	return a.tomb.Wait()
}

// Run runs a unit agent.
func (a *UnitAgent) Run(ctx *cmd.Context) error {
	defer a.tomb.Done()
	if err := a.Conf.read(a.Tag()); err != nil {
		return err
	}
	agentLogger.Infof("unit agent %v start", a.Tag())
	a.runner.StartWorker("toplevel", func() (worker.Worker, error) {
		// TODO(rog) go1.1: use method expression
		return a.Workers()
	})
	err := agentDone(a.runner.Wait())
	a.tomb.Kill(err)
	return err
}

// Workers returns a worker that runs the unit agent workers.
func (a *UnitAgent) Workers() (worker.Worker, error) {
	st, entity, err := openState(a.Conf.Conf, a)
	if err != nil {
		return nil, err
	}
	if err := EnsureAPIInfo(a.Conf.Conf, st, entity); err != nil {
		// We suppress this error, because it is probably more interesting
		// to see other failures, but we log it, in case it is a root cause
		agentLogger.Warningf("error while calling EnsureAPIInfo: %v", err)
	}
	unit := entity.(*state.Unit)
	dataDir := a.Conf.DataDir
	runner := worker.NewRunner(allFatal, moreImportant)
	runner.StartWorker("upgrader", func() (worker.Worker, error) {
		return NewUpgrader(st, unit, dataDir), nil
	})
	runner.StartWorker("uniter", func() (worker.Worker, error) {
		return uniter.NewUniter(st, unit.Name(), dataDir), nil
	})
	return newCloseWorker(runner, st), nil
}

func (a *UnitAgent) Entity(st *state.State) (AgentState, error) {
	return st.Unit(a.UnitName)
}

func (a *UnitAgent) APIEntity(st *api.State) (AgentAPIState, error) {
	return nil, fmt.Errorf("not implemented yet")
}

func (a *UnitAgent) Tag() string {
	return state.UnitTag(a.UnitName)
}
<|endoftext|>