<commit_before>package git

import (
	"encoding/binary"
	"errors"
	"fmt"
	"os"
	"path/filepath"
	"sync/atomic"

	"github.com/yosisa/go-git/lru"
)

var packMagic = [4]byte{'P', 'A', 'C', 'K'}

var (
	ErrChecksum       = errors.New("Incorrect checksum")
	ErrObjectNotFound = errors.New("Object not found")
)

var packEntryCache = lru.NewWithEvict(1<<24, func(key interface{}, value interface{}) {
	value.(*packEntry).Close()
})

type PackHeader struct {
	Magic   [4]byte
	Version uint32
	Total   uint32
}

type Pack struct {
	PackHeader
	r   packReader
	idx *PackIndexV2
}

func OpenPack(path string) (*Pack, error) {
	path = filepath.Clean(path)
	ext := filepath.Ext(path)
	base := path[:len(path)-len(ext)]
	idx, err := OpenPackIndex(base + ".idx")
	if err != nil {
		return nil, err
	}
	f, err := os.Open(base + ".pack")
	if err != nil {
		return nil, err
	}
	pack := &Pack{
		r:   newPackReader(f),
		idx: idx,
	}
	err = pack.verify()
	return pack, err
}

func (p *Pack) verify() (err error) {
	if err = binary.Read(p.r, binary.BigEndian, &p.PackHeader); err != nil {
		return
	}
	if p.Magic != packMagic || p.Version != 2 {
		return ErrUnknownFormat
	}
	if _, err = p.r.Seek(-20, os.SEEK_END); err != nil {
		return
	}
	var checksum SHA1
	if err = checksum.Fill(p.r); err != nil {
		return
	}
	if checksum != p.idx.PackFileHash {
		return ErrChecksum
	}
	return
}

func (p *Pack) Close() error {
	return p.r.Close()
}

func (p *Pack) Object(id SHA1, repo *Repository) (Object, error) {
	entry, err := p.entry(id)
	if err != nil {
		return nil, err
	}
	obj := newObject(entry.Type(), id, repo)
	b, err := entry.ReadAll()
	if err != nil {
		return nil, err
	}
	obj.Parse(b)
	return obj, nil
}

func (p *Pack) entry(id SHA1) (*packEntry, error) {
	entry := p.idx.Entry(id)
	if entry == nil {
		return nil, ErrObjectNotFound
	}
	return p.entryAt(entry.Offset)
}

func (p *Pack) entryAt(offset int64) (*packEntry, error) {
	if pe, ok := packEntryCache.Get(offset); ok {
		if entry := pe.(*packEntry); entry.markInUse() {
			return entry, nil
		}
	}

	if _, err := p.r.Seek(offset, os.SEEK_SET); err != nil {
		return nil, err
	}

	header, err := readPackEntryHeader(p.r)
	if err != nil {
		return nil, err
	}
	size := header[0].Size0()
	typ := header[0].Type()
	for i, l := 0, len(header)-1; i < l; i++ {
		size = (header[i+1].Size() << uint(4+7*i)) | size
	}

	pe := &packEntry{
		offset:    offset,
		headerLen: len(header),
		used:      1,
	}

	switch typ {
	case packEntryCommit:
		pe.typ = "commit"
	case packEntryTree:
		pe.typ = "tree"
	case packEntryBlob:
		pe.typ = "blob"
	case packEntryTag:
		pe.typ = "tag"
	case packEntryOfsDelta:
		header, err := readPackEntryHeader(p.r)
		if err != nil {
			return nil, err
		}
		ofs := header[0].Size()
		for _, h := range header[1:] {
			ofs += 1
			ofs = (ofs << 7) + h.Size()
		}
		delta, err := p.readDelta()
		if err != nil {
			return nil, err
		}

		entry, err := p.entryAt(offset - ofs)
		if err != nil {
			return nil, err
		}
		pe.typ = entry.Type()
		if pe.buf, err = applyDelta(entry, delta); err != nil {
			return nil, err
		}
		packEntryCache.Add(offset, pe)
		return pe, nil
	case packEntryRefDelta:
		id, err := readSHA1(p.r)
		if err != nil {
			return nil, err
		}
		delta, err := p.readDelta()
		if err != nil {
			return nil, err
		}

		entry, err := p.entry(id)
		if err != nil {
			return nil, err
		}
		pe.typ = entry.Type()
		if pe.buf, err = applyDelta(entry, delta); err != nil {
			return nil, err
		}
		packEntryCache.Add(offset, pe)
		return pe, nil
	default:
		return nil, fmt.Errorf("Unknown pack entry type: %d", typ)
	}

	pe.pr = p.r
	packEntryCache.Add(offset, pe)
	return pe, nil
}

func (p *Pack) readDelta() (*bytesBuffer, error) {
	zr, err := p.r.ZlibReader()
	if err != nil {
		return nil, err
	}
	defer zr.Close()
	return newBytesBuffer(zr)
}

type packEntryType byte

const (
	packEntryNone packEntryType = iota
	packEntryCommit
	packEntryTree
	packEntryBlob
	packEntryTag
	_
	packEntryOfsDelta
	packEntryRefDelta
)

type packEntry struct {
	typ       string
	buf       *bytesBuffer
	pr        packReader
	offset    int64
	headerLen int
	used      int32
}

func (p *packEntry) Type() string {
	return p.typ
}

func (p *packEntry) ReadAll() ([]byte, error) {
	if p.buf == nil {
		if p.pr.Offset() != p.offset {
			if _, err := p.pr.Seek(p.offset+int64(p.headerLen), os.SEEK_SET); err != nil {
				return nil, err
			}
		}
		zr, err := p.pr.ZlibReader()
		if err != nil {
			return nil, err
		}
		defer zr.Close()

		if p.buf, err = newBytesBuffer(zr); err != nil {
			return nil, err
		}
	}
	return p.buf.Bytes(), nil
}

func (p *packEntry) Close() (err error) {
	// Release bytesBuffer only if no one used and not in the lru cache.
	if n := atomic.AddInt32(&p.used, -1); n < 0 && p.buf != nil {
		p.buf.Close()
	}
	return
}

func (p *packEntry) markInUse() bool {
	return atomic.AddInt32(&p.used, 1) > 0
}

func (p *packEntry) Size() int {
	size := len(p.typ) + 8 + 8 + 8 + 8
	if p.buf != nil {
		size += p.buf.Len()
	}
	return size
}

type packEntryHeader byte

func (b packEntryHeader) MSB() bool {
	return (b >> 7) == 1
}

func (b packEntryHeader) Type() packEntryType {
	return packEntryType((b >> 4) & 0x07)
}

func (b packEntryHeader) Size0() int64 {
	return int64(b & 0x0f)
}

func (b packEntryHeader) Size() int64 {
	return int64(b & 0x7f)
}

var packEntryHeaderScratch []packEntryHeader = make([]packEntryHeader, 0, 10)

func readPackEntryHeader(br byteReader) (header []packEntryHeader, err error) {
	header = packEntryHeaderScratch[:0]
	for {
		var b byte
		if b, err = br.ReadByte(); err != nil {
			return
		}
		h := packEntryHeader(b)
		header = append(header, h)
		if !h.MSB() {
			return
		}
	}
}
<commit_msg>Fix potential cache collision when opening multiple repositories<commit_after>package git

import (
	"encoding/binary"
	"errors"
	"fmt"
	"os"
	"path/filepath"
	"sync/atomic"

	"github.com/yosisa/go-git/lru"
)

var packMagic = [4]byte{'P', 'A', 'C', 'K'}

var (
	ErrChecksum       = errors.New("Incorrect checksum")
	ErrObjectNotFound = errors.New("Object not found")
)

var packEntryCache = lru.NewWithEvict(1<<24, func(key interface{}, value interface{}) {
	value.(*packEntry).Close()
})

type PackHeader struct {
	Magic   [4]byte
	Version uint32
	Total   uint32
}

type Pack struct {
	PackHeader
	r   packReader
	idx *PackIndexV2
}

func OpenPack(path string) (*Pack, error) {
	path = filepath.Clean(path)
	ext := filepath.Ext(path)
	base := path[:len(path)-len(ext)]
	idx, err := OpenPackIndex(base + ".idx")
	if err != nil {
		return nil, err
	}
	f, err := os.Open(base + ".pack")
	if err != nil {
		return nil, err
	}
	pack := &Pack{
		r:   newPackReader(f),
		idx: idx,
	}
	err = pack.verify()
	return pack, err
}

func (p *Pack) verify() (err error) {
	if err = binary.Read(p.r, binary.BigEndian, &p.PackHeader); err != nil {
		return
	}
	if p.Magic != packMagic || p.Version != 2 {
		return ErrUnknownFormat
	}
	if _, err = p.r.Seek(-20, os.SEEK_END); err != nil {
		return
	}
	var checksum SHA1
	if err = checksum.Fill(p.r); err != nil {
		return
	}
	if checksum != p.idx.PackFileHash {
		return ErrChecksum
	}
	return
}

func (p *Pack) Close() error {
	return p.r.Close()
}

func (p *Pack) Object(id SHA1, repo *Repository) (Object, error) {
	entry, err := p.entry(id)
	if err != nil {
		return nil, err
	}
	obj := newObject(entry.Type(), id, repo)
	b, err := entry.ReadAll()
	if err != nil {
		return nil, err
	}
	obj.Parse(b)
	return obj, nil
}

func (p *Pack) entry(id SHA1) (*packEntry, error) {
	entry := p.idx.Entry(id)
	if entry == nil {
		return nil, ErrObjectNotFound
	}
	return p.entryAt(entry.Offset)
}

func (p *Pack) entryAt(offset int64) (*packEntry, error) {
	if pe, ok := packEntryCache.Get(pecKey{p.idx.PackFileHash, offset}); ok {
		if entry := pe.(*packEntry); entry.markInUse() {
			return entry, nil
		}
	}

	if _, err := p.r.Seek(offset, os.SEEK_SET); err != nil {
		return nil, err
	}

	header, err := readPackEntryHeader(p.r)
	if err != nil {
		return nil, err
	}
	size := header[0].Size0()
	typ := header[0].Type()
	for i, l := 0, len(header)-1; i < l; i++ {
		size = (header[i+1].Size() << uint(4+7*i)) | size
	}

	pe := &packEntry{
		offset:    offset,
		headerLen: len(header),
		used:      1,
	}

	switch typ {
	case packEntryCommit:
		pe.typ = "commit"
	case packEntryTree:
		pe.typ = "tree"
	case packEntryBlob:
		pe.typ = "blob"
	case packEntryTag:
		pe.typ = "tag"
	case packEntryOfsDelta:
		header, err := readPackEntryHeader(p.r)
		if err != nil {
			return nil, err
		}
		ofs := header[0].Size()
		for _, h := range header[1:] {
			ofs += 1
			ofs = (ofs << 7) + h.Size()
		}
		delta, err := p.readDelta()
		if err != nil {
			return nil, err
		}

		entry, err := p.entryAt(offset - ofs)
		if err != nil {
			return nil, err
		}
		pe.typ = entry.Type()
		if pe.buf, err = applyDelta(entry, delta); err != nil {
			return nil, err
		}
		packEntryCache.Add(pecKey{p.idx.PackFileHash, offset}, pe)
		return pe, nil
	case packEntryRefDelta:
		id, err := readSHA1(p.r)
		if err != nil {
			return nil, err
		}
		delta, err := p.readDelta()
		if err != nil {
			return nil, err
		}

		entry, err := p.entry(id)
		if err != nil {
			return nil, err
		}
		pe.typ = entry.Type()
		if pe.buf, err = applyDelta(entry, delta); err != nil {
			return nil, err
		}
		packEntryCache.Add(pecKey{p.idx.PackFileHash, offset}, pe)
		return pe, nil
	default:
		return nil, fmt.Errorf("Unknown pack entry type: %d", typ)
	}

	pe.pr = p.r
	packEntryCache.Add(pecKey{p.idx.PackFileHash, offset}, pe)
	return pe, nil
}

func (p *Pack) readDelta() (*bytesBuffer, error) {
	zr, err := p.r.ZlibReader()
	if err != nil {
		return nil, err
	}
	defer zr.Close()
	return newBytesBuffer(zr)
}

type packEntryType byte

const (
	packEntryNone packEntryType = iota
	packEntryCommit
	packEntryTree
	packEntryBlob
	packEntryTag
	_
	packEntryOfsDelta
	packEntryRefDelta
)

type packEntry struct {
	typ       string
	buf       *bytesBuffer
	pr        packReader
	offset    int64
	headerLen int
	used      int32
}

func (p *packEntry) Type() string {
	return p.typ
}

func (p *packEntry) ReadAll() ([]byte, error) {
	if p.buf == nil {
		if p.pr.Offset() != p.offset {
			if _, err := p.pr.Seek(p.offset+int64(p.headerLen), os.SEEK_SET); err != nil {
				return nil, err
			}
		}
		zr, err := p.pr.ZlibReader()
		if err != nil {
			return nil, err
		}
		defer zr.Close()

		if p.buf, err = newBytesBuffer(zr); err != nil {
			return nil, err
		}
	}
	return p.buf.Bytes(), nil
}

func (p *packEntry) Close() (err error) {
	// Release bytesBuffer only if no one used and not in the lru cache.
	if n := atomic.AddInt32(&p.used, -1); n < 0 && p.buf != nil {
		p.buf.Close()
	}
	return
}

func (p *packEntry) markInUse() bool {
	return atomic.AddInt32(&p.used, 1) > 0
}

