<commit_before>package dmr

import (
	"bytes"
	"errors"
	"fmt"

	"golang.org/x/text/encoding"
	"golang.org/x/text/encoding/charmap"
	"golang.org/x/text/encoding/unicode"
)

const (
	// n_DFragMax, see DMR AI spec. page 163.
	MaxPacketFragmentSize = 1500
)

type DataBlock struct {
	Serial uint8
	CRC    uint16
	OK     bool
	Data   []byte
	Length uint8
}

func ParseDataBlock(data []byte, dataType uint8, confirmed bool) (*DataBlock, error) {
	var (
		crc uint16
		db  = &DataBlock{
			Length: dataBlockLength(dataType, confirmed),
		}
	)

	if confirmed {
		db.Serial = data[0] >> 1
		db.CRC = uint16(data[0]&B00000001)<<8 | uint16(data[1])
		db.Data = make([]byte, db.Length)
		copy(db.Data, data[2:2+db.Length])

		for _, block := range db.Data {
			crc9(&crc, block, 8)
		}
		crc9(&crc, db.Serial, 7)
		crc9end(&crc, 8)

		// Inverting according to the inversion polynomial.
		crc = ^crc
		crc &= 0x01ff
		// Applying CRC mask, see DMR AI spec. page 143
		crc ^= 0x01ff

		// FIXME(pd0mz): this is not working
		if crc != db.CRC {
			return nil, fmt.Errorf("dmr: block CRC error (%#04x != %#04x)", crc, db.CRC)
		}
	} else {
		db.Data = make([]byte, db.Length)
		copy(db.Data, data[:db.Length])
	}

	db.OK = true
	return db, nil
}

func (db *DataBlock) Bytes(dataType uint8, confirmed bool) []byte {
	var (
		size = dataBlockLength(dataType, confirmed)
		data = make([]byte, size)
	)

	if confirmed {
		for _, block := range db.Data {
			crc9(&db.CRC, block, 8)
		}
		crc9(&db.CRC, db.Serial, 7)
		crc9end(&db.CRC, 8)

		// Inverting according to the inversion polynomial.
		db.CRC = ^db.CRC
		db.CRC &= 0x01ff
		// Applying CRC mask, see DMR AI spec. page 143
		db.CRC ^= 0x01ff

		data[0] = (db.Serial << 1) | (uint8(db.CRC>>8) & 0x01)
		data[1] = uint8(db.CRC)
		copy(data[2:], db.Data)
	} else {
		copy(data, db.Data)
	}

	return data
}

func dataBlockLength(dataType uint8, confirmed bool) uint8 {
	var size uint8

	switch dataType {
	case Data:
		size = 22
		break
	case Rate12Data:
		size = 10
		break
	case Rate34Data:
		size = 16
		break
	default:
		return 0
	}

	if !confirmed {
		return size + 2
	}
	return size
}

type DataFragment struct {
	Data   []byte
	Stored int
	Needed int
	CRC    uint32
}

func (df *DataFragment) DataBlocks(dataType uint8, confirm bool) ([]*DataBlock, error) {
	df.Stored = len(df.Data)
	if df.Stored > MaxPacketFragmentSize {
		df.Stored = MaxPacketFragmentSize
	}

	// See DMR AI spec. page. 73. for block sizes.
	var size = int(dataBlockLength(dataType, confirm))
	df.Needed = (df.Stored + size - 1) / size

	// Leave enough room for the 4 bytes CRC32
	if (df.Needed*size)-df.Stored < 4 {
		df.Needed++
	}

	// Calculate fragment CRC32
	for i := 0; i < (df.Needed*size)-4; i += 2 {
		if i+1 < df.Stored {
			crc32(&df.CRC, df.Data[i+1])
		} else {
			crc32(&df.CRC, 0)
		}
		if i < df.Stored {
			crc32(&df.CRC, df.Data[i])
		} else {
			crc32(&df.CRC, 0)
		}
	}
	crc32end(&df.CRC)

	var (
		blocks = make([]*DataBlock, df.Needed)
		stored int
	)
	for i := range blocks {
		block := &DataBlock{
			Serial: uint8(i % 128),
			Length: dataBlockLength(dataType, confirm),
		}
		block.Data = make([]byte, block.Length)

		store := int(block.Length)
		if df.Stored-stored < store {
			store = df.Stored - store
		}
		copy(block.Data, df.Data[stored:stored+store])
		stored += store

		if i == (df.Needed - 1) {
			block.Data[block.Length-1] = uint8(df.CRC >> 24)
			block.Data[block.Length-2] = uint8(df.CRC >> 16)
			block.Data[block.Length-3] = uint8(df.CRC >> 8)
			block.Data[block.Length-4] = uint8(df.CRC)
		}

		// Calculate block CRC9
		block.CRC = 0
		for _, b := range block.Data {
			crc9(&block.CRC, b, 8)
		}
		crc9(&block.CRC, block.Serial, 7)
		crc9end(&block.CRC, 8)

		// Inverting according to the inversion polynomial
		block.CRC = ^block.CRC
		block.CRC &= 0x01ff
		// Applying CRC mask, see DMR AI spec. page 143
		block.CRC ^= 0x01ff

		blocks[i] = block
	}

	return blocks, nil
}

func CombineDataBlocks(blocks []*DataBlock) (*DataFragment, error) {
	if blocks == nil || len(blocks) == 0 {
		return nil, errors.New("dmr: no data blocks to combine")
	}

	f := &DataFragment{
		Data: make([]byte, MaxPacketFragmentSize),
	}
	for i, block := range blocks {
		if block.Length == 0 {
			continue
		}
		if i < (len(blocks) - 1) {
			if f.Stored+int(block.Length) < len(f.Data) {
				copy(f.Data[f.Stored:], block.Data[:block.Length])
				f.Stored += int(block.Length)
			}
		} else {
			if f.Stored+int(block.Length)-4 < len(f.Data) {
				copy(f.Data[f.Stored:], block.Data[:block.Length])
				f.Stored += int(block.Length)
			}
			f.CRC = 0
			f.CRC |= uint32(block.Data[block.Length-4])
			f.CRC |= uint32(block.Data[block.Length-3]) << 8
			f.CRC |= uint32(block.Data[block.Length-2]) << 16
			f.CRC |= uint32(block.Data[block.Length-1]) << 24
		}
	}

	var crc uint32
	for i := 0; i < f.Stored-4; i += 2 {
		crc32(&crc, f.Data[i+1])
		crc32(&crc, f.Data[i])
	}
	crc32end(&crc)

	if crc != f.CRC {
		return nil, fmt.Errorf("dmr: fragment CRC error (%#08x != %#08x)", crc, f.CRC)
	}
	return f, nil
}

var encodingMap map[uint8]encoding.Encoding

func BuildMessageData(msg string, ddFormat uint8, nullTerminated bool) ([]byte, error) {
	if e, ok := encodingMap[ddFormat]; ok {
		enc := e.NewEncoder()
		data, err := enc.Bytes([]byte(msg))
		if err != nil {
			return nil, err
		}
		if nullTerminated {
			data = append(data, []byte{0x00, 0x00}...)
		}
		return data, nil
	}
	return nil, fmt.Errorf("dmr: encoding %s text is not supported", DDFormatName[ddFormat])
}

func ParseMessageData(data []byte, ddFormat uint8, nullTerminated bool) (string, error) {
	if e, ok := encodingMap[ddFormat]; ok {
		dec := e.NewDecoder()
		str, err := dec.Bytes(data)
		if err != nil {
			return "", err
		}
		if nullTerminated {
			if idx := bytes.IndexByte(str, 0x00); idx >= 0 {
				str = str[:idx]
			}
		}
		return string(str), nil
	}
	return "", fmt.Errorf("dmr: decoding %s text is not supported", DDFormatName[ddFormat])
}

func init() {
	encodingMap = map[uint8]encoding.Encoding{
		DDFormatBinary:         binaryEncoding{},
		DDFormat8BitISO8859_2:  charmap.ISO8859_2,
		DDFormat8BitISO8859_3:  charmap.ISO8859_3,
		DDFormat8BitISO8859_4:  charmap.ISO8859_4,
		DDFormat8BitISO8859_5:  charmap.ISO8859_5,
		DDFormat8BitISO8859_6:  charmap.ISO8859_6,
		DDFormat8BitISO8859_7:  charmap.ISO8859_7,
		DDFormat8BitISO8859_8:  charmap.ISO8859_8,
		DDFormat8BitISO8859_10: charmap.ISO8859_10,
		DDFormat8BitISO8859_13: charmap.ISO8859_13,
		DDFormat8BitISO8859_14: charmap.ISO8859_14,
		DDFormat8BitISO8859_15: charmap.ISO8859_15,
		DDFormat8BitISO8859_16: charmap.ISO8859_16,
		DDFormatUTF8:           unicode.UTF8,
		DDFormatUTF16:          unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM),
		DDFormatUTF16BE:        unicode.UTF16(unicode.BigEndian, unicode.IgnoreBOM),
		DDFormatUTF16LE:        unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM),
	}
}
<commit_msg>Fix panic in Fragment.DataBlocks() duo to typo<commit_after>package dmr

import (
	"bytes"
	"errors"
	"fmt"

	"golang.org/x/text/encoding"
	"golang.org/x/text/encoding/charmap"
	"golang.org/x/text/encoding/unicode"
)

const (
	// n_DFragMax, see DMR AI spec. page 163.
	MaxPacketFragmentSize = 1500
)

type DataBlock struct {
	Serial uint8
	CRC    uint16
	OK     bool
	Data   []byte
	Length uint8
}

func ParseDataBlock(data []byte, dataType uint8, confirmed bool) (*DataBlock, error) {
	var (
		crc uint16
		db  = &DataBlock{
			Length: dataBlockLength(dataType, confirmed),
		}
	)

	if confirmed {
		db.Serial = data[0] >> 1
		db.CRC = uint16(data[0]&B00000001)<<8 | uint16(data[1])
		db.Data = make([]byte, db.Length)
		copy(db.Data, data[2:2+db.Length])

		for _, block := range db.Data {
			crc9(&crc, block, 8)
		}
		crc9(&crc, db.Serial, 7)
		crc9end(&crc, 8)

		// Inverting according to the inversion polynomial.
		crc = ^crc
		crc &= 0x01ff
		// Applying CRC mask, see DMR AI spec. page 143
		crc ^= 0x01ff

		// FIXME(pd0mz): this is not working
		if crc != db.CRC {
			return nil, fmt.Errorf("dmr: block CRC error (%#04x != %#04x)", crc, db.CRC)
		}
	} else {
		db.Data = make([]byte, db.Length)
		copy(db.Data, data[:db.Length])
	}

	db.OK = true
	return db, nil
}

func (db *DataBlock) Bytes(dataType uint8, confirmed bool) []byte {
	var (
		size = dataBlockLength(dataType, confirmed)
		data = make([]byte, size)
	)

	if confirmed {
		for _, block := range db.Data {
			crc9(&db.CRC, block, 8)
		}
		crc9(&db.CRC, db.Serial, 7)
		crc9end(&db.CRC, 8)

		// Inverting according to the inversion polynomial.
		db.CRC = ^db.CRC
		db.CRC &= 0x01ff
		// Applying CRC mask, see DMR AI spec. page 143
		db.CRC ^= 0x01ff

		data[0] = (db.Serial << 1) | (uint8(db.CRC>>8) & 0x01)
		data[1] = uint8(db.CRC)
		copy(data[2:], db.Data)
	} else {
		copy(data, db.Data)
	}

	return data
}

func dataBlockLength(dataType uint8, confirmed bool) uint8 {
	var size uint8

	switch dataType {
	case Data:
		size = 22
		break
	case Rate12Data:
		size = 10
		break
	case Rate34Data:
		size = 16
		break
	default:
		return 0
	}

	if !confirmed {
		return size + 2
	}
	return size
}

type DataFragment struct {
	Data   []byte
	Stored int
	Needed int
	CRC    uint32
}

func (df *DataFragment) DataBlocks(dataType uint8, confirm bool) ([]*DataBlock, error) {
	df.Stored = len(df.Data)
	if df.Stored > MaxPacketFragmentSize {
		df.Stored = MaxPacketFragmentSize
	}

	// See DMR AI spec. page. 73. for block sizes.
	var size = int(dataBlockLength(dataType, confirm))
	df.Needed = (df.Stored + size - 1) / size

	// Leave enough room for the 4 bytes CRC32
	if (df.Needed*size)-df.Stored < 4 {
		df.Needed++
	}

	// Calculate fragment CRC32
	for i := 0; i < (df.Needed*size)-4; i += 2 {
		if i+1 < df.Stored {
			crc32(&df.CRC, df.Data[i+1])
		} else {
			crc32(&df.CRC, 0)
		}
		if i < df.Stored {
			crc32(&df.CRC, df.Data[i])
		} else {
			crc32(&df.CRC, 0)
		}
	}
	crc32end(&df.CRC)

	var (
		blocks = make([]*DataBlock, df.Needed)
		stored int
	)
	for i := range blocks {
		block := &DataBlock{
			Serial: uint8(i % 128),
			Length: dataBlockLength(dataType, confirm),
		}
		block.Data = make([]byte, block.Length)

		store := int(block.Length)
		if df.Stored-stored < store {
			store = df.Stored - stored
		}
		copy(block.Data, df.Data[stored:stored+store])
		stored += store

		if i == (df.Needed - 1) {
			block.Data[block.Length-1] = uint8(df.CRC >> 24)
			block.Data[block.Length-2] = uint8(df.CRC >> 16)
			block.Data[block.Length-3] = uint8(df.CRC >> 8)
			block.Data[block.Length-4] = uint8(df.CRC)
		}

		// Calculate block CRC9
		block.CRC = 0
		for _, b := range block.Data {
			crc9(&block.CRC, b, 8)
		}
		crc9(&block.CRC, block.Serial, 7)
		crc9end(&block.CRC, 8)

		// Inverting according to the inversion polynomial
		block.CRC = ^block.CRC
		block.CRC &= 0x01ff
		// Applying CRC mask, see DMR AI spec. page 143
		block.CRC ^= 0x01ff

		blocks[i] = block
	}

	return blocks, nil
}

