<commit_before>package msgbox

import (
	"fmt"

	"strconv"

	"github.com/xiaonanln/goworld"
	"github.com/xiaonanln/goworld/engine/common"
	"github.com/xiaonanln/goworld/engine/entity"
	"github.com/xiaonanln/goworld/engine/gwlog"
	"github.com/xiaonanln/goworld/engine/gwutils"
	"github.com/xiaonanln/goworld/engine/kvdb"
	"github.com/xiaonanln/goworld/engine/kvdb/types"
	"github.com/xiaonanln/goworld/engine/netutil"
)

// msgbox is a reliable message box for entities
// Entity can use Msgbox.Send to send message to other entity and use Msgbox.Recv to receive messages
// Message can always be received by target entity even when target entity is not online, in which case target entity
// will receive this message when it is loaded and calls Msgbox.Receive.

const (
	ServiceName             = "MsgboxService"
	_LastMsgboxMsgIdAttrKey = "_lastMsgboxMsgId"
	_MaxMsgId               = 9999999999
)

var (
	msgpacker = netutil.MessagePackMsgPacker{}
)

type Msg map[string]interface{}

type MsgboxService struct {
	entity.Entity
}

// OnInit initialize MsgboxService fields
func (mbs *MsgboxService) OnInit() {
}

// OnCreated is called when MsgboxService is created
func (mbs *MsgboxService) OnCreated() {
	mbs.DeclareService(ServiceName)
	mbs.Attrs.SetDefaultInt("maxMsgId", 0)
}

// RegisterService registeres MsgboxService to goworld
func RegisterService() {
	goworld.RegisterEntity(ServiceName, &MsgboxService{}, true, false).DefineAttrs(map[string][]string{
		"maxMsgId": {"Persistent"},
	})
}

// Send requests MsgboxService to send a message to target entity
func (mbs *MsgboxService) Send(targetID common.EntityID, msg Msg) {
	gwlog.Debugf("%s: Send %s => %T %v", mbs, targetID, msg, msg)
	msgid := mbs.getNextMsgId()
	msgkey := mbs.getMsgKey(targetID, msgid)
	msgBytes, err := msgpacker.PackMsg(msg, nil)
	if err != nil {
		gwlog.Panic(err)
	}

	kvdb.Put(msgkey, string(msgBytes), func(err error) {
		if err != nil {
			gwlog.Panic(err)
		}
		gwlog.Debugf("Msg is sent ok")
	})
}

func (mbs *MsgboxService) Recv(targetID common.EntityID, beginMsgId int64) {
	beginKey := mbs.getMsgKey(targetID, beginMsgId)
	endKey := mbs.getMsgKey(targetID, _MaxMsgId)
	kvdb.GetRange(beginKey, endKey, func(items []kvdbtypes.KVItem, err error) {
		if err != nil {
			gwlog.Panic(err)
		}

		var msgs []Msg
		var endMsgId int64
		for _, item := range items {
			_, msgid := mbs.parseMsgKey(item.Key)
			endMsgId = msgid

			msgBytes := []byte(item.Val)
			var msg Msg
			err := msgpacker.UnpackMsg(msgBytes, &msg)
			if err != nil {
				gwlog.Panic(err)
			}
			msgs = append(msgs, msg)

		}

		mbs.Call(targetID, "MsgboxOnRecvMsg", beginMsgId, endMsgId, msgs)
	})
}

func (mbs *MsgboxService) getMsgKey(targetID common.EntityID, msgid int64) string {
	return fmt.Sprintf("__Msg_%s_%010d", targetID, msgid)
}

func (mbs *MsgboxService) parseMsgKey(msgkey string) (common.EntityID, int64) {
	if msgkey[:6] != "__Msg_" {
		gwlog.Panicf("not a valid msg key: %s", msgkey)
	}

	targetID := common.EntityID(msgkey[6 : 6+common.ENTITYID_LENGTH])
	msgid, err := strconv.Atoi(msgkey[6+common.ENTITYID_LENGTH+1:])
	if err != nil {
		gwlog.Panic(err)
	}
	return targetID, int64(msgid)
}

func (mbs *MsgboxService) getNextMsgId() int64 {
	id := mbs.GetInt("maxMsgId")
	id++
	mbs.Attrs.SetInt("maxMsgId", id)
	return id
}

// Msgbox is used to send messages among entities: e.x. Msgbox{&a.Entity}.Send(targetID, msg, callback)
type Msgbox struct {
	entity.Component
	msghandler func(msg Msg)
}

func (mb *Msgbox) OnInit() {
	gwlog.Debugf("%s: initializing msgbox ...", mb.Entity)
	mb.Attrs.SetDefaultInt(_LastMsgboxMsgIdAttrKey, 0)
}

func (mb *Msgbox) Send(targetID common.EntityID, msg Msg) {
	mb.CallService(ServiceName, "Send", targetID, msg)
}

func (mb *Msgbox) Recv() {
	mb.CallService(ServiceName, "Recv", mb.ID, mb.getLastMsgId()+1)
}

func (mb *Msgbox) MsgboxOnRecvMsg(beginMsgId int64, endMsgId int64, msgs []Msg) {
	gwlog.Debugf("%s: MsgBox.OnRecvMsg: %d -> %d: msgs %v", mb.Entity, beginMsgId, endMsgId, msgs)
	mb.Attrs.SetInt(_LastMsgboxMsgIdAttrKey, endMsgId)
	for _, msg := range msgs {
		gwutils.RunPanicless(func() {
			mb.msghandler(msg)
		})
	}
}

func (mb *Msgbox) SetMsgHandler(handler func(msg Msg)) {
	mb.msghandler = handler
}

func (mb *Msgbox) getLastMsgId() int64 {
	return mb.Attrs.GetInt(_LastMsgboxMsgIdAttrKey)
}

func (mb *Msgbox) setLastMsgId(id int64) {
	mb.Attrs.SetInt(_LastMsgboxMsgIdAttrKey, id)
}
<commit_msg>msgbox fix<commit_after>package msgbox

import (
	"fmt"

	"strconv"

	"github.com/xiaonanln/goworld"
	"github.com/xiaonanln/goworld/engine/common"
	"github.com/xiaonanln/goworld/engine/entity"
	"github.com/xiaonanln/goworld/engine/gwlog"
	"github.com/xiaonanln/goworld/engine/gwutils"
	"github.com/xiaonanln/goworld/engine/kvdb"
	"github.com/xiaonanln/goworld/engine/kvdb/types"
	"github.com/xiaonanln/goworld/engine/netutil"
)

// msgbox is a reliable message box for entities
// Entity can use Msgbox.Send to send message to other entity and use Msgbox.Recv to receive messages
// Message can always be received by target entity even when target entity is not online, in which case target entity
// will receive this message when it is loaded and calls Msgbox.Receive.

const (
	ServiceName             = "MsgboxService"
	_LastMsgboxMsgIdAttrKey = "_lastMsgboxMsgId"
	_MaxMsgId               = 9999999999
)

var (
	msgpacker = netutil.MessagePackMsgPacker{}
)

type Msg map[string]interface{}

type MsgboxService struct {
	entity.Entity
}

// OnInit initialize MsgboxService fields
func (mbs *MsgboxService) OnInit() {
}

// OnCreated is called when MsgboxService is created
func (mbs *MsgboxService) OnCreated() {
	mbs.DeclareService(ServiceName)
	mbs.Attrs.SetDefaultInt("maxMsgId", 0)
}

// RegisterService registeres MsgboxService to goworld
func RegisterService() {
	goworld.RegisterEntity(ServiceName, &MsgboxService{}, true, false).DefineAttrs(map[string][]string{
		"maxMsgId": {"Persistent"},
	})
}

// Send requests MsgboxService to send a message to target entity
func (mbs *MsgboxService) Send(targetID common.EntityID, msg Msg) {
	gwlog.Debugf("%s: Send %s => %T %v", mbs, targetID, msg, msg)
	msgid := mbs.getNextMsgId()
	msgkey := mbs.getMsgKey(targetID, msgid)
	msgBytes, err := msgpacker.PackMsg(msg, nil)
	if err != nil {
		gwlog.Panic(err)
	}

	kvdb.Put(msgkey, string(msgBytes), func(err error) {
		if err != nil {
			gwlog.Panic(err)
		}
		gwlog.Debugf("Msg is sent ok")
	})
}

func (mbs *MsgboxService) Recv(targetID common.EntityID, beginMsgId int64) {
	beginKey := mbs.getMsgKey(targetID, beginMsgId)
	endKey := mbs.getMsgKey(targetID, _MaxMsgId)
	kvdb.GetRange(beginKey, endKey, func(items []kvdbtypes.KVItem, err error) {
		if err != nil {
			gwlog.Panic(err)
		}

		if len(items) == 0 {
			gwlog.Debugf("found no msg")
			return
		}

		var msgs []Msg
		var endMsgId int64 = beginMsgId - 1
		for _, item := range items {
			_, msgid := mbs.parseMsgKey(item.Key)
			endMsgId = msgid

			msgBytes := []byte(item.Val)
			var msg Msg
			err := msgpacker.UnpackMsg(msgBytes, &msg)
			if err != nil {
				gwlog.Panic(err)
			}
			msgs = append(msgs, msg)

		}

		mbs.Call(targetID, "MsgboxOnRecvMsg", beginMsgId, endMsgId, msgs)
	})
}

func (mbs *MsgboxService) getMsgKey(targetID common.EntityID, msgid int64) string {
	return fmt.Sprintf("__Msg_%s_%010d", targetID, msgid)
}

func (mbs *MsgboxService) parseMsgKey(msgkey string) (common.EntityID, int64) {
	if msgkey[:6] != "__Msg_" {
		gwlog.Panicf("not a valid msg key: %s", msgkey)
	}

	targetID := common.EntityID(msgkey[6 : 6+common.ENTITYID_LENGTH])
	msgid, err := strconv.Atoi(msgkey[6+common.ENTITYID_LENGTH+1:])
	if err != nil {
		gwlog.Panic(err)
	}
	return targetID, int64(msgid)
}

func (mbs *MsgboxService) getNextMsgId() int64 {
	id := mbs.GetInt("maxMsgId")
	id++
	mbs.Attrs.SetInt("maxMsgId", id)
	return id
}

// Msgbox is used to send messages among entities: e.x. Msgbox{&a.Entity}.Send(targetID, msg, callback)
type Msgbox struct {
	entity.Component
	msghandler func(msg Msg)
}

func (mb *Msgbox) OnInit() {
	gwlog.Debugf("%s: initializing msgbox ...", mb.Entity)
	mb.Attrs.SetDefaultInt(_LastMsgboxMsgIdAttrKey, 0)
}

func (mb *Msgbox) Send(targetID common.EntityID, msg Msg) {
	mb.CallService(ServiceName, "Send", targetID, msg)
}

func (mb *Msgbox) Recv() {
	mb.CallService(ServiceName, "Recv", mb.ID, mb.getLastMsgId()+1)
}

func (mb *Msgbox) MsgboxOnRecvMsg(beginMsgId int64, endMsgId int64, msgs []Msg) {
	gwlog.Debugf("%s: MsgBox.OnRecvMsg: %d -> %d: msgs %v", mb.Entity, beginMsgId, endMsgId, msgs)
	mb.Attrs.SetInt(_LastMsgboxMsgIdAttrKey, endMsgId)
	for _, msg := range msgs {
		gwutils.RunPanicless(func() {
			mb.msghandler(msg)
		})
	}
}

func (mb *Msgbox) SetMsgHandler(handler func(msg Msg)) {
	mb.msghandler = handler
}

func (mb *Msgbox) getLastMsgId() int64 {
	return mb.Attrs.GetInt(_LastMsgboxMsgIdAttrKey)
}

func (mb *Msgbox) setLastMsgId(id int64) {
	mb.Attrs.SetInt(_LastMsgboxMsgIdAttrKey, id)
}
<|endoftext|>


<commit_before>// Copyright (c) 2014 FactomProject/FactomCode Systems LLC.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package main

import (
	//"github.com/FactomProject/FactomCode/notaryapi"
	"github.com/FactomProject/FactomCode/factomchain/factoid"
	"github.com/FactomProject/FactomCode/factomwire"
)

// TxProcessor is an interface that abstracts methods needed to process a TxMessage
// SetContext(*TxMessage) will store to concrete TxMessage in the concrete TxProcessor object
type TxProcessor interface {
	SetContext(*factomwire.MsgTx)
	Verify() bool
	//Broadcast()
	AddToMemPool()
}

//ProcessTx is an abstract way to process any TxMessage received from wire
//It first SetContext()  of the concrete type and then will only Broadcast and
//add to MemoryyPool if Verify returns true
func ProcessTx(tp TxProcessor, tm *factomwire.MsgTx) (ret bool) {
	tp.SetContext(tm)
	if tp.Verify() {
		//tp.server.BroadcastMessage()
		tp.AddToMemPool()
		ret = true
	}

	return
}

type txMemPool struct {
	server       *server
	TxProcessorS map[string]TxProcessor
}

func (txm *txMemPool) ProcessTransaction(tm *factomwire.MsgTx) bool {
	return ProcessTx(txm.TxProcessorS[tm.TxType()], tm)
}