func (p *packEntry) Size() int {
	size := len(p.typ) + 8 + 8 + 8 + 8
	if p.buf != nil {
		size += p.buf.Len()
	}
	return size
}

type packEntryHeader byte

func (b packEntryHeader) MSB() bool {
	return (b >> 7) == 1
}

func (b packEntryHeader) Type() packEntryType {
	return packEntryType((b >> 4) & 0x07)
}

func (b packEntryHeader) Size0() int64 {
	return int64(b & 0x0f)
}

func (b packEntryHeader) Size() int64 {
	return int64(b & 0x7f)
}

var packEntryHeaderScratch []packEntryHeader = make([]packEntryHeader, 0, 10)

func readPackEntryHeader(br byteReader) (header []packEntryHeader, err error) {
	header = packEntryHeaderScratch[:0]
	for {
		var b byte
		if b, err = br.ReadByte(); err != nil {
			return
		}
		h := packEntryHeader(b)
		header = append(header, h)
		if !h.MSB() {
			return
		}
	}
}

type pecKey struct {
	checksum SHA1
	offset   int64
}
<|endoftext|>


<commit_before>package tinycfg

import (
	"bufio"
	"errors"
	"fmt"
	"io"
	"os"
	"sort"
	"strings"
)

const (
	delim         = "="
	commentPrefix = "//"
)

// A Config stores key, value pairs.
type Config struct {
	vals map[string]string
}

// Get returns the value for a specified key or an empty string if the key was not found.
func (c Config) Get(key string) string {
	return c.vals[key]
}

// Set adds a key, value pair or modifies an existing one. The returned error can be safely
// ignored if you are certain that both the key and value are valid. Keys are invalid if
// they contain '=', newline characters or are empty. Values are invalid if they contain
// newline characters or are empty.
func (c Config) Set(key, value string) error {
	if key == "" {
		return errors.New("key cannot be empty")
	}
	if value == "" {
		return errors.New("value cannot be empty")
	}
	if strings.Contains(key, delim) {
		return fmt.Errorf("key cannot contain '%s'", delim)
	}
	if strings.Contains(value, "\n") {
		return errors.New("value cannot contain newlines")
	}
	if strings.Contains(key, "\n") {
		return errors.New("key cannot contain newlines")
	}
	c.vals[key] = value
	return nil
}

// Delete removes a key, value pair.
func (c Config) Delete(key string) {
	delete(c.vals, key)
}

// Encode writes out a Config instance in the correct format to a Writer. Key, value pairs
// are listed in alphabetical order.
func (c Config) Encode(w io.Writer) error {
	var lines []string
	for k, v := range c.vals {
		lines = append(lines, fmt.Sprintf("%s=%s", k, v))
	}
	sort.Sort(sort.StringSlice(lines))
	for _, v := range lines {
		_, err := fmt.Fprintln(w, v)
		if err != nil {
			return fmt.Errorf("unable to encode line: %s\n%s", v, err)
		}
	}
	return nil
}

// New returns an empty Config instance ready for use.
func New() Config {
	return Config{make(map[string]string)}
}

// Open is a convenience function that opens a file at a specified path, passes it to Decode
// then closes the file.
func Open(path string, required []string) (Config, []string, error) {
	file, err := os.Open(path)
	if err != nil {
		return Config{}, nil, err
	}
	defer file.Close()
	return Decode(file, required)
}

// Decode creates a new Config instance from a Reader. Required keys can be specified by passing
// in a string slice, or nil if there are no required keys. If there are missing required keys
// they are returned in a string slice along with an error.
func Decode(r io.Reader, required []string) (Config, []string, error) {
	cfg := Config{make(map[string]string)}
	scanner := bufio.NewScanner(r)
	for lineNum := 1; scanner.Scan(); lineNum++ {
		line := strings.TrimSpace(scanner.Text())
		if line == "" || strings.HasPrefix(line, commentPrefix) {
			continue
		}
		args := strings.SplitN(line, delim, 2)
		if args[0] == "" || args[1] == "" {
			return cfg, nil, fmt.Errorf("no key/value pair found at line %d", lineNum)
		}
		if _, ok := cfg.vals[args[0]]; ok {
			return cfg, nil, fmt.Errorf("duplicate entry for key %s at line %d", args[0], lineNum)
		}
		cfg.vals[strings.TrimSpace(args[0])] = strings.TrimSpace(args[1])
	}
	if scanner.Err() != nil {
		return cfg, nil, scanner.Err()
	}
	if required != nil {
		var missing []string
		for _, v := range required {
			if val := cfg.Get(v); val == "" {
				missing = append(missing, v)
			}
		}
		if len(missing) > 0 {
			return cfg, missing, fmt.Errorf("missing required keys")
		}
	}
	return cfg, nil, nil
}
<commit_msg>Fix duplicate key check.<commit_after>package tinycfg

import (
	"bufio"
	"errors"
	"fmt"
	"io"
	"os"
	"sort"
	"strings"
)

const (
	delim         = "="
	commentPrefix = "//"
)

// A Config stores key, value pairs.
type Config struct {
	vals map[string]string
}

// Get returns the value for a specified key or an empty string if the key was not found.
func (c Config) Get(key string) string {
	return c.vals[key]
}

// Set adds a key, value pair or modifies an existing one. The returned error can be safely
// ignored if you are certain that both the key and value are valid. Keys are invalid if
// they contain '=', newline characters or are empty. Values are invalid if they contain
// newline characters or are empty.
func (c Config) Set(key, value string) error {
	if key == "" {
		return errors.New("key cannot be empty")
	}
	if value == "" {
		return errors.New("value cannot be empty")
	}
	if strings.Contains(key, delim) {
		return fmt.Errorf("key cannot contain '%s'", delim)
	}
	if strings.Contains(value, "\n") {
		return errors.New("value cannot contain newlines")
	}
	if strings.Contains(key, "\n") {
		return errors.New("key cannot contain newlines")
	}
	c.vals[key] = value
	return nil
}

// Delete removes a key, value pair.
func (c Config) Delete(key string) {
	delete(c.vals, key)
}

// Encode writes out a Config instance in the correct format to a Writer. Key, value pairs
// are listed in alphabetical order.
func (c Config) Encode(w io.Writer) error {
	var lines []string
	for k, v := range c.vals {
		lines = append(lines, fmt.Sprintf("%s=%s", k, v))
	}
	sort.Sort(sort.StringSlice(lines))
	for _, v := range lines {
		_, err := fmt.Fprintln(w, v)
		if err != nil {
			return fmt.Errorf("unable to encode line: %s\n%s", v, err)
		}
	}
	return nil
}

// New returns an empty Config instance ready for use.
func New() Config {
	return Config{make(map[string]string)}
}

// Open is a convenience function that opens a file at a specified path, passes it to Decode
// then closes the file.
func Open(path string, required []string) (Config, []string, error) {
	file, err := os.Open(path)
	if err != nil {
		return Config{}, nil, err
	}
	defer file.Close()
	return Decode(file, required)
}

// Decode creates a new Config instance from a Reader. Required keys can be specified by passing
// in a string slice, or nil if there are no required keys. If there are missing required keys
// they are returned in a string slice along with an error.
func Decode(r io.Reader, required []string) (Config, []string, error) {
	cfg := Config{make(map[string]string)}
	scanner := bufio.NewScanner(r)
	for lineNum := 1; scanner.Scan(); lineNum++ {
		line := strings.TrimSpace(scanner.Text())
		if line == "" || strings.HasPrefix(line, commentPrefix) {
			continue
		}
		args := strings.SplitN(line, delim, 2)
		key, value := strings.TrimSpace(args[0]), strings.TrimSpace(args[1])
		if key == "" || value == "" {
			return cfg, nil, fmt.Errorf("no key/value pair found at line %d", lineNum)
		}
		if _, ok := cfg.vals[key]; ok {
			return cfg, nil, fmt.Errorf("duplicate entry for key %s at line %d", args[0], lineNum)
		}
		cfg.vals[key] = value
	}
	if scanner.Err() != nil {
		return cfg, nil, scanner.Err()
	}
	if required != nil {
		var missing []string
		for _, v := range required {
			if val := cfg.Get(v); val == "" {
				missing = append(missing, v)
			}
		}
		if len(missing) > 0 {
			return cfg, missing, fmt.Errorf("missing required keys")
		}
	}
	return cfg, nil, nil
}
<|endoftext|>


<commit_before>package todotxt

import (
        "time"
        "os"
        "bufio"
        "strings"
        "regexp"
        "sort"
        "unicode"
        "fmt"
        "math/rand"
)

type Task struct {
        id int
        todo string
        priority byte
        create_date time.Time
        contexts []string
        projects []string
        raw_todo string
        finished bool
        finish_date time.Time
        id_padding int
}

type TaskList []Task

func ParseTask(text string, id int) (Task) {
        var task = Task{}
        task.id = id
        task.raw_todo = text

        splits := strings.Split(text, " ")

        // checking if the task is already finished
        if text[0] == 'x' &&
           text[1] == ' ' &&
           !unicode.IsSpace(rune(text[2])) {
                task.finished = true
                splits = splits[1:]
        }

        date_regexp := "([\\d]{4})-([\\d]{2})-([\\d]{2})"

        // checking for finish date
        if match, _ := regexp.MatchString(date_regexp, splits[0]); match {
                if date, e := time.Parse("2006-01-02", splits[0]); e != nil {
                        panic(e)
                } else {
                        task.finish_date = date
                }

                splits = splits[1:]
        }

        head := splits[0]

        // checking for priority
        if (len(head) == 3) &&
           (head[0] == '(') &&
           (head[2] == ')') &&
           (head[1] >= 65 && head[1] <= 90) { // checking if it's in range [A-Z]
                task.priority = head[1]
                splits = splits[1:]
        }

        // checking for creation date and building the actual todo item
        if match, _ := regexp.MatchString(date_regexp, splits[0]); match {
                if date, e := time.Parse("2006-01-02", splits[0]); e != nil {
                        panic(e)
                } else {
                        task.create_date = date
                }

                task.todo = strings.Join(splits[1:], " ")
        } else {
                task.todo = strings.Join(splits[0:], " ")
        }

        context_regexp, _ := regexp.Compile("@[[:word:]]+")
        contexts := context_regexp.FindAllStringSubmatch(text, -1)
        if len(contexts) != 0 {
                task.contexts = contexts[0]
        }

        project_regexp, _ := regexp.Compile("\\+[[:word:]]+")
        projects := project_regexp.FindAllStringSubmatch(text, -1)
        if len(projects) != 0 {
                task.projects = projects[0]
        }

        return task
}

func LoadTaskList (filename string) (TaskList) {

        var f, err = os.Open(filename)

        if err != nil {
                panic(err)
        }

        defer f.Close()

        var tasklist = TaskList{}

        scanner := bufio.NewScanner(f)

        for scanner.Scan() {
                text := scanner.Text()
                tasklist.Add(text)
        }

        if err := scanner.Err(); err != nil {
                panic(scanner.Err())
        }

        return tasklist
}

type By func(t1, t2 Task) bool

func (by By) Sort(tasks TaskList) {
        ts := &taskSorter{
                tasks: tasks,
                by:    by,
        }
        sort.Sort(ts)
}

type taskSorter struct {
        tasks TaskList
        by func(t1, t2 Task) bool
}

func (s *taskSorter) Len() int {
        return len(s.tasks)
}

func (s *taskSorter) Swap(i, j int) {
        s.tasks[i], s.tasks[j] = s.tasks[j], s.tasks[i]
}

func (s *taskSorter) Less(i, j int) bool {
        return s.by(s.tasks[i], s.tasks[j])
}

func (tasks TaskList) Len() int {
        return len(tasks)
}

func prioCmp(t1, t2 Task) bool {
        return t1.Priority() < t2.Priority()
}

func prioRevCmp(t1, t2 Task) bool {
        return t1.Priority() > t2.Priority()
}

func dateCmp(t1, t2 Task) bool {
        tm1 := t1.CreateDate().Unix()
        tm2 := t2.CreateDate().Unix()

        // if the dates equal, let's use priority
        if tm1 == tm2 {
                return prioCmp(t1, t2)
        } else {
                return tm1 > tm2
        }
}

func dateRevCmp(t1, t2 Task) bool {
        tm1 := t1.CreateDate().Unix()
        tm2 := t2.CreateDate().Unix()

        // if the dates equal, let's use priority
        if tm1 == tm2 {
                return prioCmp(t1, t2)
        } else {
                return tm1 < tm2
        }
}

func lenCmp(t1, t2 Task) bool {
        tl1 := len(t1.raw_todo)
        tl2 := len(t2.raw_todo)
        if tl1 == tl2 {
                return prioCmp(t1, t2)
        } else {
                return tl1 < tl2
        }
}

func lenRevCmp(t1, t2 Task) bool {
        tl1 := len(t1.raw_todo)
        tl2 := len(t2.raw_todo)
        if tl1 == tl2 {
                return prioCmp(t1, t2)
        } else {
                return tl1 > tl2
        }
}

func idCmp(t1, t2 Task) bool {
        return t1.Id() < t2.Id()
}

func randCmp(t1, t2 Task) bool {
        rand.Seed(time.Now().UnixNano()%1e6/1e3)
        return rand.Intn(len(t1.raw_todo)) > rand.Intn(len(t2.raw_todo))
}