func CombineDataBlocks(blocks []*DataBlock) (*DataFragment, error) {
	if blocks == nil || len(blocks) == 0 {
		return nil, errors.New("dmr: no data blocks to combine")
	}

	f := &DataFragment{
		Data: make([]byte, MaxPacketFragmentSize),
	}
	for i, block := range blocks {
		if block.Length == 0 {
			continue
		}
		if i < (len(blocks) - 1) {
			if f.Stored+int(block.Length) < len(f.Data) {
				copy(f.Data[f.Stored:], block.Data[:block.Length])
				f.Stored += int(block.Length)
			}
		} else {
			if f.Stored+int(block.Length)-4 < len(f.Data) {
				copy(f.Data[f.Stored:], block.Data[:block.Length])
				f.Stored += int(block.Length)
			}
			f.CRC = 0
			f.CRC |= uint32(block.Data[block.Length-4])
			f.CRC |= uint32(block.Data[block.Length-3]) << 8
			f.CRC |= uint32(block.Data[block.Length-2]) << 16
			f.CRC |= uint32(block.Data[block.Length-1]) << 24
		}
	}

	var crc uint32
	for i := 0; i < f.Stored-4; i += 2 {
		crc32(&crc, f.Data[i+1])
		crc32(&crc, f.Data[i])
	}
	crc32end(&crc)

	if crc != f.CRC {
		return nil, fmt.Errorf("dmr: fragment CRC error (%#08x != %#08x)", crc, f.CRC)
	}
	return f, nil
}

var encodingMap map[uint8]encoding.Encoding

func BuildMessageData(msg string, ddFormat uint8, nullTerminated bool) ([]byte, error) {
	if e, ok := encodingMap[ddFormat]; ok {
		enc := e.NewEncoder()
		data, err := enc.Bytes([]byte(msg))
		if err != nil {
			return nil, err
		}
		if nullTerminated {
			data = append(data, []byte{0x00, 0x00}...)
		}
		return data, nil
	}
	return nil, fmt.Errorf("dmr: encoding %s text is not supported", DDFormatName[ddFormat])
}

func ParseMessageData(data []byte, ddFormat uint8, nullTerminated bool) (string, error) {
	if e, ok := encodingMap[ddFormat]; ok {
		dec := e.NewDecoder()
		str, err := dec.Bytes(data)
		if err != nil {
			return "", err
		}
		if nullTerminated {
			if idx := bytes.IndexByte(str, 0x00); idx >= 0 {
				str = str[:idx]
			}
		}
		return string(str), nil
	}
	return "", fmt.Errorf("dmr: decoding %s text is not supported", DDFormatName[ddFormat])
}

func init() {
	encodingMap = map[uint8]encoding.Encoding{
		DDFormatBinary:         binaryEncoding{},
		DDFormat8BitISO8859_2:  charmap.ISO8859_2,
		DDFormat8BitISO8859_3:  charmap.ISO8859_3,
		DDFormat8BitISO8859_4:  charmap.ISO8859_4,
		DDFormat8BitISO8859_5:  charmap.ISO8859_5,
		DDFormat8BitISO8859_6:  charmap.ISO8859_6,
		DDFormat8BitISO8859_7:  charmap.ISO8859_7,
		DDFormat8BitISO8859_8:  charmap.ISO8859_8,
		DDFormat8BitISO8859_10: charmap.ISO8859_10,
		DDFormat8BitISO8859_13: charmap.ISO8859_13,
		DDFormat8BitISO8859_14: charmap.ISO8859_14,
		DDFormat8BitISO8859_15: charmap.ISO8859_15,
		DDFormat8BitISO8859_16: charmap.ISO8859_16,
		DDFormatUTF8:           unicode.UTF8,
		DDFormatUTF16:          unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM),
		DDFormatUTF16BE:        unicode.UTF16(unicode.BigEndian, unicode.IgnoreBOM),
		DDFormatUTF16LE:        unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM),
	}
}
<|endoftext|>


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

package sqlite

import (
	"database/sql/driver"
	"fmt"
	"time"
)

const (
	julianDay    = 2440587.5 // 1970-01-01 00:00:00 is JD 2440587.5
	dayInSeconds = 60 * 60 * 24
)

// JulianDayToUTC transforms a julian day number into an UTC Time.
func JulianDayToUTC(jd float64) time.Time {
	jd -= julianDay
	jd *= dayInSeconds
	return time.Unix(int64(jd), 0).UTC()
}

// JulianDayToLocalTime transforms a julian day number into a local Time.
func JulianDayToLocalTime(jd float64) time.Time {
	jd -= julianDay
	jd *= dayInSeconds
	return time.Unix(int64(jd), 0)
}

// JulianDay converts a Time into a julian day number.
func JulianDay(t time.Time) float64 {
	ns := float64(t.Unix())
	if ns >= 0 {
		ns += 0.5
	}
	return ns/dayInSeconds + julianDay
}

// UnixTime is an alias used to persist time as int64 (max precision is 1s and timezone is lost) (default)
type UnixTime time.Time

func (t *UnixTime) Scan(src interface{}) error {
	if src == nil {
		t = nil
		return nil
	} else if unixepoch, ok := src.(int64); ok {
		*t = UnixTime(time.Unix(unixepoch, 0)) // local time
		return nil
	} else {
		return fmt.Errorf("Unsupported UnixTime src: %T", src)
	}
}
func (t UnixTime) Value() (driver.Value, error) {
	if (time.Time)(t).IsZero() {
		return nil, nil
	} else {
		return (time.Time)(t).Unix(), nil
	}
}

// JulianTime is an alias used to persist time as float64 (max precision is 1s and timezone is lost)
type JulianTime time.Time

func (t *JulianTime) Scan(src interface{}) error {
	if src == nil {
		t = nil
		return nil
	} else if jd, ok := src.(float64); ok {
		*t = JulianTime(JulianDayToLocalTime(jd)) // local time
		return nil
	} else {
		return fmt.Errorf("Unsupported JulianTime src: %T", src)
	}
}
func (t JulianTime) Value() (driver.Value, error) {
	if (time.Time)(t).IsZero() {
		return nil, nil
	} else {
		return JulianDay((time.Time)(t)), nil
	}
}

// TimeStamp is an alias used to persist time as '2006-01-02T15:04:05.999Z07:00' string
type TimeStamp time.Time

func (t *TimeStamp) Scan(src interface{}) error {
	if src == nil {
		t = nil
		return nil
	} else if txt, ok := src.(string); ok {
		v, err := time.Parse("2006-01-02T15:04:05.999Z07:00", txt)
		if err != nil {
			return err
		}
		*t = TimeStamp(v)
		return nil
	} else {
		return fmt.Errorf("Unsupported TimeStamp src: %T", src)
	}
}
func (t TimeStamp) Value() (driver.Value, error) {
	if (time.Time)(t).IsZero() {
		return nil, nil
	} else {
		return (time.Time)(t).Format("2006-01-02T15:04:05.999Z07:00"), nil
	}
}
<commit_msg>Make it compile with Go 1.0<commit_after>// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package sqlite

import (
	"database/sql/driver"
	"fmt"
	"time"
)

const (
	julianDay    = 2440587.5 // 1970-01-01 00:00:00 is JD 2440587.5
	dayInSeconds = 60 * 60 * 24
)

// JulianDayToUTC transforms a julian day number into an UTC Time.
func JulianDayToUTC(jd float64) time.Time {
	jd -= julianDay
	jd *= dayInSeconds
	return time.Unix(int64(jd), 0).UTC()
}

// JulianDayToLocalTime transforms a julian day number into a local Time.
func JulianDayToLocalTime(jd float64) time.Time {
	jd -= julianDay
	jd *= dayInSeconds
	return time.Unix(int64(jd), 0)
}

// JulianDay converts a Time into a julian day number.
func JulianDay(t time.Time) float64 {
	ns := float64(t.Unix())
	if ns >= 0 {
		ns += 0.5
	}
	return ns/dayInSeconds + julianDay
}

// UnixTime is an alias used to persist time as int64 (max precision is 1s and timezone is lost) (default)
type UnixTime time.Time

func (t *UnixTime) Scan(src interface{}) error {
	if src == nil {
		t = nil
		return nil
	} else if unixepoch, ok := src.(int64); ok {
		*t = UnixTime(time.Unix(unixepoch, 0)) // local time
		return nil
	}
	return fmt.Errorf("Unsupported UnixTime src: %T", src)
}
func (t UnixTime) Value() (driver.Value, error) {
	if (time.Time)(t).IsZero() {
		return nil, nil
	}
	return (time.Time)(t).Unix(), nil
}

// JulianTime is an alias used to persist time as float64 (max precision is 1s and timezone is lost)
type JulianTime time.Time

func (t *JulianTime) Scan(src interface{}) error {
	if src == nil {
		t = nil
		return nil
	} else if jd, ok := src.(float64); ok {
		*t = JulianTime(JulianDayToLocalTime(jd)) // local time
		return nil
	}
	return fmt.Errorf("Unsupported JulianTime src: %T", src)
}
func (t JulianTime) Value() (driver.Value, error) {
	if (time.Time)(t).IsZero() {
		return nil, nil
	}
	return JulianDay((time.Time)(t)), nil
}

// TimeStamp is an alias used to persist time as '2006-01-02T15:04:05.999Z07:00' string
type TimeStamp time.Time

func (t *TimeStamp) Scan(src interface{}) error {
	if src == nil {
		t = nil
		return nil
	} else if txt, ok := src.(string); ok {
		v, err := time.Parse("2006-01-02T15:04:05.999Z07:00", txt)
		if err != nil {
			return err
		}
		*t = TimeStamp(v)
		return nil
	}
	return fmt.Errorf("Unsupported TimeStamp src: %T", src)
}
func (t TimeStamp) Value() (driver.Value, error) {
	if (time.Time)(t).IsZero() {
		return nil, nil
	}
	return (time.Time)(t).Format("2006-01-02T15:04:05.999Z07:00"), nil
}
<|endoftext|>


<commit_before><commit_msg>without continuation token avoid infinite loop and error out (#1704)<commit_after><|endoftext|>


<commit_before>package main

import (
	"./aws"
	"./db"
	"encoding/json"
	"fmt"
	// "io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strconv"
	"time"
)

const (
	imagesRoot = "/var/www/like-av.xyz/images/"
)

type Payload struct {
	Count int
	File  string
	Data  []Face
}

type Face struct {
	Id         string
	Name       string
	Img        string
	Similarity string
}

func UploadHandler(w http.ResponseWriter, r *http.Request) {
	// allow cross domain AJAX requests
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Content-Type", "application/json")
	checkPost(w, r)

	err := r.ParseMultipartForm(32 << 20) // maxMemory
	checkNil(w, err)

	file, handler, err := r.FormFile("upload")
	checkNil(w, err)
	defer file.Close()

	b, err := ioutil.ReadAll(file)
	checkNil(w, err)

	js, err := searchFace(b, handler.Filename)
	checkNil(w, err)

	w.Write(js)
}

func FeedbackHandler(w http.ResponseWriter, r *http.Request) {
	// allow cross domain AJAX requests
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Content-Type", "application/json")
	checkPost(w, r)

	decoder := json.NewDecoder(r.Body)
	val := map[string]string{}
	err := decoder.Decode(&val)
	checkNil(w, err)

	fmt.Println(val)
	if val["ox"] == "like" {
		b, err := ioutil.ReadFile(imagesRoot + val["file"])
		checkNil(w, err)
		checkNil(w, aws.InsertIndexFaceByImage(val["id"], b))
	}

	db.UpsertOneFeedback(val["id"], val["ox"], val["file"])
}

func main() {
	http.HandleFunc("/upload", UploadHandler)     // set router
	http.HandleFunc("/feedback", FeedbackHandler) // set router
	err := http.ListenAndServe(":9090", nil)      // set listen port
	if err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}

func checkNil(w http.ResponseWriter, err error) {
	if err != nil {
		log.Println(err)
		// http.Error(w, err.Error(), http.StatusInternalServerError)
		// return

		responseEmptyPayload(w)
	}
}

func checkPost(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		log.Println("Allowed POST method only")
		// http.Error(w, "Allowed POST method only", http.StatusMethodNotAllowed)
		// return

		responseEmptyPayload(w)
	}
}

func responseEmptyPayload(w http.ResponseWriter) {
	emptyPayload := &Payload{
		Count: 0,
	}

	js, _ := json.Marshal(emptyPayload)
	w.Write(js)
}

func searchFace(b []byte, fileName string) ([]byte, error) {
	result, err := aws.SearchFacesByImage(b)
	if err != nil {
		return nil, err
	}

	emptyPayload := &Payload{
		Count: 0,
		File:  fileName,
	}

	if result == nil {
		js, err := json.Marshal(emptyPayload)
		if err != nil {
			return nil, err
		}

		return js, nil
	} else {
		today := time.Now().Local().Format("2006-01-02")
		fmt.Println(today)
		imageDir := imagesRoot + today
		os.Mkdir(imageDir, os.ModePerm)
		err := ioutil.WriteFile(imageDir+"/"+fileName, b, 0644)
		if err != nil {
			return nil, err
		}

		payload := &Payload{
			Count: 0,
			File:  today + "/" + fileName,
			Data:  []Face{},
		}

		for i := 0; i < 2 && i < len(*result); i++ {
			matchFace := (*result)[i]

			id := matchFace.Id
			similarity := strconv.FormatFloat(matchFace.Similarity, 'f', 2, 64)
			fmt.Println(id)
			fmt.Println(similarity)

			val := db.FindOneActress(id)
			fmt.Println(val)

			if len(val) == 0 {
				js, err := json.Marshal(emptyPayload)
				if err != nil {
					return nil, err
				}

				return js, nil
			}

			face := Face{
				Id:         id,
				Name:       val["name"],
				Img:        val["img"],
				Similarity: similarity,
			}

			payload.Count += 1
			payload.Data = append(payload.Data, face)
		}

		js, err := json.Marshal(payload)
		if err != nil {
			return nil, err
		}

		return js, nil
	}
}
<commit_msg>Add defer function to recover error<commit_after>package main