// newTxMemPool returns a new memory pool for validating and storing standalone
// transactions until they are confirmed into a block.
func newTxMemPool(server *server) *txMemPool {
	var txmp txMemPool
	txmp.TxProcessorS = make(map[string]TxProcessor)

	txmp.TxProcessorS["factoid"] = factoid.NewFactoidPool()

	//txmp.TxProcessorS["entrycommit"] = factom.NewEntryPool()

	return &txmp
}
<commit_msg>Temporary fix for a compiling error<commit_after>// Copyright (c) 2014 FactomProject/FactomCode Systems LLC.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package main

import (
	//"github.com/FactomProject/FactomCode/notaryapi"
	"github.com/FactomProject/FactomCode/factomchain/factoid"
	"github.com/FactomProject/FactomCode/factomwire"
)

// TxProcessor is an interface that abstracts methods needed to process a TxMessage
// SetContext(*TxMessage) will store to concrete TxMessage in the concrete TxProcessor object
type TxProcessor interface {
	SetContext(*factomwire.MsgTx)
	Verify() bool
	//Broadcast()
	AddToMemPool()
}

//ProcessTx is an abstract way to process any TxMessage received from wire
//It first SetContext()  of the concrete type and then will only Broadcast and
//add to MemoryyPool if Verify returns true
func ProcessTx(tp TxProcessor, tm *factomwire.MsgTx) (ret bool) {
	tp.SetContext(tm)
	if tp.Verify() {
		//tp.server.BroadcastMessage()
		tp.AddToMemPool()
		ret = true
	}

	return
}

type txMemPool struct {
	server       *server
	TxProcessorS map[string]TxProcessor
}

func (txm *txMemPool) ProcessTransaction(tm *factomwire.MsgTx) bool {
	return ProcessTx(txm.TxProcessorS[tm.TxType()], tm)
}

// newTxMemPool returns a new memory pool for validating and storing standalone
// transactions until they are confirmed into a block.
func newTxMemPool(server *server) *txMemPool {
	var txmp txMemPool
	txmp.TxProcessorS = make(map[string]TxProcessor)

	txmp.TxProcessorS["factoid"] = factoid.NewFactoidPool().TxProcessor//?? Pls double check

	//txmp.TxProcessorS["entrycommit"] = factom.NewEntryPool()

	return &txmp
}
<|endoftext|>


<commit_before>package main

func main() {}
<commit_msg>initfuncs: add main<commit_after>package main

func main() {
	println("main")
}
<|endoftext|>


<commit_before>package cc

import (
	"crypto/sha1"
	"fmt"

	"io"
	"strings"

	"sevki.org/build/build"
	"sevki.org/build/util"
)

type CBin struct {
	Name            string        `cxx_binary:"name" cc_binary:"name"`
	Sources         Sources       `cxx_binary:"srcs" cc_binary:"srcs" build:"path"`
	Dependencies    []string      `cxx_binary:"deps" cc_binary:"deps"`
	Includes        Includes      `cxx_binary:"headers" cc_binary:"includes" build:"path"`
	Headers         []string      `cxx_binary:"exported_headers" cc_binary:"hdrs" build:"path"`
	CompilerOptions CompilerFlags `cxx_binary:"compiler_flags" cc_binary:"copts"`
	LinkerOptions   []string      `cxx_binary:"linker_flags" cc_binary:"linkopts"`
	Source          string
}

func split(s string, c string) string {
	i := strings.Index(s, c)
	if i < 0 {
		return s
	}

	return s[i+1:]
}
func (cb *CBin) Hash() []byte {

	h := sha1.New()
	io.WriteString(h, CCVersion)
	io.WriteString(h, cb.Name)
	util.HashFiles(h, cb.Includes)
	util.HashFiles(h, []string(cb.Sources))
	util.HashStrings(h, cb.CompilerOptions)
	util.HashStrings(h, cb.LinkerOptions)
	return h.Sum(nil)
}

func (cb *CBin) Build(c *build.Context) error {

	params := []string{}
	params = append(params, cb.CompilerOptions...)
	params = append(params, cb.Sources...)
	params = append(params, cb.Includes.Includes()...)

	c.Println(strings.Join(append([]string{compiler()}, params...), " "))

	if err := c.Exec(compiler(), nil, params); err != nil {
		return fmt.Errorf(err.Error())
	}

	params = []string{"-rs", cb.Name}

	// This is done under the assumption that each src file put in this thing
	// here will comeout as a .o file
	for _, f := range cb.Sources {
		params = append(params, fmt.Sprintf("%s.o", f[:strings.LastIndex(f, ".")]))
	}
	params = append(params, "-L", "lib")
	params = append(params, cb.LinkerOptions...)
	for _, dep := range cb.Dependencies {
		d := split(dep, ":")

		if strings.TrimLeft(d, "lib") != d {
			cb.LinkerOptions = append(cb.LinkerOptions, fmt.Sprintf("-l%s", d[3:]))
		}
	}

	c.Println(strings.Join(append([]string{ld()}, params...), " "))
	if err := c.Exec(ld(), nil, params); err != nil {

		return fmt.Errorf(err.Error())
	}

	return nil
}

func (cb *CBin) Installs() map[string]string {
	exports := make(map[string]string)
	exports[cb.Name] = ""
	return exports
}

func (cb *CBin) GetName() string {
	return cb.Name
}
func (cb *CBin) GetDependencies() []string {
	return cb.Dependencies
}

func (cb *CBin) GetSource() string {
	return cb.Source
}
<commit_msg>targets/cc: fix: linkorder<commit_after>package cc

import (
	"crypto/sha1"
	"fmt"

	"io"
	"strings"

	"path/filepath"

	"sevki.org/build/build"
	"sevki.org/build/util"
)

type CBin struct {
	Name            string        `cxx_binary:"name" cc_binary:"name"`
	Sources         Sources       `cxx_binary:"srcs" cc_binary:"srcs" build:"path"`
	Dependencies    []string      `cxx_binary:"deps" cc_binary:"deps"`
	Includes        Includes      `cxx_binary:"headers" cc_binary:"includes" build:"path"`
	Headers         []string      `cxx_binary:"exported_headers" cc_binary:"hdrs" build:"path"`
	CompilerOptions CompilerFlags `cxx_binary:"compiler_flags" cc_binary:"copts"`
	LinkerOptions   []string      `cxx_binary:"linker_flags" cc_binary:"linkopts"`
	Source          string
}

func split(s string, c string) string {
	i := strings.Index(s, c)
	if i < 0 {
		return s
	}

	return s[i+1:]
}
func (cb *CBin) Hash() []byte {

	h := sha1.New()
	io.WriteString(h, CCVersion)
	io.WriteString(h, cb.Name)
	util.HashFiles(h, cb.Includes)
	util.HashFiles(h, []string(cb.Sources))
	util.HashStrings(h, cb.CompilerOptions)
	util.HashStrings(h, cb.LinkerOptions)
	return h.Sum(nil)
}

func (cb *CBin) Build(c *build.Context) error {

	params := []string{}
	params = append(params, cb.CompilerOptions...)
	params = append(params, cb.Sources...)
	params = append(params, cb.Includes.Includes()...)

	c.Println(strings.Join(append([]string{compiler()}, params...), " "))

	if err := c.Exec(compiler(), nil, params); err != nil {
		return fmt.Errorf(err.Error())
	}

	params = []string{"-o", cb.Name}

	// This is done under the assumption that each src file put in this thing
	// here will comeout as a .o file
	for _, f := range cb.Sources {
		_, fname := filepath.Split(f)
		params = append(params, fmt.Sprintf("%s.o", fname[:strings.LastIndex(fname, ".")]))
	}
	params = append(params, "-L", "lib")
	for _, dep := range cb.Dependencies {
		d := split(dep, ":")

		if strings.TrimLeft(d, "lib") != d {
			cb.LinkerOptions = append(cb.LinkerOptions, fmt.Sprintf("-l%s", d[3:]))
		}
	}
	params = append(params, cb.LinkerOptions...)
	c.Println(strings.Join(append([]string{ld()}, params...), " "))
	if err := c.Exec(ld(), nil, params); err != nil {

		return fmt.Errorf(err.Error())
	}

	return nil
}

func (cb *CBin) Installs() map[string]string {
	exports := make(map[string]string)
	exports[cb.Name] = ""
	return exports
}

func (cb *CBin) GetName() string {
	return cb.Name
}
func (cb *CBin) GetDependencies() []string {
	return cb.Dependencies
}

func (cb *CBin) GetSource() string {
	return cb.Source
}
<|endoftext|>


<commit_before>package tasks

import (
	"database/sql"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"strings"
	"time"

	"github.com/MyHomeworkSpace/api-server/mit"
	"github.com/MyHomeworkSpace/api-server/util"

	"github.com/MyHomeworkSpace/api-server/config"
)

// some classes have weird times and aren't on the catalog, so we just give up on them
var skipClasses = map[string][]string{
	"2021SP": {"20.051", "21M.442"},
	"2022FA": {"15.S24", "15.830", "21M.138", "21M.460"},
	"2022SP": {"8.962"},
	"2023FA": {"6.9130", "12.703", "15.401", "15.830", "21M.460"},
}

type catalogListing struct {
	ID         string `json:"id"`
	ShortTitle string `json:"short"`
	Title      string `json:"title"`

	OfferedFall   bool `bool:"fall"`
	OfferedIAP    bool `bool:"iap"`
	OfferedSpring bool `bool:"spring"`

	FallInstructors   string `json:"fallI"`
	SpringInstructors string `json:"springI"`
}

type subjectOffering struct {
	ID      string `json:"id"`
	Title   string `json:"title"`
	Section string `json:"section"`
	Term    string `json:"term"`

	Time  string `json:"time"`
	Place string `json:"place"`

	FacultyID   string `json:"facultyID"`
	FacultyName string `json:"facultyName"`

	IsFake   bool `json:"fake"`
	IsMaster bool `json:"master"`

	IsDesign     bool `json:"design"`
	IsLab        bool `json:"lab"`
	IsLecture    bool `json:"lecture"`
	IsRecitation bool `json:"recitation"`
}

// StartImportFromMIT begins an import of the given data from the MIT Data Warehouse.
func StartImportFromMIT(source string, db *sql.DB) error {
	if source != "catalog" && source != "coursews" && source != "offerings" {
		return errors.New("tasks: invalid parameter")
	}

	taskID := "mit_" + source
	taskName := "MIT Import - " + source

	go taskWatcher(taskID, taskName, importFromMIT, source, db)
	return nil
}