func (tasks TaskList) Sort(by string) {
        switch by {
        default:
        case "prio":
                By(prioCmp).Sort(tasks)
        case "prio-rev":
                By(prioRevCmp).Sort(tasks)
        case "date":
                By(dateCmp).Sort(tasks)
        case "date-rev":
                By(dateRevCmp).Sort(tasks)
        case "len":
                By(lenCmp).Sort(tasks)
        case "len-rev":
                By(lenRevCmp).Sort(tasks)
        case "id":
                By(idCmp).Sort(tasks)
        case "rand":
                By(randCmp).Sort(tasks)
        }
}

func (tasks TaskList) Save(filename string) {
        tasks.Sort("id")

        f, err := os.Create(filename)
        if err != nil {
                panic(err)
        }

        defer f.Close()

        for _, task := range tasks {
                f.WriteString(task.RawText() + "\n")
        }
        f.Sync()
}

func (tasks *TaskList) Add(todo string) {
        task := ParseTask(todo, tasks.Len())
        *tasks = append(*tasks, task)
}

func (tasks TaskList) Done(id int, finish_date bool) error {
        if id > tasks.Len() || id < 0 {
                return fmt.Errorf("Error: id is %v", id)
        }

        tasks[id].finished = true
        if finish_date {
                t := time.Now()
                tasks[id].raw_todo = "x " + t.Format("2006-01-02") + " " +
                                        tasks[id].raw_todo
        } else {
                tasks[id].raw_todo = "x " + tasks[id].raw_todo
        }

        return nil
}

func (task Task) Id() int {
        return task.id
}

func (task Task) Text() string {
        return task.todo
}

func (task Task) RawText() string {
        return task.raw_todo
}

func (task Task) Priority() byte {
        // if priority is not from [A-Z], let it be 94 (^)
        if task.priority < 65 || task.priority > 90 {
                return 94 // you know, ^
        } else {
                return task.priority
        }
}

func (task Task) Contexts() []string {
        return task.contexts
}

func (task Task) Projects() []string {
        return task.projects
}

func (task Task) CreateDate() time.Time {
        return task.create_date
}

func (task Task) Finished() bool {
        return task.finished
}

func (task Task) FinishDate() time.Time {
        return task.finish_date
}

func (task *Task) SetIdPaddingBy(tasklist TaskList) {
        l := tasklist.Len()

        if l >= 10000 {
                task.id_padding = 5
        } else if l >= 1000 {
                task.id_padding = 4
        } else if l >= 100 {
                task.id_padding = 3
        } else if l >= 10 {
                task.id_padding = 2
        } else {
                task.id_padding = 1
        }
}

func (task *Task) RebuildRawTodo() {
        if task.finished {
                task.raw_todo = task.PrettyPrint("x %P%t")
        } else {
                task.raw_todo = task.PrettyPrint("%P%t")
        }
}

func (task *Task) SetPriority(prio byte) {
        if task.priority < 65 || task.priority > 90 {
                task.priority = '^'
        } else {
                task.priority = prio
        }
}

func (task *Task) SetTodo(todo string) {
        task.todo = todo
}

func (task Task) IdPadding() int {
        return task.id_padding
}

func (task Task) PrettyPrint(pretty string) string {
        rp := regexp.MustCompile("(%[a-zA-Z])")
        out := rp.ReplaceAllStringFunc(pretty, func(s string) string {

                switch s{
                case "%i":
                        str := fmt.Sprintf("%%0%dd", task.IdPadding())
                        return fmt.Sprintf(str, task.Id())
                case "%t":
                        return task.Text()
                case "%T":
                        return task.RawText()
                case "%p":
                        return string(task.Priority())
                case "%P":
                        if task.Priority() != '^' {
                                return "(" + string(task.Priority()) + ") "
                        } else {
                                return ""
                        }
                default:
                        return s
                }
        })
        return out
}
<commit_msg>pad function<commit_after>package todotxt

import (
        "time"
        "os"
        "bufio"
        "strings"
        "regexp"
        "sort"
        "unicode"
        "fmt"
        "math/rand"
)

type Task struct {
        id int
        todo string
        priority byte
        create_date time.Time
        contexts []string
        projects []string
        raw_todo string
        finished bool
        finish_date time.Time
        id_padding int
}

type TaskList []Task

func ParseTask(text string, id int) (Task) {
        var task = Task{}
        task.id = id
        task.raw_todo = text

        splits := strings.Split(text, " ")

        // checking if the task is already finished
        if text[0] == 'x' &&
           text[1] == ' ' &&
           !unicode.IsSpace(rune(text[2])) {
                task.finished = true
                splits = splits[1:]
        }

        date_regexp := "([\\d]{4})-([\\d]{2})-([\\d]{2})"

        // checking for finish date
        if match, _ := regexp.MatchString(date_regexp, splits[0]); match {
                if date, e := time.Parse("2006-01-02", splits[0]); e != nil {
                        panic(e)
                } else {
                        task.finish_date = date
                }

                splits = splits[1:]
        }

        head := splits[0]

        // checking for priority
        if (len(head) == 3) &&
           (head[0] == '(') &&
           (head[2] == ')') &&
           (head[1] >= 65 && head[1] <= 90) { // checking if it's in range [A-Z]
                task.priority = head[1]
                splits = splits[1:]
        }

        // checking for creation date and building the actual todo item
        if match, _ := regexp.MatchString(date_regexp, splits[0]); match {
                if date, e := time.Parse("2006-01-02", splits[0]); e != nil {
                        panic(e)
                } else {
                        task.create_date = date
                }

                task.todo = strings.Join(splits[1:], " ")
        } else {
                task.todo = strings.Join(splits[0:], " ")
        }

        context_regexp, _ := regexp.Compile("@[[:word:]]+")
        contexts := context_regexp.FindAllStringSubmatch(text, -1)
        if len(contexts) != 0 {
                task.contexts = contexts[0]
        }

        project_regexp, _ := regexp.Compile("\\+[[:word:]]+")
        projects := project_regexp.FindAllStringSubmatch(text, -1)
        if len(projects) != 0 {
                task.projects = projects[0]
        }

        return task
}

func LoadTaskList (filename string) (TaskList) {

        var f, err = os.Open(filename)

        if err != nil {
                panic(err)
        }

        defer f.Close()

        var tasklist = TaskList{}

        scanner := bufio.NewScanner(f)

        for scanner.Scan() {
                text := scanner.Text()
                tasklist.Add(text)
        }

        if err := scanner.Err(); err != nil {
                panic(scanner.Err())
        }

        return tasklist
}

type By func(t1, t2 Task) bool

func (by By) Sort(tasks TaskList) {
        ts := &taskSorter{
                tasks: tasks,
                by:    by,
        }
        sort.Sort(ts)
}

type taskSorter struct {
        tasks TaskList
        by func(t1, t2 Task) bool
}

func (s *taskSorter) Len() int {
        return len(s.tasks)
}

func (s *taskSorter) Swap(i, j int) {
        s.tasks[i], s.tasks[j] = s.tasks[j], s.tasks[i]
}

func (s *taskSorter) Less(i, j int) bool {
        return s.by(s.tasks[i], s.tasks[j])
}

func (tasks TaskList) Len() int {
        return len(tasks)
}

func prioCmp(t1, t2 Task) bool {
        return t1.Priority() < t2.Priority()
}

func prioRevCmp(t1, t2 Task) bool {
        return t1.Priority() > t2.Priority()
}

func dateCmp(t1, t2 Task) bool {
        tm1 := t1.CreateDate().Unix()
        tm2 := t2.CreateDate().Unix()

        // if the dates equal, let's use priority
        if tm1 == tm2 {
                return prioCmp(t1, t2)
        } else {
                return tm1 > tm2
        }
}

func dateRevCmp(t1, t2 Task) bool {
        tm1 := t1.CreateDate().Unix()
        tm2 := t2.CreateDate().Unix()

        // if the dates equal, let's use priority
        if tm1 == tm2 {
                return prioCmp(t1, t2)
        } else {
                return tm1 < tm2
        }
}

func lenCmp(t1, t2 Task) bool {
        tl1 := len(t1.raw_todo)
        tl2 := len(t2.raw_todo)
        if tl1 == tl2 {
                return prioCmp(t1, t2)
        } else {
                return tl1 < tl2
        }
}

func lenRevCmp(t1, t2 Task) bool {
        tl1 := len(t1.raw_todo)
        tl2 := len(t2.raw_todo)
        if tl1 == tl2 {
                return prioCmp(t1, t2)
        } else {
                return tl1 > tl2
        }
}

func idCmp(t1, t2 Task) bool {
        return t1.Id() < t2.Id()
}

func randCmp(t1, t2 Task) bool {
        rand.Seed(time.Now().UnixNano()%1e6/1e3)
        return rand.Intn(len(t1.raw_todo)) > rand.Intn(len(t2.raw_todo))
}

func (tasks TaskList) Sort(by string) {
        switch by {
        default:
        case "prio":
                By(prioCmp).Sort(tasks)
        case "prio-rev":
                By(prioRevCmp).Sort(tasks)
        case "date":
                By(dateCmp).Sort(tasks)
        case "date-rev":
                By(dateRevCmp).Sort(tasks)
        case "len":
                By(lenCmp).Sort(tasks)
        case "len-rev":
                By(lenRevCmp).Sort(tasks)
        case "id":
                By(idCmp).Sort(tasks)
        case "rand":
                By(randCmp).Sort(tasks)
        }
}

func (tasks TaskList) Save(filename string) {
        tasks.Sort("id")

        f, err := os.Create(filename)
        if err != nil {
                panic(err)
        }

        defer f.Close()

        for _, task := range tasks {
                f.WriteString(task.RawText() + "\n")
        }
        f.Sync()
}

func (tasks *TaskList) Add(todo string) {
        task := ParseTask(todo, tasks.Len())
        *tasks = append(*tasks, task)
}

func (tasks TaskList) Done(id int, finish_date bool) error {
        if id > tasks.Len() || id < 0 {
                return fmt.Errorf("Error: id is %v", id)
        }

        tasks[id].finished = true
        if finish_date {
                t := time.Now()
                tasks[id].raw_todo = "x " + t.Format("2006-01-02") + " " +
                                        tasks[id].raw_todo
        } else {
                tasks[id].raw_todo = "x " + tasks[id].raw_todo
        }

        return nil
}

func (task Task) Id() int {
        return task.id
}

func (task Task) Text() string {
        return task.todo
}

func (task Task) RawText() string {
        return task.raw_todo
}

func (task Task) Priority() byte {
        // if priority is not from [A-Z], let it be 94 (^)
        if task.priority < 65 || task.priority > 90 {
                return 94 // you know, ^
        } else {
                return task.priority
        }
}

func (task Task) Contexts() []string {
        return task.contexts
}

func (task Task) Projects() []string {
        return task.projects
}

func (task Task) CreateDate() time.Time {
        return task.create_date
}

func (task Task) Finished() bool {
        return task.finished
}

func (task Task) FinishDate() time.Time {
        return task.finish_date
}

func (task *Task) SetIdPaddingBy(tasklist TaskList) {
        l := tasklist.Len()

        if l >= 10000 {
                task.id_padding = 5
        } else if l >= 1000 {
                task.id_padding = 4
        } else if l >= 100 {
                task.id_padding = 3
        } else if l >= 10 {
                task.id_padding = 2
        } else {
                task.id_padding = 1
        }
}

func (task *Task) RebuildRawTodo() {
        if task.finished {
                task.raw_todo = task.PrettyPrint("x %P%t")
        } else {
                task.raw_todo = task.PrettyPrint("%P%t")
        }
}

func (task *Task) SetPriority(prio byte) {
        if task.priority < 65 || task.priority > 90 {
                task.priority = '^'
        } else {
                task.priority = prio
        }
}

func (task *Task) SetTodo(todo string) {
        task.todo = todo
}

func (task Task) IdPadding() int {
        return task.id_padding
}

func pad(in string, length int) string {
        if (length > in.Len()) {
                return strings.Repeat(' ', length - in.Len()) + in
        } else {
                return in[:length]
        }
}

func (task Task) PrettyPrint(pretty string) string {
        rp := regexp.MustCompile("(%[a-zA-Z])")
        out := rp.ReplaceAllStringFunc(pretty, func(s string) string {

                switch s{
                case "%i":
                        str := fmt.Sprintf("%%0%dd", task.IdPadding())
                        return fmt.Sprintf(str, task.Id())
                case "%t":
                        return task.Text()
                case "%T":
                        return task.RawText()
                case "%p":
                        return string(task.Priority())
                case "%P":
                        if task.Priority() != '^' {
                                return "(" + string(task.Priority()) + ") "
                        } else {
                                return ""
                        }
                default:
                        return s
                }
        })
        return out
}
<|endoftext|>


<commit_before>package todotxt

import (
        "time"
        "os"
        "bufio"
        "strings"
        "regexp"
        "sort"
)

type Task struct {
        id int
        todo string
        priority byte
        create_date time.Time
        contexts []string
        projects []string
        raw_todo string
}

type TaskList []Task