import (
	"./aws"
	"./db"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strconv"
	"time"
)

const (
	imagesRoot = "/var/www/like-av.xyz/images/"
)

type Payload struct {
	Count int
	File  string
	Data  []Face
}

type Face struct {
	Id         string
	Name       string
	Img        string
	Similarity string
}

var emptyPayload = Payload{Count: 0}

func UploadHandler(w http.ResponseWriter, r *http.Request) {
	defer func() { //catch or finally
		if err := recover(); err != nil { //catch
			log.Println(err)
			js, _ := json.Marshal(emptyPayload)
			w.Write(js)
		}
	}()

	// allow cross domain AJAX requests
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Content-Type", "application/json")
	checkPost(r)

	err := r.ParseMultipartForm(32 << 20) // maxMemory
	checkError(err)

	file, handler, err := r.FormFile("upload")
	checkError(err)
	defer file.Close()

	b, err := ioutil.ReadAll(file)
	checkError(err)

	w.Write(searchFace(b, handler.Filename))
}

func FeedbackHandler(w http.ResponseWriter, r *http.Request) {
	defer func() { //catch or finally
		if err := recover(); err != nil { //catch
			log.Println(err)
			js, _ := json.Marshal(emptyPayload)
			w.Write(js)
		}
	}()

	// allow cross domain AJAX requests
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Content-Type", "application/json")
	checkPost(r)

	decoder := json.NewDecoder(r.Body)
	val := map[string]string{}
	err := decoder.Decode(&val)
	checkError(err)

	fmt.Println(val)
	if val["ox"] == "like" {
		b, err := ioutil.ReadFile(imagesRoot + val["file"])
		checkError(err)
		checkError(aws.InsertIndexFaceByImage(val["id"], b))
	}

	db.UpsertOneFeedback(val["id"], val["ox"], val["file"])
}

func main() {
	http.HandleFunc("/upload", UploadHandler)     // set router
	http.HandleFunc("/feedback", FeedbackHandler) // set router
	err := http.ListenAndServe(":9090", nil)      // set listen port
	if err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}

func checkError(err error) {
	if err != nil {
		// http.Error(w, err.Error(), http.StatusInternalServerError)
		// return
		panic(err)
	}
}

func checkPost(r *http.Request) {
	if r.Method != "POST" {
		// http.Error(w, "Allowed POST method only", http.StatusMethodNotAllowed)
		// return
		panic("Allowed POST method only")
	}
}

func searchFace(b []byte, fileName string) []byte {
	result, err := aws.SearchFacesByImage(b)
	if err != nil {
		panic(err)
	}

	if result == nil {
		js, err := json.Marshal(emptyPayload)
		if err != nil {
			panic(err)
		}

		return js
	} else {
		today := time.Now().Local().Format("2006-01-02")
		fmt.Println(today)
		imageDir := imagesRoot + today
		os.Mkdir(imageDir, os.ModePerm)
		err := ioutil.WriteFile(imageDir+"/"+fileName, b, 0644)
		if err != nil {
			panic(err)
		}

		payload := &Payload{
			Count: 0,
			File:  today + "/" + fileName,
			Data:  []Face{},
		}

		for i := 0; i < 2 && i < len(result); i++ {
			var matchFace = result[i]

			id := (*matchFace).Id
			similarity := strconv.FormatFloat((*matchFace).Similarity, 'f', 2, 64)
			fmt.Println(id)
			fmt.Println(similarity)

			val := db.FindOneActress(id)
			fmt.Println(val)

			if len(val) == 0 {
				js, err := json.Marshal(emptyPayload)
				if err != nil {
					panic(err)
				}

				return js
			}

			face := Face{
				Id:         id,
				Name:       val["name"],
				Img:        val["img"],
				Similarity: similarity,
			}

			payload.Count += 1
			payload.Data = append(payload.Data, face)
		}

		js, err := json.Marshal(payload)
		if err != nil {
			panic(err)
		}

		return js
	}
}
<|endoftext|>


<commit_before>package scaffold

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

	"golang.org/x/net/context"

	. "github.com/smartystreets/goconvey/convey"
)

func TestRouter(t *testing.T) {
	Convey("Given a router", t, func() {
		h := NewMockHandler()
		d := NewMockDispatcher()
		r := New(d)

		methods := map[string]func(pattern string, handlers ...interface{}) *Router{
			"OPTIONS": r.Options,
			"GET":     r.Get,
			"HEAD":    r.Head,
			"POST":    r.Post,
			"PUT":     r.Put,
			"DELETE":  r.Delete,
			"":        r.Handle,
		}

		Convey("When a handler function is added", func() {
			r = r.Handle("somepath", h.CtxServeHTTP)

			Convey("Then handler should be added", func() {
				So(d.HandlerHasBeenCalled, ShouldBeTrue)
				So(d.Route, ShouldNotBeNil)
			})
		})

		Convey("When a http handler is added", func() {
			r = r.Handle("somepath", http.NotFoundHandler())

			Convey("Then handler should be added", func() {
				So(d.HandlerHasBeenCalled, ShouldBeTrue)
				So(d.Route, ShouldNotBeNil)
			})
		})

		Convey("When a http handler function is added", func() {
			r = r.Handle("somepath", http.NotFound)

			Convey("Then handler should be added", func() {
				So(d.HandlerHasBeenCalled, ShouldBeTrue)
				So(d.Route, ShouldNotBeNil)
			})
		})

		for method, handler := range methods {
			when := fmt.Sprintf("When a route with method `%s` is added", method)
			Convey(when, func() {
				r = handler("somepath", h)

				then := fmt.Sprintf("Then the route method should be `%s`", method)
				Convey(then, func() {
					So(d.HandlerHasBeenCalled, ShouldBeTrue)
					So(d.Route, ShouldNotBeNil)
					So(d.Route.Method, ShouldEqual, method)
				})

				Convey("Then the route pattern should be correct", func() {
					So(d.HandlerHasBeenCalled, ShouldBeTrue)
					So(d.Route, ShouldNotBeNil)
					So(d.Route.Pattern, ShouldEqual, "somepath")
				})
			})
		}

		Convey("When a host is set", func() {
			r = r.Host("example.com", "www.example.com")

			Convey("Then the route should contain the hosts", func() {
				So(r.route.Hosts, ShouldContain, "example.com")
				So(r.route.Hosts, ShouldContain, "www.example.com")
			})
		})

		Convey("When a route pattern is set", func() {
			r = r.Route("somepath")

			Convey("Then the route pattern should be correct", func() {
				So(r.route.Pattern, ShouldEqual, "somepath")
			})
		})

		Convey("When a group is used", func() {
			r.Group("somepath", func(r *Router) {
				Convey("Then the route pattern should be correct", func() {
					So(r.route.Pattern, ShouldEqual, "somepath")
				})
			})
		})

		Convey("When a plaform is added", func() {
			platform := NewMockPlatform()
			r.Platform("somepath", platform)

			Convey("Then the route pattern should be correct", func() {
				So(platform.Route, ShouldNotBeNil)
				So(platform.Route.Pattern, ShouldEqual, "somepath")
			})
		})

		Convey("When middleware is added", func() {
			m := NewMockMiddleware()
			middleware := m.Middleware()
			r.Use(middleware)

			Convey("Then the middleware should be added", func() {
				So(d.MiddlewareHasBeenCalled, ShouldBeTrue)
				So(d.MiddlewareItems, ShouldContain, middleware)
			})
		})

		Convey("When http middlware is added", func() {
			middleware := func(next http.Handler) http.Handler {
				return next
			}
			r.Use(middleware)

			Convey("Then the middleware should be added", func() {
				So(d.MiddlewareHasBeenCalled, ShouldBeTrue)
			})
		})

		Convey("When middleware function is added", func() {
			m := NewMockMiddleware()
			middleware := (func(Handler) Handler)(m.Middleware())
			r.Use(middleware)

			Convey("Then the middleware should be added", func() {
				So(d.MiddlewareHasBeenCalled, ShouldBeTrue)
				So(d.MiddlewareItems, ShouldContain, middleware)
			})
		})

		Convey("When a not found handler is added", func() {
			h := NewMockHandler()
			r.NotFound(h)

			Convey("Then the not found handler should be set", func() {
				So(d.NotFound, ShouldEqual, h)
			})
		})
	})

	Convey("Given a handler builder", t, func() {
		b := func(i interface{}) (Handler, error) {
			if s, ok := i.(string); ok {
				return HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) {
					w.Write([]byte(s))
				}), nil
			}
			return nil, errors.New("Not a string")
		}
		d := NewMockDispatcher()
		r := New(d)
		r.AddHandlerBuilder(b)

		Convey("When the a var that can be built into a handler is routed", func() {
			r.Handle("somepath", "hello")

			Convey("Then the generated handler should be added", func() {
				So(d.HandlerHasBeenCalled, ShouldBeTrue)
				So(d.Route, ShouldNotBeNil)
			})
		})

		Convey("When the a var that cannot be built into a handler is routed", func() {
			Convey("Then router should panic", func() {
				So(func() { r.Handle("somepath", 123) }, ShouldPanic)
			})
		})

	})

	Convey("Given a platform", t, func() {
		d := NewMockDispatcher()
		platform := NewMockPlatform()

		Convey("When the platform is scaffolded", func() {
			Scaffold(d, platform)

			Convey("The platform should be routed", func() {
				So(platform.Route, ShouldNotBeNil)
			})
		})
	})
}
<commit_msg>Fixing tests that are broken in travis<commit_after>package scaffold

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

	"golang.org/x/net/context"

	. "github.com/smartystreets/goconvey/convey"
)

func TestRouter(t *testing.T) {
	Convey("Given a router", t, func() {
		h := NewMockHandler()
		d := NewMockDispatcher()
		r := New(d)

		methods := map[string]func(pattern string, handlers ...interface{}) *Router{
			"OPTIONS": r.Options,
			"GET":     r.Get,
			"HEAD":    r.Head,
			"POST":    r.Post,
			"PUT":     r.Put,
			"DELETE":  r.Delete,
			"":        r.Handle,
		}

		Convey("When a handler function is added", func() {
			r = r.Handle("somepath", h.CtxServeHTTP)

			Convey("Then handler should be added", func() {
				So(d.HandlerHasBeenCalled, ShouldBeTrue)
				So(d.Route, ShouldNotBeNil)
			})
		})

		Convey("When a http handler is added", func() {
			r = r.Handle("somepath", http.NotFoundHandler())

			Convey("Then handler should be added", func() {
				So(d.HandlerHasBeenCalled, ShouldBeTrue)
				So(d.Route, ShouldNotBeNil)
			})
		})

		Convey("When a http handler function is added", func() {
			r = r.Handle("somepath", http.NotFound)

			Convey("Then handler should be added", func() {
				So(d.HandlerHasBeenCalled, ShouldBeTrue)
				So(d.Route, ShouldNotBeNil)
			})
		})

		for method, handler := range methods {
			when := fmt.Sprintf("When a route with method `%s` is added", method)
			Convey(when, func() {
				r = handler("somepath", h)

				then := fmt.Sprintf("Then the route method should be `%s`", method)
				Convey(then, func() {
					So(d.HandlerHasBeenCalled, ShouldBeTrue)
					So(d.Route, ShouldNotBeNil)
					So(d.Route.Method, ShouldEqual, method)
				})

				Convey("Then the route pattern should be correct", func() {
					So(d.HandlerHasBeenCalled, ShouldBeTrue)
					So(d.Route, ShouldNotBeNil)
					So(d.Route.Pattern, ShouldEqual, "somepath")
				})
			})
		}

		Convey("When a host is set", func() {
			r = r.Host("example.com", "www.example.com")

			Convey("Then the route should contain the hosts", func() {
				So(r.route.Hosts, ShouldContain, "example.com")
				So(r.route.Hosts, ShouldContain, "www.example.com")
			})
		})

		Convey("When a route pattern is set", func() {
			r = r.Route("somepath")

			Convey("Then the route pattern should be correct", func() {
				So(r.route.Pattern, ShouldEqual, "somepath")
			})
		})

		Convey("When a group is used", func() {
			r.Group("somepath", func(r *Router) {
				Convey("Then the route pattern should be correct", func() {
					So(r.route.Pattern, ShouldEqual, "somepath")
				})
			})
		})

		Convey("When a plaform is added", func() {
			platform := NewMockPlatform()
			r.Platform("somepath", platform)

			Convey("Then the route pattern should be correct", func() {
				So(platform.Route, ShouldNotBeNil)
				So(platform.Route.Pattern, ShouldEqual, "somepath")
			})
		})

		Convey("When middleware is added", func() {
			m := NewMockMiddleware()
			middleware := m.Middleware()
			r.Use(middleware)

			Convey("Then the middleware should be added", func() {
				So(d.MiddlewareHasBeenCalled, ShouldBeTrue)
				So(d.MiddlewareItems, ShouldHaveLength, 1)
			})
		})

		Convey("When http middlware is added", func() {
			middleware := func(next http.Handler) http.Handler {
				return next
			}
			r.Use(middleware)

			Convey("Then the middleware should be added", func() {
				So(d.MiddlewareHasBeenCalled, ShouldBeTrue)
				So(d.MiddlewareItems, ShouldHaveLength, 1)
			})
		})

		Convey("When middleware function is added", func() {
			m := NewMockMiddleware()
			middleware := (func(Handler) Handler)(m.Middleware())
			r.Use(middleware)

			Convey("Then the middleware should be added", func() {
				So(d.MiddlewareHasBeenCalled, ShouldBeTrue)
			})
		})

		Convey("When a not found handler is added", func() {
			h := NewMockHandler()
			r.NotFound(h)

			Convey("Then the not found handler should be set", func() {
				So(d.NotFound, ShouldEqual, h)
			})
		})
	})

	Convey("Given a handler builder", t, func() {
		b := func(i interface{}) (Handler, error) {
			if s, ok := i.(string); ok {
				return HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) {
					w.Write([]byte(s))
				}), nil
			}
			return nil, errors.New("Not a string")
		}
		d := NewMockDispatcher()
		r := New(d)
		r.AddHandlerBuilder(b)

		Convey("When the a var that can be built into a handler is routed", func() {
			r.Handle("somepath", "hello")

			Convey("Then the generated handler should be added", func() {
				So(d.HandlerHasBeenCalled, ShouldBeTrue)
				So(d.Route, ShouldNotBeNil)
			})
		})

		Convey("When the a var that cannot be built into a handler is routed", func() {
			Convey("Then router should panic", func() {
				So(func() { r.Handle("somepath", 123) }, ShouldPanic)
			})
		})

	})

	Convey("Given a platform", t, func() {
		d := NewMockDispatcher()
		platform := NewMockPlatform()

		Convey("When the platform is scaffolded", func() {
			Scaffold(d, platform)

			Convey("The platform should be routed", func() {
				So(platform.Route, ShouldNotBeNil)
			})
		})
	})
}
<|endoftext|>