func importFromMIT(lastCompletion *time.Time, source string, db *sql.DB) (taskResponse, error) {
	mitConfig := config.GetCurrent().MIT
	params := url.Values{}

	params.Add("source", source)

	currentTerm := mit.GetCurrentTerm()
	params.Add("termCode", currentTerm.Code)
	params.Add("academicYear", currentTerm.Code[:4])

	// TODO: remove
	params.Add("lastUpdateDate", "2019-01-01")

	requestURL := mitConfig.DataProxyURL + "fetch?" + params.Encode()
	if source == "coursews" {
		// actually use the secret coursews API
		requestURL = "https://coursews.mit.edu/coursews/"
	}

	client := &http.Client{}
	request, err := http.NewRequest("GET", requestURL, nil)
	if err != nil {
		return taskResponse{}, err
	}

	if source != "coursews" {
		request.Header.Add("X-MHS-Auth", mitConfig.ProxyToken)
	}

	response, err := client.Do(request)
	if err != nil {
		return taskResponse{}, err
	}

	defer response.Body.Close()

	if response.StatusCode != http.StatusOK {
		bodyBytes, err := ioutil.ReadAll(response.Body)
		if err != nil {
			return taskResponse{}, err
		}

		return taskResponse{}, fmt.Errorf(
			"tasks: MIT data server returned status code %d, body: '%s'",
			response.StatusCode,
			string(bodyBytes),
		)
	}

	tx, err := db.Begin()
	if err != nil {
		return taskResponse{}, err
	}

	rowsAffected := int64(0)

	if source == "catalog" {
		listings := []catalogListing{}
		err = json.NewDecoder(response.Body).Decode(&listings)
		if err != nil {
			return taskResponse{}, err
		}

		for _, listing := range listings {
			result, err := tx.Exec(
				`INSERT INTO
					mit_listings(id, shortTitle, title, offeredFall, offeredIAP, offeredSpring, fallInstructors, springInstructors)
					VALUES(?, ?, ?, ?, ?, ?, ?, ?)
				ON DUPLICATE KEY UPDATE
					id = VALUES(id),
					shortTitle = VALUES(shortTitle),
					title = VALUES(title),
					offeredFall = VALUES(offeredFall),
					offeredIAP = VALUES(offeredIAP),
					offeredSpring = VALUES(offeredSpring),
					fallInstructors = VALUES(fallInstructors),
					springInstructors = VALUES(springInstructors)
				`,
				listing.ID,
				listing.ShortTitle,
				listing.Title,
				listing.OfferedFall,
				listing.OfferedIAP,
				listing.OfferedSpring,
				listing.FallInstructors,
				listing.SpringInstructors,
			)
			if err != nil {
				return taskResponse{}, err
			}

			rowAffected, err := result.RowsAffected()
			if err != nil {
				return taskResponse{}, err
			}
			if rowAffected > 0 {
				rowsAffected++
			}
		}
	} else if source == "coursews" {
		// unfortunately, this API gives us data in a rather annoying format
		// so we cannot just parse them into a go struct
		// instead we have to use a hacky series of typecasts :(
		wsData := map[string]interface{}{}
		err = json.NewDecoder(response.Body).Decode(&wsData)
		if err != nil {
			return taskResponse{}, err
		}

		items := wsData["items"].([]interface{})

		// assume it's all the same term
		termInfo, err := mit.GetTermByCode(currentTerm.Code)
		if err != nil {
			return taskResponse{}, err
		}

		// first, clear out any data from a previous term
		_, err = tx.Exec("DELETE FROM mit_offerings WHERE term <> ?", currentTerm.Code)
		if err != nil {
			return taskResponse{}, err
		}

		for _, itemInterface := range items {
			item := itemInterface.(map[string]interface{})

			itemType := item["type"].(string)

			if itemType == "Class" {
				// we actually don't care about classes
				continue
			}

			if itemType != "LectureSession" && itemType != "LabSession" && itemType != "RecitationSession" {
				return taskResponse{}, fmt.Errorf("tasks: unknown coursews item type '%s'", itemType)
			}

			itemLabel := item["label"].(string)
			itemSectionOf := item["section-of"].(string)
			itemTimeAndPlace := item["timeAndPlace"].(string)

			if itemTimeAndPlace == "null null" {
				// this record tells us absolutely nothing
				// ignore it
				continue
			}

			// for some reason, the labels are the section + class number joined together
			// for example, section L01 of 6.003 has a label of "L016.003"
			// parse out the section ID
			sectionID := strings.Replace(itemLabel, itemSectionOf, "", -1)

			// in order to maximize suffering, the coursews api also combines the time and place fields
			// examples of this include "MW9.30-11 4-251" (easy)
			// or "TR9-11 (MEETS 4/7 TO 5/14) MEC-209" and "M EVE (6-8 PM) BOSTON PRE-REL" (why??)
			// the high quality algorithm to parse this is to break the string into spaces, and keep removing words until it works
			timeAndPlaceParts := strings.Split(itemTimeAndPlace, " ")
			currentTimeString := ""
			parsed := false
			for i := len(timeAndPlaceParts); i > 0; i-- {
				currentTimeString = ""
				for j := 0; j < i; j++ {
					if j != 0 {
						currentTimeString += " "
					}
					currentTimeString += timeAndPlaceParts[j]
				}

				// attempt
				_, err = mit.ParseTimeInfo(currentTimeString, termInfo)
				if err != nil {
					// oofie
					continue
				}

				// we survived!
				parsed = true
				break
			}

			if !parsed {
				return taskResponse{}, fmt.Errorf("tasks: failed to parse timeAndPlace '%s'", itemTimeAndPlace)
			}

			time := currentTimeString
			place := strings.TrimSpace(strings.Replace(itemTimeAndPlace, currentTimeString, "", -1))

			if place == "" {
				return taskResponse{}, fmt.Errorf("tasks: didn't get place from timeAndPlace '%s'", itemTimeAndPlace)
			}

			if place == "null" {
				place = ""
			}

			isDesign := false // design sections seem to not be included?
			isLab := (sectionID[0] == 'B')
			isLecture := (sectionID[0] == 'L')
			isRecitation := (sectionID[0] == 'R')

			// now, try to insert this new record
			// since we have very little info, we do NOT overwrite existing faculty/extra data if we have some
			result, err := tx.Exec(
				`INSERT INTO
					mit_offerings(id, title, section, term, time, place, facultyID, facultyName, isFake, isMaster, isDesign, isLab, isLecture, isRecitation)
					VALUES(?, '', ?, ?, ?, ?, '', '', 0, 0, ?, ?, ?, ?)
				ON DUPLICATE KEY UPDATE
					id = VALUES(id),
					section = VALUES(section),
					term = VALUES(term),
					time = VALUES(time),
					place = VALUES(place),
					isDesign = VALUES(isDesign),
					isLab = VALUES(isLab),
					isLecture = VALUES(isLecture),
					isRecitation = VALUES(isRecitation)`,
				itemSectionOf,
				sectionID,
				currentTerm.Code,
				time,
				place,
				isDesign,
				isLab,
				isLecture,
				isRecitation,
			)
			if err != nil {
				return taskResponse{}, err
			}

			rowAffected, err := result.RowsAffected()
			if err != nil {
				return taskResponse{}, err
			}
			if rowAffected > 0 {
				rowsAffected++
			}
		}
	} else if source == "offerings" {
		offerings := []subjectOffering{}
		err = json.NewDecoder(response.Body).Decode(&offerings)
		if err != nil {
			return taskResponse{}, err
		}

		// first, clear out any data from a previous term
		_, err = tx.Exec("DELETE FROM mit_offerings WHERE term <> ?", currentTerm.Code)
		if err != nil {
			return taskResponse{}, err
		}

		for _, offering := range offerings {
			if offering.Time == "" {
				continue
			}

			if util.StringSliceContains(skipClasses[currentTerm.Code], offering.ID) {
				continue
			}

			termInfo, err := mit.GetTermByCode(offering.Term)
			if err != nil {
				return taskResponse{}, err
			}

			// check that we can parse the time info
			_, err = mit.ParseTimeInfo(offering.Time, termInfo)
			if err != nil {
				log.Printf("%+v", offering)
				return taskResponse{}, fmt.Errorf("mit: failed to parse time of offering of %s (%s): %s", offering.ID, offering.Section, err.Error())
			}

			result, err := tx.Exec(
				`INSERT INTO
					mit_offerings(id, title, section, term, time, place, facultyID, facultyName, isFake, isMaster, isDesign, isLab, isLecture, isRecitation)
					VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
				ON DUPLICATE KEY UPDATE
					id = VALUES(id),
					title = VALUES(title),
					section = VALUES(section),
					term = VALUES(term),
					time = VALUES(time),
					place = VALUES(place),
					facultyID = VALUES(facultyID),
					facultyName = VALUES(facultyName),
					isFake = VALUES(isFake),
					isMaster = VALUES(isMaster),
					isDesign = VALUES(isDesign),
					isLab = VALUES(isLab),
					isLecture = VALUES(isLecture),
					isRecitation = VALUES(isRecitation)`,
				offering.ID,
				offering.Title,
				offering.Section,
				offering.Term,
				offering.Time,
				offering.Place,
				offering.FacultyID,
				offering.FacultyName,
				offering.IsFake,
				offering.IsMaster,
				offering.IsDesign,
				offering.IsLab,
				offering.IsLecture,
				offering.IsRecitation,
			)
			if err != nil {
				return taskResponse{}, err
			}

			rowAffected, err := result.RowsAffected()
			if err != nil {
				return taskResponse{}, err
			}
			if rowAffected > 0 {
				rowsAffected++
			}
		}
	}

	return taskResponse{
		RowsAffected: rowsAffected,
	}, tx.Commit()
}
<commit_msg>tasks/mitImport: add 2.681 to skip class list for 2023FA<commit_after>package tasks

import (
	"database/sql"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"strings"
	"time"

	"github.com/MyHomeworkSpace/api-server/mit"
	"github.com/MyHomeworkSpace/api-server/util"

	"github.com/MyHomeworkSpace/api-server/config"
)

// some classes have weird times and aren't on the catalog, so we just give up on them
var skipClasses = map[string][]string{
	"2021SP": {"20.051", "21M.442"},
	"2022FA": {"15.S24", "15.830", "21M.138", "21M.460"},
	"2022SP": {"8.962"},
	"2023FA": {"2.681", "6.9130", "12.703", "15.401", "15.830", "21M.460"},
}

type catalogListing struct {
	ID         string `json:"id"`
	ShortTitle string `json:"short"`
	Title      string `json:"title"`

	OfferedFall   bool `bool:"fall"`
	OfferedIAP    bool `bool:"iap"`
	OfferedSpring bool `bool:"spring"`

	FallInstructors   string `json:"fallI"`
	SpringInstructors string `json:"springI"`
}

type subjectOffering struct {
	ID      string `json:"id"`
	Title   string `json:"title"`
	Section string `json:"section"`
	Term    string `json:"term"`

	Time  string `json:"time"`
	Place string `json:"place"`

	FacultyID   string `json:"facultyID"`
	FacultyName string `json:"facultyName"`

	IsFake   bool `json:"fake"`
	IsMaster bool `json:"master"`

	IsDesign     bool `json:"design"`
	IsLab        bool `json:"lab"`
	IsLecture    bool `json:"lecture"`
	IsRecitation bool `json:"recitation"`
}

// StartImportFromMIT begins an import of the given data from the MIT Data Warehouse.
func StartImportFromMIT(source string, db *sql.DB) error {
	if source != "catalog" && source != "coursews" && source != "offerings" {
		return errors.New("tasks: invalid parameter")
	}

	taskID := "mit_" + source
	taskName := "MIT Import - " + source

	go taskWatcher(taskID, taskName, importFromMIT, source, db)
	return nil
}