func LoadTaskList (filename string) (TaskList) {

        var f, err = os.Open(filename)

        if err != nil {
                panic(err)
        }

        defer f.Close()

        var tasklist = TaskList{}

        scanner := bufio.NewScanner(f)
        id := 0

        for scanner.Scan() {
                var task = Task{}
                text := scanner.Text()
                task.id = id
                task.raw_todo = text

                splits := strings.Split(text, " ")

                head := splits[0]

                if (len(head) == 3) &&
                   (head[0] == '(') &&
                   (head[2] == ')') &&
                   (head[1] >= 65 && head[1] <= 90) { // checking if it's in range [A-Z]
                        task.priority = head[1]
                        splits = splits[1:]
                }

                date_regexp := "([\\d]{4})-([\\d]{2})-([\\d]{2})"
                if match, _ := regexp.MatchString(date_regexp, splits[0]); match {
                        if date, e := time.Parse("2006-01-02", splits[0]); e != nil {
                                panic(e)
                        } else {
                                task.create_date = date
                        }

                        task.todo = strings.Join(splits[1:], " ")
                } else {
                        task.todo = strings.Join(splits[0:], " ")
                }

                context_regexp, _ := regexp.Compile("@[[:word:]]+")
                contexts := context_regexp.FindAllStringSubmatch(text, -1)
                if len(contexts) != 0 {
                        task.contexts = contexts[0]
                }

                project_regexp, _ := regexp.Compile("\\+[[:word:]]+")
                projects := project_regexp.FindAllStringSubmatch(text, -1)
                if len(projects) != 0 {
                        task.projects = projects[0]
                }

                tasklist = append(tasklist, task)
                id += 1
        }

        if err := scanner.Err(); err != nil {
                panic(scanner.Err())
        }

        return tasklist
}

type By func(t1, t2 Task) bool

func (by By) Sort(tasks TaskList) {
        ts := &taskSorter{
                tasks: tasks,
                by:    by,
        }
        sort.Sort(ts)
}

type taskSorter struct {
        tasks TaskList
        by func(t1, t2 Task) bool
}

func (s *taskSorter) Len() int {
        return len(s.tasks)
}

func (s *taskSorter) Swap(i, j int) {
        s.tasks[i], s.tasks[j] = s.tasks[j], s.tasks[i]
}

func (s *taskSorter) Less(i, j int) bool {
        return s.by(s.tasks[i], s.tasks[j])
}

func (tasks TaskList) Len() int {
        return len(tasks)
}

func prioCmp(t1, t2 Task) bool {
        return t1.Priority() < t2.Priority()
}

func prioRevCmp(t1, t2 Task) bool {
        return t1.Priority() > t2.Priority()
}

func dateCmp(t1, t2 Task) bool {
        tm1 := t1.CreateDate().Unix()
        tm2 := t2.CreateDate().Unix()

        // if the dates equal, let's use priority
        if tm1 == tm2 {
                return prioCmp(t1, t2)
        } else {
                return tm1 > tm2
        }
}

func dateRevCmp(t1, t2 Task) bool {
        tm1 := t1.CreateDate().Unix()
        tm2 := t2.CreateDate().Unix()

        // if the dates equal, let's use priority
        if tm1 == tm2 {
                return prioCmp(t1, t2)
        } else {
                return tm1 < tm2
        }
}

func lenCmp(t1, t2 Task) bool {
        tl1 := len(t1.raw_todo)
        tl2 := len(t2.raw_todo)
        if tl1 == tl2 {
                return prioCmp(t1, t2)
        } else {
                return tl1 < tl2
        }
}

func lenRevCmp(t1, t2 Task) bool {
        tl1 := len(t1.raw_todo)
        tl2 := len(t2.raw_todo)
        if tl1 == tl2 {
                return prioCmp(t1, t2)
        } else {
                return tl1 > tl2
        }
}

func idCmp(t1, t2 Task) bool {
        return t1.Id() < t2.Id()
}

func (tasks TaskList) Sort(by string) {
        switch by {
        default:
        case "prio":
                By(prioCmp).Sort(tasks)
        case "prio-rev":
                By(prioRevCmp).Sort(tasks)
        case "date":
                By(dateCmp).Sort(tasks)
        case "date-rev":
                By(dateRevCmp).Sort(tasks)
        case "len":
                By(lenCmp).Sort(tasks)
        case "len-rev":
                By(lenRevCmp).Sort(tasks)
        case "id":
                By(idCmp).Sort(tasks)
        }
}

func (tasks TaskList) Save(filename string) {
        tasks.Sort("id")

        f, err := os.Create(filename)
        if err != nil {
                panic(err)
        }

        defer f.Close()

        for _, task := range tasks {
                f.WriteString(task.RawText() + "\n")
        }
        f.Sync()
}

func (task Task) Id() int {
        return task.id
}

func (task Task) Text() string {
        return task.todo
}

func (task Task) RawText() string {
        return task.raw_todo
}

func (task Task) Priority() byte {
        // if priority is not from [A-Z], let it be 94 (^)
        if task.priority < 65 || task.priority > 90 {
                return 94 // you know, ^
        } else {
                return task.priority
        }
}

func (task Task) Contexts() []string {
        return task.contexts
}

func (task Task) Projects() []string {
        return task.projects
}

func (task Task) CreateDate() time.Time {
        return task.create_date
}
<commit_msg>finished flag<commit_after>package todotxt

import (
        "time"
        "os"
        "bufio"
        "strings"
        "regexp"
        "sort"
        "unicode"
)

type Task struct {
        id int
        todo string
        priority byte
        create_date time.Time
        contexts []string
        projects []string
        raw_todo string
        finished bool
}

type TaskList []Task

func LoadTaskList (filename string) (TaskList) {

        var f, err = os.Open(filename)

        if err != nil {
                panic(err)
        }

        defer f.Close()

        var tasklist = TaskList{}

        scanner := bufio.NewScanner(f)
        id := 0

        for scanner.Scan() {
                var task = Task{}
                text := scanner.Text()
                task.id = id
                task.raw_todo = text

                splits := strings.Split(text, " ")

                if text[0] == 'x' && text[1] == ' ' && unicode.IsSpace(text[2]) {
                        task.finished = true
                        splits = splits[1:]
                }

                head := splits[0]

                if (len(head) == 3) &&
                   (head[0] == '(') &&
                   (head[2] == ')') &&
                   (head[1] >= 65 && head[1] <= 90) { // checking if it's in range [A-Z]
                        task.priority = head[1]
                        splits = splits[1:]
                }

                date_regexp := "([\\d]{4})-([\\d]{2})-([\\d]{2})"
                if match, _ := regexp.MatchString(date_regexp, splits[0]); match {
                        if date, e := time.Parse("2006-01-02", splits[0]); e != nil {
                                panic(e)
                        } else {
                                task.create_date = date
                        }

                        task.todo = strings.Join(splits[1:], " ")
                } else {
                        task.todo = strings.Join(splits[0:], " ")
                }

                context_regexp, _ := regexp.Compile("@[[:word:]]+")
                contexts := context_regexp.FindAllStringSubmatch(text, -1)
                if len(contexts) != 0 {
                        task.contexts = contexts[0]
                }

                project_regexp, _ := regexp.Compile("\\+[[:word:]]+")
                projects := project_regexp.FindAllStringSubmatch(text, -1)
                if len(projects) != 0 {
                        task.projects = projects[0]
                }

                tasklist = append(tasklist, task)
                id += 1
        }

        if err := scanner.Err(); err != nil {
                panic(scanner.Err())
        }

        return tasklist
}

type By func(t1, t2 Task) bool

func (by By) Sort(tasks TaskList) {
        ts := &taskSorter{
                tasks: tasks,
                by:    by,
        }
        sort.Sort(ts)
}

type taskSorter struct {
        tasks TaskList
        by func(t1, t2 Task) bool
}

func (s *taskSorter) Len() int {
        return len(s.tasks)
}

func (s *taskSorter) Swap(i, j int) {
        s.tasks[i], s.tasks[j] = s.tasks[j], s.tasks[i]
}

func (s *taskSorter) Less(i, j int) bool {
        return s.by(s.tasks[i], s.tasks[j])
}

func (tasks TaskList) Len() int {
        return len(tasks)
}

func prioCmp(t1, t2 Task) bool {
        return t1.Priority() < t2.Priority()
}

func prioRevCmp(t1, t2 Task) bool {
        return t1.Priority() > t2.Priority()
}

func dateCmp(t1, t2 Task) bool {
        tm1 := t1.CreateDate().Unix()
        tm2 := t2.CreateDate().Unix()

        // if the dates equal, let's use priority
        if tm1 == tm2 {
                return prioCmp(t1, t2)
        } else {
                return tm1 > tm2
        }
}

func dateRevCmp(t1, t2 Task) bool {
        tm1 := t1.CreateDate().Unix()
        tm2 := t2.CreateDate().Unix()

        // if the dates equal, let's use priority
        if tm1 == tm2 {
                return prioCmp(t1, t2)
        } else {
                return tm1 < tm2
        }
}

func lenCmp(t1, t2 Task) bool {
        tl1 := len(t1.raw_todo)
        tl2 := len(t2.raw_todo)
        if tl1 == tl2 {
                return prioCmp(t1, t2)
        } else {
                return tl1 < tl2
        }
}

func lenRevCmp(t1, t2 Task) bool {
        tl1 := len(t1.raw_todo)
        tl2 := len(t2.raw_todo)
        if tl1 == tl2 {
                return prioCmp(t1, t2)
        } else {
                return tl1 > tl2
        }
}

func idCmp(t1, t2 Task) bool {
        return t1.Id() < t2.Id()
}

func (tasks TaskList) Sort(by string) {
        switch by {
        default:
        case "prio":
                By(prioCmp).Sort(tasks)
        case "prio-rev":
                By(prioRevCmp).Sort(tasks)
        case "date":
                By(dateCmp).Sort(tasks)
        case "date-rev":
                By(dateRevCmp).Sort(tasks)
        case "len":
                By(lenCmp).Sort(tasks)
        case "len-rev":
                By(lenRevCmp).Sort(tasks)
        case "id":
                By(idCmp).Sort(tasks)
        }
}

func (tasks TaskList) Save(filename string) {
        tasks.Sort("id")

        f, err := os.Create(filename)
        if err != nil {
                panic(err)
        }

        defer f.Close()

        for _, task := range tasks {
                f.WriteString(task.RawText() + "\n")
        }
        f.Sync()
}

func (task Task) Id() int {
        return task.id
}

func (task Task) Text() string {
        return task.todo
}

func (task Task) RawText() string {
        return task.raw_todo
}

func (task Task) Priority() byte {
        // if priority is not from [A-Z], let it be 94 (^)
        if task.priority < 65 || task.priority > 90 {
                return 94 // you know, ^
        } else {
                return task.priority
        }
}

func (task Task) Contexts() []string {
        return task.contexts
}

func (task Task) Projects() []string {
        return task.projects
}

func (task Task) CreateDate() time.Time {
        return task.create_date
}
<|endoftext|>


<commit_before>package main

import (
	"gopkg.in/yaml.v2"
	"io/ioutil"
	"log"
	"net"
	"os"
)

func checkErr(err error) {
	if err != nil {
		log.Fatal("Error:", err)
	}
}

type udproxyConfig struct {
	Backends []struct {
		Name           string `json:"name"`
		BackendAddress string `json:"backend_address"`
		LocalAddress   string `json:"local_address"`
	} `json:"backends"`
	Clients []struct {
		IP      string `json:"ip"`
		Backend string `json:"backend"`
	} `json:"clients"`
}

func backend(local, remote string, quit chan struct{}, input chan []byte) {
	laddr, err := net.ResolveUDPAddr("udp", local)
	checkErr(err)

	raddr, err := net.ResolveUDPAddr("udp", remote)
	checkErr(err)

	conn, err := net.DialUDP("udp", laddr, raddr)
	checkErr(err)

	defer conn.Close()

	for {
		select {
		case <-quit:
			return
		case msg := <-input:
			_, err := conn.Write(msg)
			checkErr(err)
		}
	}
}

func spawnBackend(local, remote string) (chan struct{}, chan []byte) {
	quit := make(chan struct{})
	input := make(chan []byte)

	go backend(local, remote, quit, input)

	return quit, input
}

func main() {
	var config udproxyConfig

	if len(os.Args) < 2 {
		log.Fatal("Usage:", os.Args[0], "<config file>")
	}

	data, err := ioutil.ReadFile(os.Args[1])
	checkErr(err)

	err = yaml.Unmarshal(data, &config)
	checkErr(err)
}
<commit_msg>Simplify configuration.<commit_after>package main

import (
	"gopkg.in/yaml.v2"
	"io/ioutil"
	"log"
	"net"
	"os"
)

func checkErr(err error) {
	if err != nil {
		log.Fatalln("Error:", err)
	}
}

type udproxyConfig struct {
	Backends map[string]string `json:"backends"`
	Clients  map[string]string `json:"clients"`
}

func backend(local, remote string, quit chan struct{}, input chan []byte) {
	laddr, err := net.ResolveUDPAddr("udp", local)
	checkErr(err)

	raddr, err := net.ResolveUDPAddr("udp", remote)
	checkErr(err)

	conn, err := net.DialUDP("udp", laddr, raddr)
	checkErr(err)

	defer conn.Close()

	for {
		select {
		case <-quit:
			return
		case msg := <-input:
			_, err := conn.Write(msg)
			checkErr(err)
		}
	}
}

func spawnBackend(local, remote string) (chan struct{}, chan []byte) {
	quit := make(chan struct{})
	input := make(chan []byte)

	go backend(local, remote, quit, input)

	return quit, input
}

func main() {
	var config udproxyConfig

	if len(os.Args) < 2 {
		log.Fatalln("Usage:", os.Args[0], "<config file>")
	}

	data, err := ioutil.ReadFile(os.Args[1])
	checkErr(err)

	err = yaml.Unmarshal(data, &config)
	checkErr(err)
}
<|endoftext|>


<commit_before>package libct