<commit_before>// Copyright 2019 Georg Großberger <contact@grossberger-ge.org>
// This is free software; it is provided under the terms of the MIT License
// See the file LICENSE or <https://opensource.org/licenses/MIT> for details

package labels

import (
	"path/filepath"
	"time"

	"github.com/garfieldius/t3ll/log"

	"github.com/kr/pretty"
)

// Xliff is the root of all languages and labels
type Xliff struct {
	SourceFile string
	Files      []*XliffRoot
}

// Labels converts a Xliff tree into a Labels tree
func (x *Xliff) Labels() *Labels {
	codes := make(map[string]bool)
	labels := &Labels{
		Type:      XMLXliffv1,
		SrcXlif:   x,
		File:      extPathOfFile(x.SourceFile),
		FromFile:  x.SourceFile,
		Languages: make([]string, 0),
		Data:      make([]*Label, 0),
	}

	for _, file := range x.Files {
		langCode := file.File.ToLang

		if langCode == "" {
			langCode = file.File.SrcLang
		}

		codes[langCode] = true

		for _, unit := range file.File.Body.Units {
			t := &Translation{
				Language: langCode,
				Content:  unit.To,
			}

			if langCode == "en" {
				t.Content = unit.Src
				labels.File = extPathOfFile(file.SourceFile)
			}

			found := false

			for _, label := range labels.Data {
				if label.ID == unit.ID {
					found = true
					label.Translations = append(label.Translations, t)
				}
			}

			if !found {
				labels.Data = append(labels.Data, &Label{
					ID:           unit.ID,
					Translations: []*Translation{t},
				})
			}
		}
	}

	for langCode := range codes {
		labels.Languages = append(labels.Languages, langCode)
	}

	log.Msg("Converted xlif into %# v", pretty.Formatter(labels))

	return labels
}

// XliffRoot is the virtual root node of a XML document
type XliffRoot struct {
	XMLName    string     `xml:"xliff"`
	Version    string     `xml:"version,attr,omitempty"`
	File       *XliffFile `xml:"file,omitempty"`
	Language   string     `xml:"-"`
	SourceFile string     `xml:"-"`
}

// Labels in this implementation has no function, because the
// calling party handles the conversion
func (x *XliffRoot) Labels() *Labels {
	return nil // Noop
}

// IndentChar determines the string for indentatio or
// XML tags
func (x *XliffRoot) IndentChar() string {
	return indentOfFile(x.SourceFile)
}

// XliffFile is the actual root node of a Xliff document
type XliffFile struct {
	SrcLang string       `xml:"source-language,attr,omitempty"`
	ToLang  string       `xml:"target-language,attr,omitempty"`
	Orig    string       `xml:"original,attr,omitempty"`
	Name    string       `xml:"product-name,attr,omitempty"`
	Date    string       `xml:"date,attr,omitempty"`
	Header  *XliffHeader `xml:"header,omitempty"`
	Body    *XliffBody   `xml:"body,omitempty"`
}

// XliffHeader is a collection of common metadata
type XliffHeader struct {
	Skl      string `xml:"skl,omitempty"`
	PhaseGrp string `xml:"phase-group,omitempty"`
	Glossary string `xml:"glossary,omitempty"`
	Ref      string `xml:"reference,omitempty"`
	CountGrp string `xml:"count-group,omitempty"`
	Tool     string `xml:"tool,omitempty"`
	PopGrp   string `xml:"pop-group,omitempty"`
	Note     string `xml:"note,omitempty"`

	// Non-standard, but common in TYPO3
	Type        string `xml:"type,omitempty"`
	Description string `xml:"description,omitempty"`
	AuthName    string `xml:"authorName,omitempty"`
	AuthMail    string `xml:"authorEmail,omitempty"`
	AuthCompany string `xml:"authorCompany,omitempty"`
	Generator   string `xml:"generator,omitempty"`
}

// XliffBody contains the units of a Xliff document
type XliffBody struct {
	Units []*XliffUnit `xml:"trans-unit,omitempty"`
}

// XliffUnit is a single ID + Content unit of a Xliff document
type XliffUnit struct {
	ID  string `xml:"id,attr,omitempty"`
	Src string `xml:"source,omitempty"`
	To  string `xml:"target,omitempty"`
}

// XliffConverter will convert a Xliff structure to struct Lables
type XliffConverter struct {
	src  *Labels
	file *XliffFile
	lang string
}

// XML will return the Xliff structure of a Labels structure
func (c *XliffConverter) XML() LangFile {
	b := &XliffBody{
		Units: make([]*XliffUnit, 0, len(c.src.Data)),
	}
	f := &XliffFile{
		SrcLang: "en",
		Date:    time.Now().Format(time.RFC3339),
		Body:    b,
	}

	if c.file != nil {
		f.Header = c.file.Header
		f.Orig = c.file.Orig
		f.Name = c.file.Name
	}

	l := "en"

	if c.lang != "en" {
		f.ToLang = c.lang
		l = c.lang
	}

	for _, label := range c.src.Data {
		for _, trans := range label.Translations {
			if trans.Language == l {
				u := &XliffUnit{
					ID: label.ID,
				}

				if c.lang == "en" {
					u.Src = trans.Content
				} else {
					if trans.Content == "" {
						continue
					}
					u.To = trans.Content
					for _, orig := range label.Translations {
						if orig.Language == "en" {
							u.Src = orig.Content
						}
					}
				}

				b.Units = append(b.Units, u)
			}
		}
	}

	if len(b.Units) < 1 {
		return nil
	}

	x := &XliffRoot{
		SourceFile: c.src.FromFile,
		Language:   c.lang,
		Version:    "1.0",
		File:       f,
	}

	return x
}

// File determines the desired target file of this document
func (c *XliffConverter) File() string {
	d := filepath.Dir(c.src.FromFile)
	f := xliffLangPrefix.ReplaceAllString(filepath.Base(c.src.FromFile), "")
	p := ""

	if c.lang != "en" {
		p = c.lang + "."
	}

	full := d + string(filepath.Separator) + p + f
	log.Msg("Nomalized from %s to %s", c.src.FromFile, full)

	return full
}
<commit_msg>Add resname attribute<commit_after>// Copyright 2019 Georg Großberger <contact@grossberger-ge.org>
// This is free software; it is provided under the terms of the MIT License
// See the file LICENSE or <https://opensource.org/licenses/MIT> for details

package labels

import (
	"path/filepath"
	"time"

	"github.com/garfieldius/t3ll/log"

	"github.com/kr/pretty"
)

// Xliff is the root of all languages and labels
type Xliff struct {
	SourceFile string
	Files      []*XliffRoot
}

// Labels converts a Xliff tree into a Labels tree
func (x *Xliff) Labels() *Labels {
	codes := make(map[string]bool)
	labels := &Labels{
		Type:      XMLXliffv1,
		SrcXlif:   x,
		File:      extPathOfFile(x.SourceFile),
		FromFile:  x.SourceFile,
		Languages: make([]string, 0),
		Data:      make([]*Label, 0),
	}

	for _, file := range x.Files {
		langCode := file.File.ToLang

		if langCode == "" {
			langCode = file.File.SrcLang
		}

		codes[langCode] = true

		for _, unit := range file.File.Body.Units {
			t := &Translation{
				Language: langCode,
				Content:  unit.To,
			}

			if langCode == "en" {
				t.Content = unit.Src
				labels.File = extPathOfFile(file.SourceFile)
			}

			found := false

			for _, label := range labels.Data {
				if label.ID == unit.ID {
					found = true
					label.Translations = append(label.Translations, t)
				}
			}

			if !found {
				labels.Data = append(labels.Data, &Label{
					ID:           unit.ID,
					Translations: []*Translation{t},
				})
			}
		}
	}

	for langCode := range codes {
		labels.Languages = append(labels.Languages, langCode)
	}

	log.Msg("Converted xlif into %# v", pretty.Formatter(labels))

	return labels
}

// XliffRoot is the virtual root node of a XML document
type XliffRoot struct {
	XMLName    string     `xml:"xliff"`
	Version    string     `xml:"version,attr,omitempty"`
	File       *XliffFile `xml:"file,omitempty"`
	Language   string     `xml:"-"`
	SourceFile string     `xml:"-"`
}

// Labels in this implementation has no function, because the
// calling party handles the conversion
func (x *XliffRoot) Labels() *Labels {
	return nil // Noop
}

// IndentChar determines the string for indentatio or
// XML tags
func (x *XliffRoot) IndentChar() string {
	return indentOfFile(x.SourceFile)
}

// XliffFile is the actual root node of a Xliff document
type XliffFile struct {
	SrcLang string       `xml:"source-language,attr,omitempty"`
	ToLang  string       `xml:"target-language,attr,omitempty"`
	Orig    string       `xml:"original,attr,omitempty"`
	Name    string       `xml:"product-name,attr,omitempty"`
	Date    string       `xml:"date,attr,omitempty"`
	Header  *XliffHeader `xml:"header,omitempty"`
	Body    *XliffBody   `xml:"body,omitempty"`
}

// XliffHeader is a collection of common metadata
type XliffHeader struct {
	Skl      string `xml:"skl,omitempty"`
	PhaseGrp string `xml:"phase-group,omitempty"`
	Glossary string `xml:"glossary,omitempty"`
	Ref      string `xml:"reference,omitempty"`
	CountGrp string `xml:"count-group,omitempty"`
	Tool     string `xml:"tool,omitempty"`
	PopGrp   string `xml:"pop-group,omitempty"`
	Note     string `xml:"note,omitempty"`

	// Non-standard, but common in TYPO3
	Type        string `xml:"type,omitempty"`
	Description string `xml:"description,omitempty"`
	AuthName    string `xml:"authorName,omitempty"`
	AuthMail    string `xml:"authorEmail,omitempty"`
	AuthCompany string `xml:"authorCompany,omitempty"`
	Generator   string `xml:"generator,omitempty"`
}

// XliffBody contains the units of a Xliff document
type XliffBody struct {
	Units []*XliffUnit `xml:"trans-unit,omitempty"`
}

// XliffUnit is a single ID + Content unit of a Xliff document
type XliffUnit struct {
	ID  string `xml:"id,attr,omitempty"`
	ResName  string `xml:"resname,attr,omitempty"`
	Src string `xml:"source,omitempty"`
	To  string `xml:"target,omitempty"`
}

// XliffConverter will convert a Xliff structure to struct Lables
type XliffConverter struct {
	src  *Labels
	file *XliffFile
	lang string
}

// XML will return the Xliff structure of a Labels structure
func (c *XliffConverter) XML() LangFile {
	b := &XliffBody{
		Units: make([]*XliffUnit, 0, len(c.src.Data)),
	}
	f := &XliffFile{
		SrcLang: "en",
		Date:    time.Now().Format(time.RFC3339),
		Body:    b,
	}

	if c.file != nil {
		f.Header = c.file.Header
		f.Orig = c.file.Orig
		f.Name = c.file.Name
	}

	l := "en"

	if c.lang != "en" {
		f.ToLang = c.lang
		l = c.lang
	}

	for _, label := range c.src.Data {
		for _, trans := range label.Translations {
			if trans.Language == l {
				u := &XliffUnit{
					ResName: label.ID,
					// ID is not the correct attribute for this, but is used by TYPO3
					ID: label.ID,
				}

				if c.lang == "en" {
					u.Src = trans.Content
				} else {
					if trans.Content == "" {
						continue
					}
					u.To = trans.Content
					for _, orig := range label.Translations {
						if orig.Language == "en" {
							u.Src = orig.Content
						}
					}
				}

				b.Units = append(b.Units, u)
			}
		}
	}

	if len(b.Units) < 1 {
		return nil
	}

	x := &XliffRoot{
		SourceFile: c.src.FromFile,
		Language:   c.lang,
		Version:    "1.0",
		File:       f,
	}

	return x
}

// File determines the desired target file of this document
func (c *XliffConverter) File() string {
	d := filepath.Dir(c.src.FromFile)
	f := xliffLangPrefix.ReplaceAllString(filepath.Base(c.src.FromFile), "")
	p := ""

	if c.lang != "en" {
		p = c.lang + "."
	}

	full := d + string(filepath.Separator) + p + f
	log.Msg("Nomalized from %s to %s", c.src.FromFile, full)

	return full
}
<|endoftext|>


<commit_before>// Copyright 2012 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package app

import (
	"github.com/globocom/tsuru/fs"
	"io"
)

var fsystem fs.Fs

func filesystem() fs.Fs {
	if fsystem == nil {
		fsystem = fs.OsFs{}
	}
	return fsystem
}

func randomBytes(n int) ([]byte, error) {
	f, err := filesystem().Open("/dev/urandom")
	if err != nil {
		return nil, err
	}
	b := make([]byte, n)
	read, err := f.Read(b)
	if err != nil {
		return nil, err
	}
	if read != n {
		return nil, io.ErrShortBuffer
	}
	err = f.Close()
	if err != nil {
		return nil, err
	}
	return b, nil
}
<commit_msg>app: update license header in util.go<commit_after>// Copyright 2013 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package app