func importFromMIT(lastCompletion *time.Time, source string, db *sql.DB) (taskResponse, error) {
	mitConfig := config.GetCurrent().MIT
	params := url.Values{}

	params.Add("source", source)

	currentTerm := mit.GetCurrentTerm()
	params.Add("termCode", currentTerm.Code)
	params.Add("academicYear", currentTerm.Code[:4])

	// TODO: remove
	params.Add("lastUpdateDate", "2019-01-01")

	requestURL := mitConfig.DataProxyURL + "fetch?" + params.Encode()
	if source == "coursews" {
		// actually use the secret coursews API
		requestURL = "https://coursews.mit.edu/coursews/"
	}

	client := &http.Client{}
	request, err := http.NewRequest("GET", requestURL, nil)
	if err != nil {
		return taskResponse{}, err
	}

	if source != "coursews" {
		request.Header.Add("X-MHS-Auth", mitConfig.ProxyToken)
	}

	response, err := client.Do(request)
	if err != nil {
		return taskResponse{}, err
	}

	defer response.Body.Close()

	if response.StatusCode != http.StatusOK {
		bodyBytes, err := ioutil.ReadAll(response.Body)
		if err != nil {
			return taskResponse{}, err
		}

		return taskResponse{}, fmt.Errorf(
			"tasks: MIT data server returned status code %d, body: '%s'",
			response.StatusCode,
			string(bodyBytes),
		)
	}

	tx, err := db.Begin()
	if err != nil {
		return taskResponse{}, err
	}

	rowsAffected := int64(0)

	if source == "catalog" {
		listings := []catalogListing{}
		err = json.NewDecoder(response.Body).Decode(&listings)
		if err != nil {
			return taskResponse{}, err
		}

		for _, listing := range listings {
			result, err := tx.Exec(
				`INSERT INTO
					mit_listings(id, shortTitle, title, offeredFall, offeredIAP, offeredSpring, fallInstructors, springInstructors)
					VALUES(?, ?, ?, ?, ?, ?, ?, ?)
				ON DUPLICATE KEY UPDATE
					id = VALUES(id),
					shortTitle = VALUES(shortTitle),
					title = VALUES(title),
					offeredFall = VALUES(offeredFall),
					offeredIAP = VALUES(offeredIAP),
					offeredSpring = VALUES(offeredSpring),
					fallInstructors = VALUES(fallInstructors),
					springInstructors = VALUES(springInstructors)
				`,
				listing.ID,
				listing.ShortTitle,
				listing.Title,
				listing.OfferedFall,
				listing.OfferedIAP,
				listing.OfferedSpring,
				listing.FallInstructors,
				listing.SpringInstructors,
			)
			if err != nil {
				return taskResponse{}, err
			}

			rowAffected, err := result.RowsAffected()
			if err != nil {
				return taskResponse{}, err
			}
			if rowAffected > 0 {
				rowsAffected++
			}
		}
	} else if source == "coursews" {
		// unfortunately, this API gives us data in a rather annoying format
		// so we cannot just parse them into a go struct
		// instead we have to use a hacky series of typecasts :(
		wsData := map[string]interface{}{}
		err = json.NewDecoder(response.Body).Decode(&wsData)
		if err != nil {
			return taskResponse{}, err
		}

		items := wsData["items"].([]interface{})

		// assume it's all the same term
		termInfo, err := mit.GetTermByCode(currentTerm.Code)
		if err != nil {
			return taskResponse{}, err
		}

		// first, clear out any data from a previous term
		_, err = tx.Exec("DELETE FROM mit_offerings WHERE term <> ?", currentTerm.Code)
		if err != nil {
			return taskResponse{}, err
		}

		for _, itemInterface := range items {
			item := itemInterface.(map[string]interface{})

			itemType := item["type"].(string)

			if itemType == "Class" {
				// we actually don't care about classes
				continue
			}

			if itemType != "LectureSession" && itemType != "LabSession" && itemType != "RecitationSession" {
				return taskResponse{}, fmt.Errorf("tasks: unknown coursews item type '%s'", itemType)
			}

			itemLabel := item["label"].(string)
			itemSectionOf := item["section-of"].(string)
			itemTimeAndPlace := item["timeAndPlace"].(string)

			if itemTimeAndPlace == "null null" {
				// this record tells us absolutely nothing
				// ignore it
				continue
			}

			// for some reason, the labels are the section + class number joined together
			// for example, section L01 of 6.003 has a label of "L016.003"
			// parse out the section ID
			sectionID := strings.Replace(itemLabel, itemSectionOf, "", -1)

			// in order to maximize suffering, the coursews api also combines the time and place fields
			// examples of this include "MW9.30-11 4-251" (easy)
			// or "TR9-11 (MEETS 4/7 TO 5/14) MEC-209" and "M EVE (6-8 PM) BOSTON PRE-REL" (why??)
			// the high quality algorithm to parse this is to break the string into spaces, and keep removing words until it works
			timeAndPlaceParts := strings.Split(itemTimeAndPlace, " ")
			currentTimeString := ""
			parsed := false
			for i := len(timeAndPlaceParts); i > 0; i-- {
				currentTimeString = ""
				for j := 0; j < i; j++ {
					if j != 0 {
						currentTimeString += " "
					}
					currentTimeString += timeAndPlaceParts[j]
				}

				// attempt
				_, err = mit.ParseTimeInfo(currentTimeString, termInfo)
				if err != nil {
					// oofie
					continue
				}

				// we survived!
				parsed = true
				break
			}

			if !parsed {
				return taskResponse{}, fmt.Errorf("tasks: failed to parse timeAndPlace '%s'", itemTimeAndPlace)
			}

			time := currentTimeString
			place := strings.TrimSpace(strings.Replace(itemTimeAndPlace, currentTimeString, "", -1))

			if place == "" {
				return taskResponse{}, fmt.Errorf("tasks: didn't get place from timeAndPlace '%s'", itemTimeAndPlace)
			}

			if place == "null" {
				place = ""
			}

			isDesign := false // design sections seem to not be included?
			isLab := (sectionID[0] == 'B')
			isLecture := (sectionID[0] == 'L')
			isRecitation := (sectionID[0] == 'R')

			// now, try to insert this new record
			// since we have very little info, we do NOT overwrite existing faculty/extra data if we have some
			result, err := tx.Exec(
				`INSERT INTO
					mit_offerings(id, title, section, term, time, place, facultyID, facultyName, isFake, isMaster, isDesign, isLab, isLecture, isRecitation)
					VALUES(?, '', ?, ?, ?, ?, '', '', 0, 0, ?, ?, ?, ?)
				ON DUPLICATE KEY UPDATE
					id = VALUES(id),
					section = VALUES(section),
					term = VALUES(term),
					time = VALUES(time),
					place = VALUES(place),
					isDesign = VALUES(isDesign),
					isLab = VALUES(isLab),
					isLecture = VALUES(isLecture),
					isRecitation = VALUES(isRecitation)`,
				itemSectionOf,
				sectionID,
				currentTerm.Code,
				time,
				place,
				isDesign,
				isLab,
				isLecture,
				isRecitation,
			)
			if err != nil {
				return taskResponse{}, err
			}

			rowAffected, err := result.RowsAffected()
			if err != nil {
				return taskResponse{}, err
			}
			if rowAffected > 0 {
				rowsAffected++
			}
		}
	} else if source == "offerings" {
		offerings := []subjectOffering{}
		err = json.NewDecoder(response.Body).Decode(&offerings)
		if err != nil {
			return taskResponse{}, err
		}

		// first, clear out any data from a previous term
		_, err = tx.Exec("DELETE FROM mit_offerings WHERE term <> ?", currentTerm.Code)
		if err != nil {
			return taskResponse{}, err
		}

		for _, offering := range offerings {
			if offering.Time == "" {
				continue
			}

			if util.StringSliceContains(skipClasses[currentTerm.Code], offering.ID) {
				continue
			}

			termInfo, err := mit.GetTermByCode(offering.Term)
			if err != nil {
				return taskResponse{}, err
			}

			// check that we can parse the time info
			_, err = mit.ParseTimeInfo(offering.Time, termInfo)
			if err != nil {
				log.Printf("%+v", offering)
				return taskResponse{}, fmt.Errorf("mit: failed to parse time of offering of %s (%s): %s", offering.ID, offering.Section, err.Error())
			}

			result, err := tx.Exec(
				`INSERT INTO
					mit_offerings(id, title, section, term, time, place, facultyID, facultyName, isFake, isMaster, isDesign, isLab, isLecture, isRecitation)
					VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
				ON DUPLICATE KEY UPDATE
					id = VALUES(id),
					title = VALUES(title),
					section = VALUES(section),
					term = VALUES(term),
					time = VALUES(time),
					place = VALUES(place),
					facultyID = VALUES(facultyID),
					facultyName = VALUES(facultyName),
					isFake = VALUES(isFake),
					isMaster = VALUES(isMaster),
					isDesign = VALUES(isDesign),
					isLab = VALUES(isLab),
					isLecture = VALUES(isLecture),
					isRecitation = VALUES(isRecitation)`,
				offering.ID,
				offering.Title,
				offering.Section,
				offering.Term,
				offering.Time,
				offering.Place,
				offering.FacultyID,
				offering.FacultyName,
				offering.IsFake,
				offering.IsMaster,
				offering.IsDesign,
				offering.IsLab,
				offering.IsLecture,
				offering.IsRecitation,
			)
			if err != nil {
				return taskResponse{}, err
			}

			rowAffected, err := result.RowsAffected()
			if err != nil {
				return taskResponse{}, err
			}
			if rowAffected > 0 {
				rowsAffected++
			}
		}
	}

	return taskResponse{
		RowsAffected: rowsAffected,
	}, tx.Commit()
}
<|endoftext|>


<commit_before>// errorcheck -0 -m -l

// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Test, using compiler diagnostic flags, that the escape analysis is working.
// Compiles but does not run.  Inlining is disabled.

package foo

import (
	"runtime"
	"unsafe"
)

func noleak(p *int) int { // ERROR "p does not escape"
	return *p
}

func leaktoret(p *int) *int { // ERROR "leaking param: p to result"
	return p
}

func leaktoret2(p *int) (*int, *int) { // ERROR "leaking param: p to result ~r1" "leaking param: p to result ~r2"
	return p, p
}

func leaktoret22(p, q *int) (*int, *int) { // ERROR "leaking param: p to result ~r2" "leaking param: q to result ~r3"
	return p, q
}

func leaktoret22b(p, q *int) (*int, *int) { // ERROR "leaking param: p to result ~r3" "leaking param: q to result ~r2"
	return leaktoret22(q, p)
}

func leaktoret22c(p, q *int) (*int, *int) { // ERROR "leaking param: p to result ~r3" "leaking param: q to result ~r2"
	r, s := leaktoret22(q, p)
	return r, s
}

func leaktoret22d(p, q *int) (r, s *int) { // ERROR "leaking param: p to result s" "leaking param: q to result r"
	r, s = leaktoret22(q, p)
	return
}

func leaktoret22e(p, q *int) (r, s *int) { // ERROR "leaking param: p to result s" "leaking param: q to result r"
	r, s = leaktoret22(q, p)
	return r, s
}

func leaktoret22f(p, q *int) (r, s *int) { // ERROR "leaking param: p to result s" "leaking param: q to result r"
	rr, ss := leaktoret22(q, p)
	return rr, ss
}

var gp *int

func leaktosink(p *int) *int { // ERROR "leaking param: p"
	gp = p
	return p
}

func f1() {
	var x int
	p := noleak(&x)
	_ = p
}

func f2() {
	var x int
	p := leaktoret(&x)
	_ = p
}

func f3() {
	var x int // ERROR "moved to heap: x"
	p := leaktoret(&x)
	gp = p
}

func f4() {
	var x int // ERROR "moved to heap: x"
	p, q := leaktoret2(&x)
	gp = p
	gp = q
}

func f5() {
	var x int
	leaktoret22(leaktoret2(&x))
}

func f6() {
	var x int // ERROR "moved to heap: x"
	px1, px2 := leaktoret22(leaktoret2(&x))
	gp = px1
	_ = px2
}

type T struct{ x int }

func (t *T) Foo(u int) (*T, bool) { // ERROR "leaking param: t to result"
	t.x += u
	return t, true
}

func f7() *T {
	r, _ := new(T).Foo(42) // ERROR "new.T. escapes to heap"
	return r
}

func leakrecursive1(p, q *int) (*int, *int) { // ERROR "leaking param: p" "leaking param: q"
	return leakrecursive2(q, p)
}

func leakrecursive2(p, q *int) (*int, *int) { // ERROR "leaking param: p" "leaking param: q"
	if *p > *q {
		return leakrecursive1(q, p)
	}
	// without this, leakrecursive? are safe for p and q, b/c in fact their graph does not have leaking edges.
	return p, q
}

var global interface{}

type T1 struct {
	X *int
}

type T2 struct {
	Y *T1
}

func f8(p *T1) (k T2) { // ERROR "leaking param: p$"
	if p == nil {
		k = T2{}
		return
	}

	// should make p leak always
	global = p
	return T2{p}
}

func f9() {
	var j T1 // ERROR "moved to heap: j"
	f8(&j)
}

func f10() {
	// These don't escape but are too big for the stack
	var x [1 << 30]byte         // ERROR "moved to heap: x"
	var y = make([]byte, 1<<30) // ERROR "make\(\[\]byte, 1 << 30\) escapes to heap"
	_ = x[0] + y[0]
}

// Test for issue 19687 (passing to unnamed parameters does not escape).
func f11(**int) {
}
func f12(_ **int) {
}
func f13() {
	var x *int
	f11(&x)
	f12(&x)
	runtime.KeepAlive(&x)
}

// Test for issue 24305 (passing to unnamed receivers does not escape).
type U int

func (*U) M()   {}
func (_ *U) N() {}

func _() {
	var u U
	u.M()
	u.N()
}

// Issue 24730: taking address in a loop causes unnecessary escape
type T24730 struct {
	x [64]byte
}

func (t *T24730) g() { // ERROR "t does not escape"
	y := t.x[:]
	for i := range t.x[:] {
		y = t.x[:]
		y[i] = 1
	}

	var z *byte
	for i := range t.x[:] {
		z = &t.x[i]
		*z = 2
	}
}

// Issue 15730: copy causes unnecessary escape

var sink []byte
var sink2 []int
var sink3 []*int

func f15730a(args ...interface{}) { // ERROR "args does not escape"
	for _, arg := range args {
		switch a := arg.(type) {
		case string:
			copy(sink, a)
		}
	}
}

func f15730b(args ...interface{}) { // ERROR "args does not escape"
	for _, arg := range args {
		switch a := arg.(type) {
		case []int:
			copy(sink2, a)
		}
	}
}

func f15730c(args ...interface{}) { // ERROR "leaking param content: args"
	for _, arg := range args {
		switch a := arg.(type) {
		case []*int:
			// copy pointerful data should cause escape
			copy(sink3, a)
		}
	}
}

// Issue 29000: unnamed parameter is not handled correctly

var sink4 interface{}
var alwaysFalse = false

func f29000(_ int, x interface{}) { // ERROR "leaking param: x"
	sink4 = x
	if alwaysFalse {
		g29000()
	}
}

func g29000() {
	x := 1
	f29000(2, x) // ERROR "x escapes to heap"
}

// Issue 28369: taking an address of a parameter and converting it into a uintptr causes an
// unnecessary escape.

var sink28369 uintptr

func f28369(n int) int {
	if n == 0 {
		sink28369 = uintptr(unsafe.Pointer(&n))
		return n
	}

	return 1 + f28369(n-1)
}
<commit_msg>cmd/compile: add failing test case for #24305<commit_after>// errorcheck -0 -m -l

// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Test, using compiler diagnostic flags, that the escape analysis is working.
// Compiles but does not run.  Inlining is disabled.

package foo

import (
	"runtime"
	"unsafe"
)

func noleak(p *int) int { // ERROR "p does not escape"
	return *p
}

func leaktoret(p *int) *int { // ERROR "leaking param: p to result"
	return p
}

func leaktoret2(p *int) (*int, *int) { // ERROR "leaking param: p to result ~r1" "leaking param: p to result ~r2"
	return p, p
}

func leaktoret22(p, q *int) (*int, *int) { // ERROR "leaking param: p to result ~r2" "leaking param: q to result ~r3"
	return p, q
}

func leaktoret22b(p, q *int) (*int, *int) { // ERROR "leaking param: p to result ~r3" "leaking param: q to result ~r2"
	return leaktoret22(q, p)
}

func leaktoret22c(p, q *int) (*int, *int) { // ERROR "leaking param: p to result ~r3" "leaking param: q to result ~r2"
	r, s := leaktoret22(q, p)
	return r, s
}

func leaktoret22d(p, q *int) (r, s *int) { // ERROR "leaking param: p to result s" "leaking param: q to result r"
	r, s = leaktoret22(q, p)
	return
}

func leaktoret22e(p, q *int) (r, s *int) { // ERROR "leaking param: p to result s" "leaking param: q to result r"
	r, s = leaktoret22(q, p)
	return r, s
}