// #cgo CFLAGS: -DCONFIG_X86_64 -DARCH="x86" -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
// #cgo LDFLAGS: -l:libct.a -l:libnl-route-3.a -l:libnl-3.a -l:libapparmor.a -l:libselinux.a -lm
// #include "../src/include/uapi/libct.h"
// #include "../src/include/uapi/libct-errors.h"
import "C"
import "fmt"
import "unsafe"

const (
	LIBCT_OPT_AUTO_PROC_MOUNT = C.LIBCT_OPT_AUTO_PROC_MOUNT
	CAPS_BSET                 = C.CAPS_BSET
	CAPS_ALLCAPS              = C.CAPS_ALLCAPS
	CAPS_ALL                  = C.CAPS_ALL
)

type file interface {
	Fd() uintptr
	Close() error
	Read(p []byte) (n int, err error)
	Write(p []byte) (n int, err error)
}

type console struct {
}

var Console console

func (c console) Fd() uintptr {
	return ^uintptr(0)
}

func (c console) Close() error {
	return nil
}

func (c console) Read(p []byte) (n int, err error) {
	return 0, nil
}

func (c console) Write(p []byte) (n int, err error) {
	return 0, nil
}

type Session struct {
	s C.libct_session_t
}

type Container struct {
	ct C.ct_handler_t
}

type NetDev struct {
	dev C.ct_net_t
}

type NetRoute struct {
	route C.ct_net_route_t
}

type NetRouteNextHop struct {
	nh C.ct_net_route_nh_t
}

type LibctError struct {
	Code int
}

func (e LibctError) Error() string {
	return fmt.Sprintf("LibctError: %x", e.Code)
}

func (s *Session) OpenLocal() error {
	h := C.libct_session_open_local()

	if C.libct_handle_is_err(unsafe.Pointer(h)) != 0 {
		return LibctError{int(C.libct_handle_to_err(unsafe.Pointer(h)))}
	}

	s.s = h

	return nil
}

func (s *Session) ContainerCreate(name string) (*Container, error) {
	ct := C.libct_container_create(s.s, C.CString(name))

	if C.libct_handle_is_err(unsafe.Pointer(ct)) != 0 {
		return nil, LibctError{int(C.libct_handle_to_err(unsafe.Pointer(ct)))}
	}

	return &Container{ct}, nil
}

func (s *Session) ContainerOpen(name string) (*Container, error) {
	ct := C.libct_container_open(s.s, C.CString(name))

	if C.libct_handle_is_err(unsafe.Pointer(ct)) != 0 {
		return nil, LibctError{int(C.libct_handle_to_err(unsafe.Pointer(ct)))}
	}

	return &Container{ct}, nil
}

func (s *Session) ProcessCreateDesc() (*ProcessDesc, error) {
	p := C.libct_process_desc_create(s.s)
	if C.libct_handle_is_err(unsafe.Pointer(p)) != 0 {
		return nil, LibctError{int(C.libct_handle_to_err(unsafe.Pointer(p)))}
	}

	return &ProcessDesc{desc: p}, nil
}

func (ct *Container) SetNsMask(nsmask uint64) error {
	ret := C.libct_container_set_nsmask(ct.ct, C.ulong(nsmask))

	if ret != 0 {
		return LibctError{int(ret)}
	}

	return nil
}

func (ct *Container) Kill() error {
	ret := C.libct_container_kill(ct.ct)

	if ret != 0 {
		return LibctError{int(ret)}
	}

	return nil
}

func getFd(f file) C.int {
	if _, ok := f.(console); ok {
		return C.LIBCT_CONSOLE_FD
	}

	return C.int(f.Fd())
}

func (ct *Container) SetConsoleFd(f file) error {
	ret := C.libct_container_set_console_fd(ct.ct, getFd(f))

	if ret != 0 {
		return LibctError{int(ret)}
	}

	return nil
}

func (ct *Container) SpawnExecve(p *ProcessDesc, path string, argv []string, env []string) (error) {
	var (
		i   int = 0
	)

	type F func(*ProcessDesc) (file, error)
	for _, setupFd := range []F{(*ProcessDesc).stdin, (*ProcessDesc).stdout, (*ProcessDesc).stderr} {
		fd, err := setupFd(p)
		if err != nil {
			p.closeDescriptors(p.closeAfterStart)
			p.closeDescriptors(p.closeAfterWait)
			return err
		}
		p.childFiles = append(p.childFiles, fd)
		i = i + 1
	}

	p.childFiles = append(p.childFiles, p.ExtraFiles...)

	err := ct.execve(p, path, argv, env, true)

	return err
}

func (ct *Container) EnterExecve(p *ProcessDesc, path string, argv []string, env []string) (error) {
	err := ct.execve(p, path, argv, env, false)
	p.closeDescriptors(p.closeAfterStart)
	return err
}

func (ct *Container) execve(p *ProcessDesc, path string, argv []string, env []string, spawn bool) (error) {
	var (
		h     C.ct_process_t
	)

	cargv := make([]*C.char, len(argv)+1)
	for i, arg := range argv {
		cargv[i] = C.CString(arg)
	}

	cenv := make([]*C.char, len(env)+1)
	for i, e := range env {
		cenv[i] = C.CString(e)
	}

	cfds := make([]C.int, len(p.childFiles))
	for i, fd := range p.childFiles {
		cfds[i] = C.int(getFd(fd))
	}

	C.libct_process_desc_set_fds(p.desc, &cfds[0], C.int(len(p.childFiles)))

	if spawn {
		h = C.libct_container_spawn_execve(ct.ct, p.desc, C.CString(path), &cargv[0], &cenv[0])
	} else {
		h = C.libct_container_enter_execve(ct.ct, p.desc, C.CString(path), &cargv[0], &cenv[0])
	}

	if C.libct_handle_is_err(unsafe.Pointer(h)) != 0 {
		return  LibctError{int(C.libct_handle_to_err(unsafe.Pointer(h)))}
	}

	p.handle = h

	return nil
}

func (ct *Container) Wait() error {
	ret := C.libct_container_wait(ct.ct)

	if ret != 0 {
		return LibctError{int(ret)}
	}

	return nil
}

func (ct *Container) Uname(host *string, domain *string) error {
	var chost *C.char
	var cdomain *C.char

	if host != nil {
		chost = C.CString(*host)
	}

	if domain != nil {
		cdomain = C.CString(*domain)
	}

	ret := C.libct_container_uname(ct.ct, chost, cdomain)

	if ret != 0 {
		return LibctError{int(ret)}
	}

	return nil
}

func (ct *Container) SetRoot(root string) error {

	if ret := C.libct_fs_set_root(ct.ct, C.CString(root)); ret != 0 {
		return LibctError{int(ret)}
	}

	return nil
}

const (
	CT_FS_RDONLY      = C.CT_FS_RDONLY
	CT_FS_PRIVATE     = C.CT_FS_PRIVATE
	CT_FS_NOEXEC      = C.CT_FS_NOEXEC
	CT_FS_NOSUID      = C.CT_FS_NOSUID
	CT_FS_NODEV       = C.CT_FS_NODEV
	CT_FS_STRICTATIME = C.CT_FS_STRICTATIME
)

func (ct *Container) AddBindMount(src string, dst string, flags int) error {

	if ret := C.libct_fs_add_bind_mount(ct.ct, C.CString(src), C.CString(dst), C.int(flags)); ret != 0 {
		return LibctError{int(ret)}
	}

	return nil
}

func (ct *Container) AddMount(src string, dst string, flags int, fstype string, data string) error {

	if ret := C.libct_fs_add_mount(ct.ct, C.CString(src), C.CString(dst), C.int(flags), C.CString(fstype), C.CString(data)); ret != 0 {
		return LibctError{int(ret)}
	}

	return nil
}

func (ct *Container) SetOption(opt int32) error {
	if ret := C.libct_container_set_option(ct.ct, C.int(opt), nil); ret != 0 {
		return LibctError{int(ret)}
	}

	return nil
}

func (ct *Container) AddDeviceNode(path string, mode int, major int, minor int) error {

	ret := C.libct_fs_add_devnode(ct.ct, C.CString(path), C.int(mode), C.int(major), C.int(minor))

	if ret != 0 {
		return LibctError{int(ret)}
	}

	return nil
}

func (nd *NetDev) GetPeer() (*NetDev, error) {

	dev := C.libct_net_dev_get_peer(nd.dev)

	if C.libct_handle_is_err(unsafe.Pointer(dev)) != 0 {
		return nil, LibctError{int(C.libct_handle_to_err(unsafe.Pointer(dev)))}
	}

	return &NetDev{dev}, nil
}

func (ct *Container) AddNetVeth(host_name string, ct_name string) (*NetDev, error) {

	var args C.struct_ct_net_veth_arg

	args.host_name = C.CString(host_name)
	args.ct_name = C.CString(ct_name)

	dev := C.libct_net_add(ct.ct, C.CT_NET_VETH, unsafe.Pointer(&args))

	if C.libct_handle_is_err(unsafe.Pointer(dev)) != 0 {
		return nil, LibctError{int(C.libct_handle_to_err(unsafe.Pointer(dev)))}
	}

	return &NetDev{dev}, nil
}

func (dev *NetDev) AddIpAddr(addr string) error {
	err := C.libct_net_dev_add_ip_addr(dev.dev, C.CString(addr))
	if err != 0 {
		return LibctError{int(err)}
	}

	return nil
}

func (dev *NetDev) SetMaster(master string) error {
	err := C.libct_net_dev_set_master(dev.dev, C.CString(master))
	if err != 0 {
		return LibctError{int(err)}
	}

	return nil
}

func (dev *NetDev) SetMtu(mtu int) error {
	err := C.libct_net_dev_set_mtu(dev.dev, C.int(mtu))
	if err != 0 {
		return LibctError{int(err)}
	}

	return nil
}

func (ct *Container) AddRoute() (*NetRoute, error) {
	r := C.libct_net_route_add(ct.ct)

	if C.libct_handle_is_err(unsafe.Pointer(r)) != 0 {
		return nil, LibctError{int(C.libct_handle_to_err(unsafe.Pointer(r)))}
	}

	return &NetRoute{r}, nil
}

func (route *NetRoute) SetSrc(src string) error {
	err := C.libct_net_route_set_src(route.route, C.CString(src))
	if err != 0 {
		return LibctError{int(err)}
	}

	return nil
}

func (route *NetRoute) SetDst(dst string) error {
	err := C.libct_net_route_set_dst(route.route, C.CString(dst))
	if err != 0 {
		return LibctError{int(err)}
	}

	return nil
}

func (route *NetRoute) SetDev(dev string) error {
	err := C.libct_net_route_set_dev(route.route, C.CString(dev))
	if err != 0 {
		return LibctError{int(err)}
	}

	return nil
}

func (route *NetRoute) AddNextHop() (*NetRouteNextHop, error) {
	nh := C.libct_net_route_add_nh(route.route)
	if C.libct_handle_is_err(unsafe.Pointer(nh)) != 0 {
		return nil, LibctError{int(C.libct_handle_to_err(unsafe.Pointer(nh)))}
	}

	return &NetRouteNextHop{nh}, nil
}

func (nh *NetRouteNextHop) SetGateway(addr string) error {
	err := C.libct_net_route_nh_set_gw(nh.nh, C.CString(addr))
	if err != 0 {
		return LibctError{int(err)}
	}

	return nil
}

func (nh *NetRouteNextHop) SetDev(dev string) error {
	err := C.libct_net_route_nh_set_dev(nh.nh, C.CString(dev))
	if err != 0 {
		return LibctError{int(err)}
	}

	return nil
}
<commit_msg>go: handle file descriptors for EnterExecve<commit_after>package libct

// #cgo CFLAGS: -DCONFIG_X86_64 -DARCH="x86" -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
// #cgo LDFLAGS: -l:libct.a -l:libnl-route-3.a -l:libnl-3.a -l:libapparmor.a -l:libselinux.a -lm
// #include "../src/include/uapi/libct.h"
// #include "../src/include/uapi/libct-errors.h"
import "C"
import "fmt"
import "unsafe"

const (
	LIBCT_OPT_AUTO_PROC_MOUNT = C.LIBCT_OPT_AUTO_PROC_MOUNT
	CAPS_BSET                 = C.CAPS_BSET
	CAPS_ALLCAPS              = C.CAPS_ALLCAPS
	CAPS_ALL                  = C.CAPS_ALL
)

type file interface {
	Fd() uintptr
	Close() error
	Read(p []byte) (n int, err error)
	Write(p []byte) (n int, err error)
}

type console struct {
}

var Console console

func (c console) Fd() uintptr {
	return ^uintptr(0)
}

func (c console) Close() error {
	return nil
}

func (c console) Read(p []byte) (n int, err error) {
	return 0, nil
}

func (c console) Write(p []byte) (n int, err error) {
	return 0, nil
}

type Session struct {
	s C.libct_session_t
}

type Container struct {
	ct C.ct_handler_t
}

type NetDev struct {
	dev C.ct_net_t
}

type NetRoute struct {
	route C.ct_net_route_t
}

type NetRouteNextHop struct {
	nh C.ct_net_route_nh_t
}

type LibctError struct {
	Code int
}

func (e LibctError) Error() string {
	return fmt.Sprintf("LibctError: %x", e.Code)
}

func (s *Session) OpenLocal() error {
	h := C.libct_session_open_local()

	if C.libct_handle_is_err(unsafe.Pointer(h)) != 0 {
		return LibctError{int(C.libct_handle_to_err(unsafe.Pointer(h)))}
	}

	s.s = h

	return nil
}