import (
	"github.com/globocom/tsuru/fs"
	"io"
)

var fsystem fs.Fs

func filesystem() fs.Fs {
	if fsystem == nil {
		fsystem = fs.OsFs{}
	}
	return fsystem
}

func randomBytes(n int) ([]byte, error) {
	f, err := filesystem().Open("/dev/urandom")
	if err != nil {
		return nil, err
	}
	b := make([]byte, n)
	read, err := f.Read(b)
	if err != nil {
		return nil, err
	}
	if read != n {
		return nil, io.ErrShortBuffer
	}
	err = f.Close()
	if err != nil {
		return nil, err
	}
	return b, nil
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"os"
)

const (
	VERSION = "0.3.0"
)

var options struct {
	Path  string
	Host  string
	Port  int
	Token string
	Auth  bool
}

var services []Service

func initOptions() {
	var printVersion bool

	flag.StringVar(&options.Path, "c", "", "Path to config directory")
	flag.StringVar(&options.Host, "h", "0.0.0.0", "Host to bind to")
	flag.IntVar(&options.Port, "p", 3050, "Port to listen on")
	flag.StringVar(&options.Token, "t", "", "Authentication token")
	flag.BoolVar(&printVersion, "v", false, "Print version")

	flag.Parse()

	if printVersion {
		fmt.Println(VERSION)
		os.Exit(0)
	}

	if options.Path == "" {
		fmt.Println("Please specify -c option")
		os.Exit(1)
	}

	// Load token from environment variable if not set
	if options.Token == "" {
		options.Token = os.Getenv("TOKEN")
	}

	// Do not require authentication if token is not set
	if options.Token == "" {
		options.Auth = false
	} else {
		options.Auth = true
	}
}

func main() {
	initOptions()

	var err error
	services, err = readServices(options.Path)

	if err != nil {
		fmt.Println("Error:", err.Error())
		os.Exit(1)
	}

	fmt.Printf("envd v%s\n", VERSION)
	fmt.Println("config path:", options.Path)
	fmt.Println("services detected:", len(services))

	startServer()
}
<commit_msg>Reload config on SIGHUP<commit_after>package main

import (
	"flag"
	"fmt"
	"os"
	"os/signal"
	"syscall"
)

const (
	VERSION = "0.3.0"
)

var options struct {
	Path  string
	Host  string
	Port  int
	Token string
	Auth  bool
}

var services []Service

func initOptions() {
	var printVersion bool

	flag.StringVar(&options.Path, "c", "", "Path to config directory")
	flag.StringVar(&options.Host, "h", "0.0.0.0", "Host to bind to")
	flag.IntVar(&options.Port, "p", 3050, "Port to listen on")
	flag.StringVar(&options.Token, "t", "", "Authentication token")
	flag.BoolVar(&printVersion, "v", false, "Print version")

	flag.Parse()

	if printVersion {
		fmt.Println(VERSION)
		os.Exit(0)
	}

	if options.Path == "" {
		fmt.Println("Please specify -c option")
		os.Exit(1)
	}

	// Load token from environment variable if not set
	if options.Token == "" {
		options.Token = os.Getenv("TOKEN")
	}

	// Do not require authentication if token is not set
	if options.Token == "" {
		options.Auth = false
	} else {
		options.Auth = true
	}
}

func reloadServices() {
	newServices, err := readServices(options.Path)

	if err != nil {
		return
	}

	services = newServices
}

func setupReload() {
	c := make(chan os.Signal, 1)
	signal.Notify(c, syscall.SIGHUP)

	go func() {
		for sig := range c {
			fmt.Println("Reloading configuration...", sig)
			reloadServices()
		}
	}()
}

func main() {
	initOptions()
	setupReload()

	var err error
	services, err = readServices(options.Path)

	if err != nil {
		fmt.Println("Error:", err.Error())
		os.Exit(1)
	}

	fmt.Printf("envd v%s\n", VERSION)
	fmt.Println("config path:", options.Path)
	fmt.Println("services detected:", len(services))

	startServer()
}
<|endoftext|>


<commit_before>package connection

import (
	"log"
	"net"

	"github.com/piot/hasty-protocol/channel"
	"github.com/piot/hasty-protocol/commands"
	"github.com/piot/hasty-protocol/serializer"
	"github.com/piot/hasty-server/storage"
	"github.com/piot/hasty-server/subscribers"
)

type StreamInfo struct {
	lastOffsetSent uint64
}

type ConnectionHandler struct {
	conn        *net.Conn
	storage     *filestorage.StreamStorage
	subscribers *subscribers.Subscribers
	streamInfos map[uint32]*StreamInfo
}

// NewConnectionHandler : todo
func NewConnectionHandler(connection *net.Conn, storage *filestorage.StreamStorage, subs *subscribers.Subscribers) ConnectionHandler {
	return ConnectionHandler{conn: connection, storage: storage, subscribers: subs, streamInfos: map[uint32]*StreamInfo{}}
}

// HandleConnect : todo
func (in ConnectionHandler) HandleConnect(cmd commands.Connect) error {
	log.Println("Connection connect:", cmd)

	// _ := commands.NewConnectResult(cmd.Realm(), cmd.ProtocolVersion())
	octetsToSend := serializer.ConnectResultToOctets()
	in.sendPacket(octetsToSend)
	return nil
}

// HandlePublishStream : todo
func (in ConnectionHandler) HandlePublishStream(cmd commands.PublishStream) error {
	log.Println("Connection publish:", cmd)
	return nil
}

func (in *ConnectionHandler) StreamChanged(channelID channel.ID) {
	info := in.streamInfos[channelID.Raw()]
	file, fileErr := in.storage.ReadStream(channelID)
	if fileErr != nil {
		return
	}
	file.Seek(info.lastOffsetSent)
	data := make([]byte, 32*1024)
	octetsRead, readErr := file.Read(data)
	if readErr != nil {
		return
	}
	file.Close()
	payload := serializer.StreamDataToOctets(channelID, uint32(info.lastOffsetSent), data[:octetsRead])
	info.lastOffsetSent += uint64(octetsRead)
	in.sendPacket(payload)
}

func (in *ConnectionHandler) fetchOrCreateStreamInfo(channelID channel.ID) *StreamInfo {
	infos := in.streamInfos[channelID.Raw()]
	if infos == nil {
		infos = &StreamInfo{}
		in.streamInfos[channelID.Raw()] = infos
	}
	return infos
}

// HandleSubscribeStream : todo
func (in *ConnectionHandler) HandleSubscribeStream(cmd commands.SubscribeStream) {
	log.Println("Connection subscribe:", cmd)

	for _, v := range cmd.Infos() {
		readFile, err := in.storage.ReadStream(v.Channel())

		if err != nil {
			return
		}

		buf := make([]byte, 64*1024)
		octetsRead, readErr := readFile.Read(buf)
		if readErr != nil {
			return
		}
		data := buf[:octetsRead]

		octetsToSend := serializer.StreamDataToOctets(v.Channel(), 0, data)
		in.sendPacket(octetsToSend)
		infos := in.fetchOrCreateStreamInfo(v.Channel())
		infos.lastOffsetSent = uint64(octetsRead)
		in.subscribers.AddStreamSubscriber(v.Channel(), in)
	}
}

// HandleUnsubscribeStream : todo
func (in ConnectionHandler) HandleUnsubscribeStream(cmd commands.UnsubscribeStream) {
	log.Println("Connection unsubscribe:", cmd)
}

// HandleCreateStream : todo
func (in ConnectionHandler) HandleCreateStream(cmd commands.CreateStream) (channel.ID, error) {
	log.Println("Connection create stream:", cmd)
	return channel.ID{}, nil
}

// HandleStreamData : todo
func (in ConnectionHandler) HandleStreamData(cmd commands.StreamData) {
	log.Println("Connection stream data:", cmd)
}

func (in *ConnectionHandler) sendPacket(octets []byte) {
	header := []byte{byte(len(octets))}
	(*in.conn).Write(header)
	(*in.conn).Write(octets)
}
<commit_msg>Using small length for size<commit_after>package connection

import (
	"log"
	"net"

	"github.com/piot/hasty-protocol/channel"
	"github.com/piot/hasty-protocol/commands"
	"github.com/piot/hasty-protocol/serializer"
	"github.com/piot/hasty-server/storage"
	"github.com/piot/hasty-server/subscribers"
)

type StreamInfo struct {
	lastOffsetSent uint64
}

type ConnectionHandler struct {
	conn        *net.Conn
	storage     *filestorage.StreamStorage
	subscribers *subscribers.Subscribers
	streamInfos map[uint32]*StreamInfo
}

// NewConnectionHandler : todo
func NewConnectionHandler(connection *net.Conn, storage *filestorage.StreamStorage, subs *subscribers.Subscribers) ConnectionHandler {
	return ConnectionHandler{conn: connection, storage: storage, subscribers: subs, streamInfos: map[uint32]*StreamInfo{}}
}

// HandleConnect : todo
func (in ConnectionHandler) HandleConnect(cmd commands.Connect) error {
	log.Println("Connection connect:", cmd)

	// _ := commands.NewConnectResult(cmd.Realm(), cmd.ProtocolVersion())
	octetsToSend := serializer.ConnectResultToOctets()
	in.sendPacket(octetsToSend)
	return nil
}

// HandlePublishStream : todo
func (in ConnectionHandler) HandlePublishStream(cmd commands.PublishStream) error {
	log.Println("Connection publish:", cmd)
	return nil
}

func (in *ConnectionHandler) StreamChanged(channelID channel.ID) {
	info := in.streamInfos[channelID.Raw()]
	file, fileErr := in.storage.ReadStream(channelID)
	if fileErr != nil {
		return
	}
	file.Seek(info.lastOffsetSent)
	data := make([]byte, 32*1024)
	octetsRead, readErr := file.Read(data)
	if readErr != nil {
		return
	}
	file.Close()
	payload := serializer.StreamDataToOctets(channelID, uint32(info.lastOffsetSent), data[:octetsRead])
	info.lastOffsetSent += uint64(octetsRead)
	in.sendPacket(payload)
}

func (in *ConnectionHandler) fetchOrCreateStreamInfo(channelID channel.ID) *StreamInfo {
	infos := in.streamInfos[channelID.Raw()]
	if infos == nil {
		infos = &StreamInfo{}
		in.streamInfos[channelID.Raw()] = infos
	}
	return infos
}

// HandleSubscribeStream : todo
func (in *ConnectionHandler) HandleSubscribeStream(cmd commands.SubscribeStream) {
	log.Println("Connection subscribe:", cmd)

	for _, v := range cmd.Infos() {
		readFile, err := in.storage.ReadStream(v.Channel())

		if err != nil {
			return
		}

		buf := make([]byte, 64*1024)
		octetsRead, readErr := readFile.Read(buf)
		if readErr != nil {
			return
		}
		data := buf[:octetsRead]

		octetsToSend := serializer.StreamDataToOctets(v.Channel(), 0, data)
		in.sendPacket(octetsToSend)
		infos := in.fetchOrCreateStreamInfo(v.Channel())
		infos.lastOffsetSent = uint64(octetsRead)
		in.subscribers.AddStreamSubscriber(v.Channel(), in)
	}
}

// HandleUnsubscribeStream : todo
func (in ConnectionHandler) HandleUnsubscribeStream(cmd commands.UnsubscribeStream) {
	log.Println("Connection unsubscribe:", cmd)
}

// HandleCreateStream : todo
func (in ConnectionHandler) HandleCreateStream(cmd commands.CreateStream) (channel.ID, error) {
	log.Println("Connection create stream:", cmd)
	return channel.ID{}, nil
}

// HandleStreamData : todo
func (in ConnectionHandler) HandleStreamData(cmd commands.StreamData) {
	log.Println("Connection stream data:", cmd)
}

func (in *ConnectionHandler) sendPacket(octets []byte) {
	lengthBuf, lengthErr := serializer.SmallLengthToOctets(uint16(len(octets)))
	if lengthErr != nil {
		log.Fatalf("We couldn't write length")
		return
	}
	(*in.conn).Write(lengthBuf)
	(*in.conn).Write(octets)
}
<|endoftext|>


<commit_before>package main

import (
	"reflect"
	"testing"

	"github.com/nictuku/eliteprofit/emdn"
)

type routeTest struct {
	station string
	route   Route
}

func TestBestBuy(t *testing.T) {
	count := 0
	store := newMarketStore()
	c, err := emdn.TestSubscribe()
	if err != nil {
		t.Fatal(err)
	}
	for m := range c {
		store.record(m.Transaction)
		count += 1
	}
	if count == 0 {
		t.Fatalf("Didn't receive any transactions from the test input.")
	}
	tests := []routeTest{
		{"Eranin (AZEBAN CITY)", Route{Profit: 287, DestinationStation: "Ross 1057 (Wang Estate)"}},
		{"Asellus Primus (BEAGLE 2 LANDING)", Route{Profit: 781, DestinationStation: "Nang Ta-khian (Hay Point)"}},
		{"LHS 3262 (Louis de Lacaille Prospect)", Route{Profit: 1018, DestinationStation: "Nang Ta-khian (Hay Point)"}},
		{"Bogus", Route{Profit: 0}},
	}

	for _, testStation := range tests {
		// Find the most profitable routes.
		routes := store.bestBuy(testStation.station, 2000000, 100)
		if len(routes) == 0 {
			t.Fatalf("nope: got %d wanted > 0 ", len(routes))
		}
		// Only the first is filled for now.
		r := routes[0]
		if r.DestinationStation != testStation.route.DestinationStation {
			t.Errorf("testStation %v: destination %v (wanted %v)\n",
				testStation, r.DestinationStation, testStation.route.DestinationStation)
		}
		if r.Profit != testStation.route.Profit {
			t.Errorf("testStation %v: price %+v (wanted %v)\n", testStation, r, testStation.route.Profit)
		}
	}
	t.Logf("woot")
}