func leaktoret22f(p, q *int) (r, s *int) { // ERROR "leaking param: p to result s" "leaking param: q to result r"
	rr, ss := leaktoret22(q, p)
	return rr, ss
}

var gp *int

func leaktosink(p *int) *int { // ERROR "leaking param: p"
	gp = p
	return p
}

func f1() {
	var x int
	p := noleak(&x)
	_ = p
}

func f2() {
	var x int
	p := leaktoret(&x)
	_ = p
}

func f3() {
	var x int // ERROR "moved to heap: x"
	p := leaktoret(&x)
	gp = p
}

func f4() {
	var x int // ERROR "moved to heap: x"
	p, q := leaktoret2(&x)
	gp = p
	gp = q
}

func f5() {
	var x int
	leaktoret22(leaktoret2(&x))
}

func f6() {
	var x int // ERROR "moved to heap: x"
	px1, px2 := leaktoret22(leaktoret2(&x))
	gp = px1
	_ = px2
}

type T struct{ x int }

func (t *T) Foo(u int) (*T, bool) { // ERROR "leaking param: t to result"
	t.x += u
	return t, true
}

func f7() *T {
	r, _ := new(T).Foo(42) // ERROR "new.T. escapes to heap"
	return r
}

func leakrecursive1(p, q *int) (*int, *int) { // ERROR "leaking param: p" "leaking param: q"
	return leakrecursive2(q, p)
}

func leakrecursive2(p, q *int) (*int, *int) { // ERROR "leaking param: p" "leaking param: q"
	if *p > *q {
		return leakrecursive1(q, p)
	}
	// without this, leakrecursive? are safe for p and q, b/c in fact their graph does not have leaking edges.
	return p, q
}

var global interface{}

type T1 struct {
	X *int
}

type T2 struct {
	Y *T1
}

func f8(p *T1) (k T2) { // ERROR "leaking param: p$"
	if p == nil {
		k = T2{}
		return
	}

	// should make p leak always
	global = p
	return T2{p}
}

func f9() {
	var j T1 // ERROR "moved to heap: j"
	f8(&j)
}

func f10() {
	// These don't escape but are too big for the stack
	var x [1 << 30]byte         // ERROR "moved to heap: x"
	var y = make([]byte, 1<<30) // ERROR "make\(\[\]byte, 1 << 30\) escapes to heap"
	_ = x[0] + y[0]
}

// Test for issue 19687 (passing to unnamed parameters does not escape).
func f11(**int) {
}
func f12(_ **int) {
}
func f13() {
	var x *int
	f11(&x)
	f12(&x)
	runtime.KeepAlive(&x)
}

// Test for issue 24305 (passing to unnamed receivers does not escape).
type U int

func (*U) M()   {}
func (_ *U) N() {}

func _() {
	var u U
	u.M()
	u.N()
}

func fbad24305() {
	// BAD u should not be heap allocated
	var u U // ERROR "moved to heap: u"
	(*U).M(&u)
	(*U).N(&u)
}

// Issue 24730: taking address in a loop causes unnecessary escape
type T24730 struct {
	x [64]byte
}

func (t *T24730) g() { // ERROR "t does not escape"
	y := t.x[:]
	for i := range t.x[:] {
		y = t.x[:]
		y[i] = 1
	}

	var z *byte
	for i := range t.x[:] {
		z = &t.x[i]
		*z = 2
	}
}

// Issue 15730: copy causes unnecessary escape

var sink []byte
var sink2 []int
var sink3 []*int

func f15730a(args ...interface{}) { // ERROR "args does not escape"
	for _, arg := range args {
		switch a := arg.(type) {
		case string:
			copy(sink, a)
		}
	}
}

func f15730b(args ...interface{}) { // ERROR "args does not escape"
	for _, arg := range args {
		switch a := arg.(type) {
		case []int:
			copy(sink2, a)
		}
	}
}

func f15730c(args ...interface{}) { // ERROR "leaking param content: args"
	for _, arg := range args {
		switch a := arg.(type) {
		case []*int:
			// copy pointerful data should cause escape
			copy(sink3, a)
		}
	}
}

// Issue 29000: unnamed parameter is not handled correctly

var sink4 interface{}
var alwaysFalse = false

func f29000(_ int, x interface{}) { // ERROR "leaking param: x"
	sink4 = x
	if alwaysFalse {
		g29000()
	}
}

func g29000() {
	x := 1
	f29000(2, x) // ERROR "x escapes to heap"
}

// Issue 28369: taking an address of a parameter and converting it into a uintptr causes an
// unnecessary escape.

var sink28369 uintptr

func f28369(n int) int {
	if n == 0 {
		sink28369 = uintptr(unsafe.Pointer(&n))
		return n
	}

	return 1 + f28369(n-1)
}
<|endoftext|>


<commit_before>package api

import (
	r "github.com/pgpst/pgpst/internal/github.com/dancannon/gorethink"
	"github.com/pgpst/pgpst/internal/github.com/gin-gonic/gin"

	"github.com/pgpst/pgpst/pkg/models"
)

func (a *API) getLabelThreads(c *gin.Context) {
	// Token and account from context
	var (
		account = c.MustGet("account").(*models.Account)
		token   = c.MustGet("token").(*models.Token)
	)

	// Resolve the ID from the URL
	id := c.Param("id")

	// Get label from the database
	cursor, err := r.Table("labels").Get(id).Run(a.Rethink)
	if err != nil {
		c.JSON(500, &gin.H{
			"code":  0,
			"error": err.Error(),
		})
		return
	}
	var label *models.Label
	if err := cursor.One(&label); err != nil {
		c.JSON(500, &gin.H{
			"code":  0,
			"error": err.Error(),
		})
		return
	}

	// Check the ownership and scope
	if label.Owner == account.ID {
		if !models.InScope(token.Scope, []string{"labels:read"}) {
			c.JSON(403, &gin.H{
				"code":  0,
				"error": "Your token has insufficient scope",
			})
			return
		}
	} else {
		if !models.InScope(token.Scope, []string{"admin"}) {
			c.JSON(403, &gin.H{
				"code":  0,
				"error": "Your token has insufficient scope",
			})
			return
		}
	}

	// Get threads from the database
	cursor, err = r.Table("threads").GetAllByIndex("labels", label.ID).OrderBy(r.Desc("date_modified")).Run(a.Rethink)
	if err != nil {
		c.JSON(500, &gin.H{
			"code":  0,
			"error": err.Error(),
		})
		return
	}
	var threads []*models.Thread
	if err := cursor.All(&threads); err != nil {
		c.JSON(500, &gin.H{
			"code":  0,
			"error": err.Error(),
		})
		return
	}
	if threads == nil {
		threads = []*models.Thread{}
	}

	// Write the response
	c.JSON(200, threads)
	return
}
<commit_msg>Added extended thread responses<commit_after>package api

import (
	r "github.com/pgpst/pgpst/internal/github.com/dancannon/gorethink"
	"github.com/pgpst/pgpst/internal/github.com/gin-gonic/gin"

	"github.com/pgpst/pgpst/pkg/models"
)

type extendedThread struct {
	*models.Thread
	Manifest []byte `gorethink:"manifest" json:"manifest"`
}

func (a *API) getLabelThreads(c *gin.Context) {
	// Token and account from context
	var (
		account = c.MustGet("account").(*models.Account)
		token   = c.MustGet("token").(*models.Token)
	)

	// Resolve the ID from the URL
	id := c.Param("id")

	// Get label from the database
	cursor, err := r.Table("labels").Get(id).Run(a.Rethink)
	if err != nil {
		c.JSON(500, &gin.H{
			"code":  0,
			"error": err.Error(),
		})
		return
	}
	var label *models.Label
	if err := cursor.One(&label); err != nil {
		c.JSON(500, &gin.H{
			"code":  0,
			"error": err.Error(),
		})
		return
	}

	// Check the ownership and scope
	if label.Owner == account.ID {
		if !models.InScope(token.Scope, []string{"labels:read"}) {
			c.JSON(403, &gin.H{
				"code":  0,
				"error": "Your token has insufficient scope",
			})
			return
		}
	} else {
		if !models.InScope(token.Scope, []string{"admin"}) {
			c.JSON(403, &gin.H{
				"code":  0,
				"error": "Your token has insufficient scope",
			})
			return
		}
	}

	// Get threads from the database
	cursor, err = r.Table("threads").GetAllByIndex("labels", label.ID).OrderBy(r.Desc("date_modified")).Map(func(thread r.Term) r.Term {
		return thread.Merge(map[string]interface{}{
			"manifest": r.Table("emails").GetAllByIndex("thread", thread.Field("id")).OrderBy("date_modified").CoerceTo("array"),
		}).Do(func(thread r.Term) r.Term {
			return r.Branch(
				thread.Field("manifest").Count().Gt(0),
				thread.Merge(map[string]interface{}{
					"manifest": thread.Field("manifest").Nth(0).Field("manifest"),
				}),
				thread.Without("manifest"),
			)
		})
	}).Run(a.Rethink)
	if err != nil {
		c.JSON(500, &gin.H{
			"code":  0,
			"error": err.Error(),
		})
		return
	}
	var threads []*extendedThread
	if err := cursor.All(&threads); err != nil {
		c.JSON(500, &gin.H{
			"code":  0,
			"error": err.Error(),
		})
		return
	}
	if threads == nil {
		threads = []*extendedThread{}
	}

	// Write the response
	c.JSON(200, threads)
	return
}
<|endoftext|>


<commit_before>// Copyright 2018 the u-root Authors. 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 is the busybox main.go template.
package main

import (
	"log"
	"os"
	"path/filepath"

	"github.com/u-root/u-root/pkg/bb/bbmain"
	"github.com/u-root/u-root/pkg/upath"
)

func run() {
	name := filepath.Base(os.Args[0])
	if err := bbmain.Run(name); err != nil {
		log.Fatalf("%s: %v", name, err)
	}
}

func main() {
	os.Args[0] = upath.ResolveUntilLastSymlink(os.Args[0])

	run()
}

func init() {
	m := func() {
		// Use argv[1] as the name.
		os.Args = os.Args[1:]
		run()
	}
	bbmain.Register("bb", bbmain.Noop, m)
	bbmain.RegisterDefault(bbmain.Noop, m)
}
<commit_msg>Prevent possible panic in bbmain<commit_after>// Copyright 2018 the u-root Authors. 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 is the busybox main.go template.
package main

import (
	"log"
	"os"
	"path/filepath"

	"github.com/u-root/u-root/pkg/bb/bbmain"
	"github.com/u-root/u-root/pkg/upath"
)

func run() {
	name := filepath.Base(os.Args[0])
	if err := bbmain.Run(name); err != nil {
		log.Fatalf("%s: %v", name, err)
	}
}

func main() {
	os.Args[0] = upath.ResolveUntilLastSymlink(os.Args[0])

	run()
}

func init() {
	m := func() {
		if len(os.Args) == 1 {
			log.Fatalf("Invalid busybox command: %q", os.Args)
		}
		// Use argv[1] as the name.
		os.Args = os.Args[1:]
		run()
	}
	bbmain.Register("bb", bbmain.Noop, m)
	bbmain.RegisterDefault(bbmain.Noop, m)
}
<|endoftext|>


<commit_before>package datasrc

import (
	"errors"
	"log"
	"time"

	"github.com/tmrts/flamingo/pkg/datasrc/metadata"
	"github.com/tmrts/flamingo/pkg/datasrc/provider/gce"
	"github.com/tmrts/flamingo/pkg/datasrc/provider/openstack"
	"github.com/tmrts/flamingo/pkg/datasrc/userdata"
)

type Provider interface {
	metadata.Provider
	userdata.Provider
}

// SupportedProviders returns the table of supported meta-data sources.
func SupportedProviders() map[string]Provider {
	return map[string]Provider{
		"GCE":       &gce.MetadataService{gce.MetadataURL},
		"OpenStack": &openstack.MetadataService{openstack.MetadataURL},
	}
}

var (
	ErrDatasourceRetrievalTimeout = errors.New("datasrc: timeout during data-source retrieval")
)

// isAvailable tries to fetch meta-data from the given datasource provider
// and returns the error if it encounters any.
func isAvailable(p Provider) bool {
	_, err := p.FetchMetadata()
	if err != nil {
		log.Print("datasrc.isAvailable:", err)
	}

	return err == nil
}

// FindProvider checks the given datasource providers and returns the available one.
func FindProvider(providers map[string]Provider, timeout time.Duration) (Provider, error) {
	providerChan := make(chan Provider)

	for _, p := range providers {
		go func() {
			if isAvailable(p) {
				providerChan <- p
			}
		}()
	}

	timeoutChan := time.NewTimer(timeout).C

	select {
	case p := <-providerChan:
		return p, nil
	case <-timeoutChan:
		return nil, ErrDatasourceRetrievalTimeout
	}
}
<commit_msg>Relocate new errors<commit_after>package datasrc