func (s *Session) ContainerCreate(name string) (*Container, error) {
	ct := C.libct_container_create(s.s, C.CString(name))

	if C.libct_handle_is_err(unsafe.Pointer(ct)) != 0 {
		return nil, LibctError{int(C.libct_handle_to_err(unsafe.Pointer(ct)))}
	}

	return &Container{ct}, nil
}

func (s *Session) ContainerOpen(name string) (*Container, error) {
	ct := C.libct_container_open(s.s, C.CString(name))

	if C.libct_handle_is_err(unsafe.Pointer(ct)) != 0 {
		return nil, LibctError{int(C.libct_handle_to_err(unsafe.Pointer(ct)))}
	}

	return &Container{ct}, nil
}

func (s *Session) ProcessCreateDesc() (*ProcessDesc, error) {
	p := C.libct_process_desc_create(s.s)
	if C.libct_handle_is_err(unsafe.Pointer(p)) != 0 {
		return nil, LibctError{int(C.libct_handle_to_err(unsafe.Pointer(p)))}
	}

	return &ProcessDesc{desc: p}, nil
}

func (ct *Container) SetNsMask(nsmask uint64) error {
	ret := C.libct_container_set_nsmask(ct.ct, C.ulong(nsmask))

	if ret != 0 {
		return LibctError{int(ret)}
	}

	return nil
}

func (ct *Container) Kill() error {
	ret := C.libct_container_kill(ct.ct)

	if ret != 0 {
		return LibctError{int(ret)}
	}

	return nil
}

func getFd(f file) C.int {
	if _, ok := f.(console); ok {
		return C.LIBCT_CONSOLE_FD
	}

	return C.int(f.Fd())
}

func (ct *Container) SetConsoleFd(f file) error {
	ret := C.libct_container_set_console_fd(ct.ct, getFd(f))

	if ret != 0 {
		return LibctError{int(ret)}
	}

	return nil
}

func (ct *Container) SpawnExecve(p *ProcessDesc, path string, argv []string, env []string) (error) {
	err := ct.execve(p, path, argv, env, true)

	return err
}

func (ct *Container) EnterExecve(p *ProcessDesc, path string, argv []string, env []string) (error) {
	err := ct.execve(p, path, argv, env, false)
	return err
}

func (ct *Container) execve(p *ProcessDesc, path string, argv []string, env []string, spawn bool) (error) {
	var (
		h     C.ct_process_t
		i   int = 0
	)

	type F func(*ProcessDesc) (file, error)
	for _, setupFd := range []F{(*ProcessDesc).stdin, (*ProcessDesc).stdout, (*ProcessDesc).stderr} {
		fd, err := setupFd(p)
		if err != nil {
			p.closeDescriptors(p.closeAfterStart)
			p.closeDescriptors(p.closeAfterWait)
			return err
		}
		p.childFiles = append(p.childFiles, fd)
		i = i + 1
	}

	p.childFiles = append(p.childFiles, p.ExtraFiles...)

	cargv := make([]*C.char, len(argv)+1)
	for i, arg := range argv {
		cargv[i] = C.CString(arg)
	}

	cenv := make([]*C.char, len(env)+1)
	for i, e := range env {
		cenv[i] = C.CString(e)
	}

	cfds := make([]C.int, len(p.childFiles))
	for i, fd := range p.childFiles {
		cfds[i] = C.int(getFd(fd))
	}

	C.libct_process_desc_set_fds(p.desc, &cfds[0], C.int(len(p.childFiles)))

	if spawn {
		h = C.libct_container_spawn_execve(ct.ct, p.desc, C.CString(path), &cargv[0], &cenv[0])
	} else {
		h = C.libct_container_enter_execve(ct.ct, p.desc, C.CString(path), &cargv[0], &cenv[0])
	}

	if C.libct_handle_is_err(unsafe.Pointer(h)) != 0 {
		return  LibctError{int(C.libct_handle_to_err(unsafe.Pointer(h)))}
	}

	p.handle = h

	return nil
}

func (ct *Container) Wait() error {
	ret := C.libct_container_wait(ct.ct)

	if ret != 0 {
		return LibctError{int(ret)}
	}

	return nil
}

func (ct *Container) Uname(host *string, domain *string) error {
	var chost *C.char
	var cdomain *C.char

	if host != nil {
		chost = C.CString(*host)
	}

	if domain != nil {
		cdomain = C.CString(*domain)
	}

	ret := C.libct_container_uname(ct.ct, chost, cdomain)

	if ret != 0 {
		return LibctError{int(ret)}
	}

	return nil
}

func (ct *Container) SetRoot(root string) error {

	if ret := C.libct_fs_set_root(ct.ct, C.CString(root)); ret != 0 {
		return LibctError{int(ret)}
	}

	return nil
}

const (
	CT_FS_RDONLY      = C.CT_FS_RDONLY
	CT_FS_PRIVATE     = C.CT_FS_PRIVATE
	CT_FS_NOEXEC      = C.CT_FS_NOEXEC
	CT_FS_NOSUID      = C.CT_FS_NOSUID
	CT_FS_NODEV       = C.CT_FS_NODEV
	CT_FS_STRICTATIME = C.CT_FS_STRICTATIME
)

func (ct *Container) AddBindMount(src string, dst string, flags int) error {

	if ret := C.libct_fs_add_bind_mount(ct.ct, C.CString(src), C.CString(dst), C.int(flags)); ret != 0 {
		return LibctError{int(ret)}
	}

	return nil
}

func (ct *Container) AddMount(src string, dst string, flags int, fstype string, data string) error {

	if ret := C.libct_fs_add_mount(ct.ct, C.CString(src), C.CString(dst), C.int(flags), C.CString(fstype), C.CString(data)); ret != 0 {
		return LibctError{int(ret)}
	}

	return nil
}

func (ct *Container) SetOption(opt int32) error {
	if ret := C.libct_container_set_option(ct.ct, C.int(opt), nil); ret != 0 {
		return LibctError{int(ret)}
	}

	return nil
}

func (ct *Container) AddDeviceNode(path string, mode int, major int, minor int) error {

	ret := C.libct_fs_add_devnode(ct.ct, C.CString(path), C.int(mode), C.int(major), C.int(minor))

	if ret != 0 {
		return LibctError{int(ret)}
	}

	return nil
}

func (nd *NetDev) GetPeer() (*NetDev, error) {

	dev := C.libct_net_dev_get_peer(nd.dev)

	if C.libct_handle_is_err(unsafe.Pointer(dev)) != 0 {
		return nil, LibctError{int(C.libct_handle_to_err(unsafe.Pointer(dev)))}
	}

	return &NetDev{dev}, nil
}

func (ct *Container) AddNetVeth(host_name string, ct_name string) (*NetDev, error) {

	var args C.struct_ct_net_veth_arg

	args.host_name = C.CString(host_name)
	args.ct_name = C.CString(ct_name)

	dev := C.libct_net_add(ct.ct, C.CT_NET_VETH, unsafe.Pointer(&args))

	if C.libct_handle_is_err(unsafe.Pointer(dev)) != 0 {
		return nil, LibctError{int(C.libct_handle_to_err(unsafe.Pointer(dev)))}
	}

	return &NetDev{dev}, nil
}

func (dev *NetDev) AddIpAddr(addr string) error {
	err := C.libct_net_dev_add_ip_addr(dev.dev, C.CString(addr))
	if err != 0 {
		return LibctError{int(err)}
	}

	return nil
}

func (dev *NetDev) SetMaster(master string) error {
	err := C.libct_net_dev_set_master(dev.dev, C.CString(master))
	if err != 0 {
		return LibctError{int(err)}
	}

	return nil
}

func (dev *NetDev) SetMtu(mtu int) error {
	err := C.libct_net_dev_set_mtu(dev.dev, C.int(mtu))
	if err != 0 {
		return LibctError{int(err)}
	}

	return nil
}

func (ct *Container) AddRoute() (*NetRoute, error) {
	r := C.libct_net_route_add(ct.ct)

	if C.libct_handle_is_err(unsafe.Pointer(r)) != 0 {
		return nil, LibctError{int(C.libct_handle_to_err(unsafe.Pointer(r)))}
	}

	return &NetRoute{r}, nil
}

func (route *NetRoute) SetSrc(src string) error {
	err := C.libct_net_route_set_src(route.route, C.CString(src))
	if err != 0 {
		return LibctError{int(err)}
	}

	return nil
}

func (route *NetRoute) SetDst(dst string) error {
	err := C.libct_net_route_set_dst(route.route, C.CString(dst))
	if err != 0 {
		return LibctError{int(err)}
	}

	return nil
}

func (route *NetRoute) SetDev(dev string) error {
	err := C.libct_net_route_set_dev(route.route, C.CString(dev))
	if err != 0 {
		return LibctError{int(err)}
	}

	return nil
}

func (route *NetRoute) AddNextHop() (*NetRouteNextHop, error) {
	nh := C.libct_net_route_add_nh(route.route)
	if C.libct_handle_is_err(unsafe.Pointer(nh)) != 0 {
		return nil, LibctError{int(C.libct_handle_to_err(unsafe.Pointer(nh)))}
	}

	return &NetRouteNextHop{nh}, nil
}

func (nh *NetRouteNextHop) SetGateway(addr string) error {
	err := C.libct_net_route_nh_set_gw(nh.nh, C.CString(addr))
	if err != 0 {
		return LibctError{int(err)}
	}

	return nil
}

func (nh *NetRouteNextHop) SetDev(dev string) error {
	err := C.libct_net_route_nh_set_dev(nh.nh, C.CString(dev))
	if err != 0 {
		return LibctError{int(err)}
	}

	return nil
}
<|endoftext|>


<commit_before>package goregexp

import (
	"fmt"
	"regexp"
)

/* Encapsulate a regex and a string,
for managing results from FindAllStringSubmatchIndex */
type Reres struct {
	r        *regexp.Regexp
	s        string
	matches  [][]int
	i        int
	previous int
}

func (r *Reres) String() string {
	msg := fmt.Sprintf("Regexp res for '%v': (%v-%v; len %v) %v", r.r, r.i, r.previous, len(r.s), r.matches)
	return msg
}

/* Build new result from FindAllStringSubmatchIndex on a string */
func NewReres(s string, r *regexp.Regexp) *Reres {
	matches := r.FindAllStringSubmatchIndex(s, -1)
	return &Reres{r, s, matches, 0, 0}
}
<commit_msg>[golint] update comments<commit_after>package goregexp

import (
	"fmt"
	"regexp"
)

// Reres encapsulate a regex, a string, and the results
// from applying the regexp on the string
// internally managing results from FindAllStringSubmatchIndex
type Reres struct {
	r        *regexp.Regexp
	s        string
	matches  [][]int
	i        int
	previous int
}

func (r *Reres) String() string {
	msg := fmt.Sprintf("Regexp res for '%v': (%v-%v; len %v) %v", r.r, r.i, r.previous, len(r.s), r.matches)
	return msg
}

// NewReres builds a new regexp result
// (internally using FindAllStringSubmatchIndex on a string)
func NewReres(s string, r *regexp.Regexp) *Reres {
	matches := r.FindAllStringSubmatchIndex(s, -1)
	return &Reres{r, s, matches, 0, 0}
}
<|endoftext|>


<commit_before>package soaap

import (
	"encoding/gob"
	"errors"
	"fmt"
	"math"
	"os"
	"strings"
)

type CallGraph struct {
	Nodes map[string]GraphNode
	Calls map[Call]int
}

//
// Create a new, empty CallGraph with enough capacity to hold some calls.
//
func NewCallGraph() CallGraph {
	return CallGraph{
		make(map[string]GraphNode),
		make(map[Call]int),
	}
}

//
// Load a CallGraph from a binary-encoded file.
//
func LoadGraph(f *os.File, report func(string)) (CallGraph, error) {
	var graph CallGraph
	err := gob.NewDecoder(f).Decode(&graph)

	return graph, err
}

func (cg *CallGraph) AddCall(caller string, callee string) {
	cg.Calls[Call{caller, callee}] += 1
}

//
// Save a CallGraph to an os.File using a binary encoding.
//
func (cg *CallGraph) Save(f *os.File) error {
	return gob.NewEncoder(f).Encode(cg)
}

//
// Simplify a CallGraph by collapsing call chains and dropping any
// unreferenced calls.
//
func (cg *CallGraph) Simplify() {
}

func (cg *CallGraph) Union(g CallGraph) error {
	for id, node := range g.Nodes {
		// If we already have a GraphNode with this identifier,
		// merge the two descriptions and tag sets.
		if n, have := cg.Nodes[id]; have {
			if n.Name != node.Name {
				return errors.New(fmt.Sprintf(
					"Nodes in CallGraph union have"+
						" same identifier ('%s') but"+
						" different names ('%s' vs '%s')",
					id, n.Name, node.Name))
			}

			if n.Description != node.Description {
				node.Description =
					n.Description + "\\n" + node.Description
			}

			for tag := range n.Tags {
				node.Tags[tag] = true
			}
		}

		cg.Nodes[id] = node
	}

	for call, count := range g.Calls {
		cg.Calls[call] += count
	}

	return nil
}

//
// A node in a call graph.
//
// This is derived from a call site or other program location, but can have
// an arbitrary name and description appropriate to a particular analysis.
//
type GraphNode struct {
	Name        string
	Description string
	Location    SourceLocation

	// A vulnerability (current or previous) is known at this location.
	CVE []CVE

	// The name of this node's sandbox (or the empty string if unsandboxed).
	Sandbox string

	// The name of the sandbox(es) that own the data being accessed.
	Owners []string

	Tags map[string]bool
}