func TestDistance(t *testing.T) {
	d := distance("Asellus Primus", "Eranin")
	want := 4.482060596143252
	if d != want {
		t.Errorf("distance between Asellus Primus and Eranin, got %v, wanted %v", d, want)
	}
}

func TestRoute(t *testing.T) {
	var tests = []struct {
		from      string
		to        string
		jumpRange float64
		want      []string
	}{
		// Close neighbors.
		{"Asellus Primus", "Eranin", 9999, []string{"Asellus Primus", "Eranin"}},

		// 29LY distance.
		{"Dahan", "Ovid", 9999, []string{"Dahan", "Ovid"}},
		{"Dahan", "Ovid", 6.1, []string{"Dahan", "Asellus Primus", "Eranin", "i Bootis", "Styx", "Opala", "Ovid"}},
	}
	for _, r := range tests {
		route := starRoute(r.from, r.to, r.jumpRange)
		if !reflect.DeepEqual(route, r.want) {
			t.Errorf("starRoute(%q, %q) = %q; want %q", r.from, r.to, route, r.want)
		}
	}
}

func TestStarName(t *testing.T) {
	station := "i Bootis (CHANGO DOCK)"
	want := "i Bootis"

	starName := star(station)
	if starName != want {
		t.Errorf("star name got %q wanted %q", starName, want)
	}
}
<commit_msg>From my Zotac ZBOX ("biscoito").<commit_after>package main

import (
	"reflect"
	"testing"

	"github.com/nictuku/eliteprofit/emdn"
)

type routeTest struct {
	station string
	route   Route
}

func TestBestBuy(t *testing.T) {
	count := 0
	store := newMarketStore()
	c, err := emdn.TestSubscribe()
	if err != nil {
		t.Fatal(err)
	}
	for m := range c {
		store.record(m.Transaction)
		count += 1
	}
	if count == 0 {
		t.Fatalf("Didn't receive any transactions from the test input.")
	}
	tests := []routeTest{
		{"Eranin (AZEBAN CITY)", Route{Profit: 287, DestinationStation: "Ross 1057 (Wang Estate)"}},
		{"Asellus Primus (BEAGLE 2 LANDING)", Route{Profit: 781, DestinationStation: "Nang Ta-khian (Hay Point)"}},
		{"LHS 3262 (Louis de Lacaille Prospect)", Route{Profit: 1018, DestinationStation: "Nang Ta-khian (Hay Point)"}},
		{"Bogus", Route{Profit: 0}},
	}

	for _, testStation := range tests {
		// Find the most profitable routes.
		routes := store.bestBuy(testStation.station, 2000000, 100)
		if len(routes) == 0 {
			t.Fatalf("nope: got %d wanted > 0 ", len(routes))
		}
		// Only the first is filled for now.
		r := routes[0]
		if r.DestinationStation != testStation.route.DestinationStation {
			t.Errorf("testStation %v: destination %v (wanted %v)\n",
				testStation, r.DestinationStation, testStation.route.DestinationStation)
		}
		if r.Profit != testStation.route.Profit {
			t.Errorf("testStation %v: price %+v (wanted %v)\n", testStation, r, testStation.route.Profit)
		}
	}
	t.Logf("woot")
}

func TestDistance(t *testing.T) {
	d := distance("Asellus Primus", "Eranin")
	want := 4.482060596143252
	if d != want {
		t.Errorf("distance between Asellus Primus and Eranin, got %v, wanted %v", d, want)
	}
}

func TestRoute(t *testing.T) {
	var tests = []struct {
		from      string
		to        string
		jumpRange float64
		want      []string
	}{
		// Close neighbors.
		{"Asellus Primus", "Eranin", 9999, []string{"Asellus Primus", "Eranin"}},

		// 29LY distance.
		{"Dahan", "Ovid", 9999, []string{"Dahan", "Ovid"}},
		{"Dahan", "Ovid", 6.1, []string{"Dahan", "Asellus Primus", "Eranin", "i Bootis", "Styx", "Opala", "Ovid"}},
	}
	for _, r := range tests {
		route := starRoute(r.from, r.to, r.jumpRange)
		if !reflect.DeepEqual(route, r.want) {
			t.Errorf("starRoute(%q, %q) = %q; want %q", r.from, r.to, route, r.want)
		}
	}
}

func BenchmarkStarRoute(b *testing.B) {
	// Build routing plan from Eranin to all known stars (as of Beta 1).
	// For the jump range, consider a Viper with full load (cargo and
	// fuel), or 9.16 LY according to http://changodock.com.
	star := "Eranin"
	for i := 0; i < b.N; i++ {
		for dest := range locs {
			if dest == star {
				continue
			}
			starRoute(star, dest, 9.16)
		}
	}
}

func TestStarName(t *testing.T) {
	station := "i Bootis (CHANGO DOCK)"
	want := "i Bootis"

	starName := star(station)
	if starName != want {
		t.Errorf("star name got %q wanted %q", starName, want)
	}
}
<|endoftext|>


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

package errd

import (
	"context"
	"errors"
	"fmt"
)

// Default is the default Runner comfiguration.
var Default = WithDefault()

// Run calls Default.Run(f)
func Run(f func(*E)) (err error) {
	return Default.Run(f)
}

// RunWithContext calls Default.RunWithContext(ctxt, f)
func RunWithContext(ctxt context.Context, f func(*E)) (err error) {
	return Default.RunWithContext(ctxt, f)
}

// A Runner defines a default way to handle errors and options.
type Runner struct {
	*config
	context context.Context
}

// WithDefault returns a new Config for the given default handlers.
func WithDefault(h ...Handler) *Runner {
	return &Runner{
		config: &config{
			defaultHandlers: h,
		},
	}
}

// Run starts a new error handling scope. The function returns whenever an error
// is encountered with one of the methods on E.
func (r *Runner) Run(f func(e *E)) (err error) {
	// state := c.state
	var e E
	e.runner = r.config
	e.deferred = e.buf[:0]
	defer doRecover(&e, &err)
	f(&e)
	doDefers(&e, 0)
	if e.err != nil {
		return *e.err
	}
	return nil
}

// RunWithContext starts a new error handling scope. The function returns
// whenever an error is encountered with one of the methods on E.
func (r *Runner) RunWithContext(ctxt context.Context, f func(e *E)) (err error) {
	// Do defers now to save on an extra defer.
	// state := c.state
	var e E
	e.runner = r.config
	e.deferred = e.buf[:0]
	e.context = ctxt
	defer doRecover(&e, &err)
	f(&e)
	// Do defers now to save on an extra defer.
	doDefers(&e, 0)
	if e.err != nil {
		return *e.err
	}
	return nil
}

type config struct {
	defaultHandlers []Handler

	// inPanic indicates a panic is occurring: a copy of this Config with inPanic
	// set is assigned to the state if a panic occurs. This removes this field
	// from core.
	inPanic bool
}

const bufSize = 3

type core struct {
	// Fits into 128 bytes; 2 cache lines on many modern architectures.
	runner   *config
	deferred []deferData
	buf      [bufSize]deferData
	err      *error
	context  context.Context
}

// An E coordinates the error and defer handling.
type E struct{ core }

var errHandlerFirst = errors.New("errd: handler may not be first argument")

// Must causes a call to Run to return on error. An error is detected if err
// is non-nil and if it is still non-nil after passing it to error handling.
func (e *E) Must(err error, h ...Handler) {
	if err != nil {
		processError(e, err, h)
	}
}

// State represents the error state passed to custom error handlers.
type State interface {
	// Context returns the context set by WithContext, or context.TODO
	// otherwise.
	Context() context.Context

	// Panicing reports whether the error resulted from a panic. If true,
	// the panic will be resume after error handling completes. An error handler
	// cannot rewrite an error when panicing.
	Panicing() bool

	// Err reports the first error that passed through an error handler chain.
	// Note that this is always a different error (or nil) than the one passed
	// to an error handler.
	Err() error
}

type state struct{ core }

func (s *state) Context() context.Context {
	if s.context == nil {
		return context.TODO()
	}
	return s.context
}

func (s *state) Panicing() bool { return s.runner.inPanic }

func (s *state) Err() error {
	if s.err == nil {
		return nil
	}
	return *s.err
}

var errOurPanic = errors.New("errd: our panic")

func doRecover(e *E, err *error) {
	switch r := recover(); r {
	case nil:
	case errOurPanic:
		finishDefer(e, err)
		*err = *e.err
	default:
		if !e.runner.inPanic {
			c := *e.runner
			c.inPanic = true
			e.runner = &c
		}
		err2, ok := r.(error)
		if !ok {
			err2 = fmt.Errorf("errd: paniced: %v", r)
		}
		e.err = &err2
		finishDefer(e, err)
		// Check whether there are still defers left to do and then
		// recursively defer.
		panic(r)
	}
}

func doDefers(e *E, barrier int) {
	for len(e.deferred) > barrier {
		i := len(e.deferred) - 1
		d := e.deferred[i]
		e.deferred = e.deferred[:i]
		if d.f == nil {
			continue
		}
		if err := d.f((*state)(e), d.x); err != nil {
			processDeferError(e, err)
		}
	}
}

// finishDefer processes remaining defers after we already have a panic.
// We therefore ignore any panic caught here, knowing that we will panic on an
// older panic after returning.
func finishDefer(e *E, err *error) {
	if len(e.deferred) > 0 {
		defer doRecover(e, err)
		doDefers(e, 0)
	}
}

type errorHandler struct {
	e   *E
	err *error
}

func (h errorHandler) handle(eh Handler) (done bool) {
	newErr := eh.Handle((*state)(h.e), *h.err)
	if newErr == nil {
		return true
	}
	*h.err = newErr
	return false

}

func processErrorSentinel(e *E, err, sentinel error, handlers []Handler) bool {
	eh := errorHandler{e: e, err: &err}
	for _, h := range handlers {
		if eh.handle(h) {
			return false
		}
		if err == sentinel {
			return true
		}
	}
	if len(handlers) == 0 {
		for _, h := range e.runner.defaultHandlers {
			if eh.handle(h) {
				return false
			}
			if err == sentinel {
				return true
			}
		}
	}
	if e.err == nil {
		e.err = &err
	}
	bail(e)
	panic("errd: unreachable")
}

func processDeferError(e *E, err error) {
	eh := errorHandler{e: e, err: &err}
	hadHandler := false
	// Apply handlers added by Defer methods. A zero deferred value signals that
	// we have custom defer handler for the subsequent fields.
	for i := len(e.deferred); i > 0 && e.deferred[i-1].f == nil; i-- {
		hadHandler = true
		if eh.handle(e.deferred[i-1].x.(Handler)) {
			return
		}
	}
	if !hadHandler {
		for _, h := range e.runner.defaultHandlers {
			if eh.handle(h) {
				return
			}
		}
	}
	if e.err == nil {
		e.err = &err
	}
}

func processError(e *E, err error, handlers []Handler) {
	eh := errorHandler{e: e, err: &err}
	for _, h := range handlers {
		if eh.handle(h) {
			return
		}
	}
	if len(handlers) == 0 {
		for _, h := range e.runner.defaultHandlers {
			if eh.handle(h) {
				return
			}
		}
	}
	if e.err == nil {
		e.err = &err
	}
	bail(e)
}

func bail(e *E) {
	// Do defers now and save an extra defer.
	doDefers(e, 0)
	panic(errOurPanic)
}
<commit_msg>move Default in go doc under Runner<commit_after>// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package errd

import (
	"context"
	"errors"
	"fmt"
)

// Default is the default Runner comfiguration.
var (
	Default *Runner = WithDefault()
)

// Run calls Default.Run(f)
func Run(f func(*E)) (err error) {
	return Default.Run(f)
}

// RunWithContext calls Default.RunWithContext(ctxt, f)
func RunWithContext(ctxt context.Context, f func(*E)) (err error) {
	return Default.RunWithContext(ctxt, f)
}

// A Runner defines a default way to handle errors and options.
type Runner struct {
	*config
	context context.Context
}

// WithDefault returns a new Config for the given default handlers.
func WithDefault(h ...Handler) *Runner {
	return &Runner{
		config: &config{
			defaultHandlers: h,
		},
	}
}

// Run starts a new error handling scope. The function returns whenever an error
// is encountered with one of the methods on E.
func (r *Runner) Run(f func(e *E)) (err error) {
	// state := c.state
	var e E
	e.runner = r.config
	e.deferred = e.buf[:0]
	defer doRecover(&e, &err)
	f(&e)
	doDefers(&e, 0)
	if e.err != nil {
		return *e.err
	}
	return nil
}

// RunWithContext starts a new error handling scope. The function returns
// whenever an error is encountered with one of the methods on E.
func (r *Runner) RunWithContext(ctxt context.Context, f func(e *E)) (err error) {
	// Do defers now to save on an extra defer.
	// state := c.state
	var e E
	e.runner = r.config
	e.deferred = e.buf[:0]
	e.context = ctxt
	defer doRecover(&e, &err)
	f(&e)
	// Do defers now to save on an extra defer.
	doDefers(&e, 0)
	if e.err != nil {
		return *e.err
	}
	return nil
}

type config struct {
	defaultHandlers []Handler

	// inPanic indicates a panic is occurring: a copy of this Config with inPanic
	// set is assigned to the state if a panic occurs. This removes this field
	// from core.
	inPanic bool
}

const bufSize = 3

type core struct {
	// Fits into 128 bytes; 2 cache lines on many modern architectures.
	runner   *config
	deferred []deferData
	buf      [bufSize]deferData
	err      *error
	context  context.Context
}

// An E coordinates the error and defer handling.
type E struct{ core }

var errHandlerFirst = errors.New("errd: handler may not be first argument")

// Must causes a call to Run to return on error. An error is detected if err
// is non-nil and if it is still non-nil after passing it to error handling.
func (e *E) Must(err error, h ...Handler) {
	if err != nil {
		processError(e, err, h)
	}
}