import (
	"errors"
	"log"
	"time"

	"github.com/tmrts/flamingo/pkg/datasrc/metadata"
	"github.com/tmrts/flamingo/pkg/datasrc/provider/gce"
	"github.com/tmrts/flamingo/pkg/datasrc/provider/openstack"
	"github.com/tmrts/flamingo/pkg/datasrc/userdata"
)

var (
	ErrDatasourceRetrievalTimeout = errors.New("datasrc: timeout during data-source retrieval")
)

type Provider interface {
	metadata.Provider
	userdata.Provider
}

// SupportedProviders returns the table of supported meta-data sources.
func SupportedProviders() map[string]Provider {
	return map[string]Provider{
		"GCE":       &gce.MetadataService{gce.MetadataURL},
		"OpenStack": &openstack.MetadataService{openstack.MetadataURL},
	}
}

// isAvailable tries to fetch meta-data from the given datasource provider
// and returns the error if it encounters any.
func isAvailable(p Provider) bool {
	_, err := p.FetchMetadata()
	if err != nil {
		log.Print("datasrc.isAvailable:", err)
	}

	return err == nil
}

// FindProvider checks the given datasource providers and returns the available one.
func FindProvider(providers map[string]Provider, timeout time.Duration) (Provider, error) {
	providerChan := make(chan Provider)

	for _, p := range providers {
		go func() {
			if isAvailable(p) {
				providerChan <- p
			}
		}()
	}

	timeoutChan := time.NewTimer(timeout).C

	select {
	case p := <-providerChan:
		return p, nil
	case <-timeoutChan:
		return nil, ErrDatasourceRetrievalTimeout
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2014 The Kubernetes 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 cmd

import (
	"fmt"
	"io"
	"runtime"

	"github.com/spf13/cobra"

	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/kubernetes/pkg/kubectl"
	"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
	"k8s.io/kubernetes/pkg/kubectl/cmd/util/editor"
	"k8s.io/kubernetes/pkg/kubectl/resource"
	"k8s.io/kubernetes/pkg/kubectl/util/i18n"
)

type CreateOptions struct {
	FilenameOptions  resource.FilenameOptions
	Selector         string
	EditBeforeCreate bool
}

var (
	createLong = templates.LongDesc(i18n.T(`
		Create a resource from a file or from stdin.

		JSON and YAML formats are accepted.`))

	createExample = templates.Examples(i18n.T(`
		# Create a pod using the data in pod.json.
		kubectl create -f ./pod.json

		# Create a pod based on the JSON passed into stdin.
		cat pod.json | kubectl create -f -

		# Edit the data in docker-registry.yaml in JSON using the v1 API format then create the resource using the edited data.
		kubectl create -f docker-registry.yaml --edit --output-version=v1 -o json`))
)

func NewCmdCreate(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
	var options CreateOptions

	cmd := &cobra.Command{
		Use:     "create -f FILENAME",
		Short:   i18n.T("Create a resource from a file or from stdin."),
		Long:    createLong,
		Example: createExample,
		Run: func(cmd *cobra.Command, args []string) {
			if cmdutil.IsFilenameSliceEmpty(options.FilenameOptions.Filenames) {
				defaultRunFunc := cmdutil.DefaultSubCommandRun(errOut)
				defaultRunFunc(cmd, args)
				return
			}
			cmdutil.CheckErr(ValidateArgs(cmd, args))
			cmdutil.CheckErr(RunCreate(f, cmd, out, errOut, &options))
		},
	}

	usage := "to use to create the resource"
	cmdutil.AddFilenameOptionFlags(cmd, &options.FilenameOptions, usage)
	cmd.MarkFlagRequired("filename")
	cmdutil.AddValidateFlags(cmd)
	cmdutil.AddPrinterFlags(cmd)
	cmd.Flags().BoolVar(&options.EditBeforeCreate, "edit", false, "Edit the API resource before creating")
	cmd.Flags().Bool("windows-line-endings", runtime.GOOS == "windows",
		"Only relevant if --edit=true. Defaults to the line ending native to your platform.")
	cmdutil.AddApplyAnnotationFlags(cmd)
	cmdutil.AddRecordFlag(cmd)
	cmdutil.AddDryRunFlag(cmd)
	cmdutil.AddInclude3rdPartyFlags(cmd)
	cmd.Flags().StringVarP(&options.Selector, "selector", "l", "", "Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)")

	// create subcommands
	cmd.AddCommand(NewCmdCreateNamespace(f, out))
	cmd.AddCommand(NewCmdCreateQuota(f, out))
	cmd.AddCommand(NewCmdCreateSecret(f, out, errOut))
	cmd.AddCommand(NewCmdCreateConfigMap(f, out))
	cmd.AddCommand(NewCmdCreateServiceAccount(f, out))
	cmd.AddCommand(NewCmdCreateService(f, out, errOut))
	cmd.AddCommand(NewCmdCreateDeployment(f, out, errOut))
	cmd.AddCommand(NewCmdCreateClusterRole(f, out))
	cmd.AddCommand(NewCmdCreateClusterRoleBinding(f, out))
	cmd.AddCommand(NewCmdCreateRole(f, out))
	cmd.AddCommand(NewCmdCreateRoleBinding(f, out))
	cmd.AddCommand(NewCmdCreatePodDisruptionBudget(f, out))
	return cmd
}

func ValidateArgs(cmd *cobra.Command, args []string) error {
	if len(args) != 0 {
		return cmdutil.UsageErrorf(cmd, "Unexpected args: %v", args)
	}
	return nil
}

func RunCreate(f cmdutil.Factory, cmd *cobra.Command, out, errOut io.Writer, options *CreateOptions) error {
	if options.EditBeforeCreate {
		return RunEditOnCreate(f, out, errOut, cmd, &options.FilenameOptions)
	}
	schema, err := f.Validator(cmdutil.GetFlagBool(cmd, "validate"))
	if err != nil {
		return err
	}

	cmdNamespace, enforceNamespace, err := f.DefaultNamespace()
	if err != nil {
		return err
	}

	mapper, typer, err := f.UnstructuredObject()
	if err != nil {
		return err
	}

	r := f.NewBuilder().
		Unstructured(f.UnstructuredClientForMapping, mapper, typer).
		Schema(schema).
		ContinueOnError().
		NamespaceParam(cmdNamespace).DefaultNamespace().
		FilenameParam(enforceNamespace, &options.FilenameOptions).
		SelectorParam(options.Selector).
		Flatten().
		Do()
	err = r.Err()
	if err != nil {
		return err
	}

	dryRun := cmdutil.GetFlagBool(cmd, "dry-run")
	output := cmdutil.GetFlagString(cmd, "output")

	count := 0
	err = r.Visit(func(info *resource.Info, err error) error {
		if err != nil {
			return err
		}
		if err := kubectl.CreateOrUpdateAnnotation(cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag), info, f.JSONEncoder()); err != nil {
			return cmdutil.AddSourceToErr("creating", info.Source, err)
		}

		if cmdutil.ShouldRecord(cmd, info) {
			if err := cmdutil.RecordChangeCause(info.Object, f.Command(cmd, false)); err != nil {
				return cmdutil.AddSourceToErr("creating", info.Source, err)
			}
		}

		if !dryRun {
			if err := createAndRefresh(info); err != nil {
				return cmdutil.AddSourceToErr("creating", info.Source, err)
			}
		}

		count++

		shortOutput := output == "name"
		if len(output) > 0 && !shortOutput {
			return cmdutil.PrintResourceInfoForCommand(cmd, info, f, out)
		}
		if !shortOutput {
			f.PrintObjectSpecificMessage(info.Object, out)
		}

		cmdutil.PrintSuccess(mapper, shortOutput, out, info.Mapping.Resource, info.Name, dryRun, "created")
		return nil
	})
	if err != nil {
		return err
	}
	if count == 0 {
		return fmt.Errorf("no objects passed to create")
	}
	return nil
}

func RunEditOnCreate(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, options *resource.FilenameOptions) error {
	editOptions := &editor.EditOptions{
		EditMode:        editor.EditBeforeCreateMode,
		FilenameOptions: *options,
		ValidateOptions: cmdutil.ValidateOptions{
			EnableValidation: cmdutil.GetFlagBool(cmd, "validate"),
		},
		Output:             cmdutil.GetFlagString(cmd, "output"),
		WindowsLineEndings: cmdutil.GetFlagBool(cmd, "windows-line-endings"),
		ApplyAnnotation:    cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag),
		Record:             cmdutil.GetFlagBool(cmd, "record"),
		ChangeCause:        f.Command(cmd, false),
		Include3rdParty:    cmdutil.GetFlagBool(cmd, "include-extended-apis"),
	}
	err := editOptions.Complete(f, out, errOut, []string{}, cmd)
	if err != nil {
		return err
	}
	return editOptions.Run()
}

// createAndRefresh creates an object from input info and refreshes info with that object
func createAndRefresh(info *resource.Info) error {
	obj, err := resource.NewHelper(info.Client, info.Mapping).Create(info.Namespace, true, info.Object)
	if err != nil {
		return err
	}
	info.Refresh(obj, true)
	return nil
}

// NameFromCommandArgs is a utility function for commands that assume the first argument is a resource name
func NameFromCommandArgs(cmd *cobra.Command, args []string) (string, error) {
	if len(args) == 0 {
		return "", cmdutil.UsageErrorf(cmd, "NAME is required")
	}
	return args[0], nil
}

// CreateSubcommandOptions is an options struct to support create subcommands
type CreateSubcommandOptions struct {
	// Name of resource being created
	Name string
	// StructuredGenerator is the resource generator for the object being created
	StructuredGenerator kubectl.StructuredGenerator
	// DryRun is true if the command should be simulated but not run against the server
	DryRun       bool
	OutputFormat string
}