//
// Construct a GraphViz Dot description of a GraphNode.
//
// This applies SOAAP-specific styling depending on a node's tags.
//
func (n GraphNode) Dot() string {
	attrs := map[string]interface{}{
		"label": n.Description,
		"style": "filled",
	}

	if len(n.CVE) > 0 {
		attrs["label"] = fmt.Sprintf("%s\\n%s", n.CVE, n.Description)
	}

	switch true {
	case len(n.CVE) > 0 && n.Sandbox != "":
		// A vulnerability has been mitigated through sandboxing!
		attrs["fillcolor"] = "#ffff66cc"
		attrs["shape"] = "octagon"

	case len(n.CVE) > 0:
		// A vulnerability exists/existed outside a sandbox.
		attrs["fillcolor"] = "#ff9999cc"
		attrs["shape"] = "doubleoctagon"

	case len(n.Owners) > 0:
		// Sandbox-private data was accessed outside the sandbox.
		attrs["fillcolor"] = "#ff99cccc"
		attrs["shape"] = "invhouse"

	case n.Sandbox != "":
		attrs["fillcolor"] = "#99ff9999"
		attrs["style"] = "dashed,filled"

	default:
		attrs["fillcolor"] = "#cccccccc"
	}

	return fmt.Sprintf("\"%s\" %s;", n.Name, dotAttrs(attrs))
}

func (n GraphNode) HasTag(tag string) bool {
	_, present := n.Tags[tag]
	return present
}

type Call struct {
	// Identifier of the caller.
	Caller string

	// Identifier of the callee.
	Callee string
}

// Output GraphViz for a Call.
func (c Call) Dot(graph CallGraph, weight int) string {
	caller := graph.Nodes[c.Caller]
	callee := graph.Nodes[c.Callee]

	attrs := map[string]interface{}{
		"label":    caller.Location.String(),
		"penwidth": weight,
		"weight":   weight,
	}

	return fmt.Sprintf("\"%s\" -> \"%s\" %s;\n",
		caller.Name, callee.Name, dotAttrs(attrs))
}

//
// A function that extracts a CallGraph from SOAAP Results.
//
type graphFn func(results Results, progress func(string)) CallGraph

var graphExtractors map[string]graphFn = map[string]graphFn{
	"privaccess": PrivAccessGraph,
	"vuln":       VulnGraph,
}

func GraphAnalyses() []string {
	keys := make([]string, len(graphExtractors))

	i := 0
	for k, _ := range graphExtractors {
		keys[i] = k
		i++
	}

	return keys
}

type callSiteLabeler func(CallSite) (string, GraphNode)

//
// Construct a callgraph from SOAAP's vulnerability analysis.
//
func VulnGraph(results Results, progress func(string)) CallGraph {
	graph := NewCallGraph()

	for _, v := range results.Vulnerabilities {
		trace := results.Traces[v.Trace]
		top := true

		fn := func(cs CallSite) (string, GraphNode) {
			key := cs.String() + " " + v.Sandbox

			desc := cs.Function
			if v.Sandbox != "" {
				desc += "\\n<<" + v.Sandbox + ">>"
			}

			var node GraphNode
			node.Name = cs.String() + "_" + v.Sandbox
			node.Description = desc
			node.Location = cs.Location
			node.Sandbox = v.Sandbox

			if top {
				node.CVE = v.CVE
				top = false
			}

			return key, node
		}

		graph.Union(trace.graph(results.Traces, fn))
	}

	return graph
}

//
// Construct a callgraph of sandbox-private data accesses outside of sandboxes.
//
func PrivAccessGraph(results Results, progress func(string)) CallGraph {
	graph := NewCallGraph()
	accesses := results.PrivateAccess
	total := len(accesses)
	chunk := int(math.Ceil(math.Pow(10, math.Log10(float64(total)/500))))

	go progress(fmt.Sprintf("Processing %d private accesses", total))

	count := 0
	for _, a := range accesses {
		trace := results.Traces[a.Trace]

		fn := func(cs CallSite) (string, GraphNode) {
			sandboxes := strings.Join(a.Sandboxes, ",")
			key := cs.String() + " " + sandboxes

			desc := cs.Function
			if sandboxes != "" {
				desc += "\\n<<" + sandboxes + ">>"
			}

			var node GraphNode
			node.Name = cs.String() + "_" + sandboxes
			node.Description = desc
			node.Location = cs.Location
			node.Owners = a.Sandboxes

			return key, node
		}

		graph.Union(trace.graph(results.Traces, fn))

		count++
		if count%chunk == 0 {
			go progress(
				fmt.Sprintf("Processed %d/%d accesses",
					count, total))
		}
	}

	return graph
}

//
// Graph a single CallTrace, using a callSiteLabeler function to convert
// CallSite instances into graph nodes with identifiers, tags, etc.,
// appropriate to the analysis we're performing.
//
func (t CallTrace) graph(traces []CallTrace, nm callSiteLabeler) CallGraph {
	graph := NewCallGraph()
	var callee string

	t.Foreach(traces, func(cs CallSite) {
		identifier, node := nm(cs)
		graph.Nodes[identifier] = node

		caller := identifier

		if callee != "" {
			graph.AddCall(caller, callee)
		}

		callee = caller
	})

	return graph
}

//
// Format a map as a GraphViz attribute list.
//
func dotAttrs(attrs map[string]interface{}) string {
	fields := make([]string, len(attrs))

	i := 0
	for k, v := range attrs {
		switch v.(type) {
		case string:
			v = fmt.Sprintf("\"%s\"", v)
		}

		fields[i] = fmt.Sprintf("\"%s\" = %v", k, v)
		i++
	}

	return fmt.Sprintf("[ %s ]", strings.Join(fields, ", "))
}
<commit_msg>The top of a warning trace should be the warning.<commit_after>package soaap

import (
	"encoding/gob"
	"errors"
	"fmt"
	"math"
	"os"
	"strings"
)

type CallGraph struct {
	Nodes map[string]GraphNode
	Calls map[Call]int
}

//
// Create a new, empty CallGraph with enough capacity to hold some calls.
//
func NewCallGraph() CallGraph {
	return CallGraph{
		make(map[string]GraphNode),
		make(map[Call]int),
	}
}

//
// Load a CallGraph from a binary-encoded file.
//
func LoadGraph(f *os.File, report func(string)) (CallGraph, error) {
	var graph CallGraph
	err := gob.NewDecoder(f).Decode(&graph)

	return graph, err
}

func (cg *CallGraph) AddCall(caller string, callee string) {
	cg.Calls[Call{caller, callee}] += 1
}

//
// Save a CallGraph to an os.File using a binary encoding.
//
func (cg *CallGraph) Save(f *os.File) error {
	return gob.NewEncoder(f).Encode(cg)
}

//
// Simplify a CallGraph by collapsing call chains and dropping any
// unreferenced calls.
//
func (cg *CallGraph) Simplify() {
}

func (cg *CallGraph) Union(g CallGraph) error {
	for id, node := range g.Nodes {
		// If we already have a GraphNode with this identifier,
		// merge the two descriptions and tag sets.
		if n, have := cg.Nodes[id]; have {
			if n.Name != node.Name {
				return errors.New(fmt.Sprintf(
					"Nodes in CallGraph union have"+
						" same identifier ('%s') but"+
						" different names ('%s' vs '%s')",
					id, n.Name, node.Name))
			}

			if n.Description != node.Description {
				node.Description =
					n.Description + "\\n" + node.Description
			}

			for tag := range n.Tags {
				node.Tags[tag] = true
			}
		}

		cg.Nodes[id] = node
	}

	for call, count := range g.Calls {
		cg.Calls[call] += count
	}

	return nil
}

//
// A node in a call graph.
//
// This is derived from a call site or other program location, but can have
// an arbitrary name and description appropriate to a particular analysis.
//
type GraphNode struct {
	Name        string
	Description string
	Location    SourceLocation

	// A vulnerability (current or previous) is known at this location.
	CVE []CVE

	// The name of this node's sandbox (or the empty string if unsandboxed).
	Sandbox string

	// The name of the sandbox(es) that own the data being accessed.
	Owners []string

	Tags map[string]bool
}

//
// Construct a GraphViz Dot description of a GraphNode.
//
// This applies SOAAP-specific styling depending on a node's tags.
//
func (n GraphNode) Dot() string {
	attrs := map[string]interface{}{
		"label": n.Description,
		"style": "filled",
	}

	if len(n.CVE) > 0 {
		attrs["label"] = fmt.Sprintf("%s\\n%s", n.CVE, n.Description)
	}

	switch true {
	case len(n.CVE) > 0 && n.Sandbox != "":
		// A vulnerability has been mitigated through sandboxing!
		attrs["fillcolor"] = "#ffff66cc"
		attrs["shape"] = "octagon"

	case len(n.CVE) > 0:
		// A vulnerability exists/existed outside a sandbox.
		attrs["fillcolor"] = "#ff9999cc"
		attrs["shape"] = "doubleoctagon"

	case len(n.Owners) > 0:
		// Sandbox-private data was accessed outside the sandbox.
		attrs["fillcolor"] = "#ff99cccc"
		attrs["shape"] = "invhouse"

	case n.Sandbox != "":
		attrs["fillcolor"] = "#99ff9999"
		attrs["style"] = "dashed,filled"

	default:
		attrs["fillcolor"] = "#cccccccc"
	}

	return fmt.Sprintf("\"%s\" %s;", n.Name, dotAttrs(attrs))
}

func (n GraphNode) HasTag(tag string) bool {
	_, present := n.Tags[tag]
	return present
}

type Call struct {
	// Identifier of the caller.
	Caller string

	// Identifier of the callee.
	Callee string
}

// Output GraphViz for a Call.
func (c Call) Dot(graph CallGraph, weight int) string {
	caller := graph.Nodes[c.Caller]
	callee := graph.Nodes[c.Callee]

	attrs := map[string]interface{}{
		"label":    caller.Location.String(),
		"penwidth": weight,
		"weight":   weight,
	}

	return fmt.Sprintf("\"%s\" -> \"%s\" %s;\n",
		caller.Name, callee.Name, dotAttrs(attrs))
}

//
// A function that extracts a CallGraph from SOAAP Results.
//
type graphFn func(results Results, progress func(string)) CallGraph

var graphExtractors map[string]graphFn = map[string]graphFn{
	"privaccess": PrivAccessGraph,
	"vuln":       VulnGraph,
}

func GraphAnalyses() []string {
	keys := make([]string, len(graphExtractors))

	i := 0
	for k, _ := range graphExtractors {
		keys[i] = k
		i++
	}

	return keys
}

type callSiteLabeler func(CallSite) (string, GraphNode)

//
// Construct a callgraph from SOAAP's vulnerability analysis.
//
func VulnGraph(results Results, progress func(string)) CallGraph {
	graph := NewCallGraph()

	for _, v := range results.Vulnerabilities {
		trace := results.Traces[v.Trace]

		fn := func(cs CallSite) (string, GraphNode) {
			key := cs.String() + " " + v.Sandbox

			desc := cs.Function
			if v.Sandbox != "" {
				desc += "\\n<<" + v.Sandbox + ">>"
			}

			var node GraphNode
			node.Name = cs.String() + "_" + v.Sandbox
			node.Description = desc
			node.Location = cs.Location
			node.Sandbox = v.Sandbox

			return key, node
		}

		id, top := fn(v.CallSite)
		top.CVE = v.CVE
		graph.Nodes[id] = top

		graph.Union(trace.graph(id, results.Traces, fn))
	}

	return graph
}

//
// Construct a callgraph of sandbox-private data accesses outside of sandboxes.
//
func PrivAccessGraph(results Results, progress func(string)) CallGraph {
	graph := NewCallGraph()
	accesses := results.PrivateAccess
	total := len(accesses)
	chunk := int(math.Ceil(math.Pow(10, math.Log10(float64(total)/500))))

	go progress(fmt.Sprintf("Processing %d private accesses", total))

	count := 0
	for _, a := range accesses {
		trace := results.Traces[a.Trace]

		fn := func(cs CallSite) (string, GraphNode) {
			sandboxes := strings.Join(a.Sandboxes, ",")
			key := cs.String() + " " + sandboxes

			desc := cs.Function
			if sandboxes != "" {
				desc += "\\n<<" + sandboxes + ">>"
			}

			var node GraphNode
			node.Name = cs.String() + "_" + sandboxes
			node.Description = desc
			node.Location = cs.Location
			node.Owners = a.Sandboxes

			return key, node
		}

		id, top := fn(a.CallSite)
		graph.Nodes[id] = top

		graph.Union(trace.graph(id, results.Traces, fn))

		count++
		if count%chunk == 0 {
			go progress(
				fmt.Sprintf("Processed %d/%d accesses",
					count, total))
		}
	}

	return graph
}

//
// Graph a single CallTrace, using a callSiteLabeler function to convert
// CallSite instances into graph nodes with identifiers, tags, etc.,
// appropriate to the analysis we're performing.
//
func (t CallTrace) graph(top string, traces []CallTrace, nm callSiteLabeler) CallGraph {
	graph := NewCallGraph()
	callee := top

	t.Foreach(traces, func(cs CallSite) {
		identifier, node := nm(cs)
		graph.Nodes[identifier] = node

		caller := identifier
		graph.AddCall(caller, callee)
		callee = caller
	})

	return graph
}