// State represents the error state passed to custom error handlers.
type State interface {
	// Context returns the context set by WithContext, or context.TODO
	// otherwise.
	Context() context.Context

	// Panicing reports whether the error resulted from a panic. If true,
	// the panic will be resume after error handling completes. An error handler
	// cannot rewrite an error when panicing.
	Panicing() bool

	// Err reports the first error that passed through an error handler chain.
	// Note that this is always a different error (or nil) than the one passed
	// to an error handler.
	Err() error
}

type state struct{ core }

func (s *state) Context() context.Context {
	if s.context == nil {
		return context.TODO()
	}
	return s.context
}

func (s *state) Panicing() bool { return s.runner.inPanic }

func (s *state) Err() error {
	if s.err == nil {
		return nil
	}
	return *s.err
}

var errOurPanic = errors.New("errd: our panic")

func doRecover(e *E, err *error) {
	switch r := recover(); r {
	case nil:
	case errOurPanic:
		finishDefer(e, err)
		*err = *e.err
	default:
		if !e.runner.inPanic {
			c := *e.runner
			c.inPanic = true
			e.runner = &c
		}
		err2, ok := r.(error)
		if !ok {
			err2 = fmt.Errorf("errd: paniced: %v", r)
		}
		e.err = &err2
		finishDefer(e, err)
		// Check whether there are still defers left to do and then
		// recursively defer.
		panic(r)
	}
}

func doDefers(e *E, barrier int) {
	for len(e.deferred) > barrier {
		i := len(e.deferred) - 1
		d := e.deferred[i]
		e.deferred = e.deferred[:i]
		if d.f == nil {
			continue
		}
		if err := d.f((*state)(e), d.x); err != nil {
			processDeferError(e, err)
		}
	}
}

// finishDefer processes remaining defers after we already have a panic.
// We therefore ignore any panic caught here, knowing that we will panic on an
// older panic after returning.
func finishDefer(e *E, err *error) {
	if len(e.deferred) > 0 {
		defer doRecover(e, err)
		doDefers(e, 0)
	}
}

type errorHandler struct {
	e   *E
	err *error
}

func (h errorHandler) handle(eh Handler) (done bool) {
	newErr := eh.Handle((*state)(h.e), *h.err)
	if newErr == nil {
		return true
	}
	*h.err = newErr
	return false

}

func processErrorSentinel(e *E, err, sentinel error, handlers []Handler) bool {
	eh := errorHandler{e: e, err: &err}
	for _, h := range handlers {
		if eh.handle(h) {
			return false
		}
		if err == sentinel {
			return true
		}
	}
	if len(handlers) == 0 {
		for _, h := range e.runner.defaultHandlers {
			if eh.handle(h) {
				return false
			}
			if err == sentinel {
				return true
			}
		}
	}
	if e.err == nil {
		e.err = &err
	}
	bail(e)
	panic("errd: unreachable")
}

func processDeferError(e *E, err error) {
	eh := errorHandler{e: e, err: &err}
	hadHandler := false
	// Apply handlers added by Defer methods. A zero deferred value signals that
	// we have custom defer handler for the subsequent fields.
	for i := len(e.deferred); i > 0 && e.deferred[i-1].f == nil; i-- {
		hadHandler = true
		if eh.handle(e.deferred[i-1].x.(Handler)) {
			return
		}
	}
	if !hadHandler {
		for _, h := range e.runner.defaultHandlers {
			if eh.handle(h) {
				return
			}
		}
	}
	if e.err == nil {
		e.err = &err
	}
}

func processError(e *E, err error, handlers []Handler) {
	eh := errorHandler{e: e, err: &err}
	for _, h := range handlers {
		if eh.handle(h) {
			return
		}
	}
	if len(handlers) == 0 {
		for _, h := range e.runner.defaultHandlers {
			if eh.handle(h) {
				return
			}
		}
	}
	if e.err == nil {
		e.err = &err
	}
	bail(e)
}

func bail(e *E) {
	// Do defers now and save an extra defer.
	doDefers(e, 0)
	panic(errOurPanic)
}
<|endoftext|>


<commit_before>package config

import (
	"encoding/json"
	"os"

	"github.com/koding/multiconfig"
)

var (
	conf *Config
)

// Returns config, if it is nil, panics
func MustGet() *Config {
	if conf == nil {
		panic("config is not set, please call Config.MustRead(pathToConfFile)")
	}

	return conf
}

// MustRead takes a relative file path
// and tries to open and read it into Config struct
// If file is not there or file is not given, it panics
// If the given file is not formatted well, panics
func MustRead(path string) *Config {
	conf = &Config{}

	d := &multiconfig.DefaultLoader{
		Loader: multiconfig.MultiLoader(
			&multiconfig.TOMLLoader{Path: path},
			&multiconfig.EnvironmentLoader{Prefix: "KONFIG_SOCIALAPI"},
		),
	}

	if err := d.Load(conf); err != nil {
		panic(err)
	}

	return conf
}

type EnvJSONLoader struct {
	Name string
}

func (e *EnvJSONLoader) Load(s interface{}) error {
	v := os.Getenv(e.Name)
	if v == "" {
		// we are ignoring this case when the config is not set
		// reading a Specific Env key is not mandatory
		return nil
	}

	return json.Unmarshal([]byte(v), s)
}
<commit_msg>Socialapi: remove unused code block<commit_after>package config

import "github.com/koding/multiconfig"

var (
	conf *Config
)

// Returns config, if it is nil, panics
func MustGet() *Config {
	if conf == nil {
		panic("config is not set, please call Config.MustRead(pathToConfFile)")
	}

	return conf
}

// MustRead takes a relative file path
// and tries to open and read it into Config struct
// If file is not there or file is not given, it panics
// If the given file is not formatted well, panics
func MustRead(path string) *Config {
	conf = &Config{}

	d := &multiconfig.DefaultLoader{
		Loader: multiconfig.MultiLoader(
			&multiconfig.TOMLLoader{Path: path},
			&multiconfig.EnvironmentLoader{Prefix: "KONFIG_SOCIALAPI"},
		),
	}

	if err := d.Load(conf); err != nil {
		panic(err)
	}

	return conf
}
<|endoftext|>


<commit_before>package core

import (
	"time"

	"github.com/af83/edwig/model"
)

type StopAreaUpdateRequestId string

type StopAreaUpdateRequest struct {
	id         StopAreaUpdateRequestId
	stopAreaId model.StopAreaId
	createdAt  time.Time
}

func NewStopAreaUpdateRequest(givenStopAreaId model.StopAreaId) *StopAreaUpdateRequest {
	return &StopAreaUpdateRequest{
		id:         StopAreaUpdateRequestId(model.DefaultUUIDGenerator().NewUUID()),
		stopAreaId: givenStopAreaId,
		createdAt:  model.DefaultClock().Now(),
	}
}

func (stopAreaUpdateRequest *StopAreaUpdateRequest) Id() StopAreaUpdateRequestId {
	return stopAreaUpdateRequest.id
}

func (stopAreaUpdateRequest *StopAreaUpdateRequest) StopAreaId() model.StopAreaId {
	return stopAreaUpdateRequest.stopAreaId
}

func (stopAreaUpdateRequest *StopAreaUpdateRequest) CreatedAt() time.Time {
	return stopAreaUpdateRequest.createdAt
}
<commit_msg>small change in a method argument<commit_after>package core

import (
	"time"

	"github.com/af83/edwig/model"
)

type StopAreaUpdateRequestId string

type StopAreaUpdateRequest struct {
	id         StopAreaUpdateRequestId
	stopAreaId model.StopAreaId
	createdAt  time.Time
}

func NewStopAreaUpdateRequest(stopAreaId model.StopAreaId) *StopAreaUpdateRequest {
	return &StopAreaUpdateRequest{
		id:         StopAreaUpdateRequestId(model.DefaultUUIDGenerator().NewUUID()),
		stopAreaId: stopAreaId,
		createdAt:  model.DefaultClock().Now(),
	}
}

func (stopAreaUpdateRequest *StopAreaUpdateRequest) Id() StopAreaUpdateRequestId {
	return stopAreaUpdateRequest.id
}

func (stopAreaUpdateRequest *StopAreaUpdateRequest) StopAreaId() model.StopAreaId {
	return stopAreaUpdateRequest.stopAreaId
}

func (stopAreaUpdateRequest *StopAreaUpdateRequest) CreatedAt() time.Time {
	return stopAreaUpdateRequest.createdAt
}
<|endoftext|>


<commit_before>/*
ImagePartition Action

This action creates an image file, partitions it and formats the filesystems.

Yaml syntax:
 - action: image-partition
   imagename: image_name
   imagesize: size
   partitiontype: gpt
   partitions:
     <list of partitions>
   mountpoints:
     <list of mount points>

Mandatory properties:

- imagename -- the name of the image file.

- imagesize -- generated image size in human-readable form, examples: 100MB, 1GB, etc.

- partitiontype -- partition table type. Currently only 'gpt' and 'msdos'
partition tables are supported.

- partitions -- list of partitions, at least one partition is needed.
Partition properties are described below.

- mountpoints -- list of mount points for partitions.
Properties for mount points are described below.

Yaml syntax for partitions:

   partitions:
     - name: label
	   name: partition name
	   fs: filesystem
	   start: offset
	   end: offset
	   flags: list of flags

Mandatory properties:

- name -- is used for referencing named partition for mount points
configuration (below) and label the filesystem located on this partition.

- fs -- filesystem type used for formatting.

NB: the FAT (vfat) filesystem is named 'fat32' in configuration file.

- start -- offset from beginning of the disk there the partition starts.

- end -- offset from beginning of the disk there the partition ends.

For 'start' and 'end' properties offset can be written in human readable
form -- '32MB', '1GB' or as disk percentage -- '100%'.

Optional properties:

- flags -- list of additional flags for partition compatible with parted(8)
'set' command.

Yaml syntax for mount points:

   mountpoints:
     - mountpoint: path
	   partition: partition label
	   options: list of options

Mandatory properties:

- partition -- partition name for mounting.

- mountpoint -- path in the target root filesystem where the named partition
should be mounted.

Optional properties:

- options -- list of options to be added to appropriate entry in fstab file.

Layout example for Raspberry PI 3:

 - action: image-partition
   imagename: "debian-rpi3.img"
   imagesize: 1GB
   partitiontype: msdos
   mountpoints:
     - mountpoint: /
       partition: root
     - mountpoint: /boot/firmware
       partition: firmware
       options: [ x-systemd.automount ]
   partitions:
     - name: firmware
       fs: fat32
       start: 0%
       end: 64MB
     - name: root
       fs: ext4
       start: 64MB
       end: 100%
       flags: [ boot ]
*/
package actions

import (
	"errors"
	"fmt"
	"github.com/docker/go-units"
	"github.com/go-debos/fakemachine"
	"os"
	"os/exec"
	"path"
	"strings"
	"syscall"

	"github.com/go-debos/debos"
)

type Partition struct {
	number int
	Name   string
	Start  string
	End    string
	FS     string
	Flags  []string
	FSUUID string
}

type Mountpoint struct {
	Mountpoint string
	Partition  string
	Options    []string
	part       *Partition
}

type ImagePartitionAction struct {
	debos.BaseAction `yaml:",inline"`
	ImageName        string
	ImageSize        string
	PartitionType    string
	Partitions       []Partition
	Mountpoints      []Mountpoint
	size             int64
	usingLoop        bool
}

func (i *ImagePartitionAction) generateFSTab(context *debos.DebosContext) error {
	context.ImageFSTab.Reset()

	for _, m := range i.Mountpoints {
		options := []string{"defaults"}
		options = append(options, m.Options...)
		if m.part.FSUUID == "" {
			return fmt.Errorf("Missing fs UUID for partition %s!?!", m.part.Name)
		}
		fs := m.part.FS
		switch m.part.FS {
		case "fat32":
			fs = "vfat"
		}
		context.ImageFSTab.WriteString(fmt.Sprintf("UUID=%s\t%s\t%s\t%s\t0\t0\n",
			m.part.FSUUID, m.Mountpoint, fs,
			strings.Join(options, ",")))
	}

	return nil
}

func (i *ImagePartitionAction) generateKernelRoot(context *debos.DebosContext) error {
	for _, m := range i.Mountpoints {
		if m.Mountpoint == "/" {
			if m.part.FSUUID == "" {
				return errors.New("No fs UUID for root partition !?!")
			}
			context.ImageKernelRoot = fmt.Sprintf("root=UUID=%s", m.part.FSUUID)
			break
		}
	}

	return nil
}

func (i ImagePartitionAction) getPartitionDevice(number int, context debos.DebosContext) string {
	/* If the iamge device has a digit as the last character, the partition
	 * suffix is p<number> else it's just <number> */
	last := context.Image[len(context.Image)-1]
	if last >= '0' && last <= '9' {
		return fmt.Sprintf("%sp%d", context.Image, number)
	} else {
		return fmt.Sprintf("%s%d", context.Image, number)
	}
}

func (i ImagePartitionAction) PreMachine(context *debos.DebosContext, m *fakemachine.Machine,
	args *[]string) error {
	err := m.CreateImage(i.ImageName, i.size)
	if err != nil {
		return err
	}

	context.Image = "/dev/vda"
	*args = append(*args, "--internal-image", "/dev/vda")
	return nil
}

func (i ImagePartitionAction) formatPartition(p *Partition, context debos.DebosContext) error {
	label := fmt.Sprintf("Formatting partition %d", p.number)
	path := i.getPartitionDevice(p.number, context)

	cmdline := []string{}
	switch p.FS {
	case "fat32":
		cmdline = append(cmdline, "mkfs.vfat", "-n", p.Name)
	default:
		cmdline = append(cmdline, fmt.Sprintf("mkfs.%s", p.FS), "-L", p.Name)
	}
	cmdline = append(cmdline, path)

	debos.Command{}.Run(label, cmdline...)

	uuid, err := exec.Command("blkid", "-o", "value", "-s", "UUID", "-p", "-c", "none", path).Output()
	if err != nil {
		return fmt.Errorf("Failed to get uuid: %s", err)
	}
	p.FSUUID = strings.TrimSpace(string(uuid[:]))

	return nil
}