// RunCreateSubcommand executes a create subcommand using the specified options
func RunCreateSubcommand(f cmdutil.Factory, cmd *cobra.Command, out io.Writer, options *CreateSubcommandOptions) error {
	namespace, _, err := f.DefaultNamespace()
	if err != nil {
		return err
	}
	obj, err := options.StructuredGenerator.StructuredGenerate()
	if err != nil {
		return err
	}
	mapper, typer := f.Object()
	gvks, _, err := typer.ObjectKinds(obj)
	if err != nil {
		return err
	}
	gvk := gvks[0]
	mapping, err := mapper.RESTMapping(schema.GroupKind{Group: gvk.Group, Kind: gvk.Kind}, gvk.Version)
	if err != nil {
		return err
	}
	client, err := f.ClientForMapping(mapping)
	if err != nil {
		return err
	}
	resourceMapper := &resource.Mapper{
		ObjectTyper:  typer,
		RESTMapper:   mapper,
		ClientMapper: resource.ClientMapperFunc(f.ClientForMapping),
	}
	info, err := resourceMapper.InfoForObject(obj, nil)
	if err != nil {
		return err
	}
	if err := kubectl.CreateOrUpdateAnnotation(cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag), info, f.JSONEncoder()); err != nil {
		return err
	}
	obj = info.Object

	if !options.DryRun {
		obj, err = resource.NewHelper(client, mapping).Create(namespace, false, info.Object)
		if err != nil {
			return err
		}
	}

	if useShortOutput := options.OutputFormat == "name"; useShortOutput || len(options.OutputFormat) == 0 {
		cmdutil.PrintSuccess(mapper, useShortOutput, out, mapping.Resource, info.Name, options.DryRun, "created")
		return nil
	}

	return f.PrintObject(cmd, false, mapper, obj, out)
}
<commit_msg>add user-specified  ns to --dry-run created obj<commit_after>/*
Copyright 2014 The Kubernetes 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 cmd

import (
	"fmt"
	"io"
	"runtime"

	"github.com/spf13/cobra"

	"k8s.io/apimachinery/pkg/api/meta"
	"k8s.io/apimachinery/pkg/runtime/schema"

	"k8s.io/kubernetes/pkg/kubectl"
	"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
	"k8s.io/kubernetes/pkg/kubectl/cmd/util/editor"
	"k8s.io/kubernetes/pkg/kubectl/resource"
	"k8s.io/kubernetes/pkg/kubectl/util/i18n"
)

type CreateOptions struct {
	FilenameOptions  resource.FilenameOptions
	Selector         string
	EditBeforeCreate bool
}

var (
	createLong = templates.LongDesc(i18n.T(`
		Create a resource from a file or from stdin.

		JSON and YAML formats are accepted.`))

	createExample = templates.Examples(i18n.T(`
		# Create a pod using the data in pod.json.
		kubectl create -f ./pod.json

		# Create a pod based on the JSON passed into stdin.
		cat pod.json | kubectl create -f -

		# Edit the data in docker-registry.yaml in JSON using the v1 API format then create the resource using the edited data.
		kubectl create -f docker-registry.yaml --edit --output-version=v1 -o json`))
)

func NewCmdCreate(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
	var options CreateOptions

	cmd := &cobra.Command{
		Use:     "create -f FILENAME",
		Short:   i18n.T("Create a resource from a file or from stdin."),
		Long:    createLong,
		Example: createExample,
		Run: func(cmd *cobra.Command, args []string) {
			if cmdutil.IsFilenameSliceEmpty(options.FilenameOptions.Filenames) {
				defaultRunFunc := cmdutil.DefaultSubCommandRun(errOut)
				defaultRunFunc(cmd, args)
				return
			}
			cmdutil.CheckErr(ValidateArgs(cmd, args))
			cmdutil.CheckErr(RunCreate(f, cmd, out, errOut, &options))
		},
	}

	usage := "to use to create the resource"
	cmdutil.AddFilenameOptionFlags(cmd, &options.FilenameOptions, usage)
	cmd.MarkFlagRequired("filename")
	cmdutil.AddValidateFlags(cmd)
	cmdutil.AddPrinterFlags(cmd)
	cmd.Flags().BoolVar(&options.EditBeforeCreate, "edit", false, "Edit the API resource before creating")
	cmd.Flags().Bool("windows-line-endings", runtime.GOOS == "windows",
		"Only relevant if --edit=true. Defaults to the line ending native to your platform.")
	cmdutil.AddApplyAnnotationFlags(cmd)
	cmdutil.AddRecordFlag(cmd)
	cmdutil.AddDryRunFlag(cmd)
	cmdutil.AddInclude3rdPartyFlags(cmd)
	cmd.Flags().StringVarP(&options.Selector, "selector", "l", "", "Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)")

	// create subcommands
	cmd.AddCommand(NewCmdCreateNamespace(f, out))
	cmd.AddCommand(NewCmdCreateQuota(f, out))
	cmd.AddCommand(NewCmdCreateSecret(f, out, errOut))
	cmd.AddCommand(NewCmdCreateConfigMap(f, out))
	cmd.AddCommand(NewCmdCreateServiceAccount(f, out))
	cmd.AddCommand(NewCmdCreateService(f, out, errOut))
	cmd.AddCommand(NewCmdCreateDeployment(f, out, errOut))
	cmd.AddCommand(NewCmdCreateClusterRole(f, out))
	cmd.AddCommand(NewCmdCreateClusterRoleBinding(f, out))
	cmd.AddCommand(NewCmdCreateRole(f, out))
	cmd.AddCommand(NewCmdCreateRoleBinding(f, out))
	cmd.AddCommand(NewCmdCreatePodDisruptionBudget(f, out))
	return cmd
}

func ValidateArgs(cmd *cobra.Command, args []string) error {
	if len(args) != 0 {
		return cmdutil.UsageErrorf(cmd, "Unexpected args: %v", args)
	}
	return nil
}

func RunCreate(f cmdutil.Factory, cmd *cobra.Command, out, errOut io.Writer, options *CreateOptions) error {
	if options.EditBeforeCreate {
		return RunEditOnCreate(f, out, errOut, cmd, &options.FilenameOptions)
	}
	schema, err := f.Validator(cmdutil.GetFlagBool(cmd, "validate"))
	if err != nil {
		return err
	}

	cmdNamespace, enforceNamespace, err := f.DefaultNamespace()
	if err != nil {
		return err
	}

	mapper, typer, err := f.UnstructuredObject()
	if err != nil {
		return err
	}

	r := f.NewBuilder().
		Unstructured(f.UnstructuredClientForMapping, mapper, typer).
		Schema(schema).
		ContinueOnError().
		NamespaceParam(cmdNamespace).DefaultNamespace().
		FilenameParam(enforceNamespace, &options.FilenameOptions).
		SelectorParam(options.Selector).
		Flatten().
		Do()
	err = r.Err()
	if err != nil {
		return err
	}

	dryRun := cmdutil.GetFlagBool(cmd, "dry-run")
	output := cmdutil.GetFlagString(cmd, "output")

	count := 0
	err = r.Visit(func(info *resource.Info, err error) error {
		if err != nil {
			return err
		}
		if err := kubectl.CreateOrUpdateAnnotation(cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag), info, f.JSONEncoder()); err != nil {
			return cmdutil.AddSourceToErr("creating", info.Source, err)
		}

		if cmdutil.ShouldRecord(cmd, info) {
			if err := cmdutil.RecordChangeCause(info.Object, f.Command(cmd, false)); err != nil {
				return cmdutil.AddSourceToErr("creating", info.Source, err)
			}
		}

		if !dryRun {
			if err := createAndRefresh(info); err != nil {
				return cmdutil.AddSourceToErr("creating", info.Source, err)
			}
		}

		count++

		shortOutput := output == "name"
		if len(output) > 0 && !shortOutput {
			return cmdutil.PrintResourceInfoForCommand(cmd, info, f, out)
		}
		if !shortOutput {
			f.PrintObjectSpecificMessage(info.Object, out)
		}

		cmdutil.PrintSuccess(mapper, shortOutput, out, info.Mapping.Resource, info.Name, dryRun, "created")
		return nil
	})
	if err != nil {
		return err
	}
	if count == 0 {
		return fmt.Errorf("no objects passed to create")
	}
	return nil
}

func RunEditOnCreate(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, options *resource.FilenameOptions) error {
	editOptions := &editor.EditOptions{
		EditMode:        editor.EditBeforeCreateMode,
		FilenameOptions: *options,
		ValidateOptions: cmdutil.ValidateOptions{
			EnableValidation: cmdutil.GetFlagBool(cmd, "validate"),
		},
		Output:             cmdutil.GetFlagString(cmd, "output"),
		WindowsLineEndings: cmdutil.GetFlagBool(cmd, "windows-line-endings"),
		ApplyAnnotation:    cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag),
		Record:             cmdutil.GetFlagBool(cmd, "record"),
		ChangeCause:        f.Command(cmd, false),
		Include3rdParty:    cmdutil.GetFlagBool(cmd, "include-extended-apis"),
	}
	err := editOptions.Complete(f, out, errOut, []string{}, cmd)
	if err != nil {
		return err
	}
	return editOptions.Run()
}

// createAndRefresh creates an object from input info and refreshes info with that object
func createAndRefresh(info *resource.Info) error {
	obj, err := resource.NewHelper(info.Client, info.Mapping).Create(info.Namespace, true, info.Object)
	if err != nil {
		return err
	}
	info.Refresh(obj, true)
	return nil
}

// NameFromCommandArgs is a utility function for commands that assume the first argument is a resource name
func NameFromCommandArgs(cmd *cobra.Command, args []string) (string, error) {
	if len(args) == 0 {
		return "", cmdutil.UsageErrorf(cmd, "NAME is required")
	}
	return args[0], nil
}

// CreateSubcommandOptions is an options struct to support create subcommands
type CreateSubcommandOptions struct {
	// Name of resource being created
	Name string
	// StructuredGenerator is the resource generator for the object being created
	StructuredGenerator kubectl.StructuredGenerator
	// DryRun is true if the command should be simulated but not run against the server
	DryRun       bool
	OutputFormat string
}

// RunCreateSubcommand executes a create subcommand using the specified options
func RunCreateSubcommand(f cmdutil.Factory, cmd *cobra.Command, out io.Writer, options *CreateSubcommandOptions) error {
	namespace, nsOverriden, err := f.DefaultNamespace()
	if err != nil {
		return err
	}
	obj, err := options.StructuredGenerator.StructuredGenerate()
	if err != nil {
		return err
	}
	mapper, typer := f.Object()
	gvks, _, err := typer.ObjectKinds(obj)
	if err != nil {
		return err
	}
	gvk := gvks[0]
	mapping, err := mapper.RESTMapping(schema.GroupKind{Group: gvk.Group, Kind: gvk.Kind}, gvk.Version)
	if err != nil {
		return err
	}
	client, err := f.ClientForMapping(mapping)
	if err != nil {
		return err
	}
	resourceMapper := &resource.Mapper{
		ObjectTyper:  typer,
		RESTMapper:   mapper,
		ClientMapper: resource.ClientMapperFunc(f.ClientForMapping),
	}
	info, err := resourceMapper.InfoForObject(obj, nil)
	if err != nil {
		return err
	}
	if err := kubectl.CreateOrUpdateAnnotation(cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag), info, f.JSONEncoder()); err != nil {
		return err
	}
	obj = info.Object

	if !options.DryRun {
		obj, err = resource.NewHelper(client, mapping).Create(namespace, false, info.Object)
		if err != nil {
			return err
		}
	} else {
		if meta, err := meta.Accessor(obj); err == nil && nsOverriden {
			meta.SetNamespace(namespace)
		}
	}

	if useShortOutput := options.OutputFormat == "name"; useShortOutput || len(options.OutputFormat) == 0 {
		cmdutil.PrintSuccess(mapper, useShortOutput, out, mapping.Resource, info.Name, options.DryRun, "created")
		return nil
	}

	return f.PrintObject(cmd, false, mapper, obj, out)
}
<|endoftext|>


<commit_before>// Copyright 2014-2019 the u-root Authors. All rights reserved
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package libinit creates the environment and root file system for u-root.
package libinit

import (
	"fmt"
	"os"
	"runtime"
	"strconv"
	"syscall"

	"github.com/u-root/u-root/pkg/cmdline"
	"github.com/u-root/u-root/pkg/ulog"
	"golang.org/x/sys/unix"
)

type creator interface {
	create() error
	fmt.Stringer
}

type dir struct {
	Name string
	Mode os.FileMode
}

func (d dir) create() error {
	return os.MkdirAll(d.Name, d.Mode)
}

func (d dir) String() string {
	return fmt.Sprintf("dir %q (mode %#o)", d.Name, d.Mode)
}

type symlink struct {
	Target  string
	NewPath string
}

func (s symlink) create() error {
	os.Remove(s.NewPath)
	return os.Symlink(s.Target, s.NewPath)
}

func (s symlink) String() string {
	return fmt.Sprintf("symlink %q -> %q", s.NewPath, s.Target)
}

type dev struct {
	Name string
	Mode uint32
	Dev  int
}

func (d dev) create() error {
	os.Remove(d.Name)
	return syscall.Mknod(d.Name, d.Mode, d.Dev)
}

func (d dev) String() string {
	return fmt.Sprintf("dev %q (mode %#o; magic %d)", d.Name, d.Mode, d.Dev)
}

type mount struct {
	Source string
	Target string
	FSType string
	Flags  uintptr
	Opts   string
}

func (m mount) create() error {
	return syscall.Mount(m.Source, m.Target, m.FSType, m.Flags, m.Opts)
}

func (m mount) String() string {
	return fmt.Sprintf("mount -t %q -o %s %q %q flags %#x", m.FSType, m.Opts, m.Source, m.Target, m.Flags)
}

var (
	// These have to be created / mounted first, so that the logging works correctly.
	preNamespace = []creator{
		dir{Name: "/dev", Mode: 0777},

		// Kernel must be compiled with CONFIG_DEVTMPFS.
		mount{Source: "devtmpfs", Target: "/dev", FSType: "devtmpfs"},
	}
	namespace = []creator{
		dir{Name: "/buildbin", Mode: 0777},
		dir{Name: "/ubin", Mode: 0777},
		dir{Name: "/tmp", Mode: 0777},
		dir{Name: "/env", Mode: 0777},
		dir{Name: "/tcz", Mode: 0777},
		dir{Name: "/lib", Mode: 0777},
		dir{Name: "/usr/lib", Mode: 0777},
		dir{Name: "/var/log", Mode: 0777},
		dir{Name: "/go/pkg/linux_amd64", Mode: 0777},

		dir{Name: "/etc", Mode: 0777},

		dir{Name: "/proc", Mode: 0555},
		mount{Source: "proc", Target: "/proc", FSType: "proc"},
		mount{Source: "tmpfs", Target: "/tmp", FSType: "tmpfs"},

		dev{Name: "/dev/tty", Mode: syscall.S_IFCHR | 0666, Dev: 0x0500},
		dev{Name: "/dev/urandom", Mode: syscall.S_IFCHR | 0444, Dev: 0x0109},
		dev{Name: "/dev/port", Mode: syscall.S_IFCHR | 0640, Dev: 0x0104},

		dir{Name: "/dev/pts", Mode: 0777},
		mount{Source: "devpts", Target: "/dev/pts", FSType: "devpts", Opts: "newinstance,ptmxmode=666,gid=5,mode=620"},
		dev{Name: "/dev/ptmx", Mode: syscall.S_IFCHR | 0666, Dev: 0x0502},
		// Note: shm is required at least for Chrome. If you don't mount
		// it chrome throws a bogus "out of memory" error, not the more
		// useful "I can't open /dev/shm/whatever". SAD!
		dir{Name: "/dev/shm", Mode: 0777},
		mount{Source: "tmpfs", Target: "/dev/shm", FSType: "tmpfs"},

		dir{Name: "/sys", Mode: 0555},
		mount{Source: "sysfs", Target: "/sys", FSType: "sysfs"},
		mount{Source: "securityfs", Target: "/sys/kernel/security", FSType: "securityfs"},
	}
	cgroupsnamespace = []creator{
		mount{Source: "cgroup", Target: "/sys/fs/cgroup", FSType: "tmpfs"},
		dir{Name: "/sys/fs/cgroup/memory", Mode: 0555},
		dir{Name: "/sys/fs/cgroup/freezer", Mode: 0555},
		dir{Name: "/sys/fs/cgroup/devices", Mode: 0555},
		dir{Name: "/sys/fs/cgroup/cpu,cpuacct", Mode: 0555},
		dir{Name: "/sys/fs/cgroup/blkio", Mode: 0555},
		dir{Name: "/sys/fs/cgroup/cpuset", Mode: 0555},
		dir{Name: "/sys/fs/cgroup/pids", Mode: 0555},
		dir{Name: "/sys/fs/cgroup/net_cls,net_prio", Mode: 0555},
		dir{Name: "/sys/fs/cgroup/hugetlb", Mode: 0555},
		dir{Name: "/sys/fs/cgroup/perf_event", Mode: 0555},
		symlink{NewPath: "/sys/fs/cgroup/cpu", Target: "/sys/fs/cgroup/cpu,cpuacct"},
		symlink{NewPath: "/sys/fs/cgroup/cpuacct", Target: "/sys/fs/cgroup/cpu,cpuacct"},
		symlink{NewPath: "/sys/fs/cgroup/net_cls", Target: "/sys/fs/cgroup/net_cls,net_prio"},
		symlink{NewPath: "/sys/fs/cgroup/net_prio", Target: "/sys/fs/cgroup/net_cls,net_prio"},
		mount{Source: "cgroup", Target: "/sys/fs/cgroup/memory", FSType: "cgroup", Opts: "memory"},
		mount{Source: "cgroup", Target: "/sys/fs/cgroup/freezer", FSType: "cgroup", Opts: "freezer"},
		mount{Source: "cgroup", Target: "/sys/fs/cgroup/devices", FSType: "cgroup", Opts: "devices"},
		mount{Source: "cgroup", Target: "/sys/fs/cgroup/cpu,cpuacct", FSType: "cgroup", Opts: "cpu,cpuacct"},
		mount{Source: "cgroup", Target: "/sys/fs/cgroup/blkio", FSType: "cgroup", Opts: "blkio"},
		mount{Source: "cgroup", Target: "/sys/fs/cgroup/cpuset", FSType: "cgroup", Opts: "cpuset"},
		mount{Source: "cgroup", Target: "/sys/fs/cgroup/pids", FSType: "cgroup", Opts: "pids"},
		mount{Source: "cgroup", Target: "/sys/fs/cgroup/net_cls,net_prio", FSType: "cgroup", Opts: "net_cls,net_prio"},
		mount{Source: "cgroup", Target: "/sys/fs/cgroup/hugetlb", FSType: "cgroup", Opts: "hugetlb"},
		mount{Source: "cgroup", Target: "/sys/fs/cgroup/perf_event", FSType: "cgroup", Opts: "perf_event"},
	}
)

func goBin() string {
	return fmt.Sprintf("/go/bin/%s_%s:/go/bin:/go/pkg/tool/%s_%s", runtime.GOOS, runtime.GOARCH, runtime.GOOS, runtime.GOARCH)
}

func create(namespace []creator) {
	// Clear umask bits so that we get stuff like ptmx right.
	m := unix.Umask(0)
	defer unix.Umask(m)
	for _, c := range namespace {
		if err := c.create(); err != nil {
			ulog.KernelLog.Printf("u-root init: error creating %s: %v", c, err)
		}
	}
}

// SetEnv sets the default u-root environment.
func SetEnv() {
	env := map[string]string{
		"LD_LIBRARY_PATH": "/usr/local/lib",
		"GOROOT":          "/go",
		"GOPATH":          "/",
		"GOBIN":           "/ubin",
		"CGO_ENABLED":     "0",
	}

	// Not all these paths may be populated or even exist but OTOH they might.
	path := "/ubin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/bin:/usr/local/sbin:/buildbin:/bbin"

	env["PATH"] = fmt.Sprintf("%v:%v", goBin(), path)
	for k, v := range env {
		os.Setenv(k, v)
	}
}

// CreateRootfs creates the default u-root file system.
func CreateRootfs() {
	// Mount devtmpfs, then open /dev/kmsg with Reinit.
	create(preNamespace)
	ulog.KernelLog.Reinit()

	create(namespace)

	// systemd gets upset when it discovers something has already setup cgroups
	// We have to do this after the base namespace is created, so we have /proc
	initFlags := cmdline.GetInitFlagMap()
	systemd, present := initFlags["systemd"]
	systemdEnabled, boolErr := strconv.ParseBool(systemd)
	if !present || boolErr != nil || !systemdEnabled {
		create(cgroupsnamespace)
	}
}
<commit_msg>the devpts newinstance option breaks on some kernels, safer to omit it<commit_after>// Copyright 2014-2019 the u-root Authors. All rights reserved
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package libinit creates the environment and root file system for u-root.
package libinit

import (
	"fmt"
	"os"
	"runtime"
	"strconv"
	"syscall"

	"github.com/u-root/u-root/pkg/cmdline"
	"github.com/u-root/u-root/pkg/ulog"
	"golang.org/x/sys/unix"
)

type creator interface {
	create() error
	fmt.Stringer
}

type dir struct {
	Name string
	Mode os.FileMode
}

func (d dir) create() error {
	return os.MkdirAll(d.Name, d.Mode)
}

func (d dir) String() string {
	return fmt.Sprintf("dir %q (mode %#o)", d.Name, d.Mode)
}

type symlink struct {
	Target  string
	NewPath string
}

func (s symlink) create() error {
	os.Remove(s.NewPath)
	return os.Symlink(s.Target, s.NewPath)
}

func (s symlink) String() string {
	return fmt.Sprintf("symlink %q -> %q", s.NewPath, s.Target)
}

type dev struct {
	Name string
	Mode uint32
	Dev  int
}

func (d dev) create() error {
	os.Remove(d.Name)
	return syscall.Mknod(d.Name, d.Mode, d.Dev)
}

func (d dev) String() string {
	return fmt.Sprintf("dev %q (mode %#o; magic %d)", d.Name, d.Mode, d.Dev)
}

type mount struct {
	Source string
	Target string
	FSType string
	Flags  uintptr
	Opts   string
}

func (m mount) create() error {
	return syscall.Mount(m.Source, m.Target, m.FSType, m.Flags, m.Opts)
}

func (m mount) String() string {
	return fmt.Sprintf("mount -t %q -o %s %q %q flags %#x", m.FSType, m.Opts, m.Source, m.Target, m.Flags)
}

var (
	// These have to be created / mounted first, so that the logging works correctly.
	preNamespace = []creator{
		dir{Name: "/dev", Mode: 0777},

		// Kernel must be compiled with CONFIG_DEVTMPFS.
		mount{Source: "devtmpfs", Target: "/dev", FSType: "devtmpfs"},
	}
	namespace = []creator{
		dir{Name: "/buildbin", Mode: 0777},
		dir{Name: "/ubin", Mode: 0777},
		dir{Name: "/tmp", Mode: 0777},
		dir{Name: "/env", Mode: 0777},
		dir{Name: "/tcz", Mode: 0777},
		dir{Name: "/lib", Mode: 0777},
		dir{Name: "/usr/lib", Mode: 0777},
		dir{Name: "/var/log", Mode: 0777},
		dir{Name: "/go/pkg/linux_amd64", Mode: 0777},

		dir{Name: "/etc", Mode: 0777},

		dir{Name: "/proc", Mode: 0555},
		mount{Source: "proc", Target: "/proc", FSType: "proc"},
		mount{Source: "tmpfs", Target: "/tmp", FSType: "tmpfs"},

		dev{Name: "/dev/tty", Mode: syscall.S_IFCHR | 0666, Dev: 0x0500},
		dev{Name: "/dev/urandom", Mode: syscall.S_IFCHR | 0444, Dev: 0x0109},
		dev{Name: "/dev/port", Mode: syscall.S_IFCHR | 0640, Dev: 0x0104},

		dir{Name: "/dev/pts", Mode: 0777},
		mount{Source: "devpts", Target: "/dev/pts", FSType: "devpts", Opts: "ptmxmode=666,gid=5,mode=620"},
		dev{Name: "/dev/ptmx", Mode: syscall.S_IFCHR | 0666, Dev: 0x0502},
		// Note: shm is required at least for Chrome. If you don't mount
		// it chrome throws a bogus "out of memory" error, not the more
		// useful "I can't open /dev/shm/whatever". SAD!
		dir{Name: "/dev/shm", Mode: 0777},
		mount{Source: "tmpfs", Target: "/dev/shm", FSType: "tmpfs"},

		dir{Name: "/sys", Mode: 0555},
		mount{Source: "sysfs", Target: "/sys", FSType: "sysfs"},
		mount{Source: "securityfs", Target: "/sys/kernel/security", FSType: "securityfs"},
	}
	cgroupsnamespace = []creator{
		mount{Source: "cgroup", Target: "/sys/fs/cgroup", FSType: "tmpfs"},
		dir{Name: "/sys/fs/cgroup/memory", Mode: 0555},
		dir{Name: "/sys/fs/cgroup/freezer", Mode: 0555},
		dir{Name: "/sys/fs/cgroup/devices", Mode: 0555},
		dir{Name: "/sys/fs/cgroup/cpu,cpuacct", Mode: 0555},
		dir{Name: "/sys/fs/cgroup/blkio", Mode: 0555},
		dir{Name: "/sys/fs/cgroup/cpuset", Mode: 0555},
		dir{Name: "/sys/fs/cgroup/pids", Mode: 0555},
		dir{Name: "/sys/fs/cgroup/net_cls,net_prio", Mode: 0555},
		dir{Name: "/sys/fs/cgroup/hugetlb", Mode: 0555},
		dir{Name: "/sys/fs/cgroup/perf_event", Mode: 0555},
		symlink{NewPath: "/sys/fs/cgroup/cpu", Target: "/sys/fs/cgroup/cpu,cpuacct"},
		symlink{NewPath: "/sys/fs/cgroup/cpuacct", Target: "/sys/fs/cgroup/cpu,cpuacct"},
		symlink{NewPath: "/sys/fs/cgroup/net_cls", Target: "/sys/fs/cgroup/net_cls,net_prio"},
		symlink{NewPath: "/sys/fs/cgroup/net_prio", Target: "/sys/fs/cgroup/net_cls,net_prio"},
		mount{Source: "cgroup", Target: "/sys/fs/cgroup/memory", FSType: "cgroup", Opts: "memory"},
		mount{Source: "cgroup", Target: "/sys/fs/cgroup/freezer", FSType: "cgroup", Opts: "freezer"},
		mount{Source: "cgroup", Target: "/sys/fs/cgroup/devices", FSType: "cgroup", Opts: "devices"},
		mount{Source: "cgroup", Target: "/sys/fs/cgroup/cpu,cpuacct", FSType: "cgroup", Opts: "cpu,cpuacct"},
		mount{Source: "cgroup", Target: "/sys/fs/cgroup/blkio", FSType: "cgroup", Opts: "blkio"},
		mount{Source: "cgroup", Target: "/sys/fs/cgroup/cpuset", FSType: "cgroup", Opts: "cpuset"},
		mount{Source: "cgroup", Target: "/sys/fs/cgroup/pids", FSType: "cgroup", Opts: "pids"},
		mount{Source: "cgroup", Target: "/sys/fs/cgroup/net_cls,net_prio", FSType: "cgroup", Opts: "net_cls,net_prio"},
		mount{Source: "cgroup", Target: "/sys/fs/cgroup/hugetlb", FSType: "cgroup", Opts: "hugetlb"},
		mount{Source: "cgroup", Target: "/sys/fs/cgroup/perf_event", FSType: "cgroup", Opts: "perf_event"},
	}
)

func goBin() string {
	return fmt.Sprintf("/go/bin/%s_%s:/go/bin:/go/pkg/tool/%s_%s", runtime.GOOS, runtime.GOARCH, runtime.GOOS, runtime.GOARCH)
}

func create(namespace []creator) {
	// Clear umask bits so that we get stuff like ptmx right.
	m := unix.Umask(0)
	defer unix.Umask(m)
	for _, c := range namespace {
		if err := c.create(); err != nil {
			ulog.KernelLog.Printf("u-root init: error creating %s: %v", c, err)
		}
	}
}

// SetEnv sets the default u-root environment.
func SetEnv() {
	env := map[string]string{
		"LD_LIBRARY_PATH": "/usr/local/lib",
		"GOROOT":          "/go",
		"GOPATH":          "/",
		"GOBIN":           "/ubin",
		"CGO_ENABLED":     "0",
	}

	// Not all these paths may be populated or even exist but OTOH they might.
	path := "/ubin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/bin:/usr/local/sbin:/buildbin:/bbin"

	env["PATH"] = fmt.Sprintf("%v:%v", goBin(), path)
	for k, v := range env {
		os.Setenv(k, v)
	}
}

// CreateRootfs creates the default u-root file system.
func CreateRootfs() {
	// Mount devtmpfs, then open /dev/kmsg with Reinit.
	create(preNamespace)
	ulog.KernelLog.Reinit()

	create(namespace)

	// systemd gets upset when it discovers something has already setup cgroups
	// We have to do this after the base namespace is created, so we have /proc
	initFlags := cmdline.GetInitFlagMap()
	systemd, present := initFlags["systemd"]
	systemdEnabled, boolErr := strconv.ParseBool(systemd)
	if !present || boolErr != nil || !systemdEnabled {
		create(cgroupsnamespace)
	}
}
<|endoftext|>