//
// Format a map as a GraphViz attribute list.
//
func dotAttrs(attrs map[string]interface{}) string {
	fields := make([]string, len(attrs))

	i := 0
	for k, v := range attrs {
		switch v.(type) {
		case string:
			v = fmt.Sprintf("\"%s\"", v)
		}

		fields[i] = fmt.Sprintf("\"%s\" = %v", k, v)
		i++
	}

	return fmt.Sprintf("[ %s ]", strings.Join(fields, ", "))
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"log"
	"net"
	"time"
)

var bind, root, userDir string
var cgi bool

func main() {
	flag.StringVar(&bind, "bind", ":70", "Interface/port to bind to.")
	flag.StringVar(&root, "root", "/srv/gopher", "Directory to serve from.")
	flag.BoolVar(&cgi, "cgi", false, "Allow CGI scripts.")
	flag.StringVar(&userDir, "userdir", "", "Expose user directories over gopher.")
	flag.Parse()

	ln, err := net.Listen("tcp", bind)
	if err != nil {
		panic(err)
	}
	defer ln.Close()

	var delay time.Duration
	for {
		conn, err := ln.Accept()
		if err != nil {
			if ne, ok := err.(net.Error); ok && ne.Temporary() {
				if delay == 0 {
					delay = 5 * time.Millisecond
				} else {
					delay *= 2
				}
				if max := 1 * time.Second; delay > max {
					delay = max
				}
				log.Printf("Accept error: %v; retrying in %v", err, delay)
				time.Sleep(delay)
			} else {
				panic(err)
			}
		} else {
			delay = 0
			go handleConnection(conn)
		}
	}
}

func handleConnection(conn net.Conn) {
	log.Printf("Connection accepted")
}
<commit_msg>Commit what I have. Screw it.<commit_after>package main

import (
	"bufio"
	"flag"
	"log"
	"net"
	"strings"
	"time"
)

var bind, root, userDir string
var cgi bool

func main() {
	flag.StringVar(&bind, "bind", ":70", "Interface/port to bind to.")
	flag.StringVar(&root, "root", "/srv/gopher", "Directory to serve from.")
	flag.BoolVar(&cgi, "cgi", false, "Allow CGI scripts.")
	flag.StringVar(&userDir, "userdir", "", "Expose user directories over gopher.")
	flag.Parse()

	ln, err := net.Listen("tcp", bind)
	if err != nil {
		panic(err)
	}
	defer ln.Close()

	var delay time.Duration
	for {
		conn, err := ln.Accept()
		if err != nil {
			if ne, ok := err.(net.Error); ok && ne.Temporary() {
				if delay == 0 {
					delay = 5 * time.Millisecond
				} else {
					delay *= 2
				}
				if max := 1 * time.Second; delay > max {
					delay = max
				}
				log.Printf("Accept error: %v; retrying in %v", err, delay)
				time.Sleep(delay)
			} else {
				panic(err)
			}
		} else {
			delay = 0
			go handleConnection(conn)
		}
	}
}

func handleConnection(conn net.Conn) {
	defer conn.Close()

	log.Printf("Connection accepted")

	reader := bufio.NewReader(conn)
	if line, err := reader.ReadString('\n'); err != nil {
		log.Print(err)
	} else {
		// Format is <selector>TAB<query>CRLF
		parts := strings.SplitN(strings.TrimRight(line, "\r\n"), "\t", 2)
		log.Printf("%q", parts)
		conn.Write([]byte("iMessage\t\t\t\r\n"))
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 CoreOS, Inc.
//
// 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 systemd

import (
	"fmt"

	"github.com/coreos/ignition/third_party/github.com/coreos/go-systemd/dbus"
	"github.com/coreos/ignition/third_party/github.com/coreos/go-systemd/unit"
)

// WaitOnDevices waits for the devices named in devs to be plugged before returning.
func WaitOnDevices(devs []string, stage string) error {
	conn, err := dbus.New()
	if err != nil {
		return err
	}

	devUnits := []string{}
	for _, d := range devs {
		devUnits = append(devUnits, unit.UnitNamePathEscape(d)+".device")
	}

	unitName := unit.UnitNameEscape(fmt.Sprintf("ignition_%s.service", stage))
	props := []dbus.Property{
		dbus.PropExecStart([]string{"/bin/true"}, false), // XXX(vc): we apparently are required to ExecStart _something_
		dbus.PropAfter(devUnits...),
		dbus.PropRequires(devUnits...),
	}

	res := make(chan string)
	if _, err = conn.StartTransientUnit(unitName, "replace", props, res); err != nil {
		return fmt.Errorf("failed creating transient unit %s: %v", unitName, err)
	}
	s := <-res

	if s != "done" {
		return fmt.Errorf("transient unit %s %s", unitName, s)
	}

	return nil
}
<commit_msg>systemd: use dbus.NewSystemdConnection()<commit_after>// Copyright 2015 CoreOS, Inc.
//
// 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 systemd

import (
	"fmt"

	"github.com/coreos/ignition/third_party/github.com/coreos/go-systemd/dbus"
	"github.com/coreos/ignition/third_party/github.com/coreos/go-systemd/unit"
)

// WaitOnDevices waits for the devices named in devs to be plugged before returning.
func WaitOnDevices(devs []string, stage string) error {
	conn, err := dbus.NewSystemdConnection()
	if err != nil {
		return err
	}

	devUnits := []string{}
	for _, d := range devs {
		devUnits = append(devUnits, unit.UnitNamePathEscape(d)+".device")
	}

	unitName := unit.UnitNameEscape(fmt.Sprintf("ignition_%s.service", stage))
	props := []dbus.Property{
		dbus.PropExecStart([]string{"/bin/true"}, false), // XXX(vc): we apparently are required to ExecStart _something_
		dbus.PropAfter(devUnits...),
		dbus.PropRequires(devUnits...),
	}

	res := make(chan string)
	if _, err = conn.StartTransientUnit(unitName, "replace", props, res); err != nil {
		return fmt.Errorf("failed creating transient unit %s: %v", unitName, err)
	}
	s := <-res

	if s != "done" {
		return fmt.Errorf("transient unit %s %s", unitName, s)
	}

	return nil
}
<|endoftext|>


<commit_before>package ssh

import (
	"errors"
	"fmt"
	"io"
	"net"
	"os"
	"sync"

	"github.com/blacknon/lssh/common"
	"golang.org/x/crypto/ssh"
)

type x11request struct {
	SingleConnection bool
	AuthProtocol     string
	AuthCookie       string
	ScreenNumber     uint32
}

func x11SocketForward(channel ssh.Channel) {
	// TODO(blacknon): Socket通信しか考慮されていないので、TCP通信での指定もできるようにする
	conn, err := net.Dial("unix", os.Getenv("DISPLAY"))
	if err != nil {
		return
	}

	var wg sync.WaitGroup
	wg.Add(2)
	go func() {
		io.Copy(conn, channel)
		conn.(*net.UnixConn).CloseWrite()
		wg.Done()
	}()
	go func() {
		io.Copy(channel, conn)
		channel.CloseWrite()
		wg.Done()
	}()

	wg.Wait()
	conn.Close()
	channel.Close()
}

func (c *Connect) X11Forwarder(session *ssh.Session) {
	// set x11-req Payload
	payload := x11request{
		SingleConnection: false,
		AuthProtocol:     string("MIT-MAGIC-COOKIE-1"),
		AuthCookie:       string(common.NewSHA1Hash()),
		ScreenNumber:     uint32(0),
	}

	// Send x11-req Request
	ok, err := session.SendRequest("x11-req", true, ssh.Marshal(payload))
	if err == nil && !ok {
		fmt.Println(errors.New("ssh: x11-req failed"))
	} else {
		// Open HandleChannel x11
		x11channels := c.Client.HandleChannelOpen("x11")

		go func() {
			for ch := range x11channels {
				channel, _, err := ch.Accept()
				if err != nil {
					continue
				}

				go x11SocketForward(channel)
			}
		}()
	}
}

// forward function to do port io.Copy with goroutine
func (c *Connect) portForward(localConn net.Conn) {
	// TODO(blacknon): 関数名等をちゃんと考える

	// Create ssh connect
	sshConn, err := c.Client.Dial("tcp", c.ForwardRemote)

	// Copy localConn.Reader to sshConn.Writer
	go func() {
		_, err = io.Copy(sshConn, localConn)
		if err != nil {
			fmt.Printf("Port forward local to remote failed: %v\n", err)
		}
	}()

	// Copy sshConn.Reader to localConn.Writer
	go func() {
		_, err = io.Copy(localConn, sshConn)
		if err != nil {
			fmt.Printf("Port forward remote to local failed: %v\n", err)
		}
	}()
}

// PortForwarder port forwarding based on the value of Connect
func (c *Connect) PortForwarder() {
	// TODO(blacknon):
	// 現在の方式だと、クライアント側で無理やりポートフォワーディングをしている状態なので、RFCに沿ってport forwardさせる処理についても追加する
	//
	// 【参考】
	//     - https://github.com/maxhawkins/easyssh/blob/a4ce364b6dd8bf2433a0d67ae76cf1d880c71d75/tcpip.go
	//     - https://www.unixuser.org/~haruyama/RFC/ssh/rfc4254.txt
	//
	// TODO(blacknon): 関数名等をちゃんと考える

	// Open local port.
	localListener, err := net.Listen("tcp", c.ForwardLocal)

	if err != nil {
		// error local port open.
		fmt.Fprintf(os.Stdout, "local port listen failed: %v\n", err)
	} else {
		// start port forwarding.
		go func() {
			for {
				// Setup localConn (type net.Conn)
				localConn, err := localListener.Accept()
				if err != nil {
					fmt.Printf("listen.Accept failed: %v\n", err)
				}
				go c.portForward(localConn)
			}
		}()
	}
}
<commit_msg>add comment<commit_after>package ssh

import (
	"errors"
	"fmt"
	"io"
	"net"
	"os"
	"sync"

	"github.com/blacknon/lssh/common"
	"golang.org/x/crypto/ssh"
)

// TODO(blacknon):
//     socket forwardについても実装する

type x11request struct {
	SingleConnection bool
	AuthProtocol     string
	AuthCookie       string
	ScreenNumber     uint32
}

func x11SocketForward(channel ssh.Channel) {
	// TODO(blacknon): Socket通信しか考慮されていないので、TCP通信での指定もできるようにする
	conn, err := net.Dial("unix", os.Getenv("DISPLAY"))
	if err != nil {
		return
	}

	var wg sync.WaitGroup
	wg.Add(2)
	go func() {
		io.Copy(conn, channel)
		conn.(*net.UnixConn).CloseWrite()
		wg.Done()
	}()
	go func() {
		io.Copy(channel, conn)
		channel.CloseWrite()
		wg.Done()
	}()

	wg.Wait()
	conn.Close()
	channel.Close()
}

func (c *Connect) X11Forwarder(session *ssh.Session) {
	// set x11-req Payload
	payload := x11request{
		SingleConnection: false,
		AuthProtocol:     string("MIT-MAGIC-COOKIE-1"),
		AuthCookie:       string(common.NewSHA1Hash()),
		ScreenNumber:     uint32(0),
	}

	// Send x11-req Request
	ok, err := session.SendRequest("x11-req", true, ssh.Marshal(payload))
	if err == nil && !ok {
		fmt.Println(errors.New("ssh: x11-req failed"))
	} else {
		// Open HandleChannel x11
		x11channels := c.Client.HandleChannelOpen("x11")

		go func() {
			for ch := range x11channels {
				channel, _, err := ch.Accept()
				if err != nil {
					continue
				}

				go x11SocketForward(channel)
			}
		}()
	}
}

// forward function to do port io.Copy with goroutine
func (c *Connect) portForward(localConn net.Conn) {
	// TODO(blacknon): 関数名等をちゃんと考える

	// Create ssh connect
	sshConn, err := c.Client.Dial("tcp", c.ForwardRemote)

	// Copy localConn.Reader to sshConn.Writer
	go func() {
		_, err = io.Copy(sshConn, localConn)
		if err != nil {
			fmt.Printf("Port forward local to remote failed: %v\n", err)
		}
	}()

	// Copy sshConn.Reader to localConn.Writer
	go func() {
		_, err = io.Copy(localConn, sshConn)
		if err != nil {
			fmt.Printf("Port forward remote to local failed: %v\n", err)
		}
	}()
}

// PortForwarder port forwarding based on the value of Connect
func (c *Connect) PortForwarder() {
	// TODO(blacknon):
	// 現在の方式だと、クライアント側で無理やりポートフォワーディングをしている状態なので、RFCに沿ってport forwardさせる処理についても追加する
	//
	// 【参考】
	//     - https://github.com/maxhawkins/easyssh/blob/a4ce364b6dd8bf2433a0d67ae76cf1d880c71d75/tcpip.go
	//     - https://www.unixuser.org/~haruyama/RFC/ssh/rfc4254.txt
	//
	// TODO(blacknon): 関数名等をちゃんと考える

	// Open local port.
	localListener, err := net.Listen("tcp", c.ForwardLocal)

	if err != nil {
		// error local port open.
		fmt.Fprintf(os.Stdout, "local port listen failed: %v\n", err)
	} else {
		// start port forwarding.
		go func() {
			for {
				// Setup localConn (type net.Conn)
				localConn, err := localListener.Accept()
				if err != nil {
					fmt.Printf("listen.Accept failed: %v\n", err)
				}
				go c.portForward(localConn)
			}
		}()
	}
}
<|endoftext|>