func (i ImagePartitionAction) PreNoMachine(context *debos.DebosContext) error {

	img, err := os.OpenFile(i.ImageName, os.O_WRONLY|os.O_CREATE, 0666)
	if err != nil {
		return fmt.Errorf("Couldn't open image file: %v", err)
	}

	err = img.Truncate(i.size)
	if err != nil {
		return fmt.Errorf("Couldn't resize image file: %v", err)
	}

	img.Close()

	loop, err := exec.Command("losetup", "-f", "--show", i.ImageName).Output()
	if err != nil {
		return fmt.Errorf("Failed to setup loop device")
	}
	context.Image = strings.TrimSpace(string(loop[:]))
	i.usingLoop = true

	return nil
}

func (i ImagePartitionAction) Run(context *debos.DebosContext) error {
	i.LogStart()
	err := debos.Command{}.Run("parted", "parted", "-s", context.Image, "mklabel", i.PartitionType)
	if err != nil {
		return err
	}
	for idx, _ := range i.Partitions {
		p := &i.Partitions[idx]
		var name string
		if i.PartitionType == "gpt" {
			name = p.Name
		} else {
			name = "primary"
		}
		err = debos.Command{}.Run("parted", "parted", "-a", "none", "-s", context.Image, "mkpart",
			name, p.FS, p.Start, p.End)
		if err != nil {
			return err
		}

		if p.Flags != nil {
			for _, flag := range p.Flags {
				err = debos.Command{}.Run("parted", "parted", "-s", context.Image, "set",
					fmt.Sprintf("%d", p.number), flag, "on")
				if err != nil {
					return err
				}
			}
		}

		err = i.formatPartition(p, *context)
		if err != nil {
			return err
		}
	}

	context.ImageMntDir = path.Join(context.Scratchdir, "mnt")
	os.MkdirAll(context.ImageMntDir, 755)
	for _, m := range i.Mountpoints {
		dev := i.getPartitionDevice(m.part.number, *context)
		mntpath := path.Join(context.ImageMntDir, m.Mountpoint)
		os.MkdirAll(mntpath, 755)
		var fs string
		switch m.part.FS {
		case "fat32":
			fs = "vfat"
		default:
			fs = m.part.FS
		}
		err := syscall.Mount(dev, mntpath, fs, 0, "")
		if err != nil {
			return fmt.Errorf("%s mount failed: %v", m.part.Name, err)
		}
	}

	err = i.generateFSTab(context)
	if err != nil {
		return err
	}

	err = i.generateKernelRoot(context)
	if err != nil {
		return err
	}

	return nil
}

func (i ImagePartitionAction) Cleanup(context debos.DebosContext) error {
	for idx := len(i.Mountpoints) - 1; idx >= 0; idx-- {
		m := i.Mountpoints[idx]
		mntpath := path.Join(context.ImageMntDir, m.Mountpoint)
		syscall.Unmount(mntpath, 0)
	}

	if i.usingLoop {
		exec.Command("losetup", "-d", context.Image).Run()
	}

	return nil
}

func (i *ImagePartitionAction) Verify(context *debos.DebosContext) error {
	num := 1
	for idx, _ := range i.Partitions {
		p := &i.Partitions[idx]
		p.number = num
		num++
		if p.Name == "" {
			return fmt.Errorf("Partition without a name")
		}
		if p.Start == "" {
			return fmt.Errorf("Partition %s missing start", p.Name)
		}
		if p.End == "" {
			return fmt.Errorf("Partition %s missing end", p.Name)
		}

		if p.FS == "" {
			return fmt.Errorf("Partition %s missing fs type", p.Name)
		}
	}

	for idx, _ := range i.Mountpoints {
		m := &i.Mountpoints[idx]
		for pidx, _ := range i.Partitions {
			p := &i.Partitions[pidx]
			if m.Partition == p.Name {
				m.part = p
				break
			}
		}
		if m.part == nil {
			return fmt.Errorf("Couldn't fount partition for %s", m.Mountpoint)
		}
	}

	size, err := units.FromHumanSize(i.ImageSize)
	if err != nil {
		return fmt.Errorf("Failed to parse image size: %s", i.ImageSize)
	}

	i.size = size
	return nil
}
<commit_msg>Adjust for fakemachine image API update<commit_after>/*
ImagePartition Action

This action creates an image file, partitions it and formats the filesystems.

Yaml syntax:
 - action: image-partition
   imagename: image_name
   imagesize: size
   partitiontype: gpt
   partitions:
     <list of partitions>
   mountpoints:
     <list of mount points>

Mandatory properties:

- imagename -- the name of the image file.

- imagesize -- generated image size in human-readable form, examples: 100MB, 1GB, etc.

- partitiontype -- partition table type. Currently only 'gpt' and 'msdos'
partition tables are supported.

- partitions -- list of partitions, at least one partition is needed.
Partition properties are described below.

- mountpoints -- list of mount points for partitions.
Properties for mount points are described below.

Yaml syntax for partitions:

   partitions:
     - name: label
	   name: partition name
	   fs: filesystem
	   start: offset
	   end: offset
	   flags: list of flags

Mandatory properties:

- name -- is used for referencing named partition for mount points
configuration (below) and label the filesystem located on this partition.

- fs -- filesystem type used for formatting.

NB: the FAT (vfat) filesystem is named 'fat32' in configuration file.

- start -- offset from beginning of the disk there the partition starts.

- end -- offset from beginning of the disk there the partition ends.

For 'start' and 'end' properties offset can be written in human readable
form -- '32MB', '1GB' or as disk percentage -- '100%'.

Optional properties:

- flags -- list of additional flags for partition compatible with parted(8)
'set' command.

Yaml syntax for mount points:

   mountpoints:
     - mountpoint: path
	   partition: partition label
	   options: list of options

Mandatory properties:

- partition -- partition name for mounting.

- mountpoint -- path in the target root filesystem where the named partition
should be mounted.

Optional properties:

- options -- list of options to be added to appropriate entry in fstab file.

Layout example for Raspberry PI 3:

 - action: image-partition
   imagename: "debian-rpi3.img"
   imagesize: 1GB
   partitiontype: msdos
   mountpoints:
     - mountpoint: /
       partition: root
     - mountpoint: /boot/firmware
       partition: firmware
       options: [ x-systemd.automount ]
   partitions:
     - name: firmware
       fs: fat32
       start: 0%
       end: 64MB
     - name: root
       fs: ext4
       start: 64MB
       end: 100%
       flags: [ boot ]
*/
package actions

import (
	"errors"
	"fmt"
	"github.com/docker/go-units"
	"github.com/go-debos/fakemachine"
	"os"
	"os/exec"
	"path"
	"strings"
	"syscall"

	"github.com/go-debos/debos"
)

type Partition struct {
	number int
	Name   string
	Start  string
	End    string
	FS     string
	Flags  []string
	FSUUID string
}

type Mountpoint struct {
	Mountpoint string
	Partition  string
	Options    []string
	part       *Partition
}

type ImagePartitionAction struct {
	debos.BaseAction `yaml:",inline"`
	ImageName        string
	ImageSize        string
	PartitionType    string
	Partitions       []Partition
	Mountpoints      []Mountpoint
	size             int64
	usingLoop        bool
}

func (i *ImagePartitionAction) generateFSTab(context *debos.DebosContext) error {
	context.ImageFSTab.Reset()

	for _, m := range i.Mountpoints {
		options := []string{"defaults"}
		options = append(options, m.Options...)
		if m.part.FSUUID == "" {
			return fmt.Errorf("Missing fs UUID for partition %s!?!", m.part.Name)
		}
		fs := m.part.FS
		switch m.part.FS {
		case "fat32":
			fs = "vfat"
		}
		context.ImageFSTab.WriteString(fmt.Sprintf("UUID=%s\t%s\t%s\t%s\t0\t0\n",
			m.part.FSUUID, m.Mountpoint, fs,
			strings.Join(options, ",")))
	}

	return nil
}

func (i *ImagePartitionAction) generateKernelRoot(context *debos.DebosContext) error {
	for _, m := range i.Mountpoints {
		if m.Mountpoint == "/" {
			if m.part.FSUUID == "" {
				return errors.New("No fs UUID for root partition !?!")
			}
			context.ImageKernelRoot = fmt.Sprintf("root=UUID=%s", m.part.FSUUID)
			break
		}
	}

	return nil
}

func (i ImagePartitionAction) getPartitionDevice(number int, context debos.DebosContext) string {
	/* If the iamge device has a digit as the last character, the partition
	 * suffix is p<number> else it's just <number> */
	last := context.Image[len(context.Image)-1]
	if last >= '0' && last <= '9' {
		return fmt.Sprintf("%sp%d", context.Image, number)
	} else {
		return fmt.Sprintf("%s%d", context.Image, number)
	}
}

func (i ImagePartitionAction) PreMachine(context *debos.DebosContext, m *fakemachine.Machine,
	args *[]string) error {
	image, err := m.CreateImage(i.ImageName, i.size)
	if err != nil {
		return err
	}

	context.Image = image
	*args = append(*args, "--internal-image", image)
	return nil
}

func (i ImagePartitionAction) formatPartition(p *Partition, context debos.DebosContext) error {
	label := fmt.Sprintf("Formatting partition %d", p.number)
	path := i.getPartitionDevice(p.number, context)

	cmdline := []string{}
	switch p.FS {
	case "fat32":
		cmdline = append(cmdline, "mkfs.vfat", "-n", p.Name)
	default:
		cmdline = append(cmdline, fmt.Sprintf("mkfs.%s", p.FS), "-L", p.Name)
	}
	cmdline = append(cmdline, path)

	debos.Command{}.Run(label, cmdline...)

	uuid, err := exec.Command("blkid", "-o", "value", "-s", "UUID", "-p", "-c", "none", path).Output()
	if err != nil {
		return fmt.Errorf("Failed to get uuid: %s", err)
	}
	p.FSUUID = strings.TrimSpace(string(uuid[:]))

	return nil
}

func (i ImagePartitionAction) PreNoMachine(context *debos.DebosContext) error {

	img, err := os.OpenFile(i.ImageName, os.O_WRONLY|os.O_CREATE, 0666)
	if err != nil {
		return fmt.Errorf("Couldn't open image file: %v", err)
	}

	err = img.Truncate(i.size)
	if err != nil {
		return fmt.Errorf("Couldn't resize image file: %v", err)
	}

	img.Close()

	loop, err := exec.Command("losetup", "-f", "--show", i.ImageName).Output()
	if err != nil {
		return fmt.Errorf("Failed to setup loop device")
	}
	context.Image = strings.TrimSpace(string(loop[:]))
	i.usingLoop = true

	return nil
}

func (i ImagePartitionAction) Run(context *debos.DebosContext) error {
	i.LogStart()
	err := debos.Command{}.Run("parted", "parted", "-s", context.Image, "mklabel", i.PartitionType)
	if err != nil {
		return err
	}
	for idx, _ := range i.Partitions {
		p := &i.Partitions[idx]
		var name string
		if i.PartitionType == "gpt" {
			name = p.Name
		} else {
			name = "primary"
		}
		err = debos.Command{}.Run("parted", "parted", "-a", "none", "-s", context.Image, "mkpart",
			name, p.FS, p.Start, p.End)
		if err != nil {
			return err
		}

		if p.Flags != nil {
			for _, flag := range p.Flags {
				err = debos.Command{}.Run("parted", "parted", "-s", context.Image, "set",
					fmt.Sprintf("%d", p.number), flag, "on")
				if err != nil {
					return err
				}
			}
		}

		err = i.formatPartition(p, *context)
		if err != nil {
			return err
		}
	}

	context.ImageMntDir = path.Join(context.Scratchdir, "mnt")
	os.MkdirAll(context.ImageMntDir, 755)
	for _, m := range i.Mountpoints {
		dev := i.getPartitionDevice(m.part.number, *context)
		mntpath := path.Join(context.ImageMntDir, m.Mountpoint)
		os.MkdirAll(mntpath, 755)
		var fs string
		switch m.part.FS {
		case "fat32":
			fs = "vfat"
		default:
			fs = m.part.FS
		}
		err := syscall.Mount(dev, mntpath, fs, 0, "")
		if err != nil {
			return fmt.Errorf("%s mount failed: %v", m.part.Name, err)
		}
	}

	err = i.generateFSTab(context)
	if err != nil {
		return err
	}

	err = i.generateKernelRoot(context)
	if err != nil {
		return err
	}

	return nil
}

func (i ImagePartitionAction) Cleanup(context debos.DebosContext) error {
	for idx := len(i.Mountpoints) - 1; idx >= 0; idx-- {
		m := i.Mountpoints[idx]
		mntpath := path.Join(context.ImageMntDir, m.Mountpoint)
		syscall.Unmount(mntpath, 0)
	}

	if i.usingLoop {
		exec.Command("losetup", "-d", context.Image).Run()
	}

	return nil
}

func (i *ImagePartitionAction) Verify(context *debos.DebosContext) error {
	num := 1
	for idx, _ := range i.Partitions {
		p := &i.Partitions[idx]
		p.number = num
		num++
		if p.Name == "" {
			return fmt.Errorf("Partition without a name")
		}
		if p.Start == "" {
			return fmt.Errorf("Partition %s missing start", p.Name)
		}
		if p.End == "" {
			return fmt.Errorf("Partition %s missing end", p.Name)
		}

		if p.FS == "" {
			return fmt.Errorf("Partition %s missing fs type", p.Name)
		}
	}

	for idx, _ := range i.Mountpoints {
		m := &i.Mountpoints[idx]
		for pidx, _ := range i.Partitions {
			p := &i.Partitions[pidx]
			if m.Partition == p.Name {
				m.part = p
				break
			}
		}
		if m.part == nil {
			return fmt.Errorf("Couldn't fount partition for %s", m.Mountpoint)
		}
	}

	size, err := units.FromHumanSize(i.ImageSize)
	if err != nil {
		return fmt.Errorf("Failed to parse image size: %s", i.ImageSize)
	}

	i.size = size
	return nil
}
<|endoftext|>