<commit_before>package gmf

/*

#cgo pkg-config: libavcodec libavutil

#include <string.h>

#include "libavcodec/avcodec.h"
#include "libavutil/channel_layout.h"
#include "libavutil/samplefmt.h"
#include "libavutil/opt.h"
#include "libavutil/mem.h"

static int check_sample_fmt(AVCodec *codec, enum AVSampleFormat sample_fmt) {
    const enum AVSampleFormat *p = codec->sample_fmts;

    while (*p != AV_SAMPLE_FMT_NONE) {
        if (*p == sample_fmt)
            return 1;
        p++;
    }
    return 0;
}

static int select_sample_rate(AVCodec *codec) {
    const int *p;
    int best_samplerate = 0;

    if (!codec->supported_samplerates)
        return 44100;

    p = codec->supported_samplerates;
    while (*p) {
        best_samplerate = FFMAX(*p, best_samplerate);
        p++;
    }
    return best_samplerate;
}

static int select_channel_layout(AVCodec *codec) {
    const uint64_t *p;
    uint64_t best_ch_layout = 0;
    int best_nb_channels    = 0;

    if (!codec->channel_layouts)
        return AV_CH_LAYOUT_STEREO;

    p = codec->channel_layouts;
    while (*p) {
        int nb_channels = av_get_channel_layout_nb_channels(*p);

        if (nb_channels > best_nb_channels) {
            best_ch_layout   = *p;
            best_nb_channels = nb_channels;
        }
        p++;
    }
    return best_ch_layout;
}

*/
import "C"

import (
	"errors"
	"fmt"
	"unsafe"
	//	"log"
)

var (
	AV_CODEC_ID_MPEG1VIDEO int = C.AV_CODEC_ID_MPEG1VIDEO
	AV_CODEC_ID_MPEG2VIDEO int = C.AV_CODEC_ID_MPEG2VIDEO
	AV_CODEC_ID_H264       int = C.AV_CODEC_ID_H264
	AV_CODEC_ID_MPEG4      int = C.AV_CODEC_ID_MPEG4
	AV_CODEC_ID_JPEG2000   int = C.AV_CODEC_ID_JPEG2000
	AV_CODEC_ID_MJPEG      int = C.AV_CODEC_ID_MJPEG
	AV_CODEC_ID_MSMPEG4V1  int = C.AV_CODEC_ID_MSMPEG4V1
	AV_CODEC_ID_MSMPEG4V2  int = C.AV_CODEC_ID_MSMPEG4V2
	AV_CODEC_ID_MSMPEG4V3  int = C.AV_CODEC_ID_MSMPEG4V3
	AV_CODEC_ID_WMV1       int = C.AV_CODEC_ID_WMV1
	AV_CODEC_ID_WMV2       int = C.AV_CODEC_ID_WMV2
	AV_CODEC_ID_FLV1       int = C.AV_CODEC_ID_FLV1
	AV_CODEC_ID_PNG        int = C.AV_CODEC_ID_PNG
	AV_CODEC_ID_TIFF       int = C.AV_CODEC_ID_TIFF
	AV_CODEC_ID_GIF        int = C.AV_CODEC_ID_GIF

	CODEC_FLAG_GLOBAL_HEADER int   = C.CODEC_FLAG_GLOBAL_HEADER
	FF_MB_DECISION_SIMPLE    int   = C.FF_MB_DECISION_SIMPLE
	FF_MB_DECISION_BITS      int   = C.FF_MB_DECISION_BITS
	FF_MB_DECISION_RD        int   = C.FF_MB_DECISION_RD
	AV_SAMPLE_FMT_S16        int32 = C.AV_SAMPLE_FMT_S16
	AV_SAMPLE_FMT_S16P       int32 = C.AV_SAMPLE_FMT_S16P
)

type SampleFmt int

type CodecCtx struct {
	codec      *Codec
	avCodecCtx *C.struct_AVCodecContext
	CgoMemoryManage
}

func NewCodecCtx(codec *Codec, options ...[]*Option) *CodecCtx {
	result := &CodecCtx{codec: codec}

	codecctx := C.avcodec_alloc_context3(codec.avCodec)
	if codecctx == nil {
		return nil
	}

	C.avcodec_get_context_defaults3(codecctx, codec.avCodec)

	result.avCodecCtx = codecctx

	// we're really expecting only one options-array —
	// variadic arg is used for backward compatibility
	if len(options) == 1 {
		for _, option := range options[0] {
			option.Set(result.avCodecCtx)
		}
	}

	return result
}

func (this *CodecCtx) CopyExtra(ist *Stream) *CodecCtx {
	codec := this.avCodecCtx
	icodec := ist.CodecCtx().avCodecCtx

	codec.bits_per_raw_sample = icodec.bits_per_raw_sample
	codec.chroma_sample_location = icodec.chroma_sample_location

	codec.codec_id = icodec.codec_id
	codec.codec_type = icodec.codec_type

	// codec.codec_tag = icodec.codec_tag

	codec.rc_max_rate = icodec.rc_max_rate
	codec.rc_buffer_size = icodec.rc_buffer_size

	codec.field_order = icodec.field_order

	codec.extradata = (*_Ctype_uint8_t)(C.av_mallocz((_Ctype_size_t)((C.uint64_t)(icodec.extradata_size) + C.FF_INPUT_BUFFER_PADDING_SIZE)))

	C.memcpy(unsafe.Pointer(codec.extradata), unsafe.Pointer(icodec.extradata), (_Ctype_size_t)(icodec.extradata_size))
	codec.extradata_size = icodec.extradata_size
	codec.bits_per_coded_sample = icodec.bits_per_coded_sample

	codec.has_b_frames = icodec.has_b_frames

	return this
}

func (this *CodecCtx) CopyBasic(ist *Stream) *CodecCtx {
	codec := this.avCodecCtx
	icodec := ist.CodecCtx().avCodecCtx

	codec.bit_rate = icodec.bit_rate
	codec.pix_fmt = icodec.pix_fmt
	codec.width = icodec.width
	codec.height = icodec.height

	codec.time_base = icodec.time_base
	codec.time_base.num *= icodec.ticks_per_frame

	codec.sample_fmt = icodec.sample_fmt
	codec.sample_rate = icodec.sample_rate
	codec.channels = icodec.channels

	codec.channel_layout = icodec.channel_layout

	return this
}

func (this *CodecCtx) Open(dict *Dict) error {
	if this.IsOpen() {
		return nil
	}

	var avDict *C.struct_AVDictionary
	if dict != nil {
		avDict = dict.avDict
	}

	if averr := C.avcodec_open2(this.avCodecCtx, this.codec.avCodec, &avDict); averr < 0 {
		return errors.New(fmt.Sprintf("Error opening codec '%s:%s', averror: %s", this.codec.Name(), this.codec.LongName(), AvError(int(averr))))
	}

	return nil
}

func (this *CodecCtx) Close() {
	if nil != this.avCodecCtx {
		C.avcodec_close(this.avCodecCtx)
		this.avCodecCtx = nil
	}
}

func (this *CodecCtx) Free() {
	this.CloseAndRelease()
}

func (this *CodecCtx) CloseAndRelease() {
	this.Close()
	C.av_freep(unsafe.Pointer(&this.avCodecCtx))
}

// @todo
func (this *CodecCtx) SetOpt() {
	// mock
	C.av_opt_set_int(unsafe.Pointer(this.avCodecCtx), C.CString("refcounted_frames"), 1, 0)
}

func (this *CodecCtx) Codec() *Codec {
	return &Codec{avCodec: this.avCodecCtx.codec}
}

func (this *CodecCtx) Id() int {
	return int(this.avCodecCtx.codec_id)
}

func (this *CodecCtx) Type() int32 {
	return int32(this.avCodecCtx.codec_type)
}

func (this *CodecCtx) Width() int {
	return int(this.avCodecCtx.width)
}

func (this *CodecCtx) Height() int {
	return int(this.avCodecCtx.height)
}

func (this *CodecCtx) PixFmt() int32 {
	return int32(this.avCodecCtx.pix_fmt)
}

func (this *CodecCtx) FrameSize() int {
	return int(this.avCodecCtx.frame_size)
}

func (this *CodecCtx) SampleFmt() int32 {
	return this.avCodecCtx.sample_fmt
}

func (this *CodecCtx) SampleRate() int {
	return int(this.avCodecCtx.sample_rate)
}

func (this *CodecCtx) Profile() int {
	return int(this.avCodecCtx.profile)
}

func (this *CodecCtx) IsOpen() bool {
	return (int(C.avcodec_is_open(this.avCodecCtx)) > 0)
}

func (this *CodecCtx) SetProfile(profile int) *CodecCtx {
	this.avCodecCtx.profile = C.int(profile)
	return this
}

func (this *CodecCtx) TimeBase() AVRational {
	return AVRational(this.avCodecCtx.time_base)
}

func (this *CodecCtx) ChannelLayout() int {
	return int(this.avCodecCtx.channel_layout)
}
func (this *CodecCtx) SetChannelLayout(channelLayout int) {
	this.avCodecCtx.channel_layout = C.uint64_t(channelLayout)
}

func (this *CodecCtx) BitRate() int {
	return int(this.avCodecCtx.bit_rate)
}

func (this *CodecCtx) Channels() int {
	return int(this.avCodecCtx.channels)
}

func (this *CodecCtx) SetBitRate(val int) *CodecCtx {
	this.avCodecCtx.bit_rate = C.int64_t(val)
	return this
}

func (this *CodecCtx) SetWidth(val int) *CodecCtx {
	this.avCodecCtx.width = C.int(val)
	return this
}

func (this *CodecCtx) SetHeight(val int) *CodecCtx {
	this.avCodecCtx.height = C.int(val)
	return this
}

func (this *CodecCtx) SetDimension(w, h int) *CodecCtx {
	this.avCodecCtx.width = C.int(w)
	this.avCodecCtx.height = C.int(h)
	return this
}

func (this *CodecCtx) SetTimeBase(val AVR) *CodecCtx {
	this.avCodecCtx.time_base.num = C.int(val.Num)
	this.avCodecCtx.time_base.den = C.int(val.Den)
	return this
}

func (this *CodecCtx) SetGopSize(val int) *CodecCtx {
	this.avCodecCtx.gop_size = C.int(val)
	return this
}

func (this *CodecCtx) SetMaxBFrames(val int) *CodecCtx {
	this.avCodecCtx.max_b_frames = C.int(val)
	return this
}

func (this *CodecCtx) SetPixFmt(val int32) *CodecCtx {
	this.avCodecCtx.pix_fmt = val
	return this
}

func (this *CodecCtx) SetFlag(flag int) *CodecCtx {
	this.avCodecCtx.flags |= C.int(flag)
	return this
}

func (this *CodecCtx) SetMbDecision(val int) *CodecCtx {
	this.avCodecCtx.mb_decision = C.int(val)
	return this
}

func (this *CodecCtx) SetSampleFmt(val int32) *CodecCtx {
	if int(C.check_sample_fmt(this.codec.avCodec, val)) == 0 {
		panic(fmt.Sprintf("encoder doesn't support sample format %s", GetSampleFmtName(val)))
	}

	this.avCodecCtx.sample_fmt = val
	return this
}

func (this *CodecCtx) SetSampleRate(val int) *CodecCtx {
	this.avCodecCtx.sample_rate = C.int(val)
	return this
}

var (
	FF_COMPLIANCE_VERY_STRICT  int = C.FF_COMPLIANCE_VERY_STRICT
	FF_COMPLIANCE_STRICT       int = C.FF_COMPLIANCE_STRICT
	FF_COMPLIANCE_NORMAL       int = C.FF_COMPLIANCE_NORMAL
	FF_COMPLIANCE_UNOFFICIAL   int = C.FF_COMPLIANCE_UNOFFICIAL
	FF_COMPLIANCE_EXPERIMENTAL int = C.FF_COMPLIANCE_EXPERIMENTAL
)

func (this *CodecCtx) SetStrictCompliance(val int) *CodecCtx {
	this.avCodecCtx.strict_std_compliance = C.int(val)
	return this
}

func (this *CodecCtx) SetHasBframes(val int) *CodecCtx {
	this.avCodecCtx.has_b_frames = C.int(val)
	return this
}

func (this *CodecCtx) SetChannels(val int) *CodecCtx {
	this.avCodecCtx.channels = C.int(val)
	return this
}

func (this *CodecCtx) SelectSampleRate() int {
	return int(C.select_sample_rate(this.codec.avCodec))
}

func (this *CodecCtx) SelectChannelLayout() int {
	return int(C.select_channel_layout(this.codec.avCodec))
}

func (this *CodecCtx) FlushBuffers() {
	C.avcodec_flush_buffers(this.avCodecCtx)
}

func (this *CodecCtx) Dump() {
	fmt.Println(this.avCodecCtx)
}
<commit_msg>Fix go 1.6 "cgo argument has Go pointer to Go pointer" error<commit_after>package gmf

/*

#cgo pkg-config: libavcodec libavutil

#include <string.h>

#include "libavcodec/avcodec.h"
#include "libavutil/channel_layout.h"
#include "libavutil/samplefmt.h"
#include "libavutil/opt.h"
#include "libavutil/mem.h"

static int check_sample_fmt(AVCodec *codec, enum AVSampleFormat sample_fmt) {
    const enum AVSampleFormat *p = codec->sample_fmts;

    while (*p != AV_SAMPLE_FMT_NONE) {
        if (*p == sample_fmt)
            return 1;
        p++;
    }
    return 0;
}

static int select_sample_rate(AVCodec *codec) {
    const int *p;
    int best_samplerate = 0;

    if (!codec->supported_samplerates)
        return 44100;

    p = codec->supported_samplerates;
    while (*p) {
        best_samplerate = FFMAX(*p, best_samplerate);
        p++;
    }
    return best_samplerate;
}

static int select_channel_layout(AVCodec *codec) {
    const uint64_t *p;
    uint64_t best_ch_layout = 0;
    int best_nb_channels    = 0;

    if (!codec->channel_layouts)
        return AV_CH_LAYOUT_STEREO;

    p = codec->channel_layouts;
    while (*p) {
        int nb_channels = av_get_channel_layout_nb_channels(*p);

        if (nb_channels > best_nb_channels) {
            best_ch_layout   = *p;
            best_nb_channels = nb_channels;
        }
        p++;
    }
    return best_ch_layout;
}

static void call_av_freep(AVCodecContext *out){
	return av_freep(&out);
}
*/
import "C"

import (
	"errors"
	"fmt"
	"unsafe"
	//	"log"
)

var (
	AV_CODEC_ID_MPEG1VIDEO int = C.AV_CODEC_ID_MPEG1VIDEO
	AV_CODEC_ID_MPEG2VIDEO int = C.AV_CODEC_ID_MPEG2VIDEO
	AV_CODEC_ID_H264       int = C.AV_CODEC_ID_H264
	AV_CODEC_ID_MPEG4      int = C.AV_CODEC_ID_MPEG4
	AV_CODEC_ID_JPEG2000   int = C.AV_CODEC_ID_JPEG2000
	AV_CODEC_ID_MJPEG      int = C.AV_CODEC_ID_MJPEG
	AV_CODEC_ID_MSMPEG4V1  int = C.AV_CODEC_ID_MSMPEG4V1
	AV_CODEC_ID_MSMPEG4V2  int = C.AV_CODEC_ID_MSMPEG4V2
	AV_CODEC_ID_MSMPEG4V3  int = C.AV_CODEC_ID_MSMPEG4V3
	AV_CODEC_ID_WMV1       int = C.AV_CODEC_ID_WMV1
	AV_CODEC_ID_WMV2       int = C.AV_CODEC_ID_WMV2
	AV_CODEC_ID_FLV1       int = C.AV_CODEC_ID_FLV1
	AV_CODEC_ID_PNG        int = C.AV_CODEC_ID_PNG
	AV_CODEC_ID_TIFF       int = C.AV_CODEC_ID_TIFF
	AV_CODEC_ID_GIF        int = C.AV_CODEC_ID_GIF

	CODEC_FLAG_GLOBAL_HEADER int   = C.CODEC_FLAG_GLOBAL_HEADER
	FF_MB_DECISION_SIMPLE    int   = C.FF_MB_DECISION_SIMPLE
	FF_MB_DECISION_BITS      int   = C.FF_MB_DECISION_BITS
	FF_MB_DECISION_RD        int   = C.FF_MB_DECISION_RD
	AV_SAMPLE_FMT_S16        int32 = C.AV_SAMPLE_FMT_S16
	AV_SAMPLE_FMT_S16P       int32 = C.AV_SAMPLE_FMT_S16P
)

type SampleFmt int

type CodecCtx struct {
	codec      *Codec
	avCodecCtx *C.struct_AVCodecContext
	CgoMemoryManage
}

func NewCodecCtx(codec *Codec, options ...[]*Option) *CodecCtx {
	result := &CodecCtx{codec: codec}

	codecctx := C.avcodec_alloc_context3(codec.avCodec)
	if codecctx == nil {
		return nil
	}

	C.avcodec_get_context_defaults3(codecctx, codec.avCodec)

	result.avCodecCtx = codecctx

	// we're really expecting only one options-array —
	// variadic arg is used for backward compatibility
	if len(options) == 1 {
		for _, option := range options[0] {
			option.Set(result.avCodecCtx)
		}
	}

	return result
}

func (this *CodecCtx) CopyExtra(ist *Stream) *CodecCtx {
	codec := this.avCodecCtx
	icodec := ist.CodecCtx().avCodecCtx

	codec.bits_per_raw_sample = icodec.bits_per_raw_sample
	codec.chroma_sample_location = icodec.chroma_sample_location

	codec.codec_id = icodec.codec_id
	codec.codec_type = icodec.codec_type

	// codec.codec_tag = icodec.codec_tag

	codec.rc_max_rate = icodec.rc_max_rate
	codec.rc_buffer_size = icodec.rc_buffer_size

	codec.field_order = icodec.field_order

	codec.extradata = (*_Ctype_uint8_t)(C.av_mallocz((_Ctype_size_t)((C.uint64_t)(icodec.extradata_size) + C.FF_INPUT_BUFFER_PADDING_SIZE)))

	C.memcpy(unsafe.Pointer(codec.extradata), unsafe.Pointer(icodec.extradata), (_Ctype_size_t)(icodec.extradata_size))
	codec.extradata_size = icodec.extradata_size
	codec.bits_per_coded_sample = icodec.bits_per_coded_sample

	codec.has_b_frames = icodec.has_b_frames

	return this
}

func (this *CodecCtx) CopyBasic(ist *Stream) *CodecCtx {
	codec := this.avCodecCtx
	icodec := ist.CodecCtx().avCodecCtx

	codec.bit_rate = icodec.bit_rate
	codec.pix_fmt = icodec.pix_fmt
	codec.width = icodec.width
	codec.height = icodec.height

	codec.time_base = icodec.time_base
	codec.time_base.num *= icodec.ticks_per_frame

	codec.sample_fmt = icodec.sample_fmt
	codec.sample_rate = icodec.sample_rate
	codec.channels = icodec.channels

	codec.channel_layout = icodec.channel_layout

	return this
}

func (this *CodecCtx) Open(dict *Dict) error {
	if this.IsOpen() {
		return nil
	}

	var avDict *C.struct_AVDictionary
	if dict != nil {
		avDict = dict.avDict
	}

	if averr := C.avcodec_open2(this.avCodecCtx, this.codec.avCodec, &avDict); averr < 0 {
		return errors.New(fmt.Sprintf("Error opening codec '%s:%s', averror: %s", this.codec.Name(), this.codec.LongName(), AvError(int(averr))))
	}

	return nil
}

func (this *CodecCtx) Close() {
	if nil != this.avCodecCtx {
		C.avcodec_close(this.avCodecCtx)
		this.avCodecCtx = nil
	}
}

func (this *CodecCtx) Free() {
	this.CloseAndRelease()
}

func (this *CodecCtx) CloseAndRelease() {
	this.Close()
	C.call_av_freep(this.avCodecCtx)
}

// @todo
func (this *CodecCtx) SetOpt() {
	// mock
	C.av_opt_set_int(unsafe.Pointer(this.avCodecCtx), C.CString("refcounted_frames"), 1, 0)
}

func (this *CodecCtx) Codec() *Codec {
	return &Codec{avCodec: this.avCodecCtx.codec}
}

func (this *CodecCtx) Id() int {
	return int(this.avCodecCtx.codec_id)
}

func (this *CodecCtx) Type() int32 {
	return int32(this.avCodecCtx.codec_type)
}

func (this *CodecCtx) Width() int {
	return int(this.avCodecCtx.width)
}

func (this *CodecCtx) Height() int {
	return int(this.avCodecCtx.height)
}

func (this *CodecCtx) PixFmt() int32 {
	return int32(this.avCodecCtx.pix_fmt)
}

func (this *CodecCtx) FrameSize() int {
	return int(this.avCodecCtx.frame_size)
}

func (this *CodecCtx) SampleFmt() int32 {
	return this.avCodecCtx.sample_fmt
}

func (this *CodecCtx) SampleRate() int {
	return int(this.avCodecCtx.sample_rate)
}

func (this *CodecCtx) Profile() int {
	return int(this.avCodecCtx.profile)
}

func (this *CodecCtx) IsOpen() bool {
	return (int(C.avcodec_is_open(this.avCodecCtx)) > 0)
}

func (this *CodecCtx) SetProfile(profile int) *CodecCtx {
	this.avCodecCtx.profile = C.int(profile)
	return this
}

func (this *CodecCtx) TimeBase() AVRational {
	return AVRational(this.avCodecCtx.time_base)
}

func (this *CodecCtx) ChannelLayout() int {
	return int(this.avCodecCtx.channel_layout)
}
func (this *CodecCtx) SetChannelLayout(channelLayout int) {
	this.avCodecCtx.channel_layout = C.uint64_t(channelLayout)
}

func (this *CodecCtx) BitRate() int {
	return int(this.avCodecCtx.bit_rate)
}

func (this *CodecCtx) Channels() int {
	return int(this.avCodecCtx.channels)
}

func (this *CodecCtx) SetBitRate(val int) *CodecCtx {
	this.avCodecCtx.bit_rate = C.int64_t(val)
	return this
}

func (this *CodecCtx) SetWidth(val int) *CodecCtx {
	this.avCodecCtx.width = C.int(val)
	return this
}

func (this *CodecCtx) SetHeight(val int) *CodecCtx {
	this.avCodecCtx.height = C.int(val)
	return this
}

func (this *CodecCtx) SetDimension(w, h int) *CodecCtx {
	this.avCodecCtx.width = C.int(w)
	this.avCodecCtx.height = C.int(h)
	return this
}

func (this *CodecCtx) SetTimeBase(val AVR) *CodecCtx {
	this.avCodecCtx.time_base.num = C.int(val.Num)
	this.avCodecCtx.time_base.den = C.int(val.Den)
	return this
}

func (this *CodecCtx) SetGopSize(val int) *CodecCtx {
	this.avCodecCtx.gop_size = C.int(val)
	return this
}

func (this *CodecCtx) SetMaxBFrames(val int) *CodecCtx {
	this.avCodecCtx.max_b_frames = C.int(val)
	return this
}

func (this *CodecCtx) SetPixFmt(val int32) *CodecCtx {
	this.avCodecCtx.pix_fmt = val
	return this
}

func (this *CodecCtx) SetFlag(flag int) *CodecCtx {
	this.avCodecCtx.flags |= C.int(flag)
	return this
}

func (this *CodecCtx) SetMbDecision(val int) *CodecCtx {
	this.avCodecCtx.mb_decision = C.int(val)
	return this
}

func (this *CodecCtx) SetSampleFmt(val int32) *CodecCtx {
	if int(C.check_sample_fmt(this.codec.avCodec, val)) == 0 {
		panic(fmt.Sprintf("encoder doesn't support sample format %s", GetSampleFmtName(val)))
	}

	this.avCodecCtx.sample_fmt = val
	return this
}

func (this *CodecCtx) SetSampleRate(val int) *CodecCtx {
	this.avCodecCtx.sample_rate = C.int(val)
	return this
}

var (
	FF_COMPLIANCE_VERY_STRICT  int = C.FF_COMPLIANCE_VERY_STRICT
	FF_COMPLIANCE_STRICT       int = C.FF_COMPLIANCE_STRICT
	FF_COMPLIANCE_NORMAL       int = C.FF_COMPLIANCE_NORMAL
	FF_COMPLIANCE_UNOFFICIAL   int = C.FF_COMPLIANCE_UNOFFICIAL
	FF_COMPLIANCE_EXPERIMENTAL int = C.FF_COMPLIANCE_EXPERIMENTAL
)

func (this *CodecCtx) SetStrictCompliance(val int) *CodecCtx {
	this.avCodecCtx.strict_std_compliance = C.int(val)
	return this
}

func (this *CodecCtx) SetHasBframes(val int) *CodecCtx {
	this.avCodecCtx.has_b_frames = C.int(val)
	return this
}

func (this *CodecCtx) SetChannels(val int) *CodecCtx {
	this.avCodecCtx.channels = C.int(val)
	return this
}

func (this *CodecCtx) SelectSampleRate() int {
	return int(C.select_sample_rate(this.codec.avCodec))
}

func (this *CodecCtx) SelectChannelLayout() int {
	return int(C.select_channel_layout(this.codec.avCodec))
}

func (this *CodecCtx) FlushBuffers() {
	C.avcodec_flush_buffers(this.avCodecCtx)
}

func (this *CodecCtx) Dump() {
	fmt.Println(this.avCodecCtx)
}
<|endoftext|>


<commit_before>package bot

import (
	"fmt"
	"strings"
	"time"
)

const keepListeningDuration = 77 * time.Second

// checkPluginMatchersAndRun checks either command matchers (for messages directed at
// the robot), or message matchers (for ambient commands that need not be
// directed at the robot), and calls the plugin if it matches. Note: this
// function is called under a read lock on the 'b' struct.
func (bot *botContext) checkPluginMatchersAndRun(pipelineType pipelineType) (messageMatched bool) {
	r := bot.makeRobot()
	// un-needed, but more clear
	messageMatched = false
	// If we're checking messages, debugging messages require that the user requested verboseness
	//verboseOnly := !checkCommands
	verboseOnly := false
	if pipelineType == plugMessage {
		verboseOnly = true
	}
	var runTask interface{}
	var matchedMatcher InputMatcher
	var cmdArgs []string
	for _, t := range bot.tasks.t {
		task, plugin, _ := getTask(t)
		if plugin == nil {
			continue
		}
		if task.Disabled {
			msg := fmt.Sprintf("Skipping disabled task '%s', reason: %s", task.name, task.reason)
			Log(Trace, msg)
			bot.debugT(t, msg, false)
			continue
		}
		Log(Trace, fmt.Sprintf("Checking availability of task '%s' in channel '%s' for user '%s', active in %d channels (allchannels: %t)", task.name, bot.Channel, bot.User, len(task.Channels), task.AllChannels))
		ok := bot.taskAvailable(task, false, verboseOnly)
		if !ok {
			Log(Trace, fmt.Sprintf("Task '%s' not available for user '%s' in channel '%s', doesn't meet criteria", task.name, bot.User, bot.Channel))
			continue
		}
		var matchers []InputMatcher
		var ctype string
		switch pipelineType {
		case plugCommand:
			if plugin == nil {
				continue
			}
			if len(plugin.CommandMatchers) == 0 {
				bot.debugT(t, fmt.Sprintf("Plugin has no command matchers, skipping command check"), false)
				continue
			}
			matchers = plugin.CommandMatchers
			ctype = "command"
		case plugMessage:
			if plugin == nil {
				continue
			}
			if len(plugin.MessageMatchers) == 0 {
				bot.debugT(t, fmt.Sprintf("Plugin has no message matchers, skipping message check"), true)
				continue
			}
			matchers = plugin.MessageMatchers
			ctype = "message"
		}
		Log(Trace, fmt.Sprintf("Task '%s' is active, will check for matches", task.name))
		bot.debugT(t, fmt.Sprintf("Checking %d %s matchers against message: '%s'", len(matchers), ctype, bot.msg), verboseOnly)
		for _, matcher := range matchers {
			Log(Trace, fmt.Sprintf("Checking '%s' against '%s'", bot.msg, matcher.Regex))
			matches := matcher.re.FindAllStringSubmatch(bot.msg, -1)
			matched := false
			if matches != nil {
				bot.debugT(t, fmt.Sprintf("Matched %s regex '%s', command: %s", ctype, matcher.Regex, matcher.Command), false)
				matched = true
				Log(Trace, fmt.Sprintf("Message '%s' matches command '%s'", bot.msg, matcher.Command))
				cmdArgs = matches[0][1:]
				if len(matcher.Contexts) > 0 {
					// Resolve & store "it" with short-term memories
					ts := time.Now()
					shortTermMemories.Lock()
					for i, contextLabel := range matcher.Contexts {
						if contextLabel != "" {
							if len(cmdArgs) > i {
								ctx := strings.Split(contextLabel, ":")
								contextName := ctx[0]
								contextMatches := []string{""}
								contextMatches = append(contextMatches, ctx[1:]...)
								key := "context:" + contextName
								c := memoryContext{key, bot.User, bot.Channel}
								cMatch := false
								for _, cm := range contextMatches {
									if cmdArgs[i] == cm {
										cMatch = true
									}
								}
								if cMatch {
									s, ok := shortTermMemories.m[c]
									if ok {
										cmdArgs[i] = s.memory
										// TODO: it would probably be best to substitute the value
										// from "it" back in to the original message and re-check for
										// a match. Failing a match, matched should be set to false.
										s.timestamp = ts
										shortTermMemories.m[c] = s
									} else {
										bot.makeRobot().Say(fmt.Sprintf("Sorry, I don't remember which %s we were talking about - please re-enter your command and be more specific", contextLabel))
										shortTermMemories.Unlock()
										return true
									}
								} else {
									s := shortTermMemory{cmdArgs[i], ts}
									shortTermMemories.m[c] = s
								}
							} else {
								Log(Error, fmt.Sprintf("Plugin '%s', command '%s', has more contexts than match groups"))
							}
						}
					}
					shortTermMemories.Unlock()
				}
			} else {
				bot.debugT(t, fmt.Sprintf("Not matched: %s", matcher.Regex), verboseOnly)
			}
			if matched {
				if messageMatched {
					prevTask, _, _ := getTask(runTask)
					Log(Error, fmt.Sprintf("Message '%s' matched multiple tasks: %s and %s", bot.msg, prevTask.name, task.name))
					r.Say("Yikes! Your command matched multiple plugins, so I'm not doing ANYTHING")
					emit(MultipleMatchesNoAction)
					return
				}
				messageMatched = true
				runTask = t
				matchedMatcher = matcher
				break
			}
		} // end of matcher checking
	} // end of plugin checking
	if messageMatched {
		task, _, _ := getTask(runTask)
		r.messageHeard()
		matcher := matchedMatcher
		abort := false
		if task.name == "builtInadmin" && matcher.Command == "abort" {
			abort = true
		}
		robot.RLock()
		if robot.shuttingDown && !abort {
			r.Say("Sorry, I'm shutting down and can't start any new tasks")
			robot.RUnlock()
			return
		} else if robot.paused && !abort {
			r.Say("Sorry, I've been paused and can't start any new tasks")
			robot.RUnlock()
			return
		}
		robot.RUnlock()
		// Check to see if user issued a new command when a reply was being
		// waited on
		replyMatcher := replyMatcher{bot.User, bot.Channel}
		replies.Lock()
		waiters, waitingForReply := replies.m[replyMatcher]
		if waitingForReply {
			delete(replies.m, replyMatcher)
			replies.Unlock()
			for i, rep := range waiters {
				if i == 0 {
					rep.replyChannel <- reply{false, replyInterrupted, ""}
				} else {
					rep.replyChannel <- reply{false, retryPrompt, ""}
				}
			}
			Log(Debug, fmt.Sprintf("User '%s' matched a new command while the robot was waiting for a reply in channel '%s'", bot.User, bot.Channel))
		} else {
			replies.Unlock()
		}
		bot.startPipeline(runTask, pipelineType, matcher.Command, cmdArgs...)
	}
	return
}

// handleMessage checks the message against plugin commands and full-message
// matches, then dispatches it to the applicable plugin. If the robot was
// addressed directly but nothing matched, any registered CatchAll plugins are
// called. There Should Be Only One (terminal plugin called).
func (bot *botContext) handleMessage() {
	r := bot.makeRobot()
	defer checkPanic(r, bot.msg)

	if len(bot.Channel) == 0 {
		emit(BotDirectMessage)
		Log(Trace, fmt.Sprintf("Bot received a direct message from %s: %s", bot.User, bot.msg))
	}
	messageMatched := false
	ts := time.Now()
	lastMsgContext := memoryContext{"lastMsg", bot.User, bot.Channel}
	var last shortTermMemory
	var ok bool
	// See if the robot got a blank message, indicating that the last message
	// was meant for it (if it was in the keepListeningDuration)
	if bot.isCommand && bot.msg == "" {
		shortTermMemories.Lock()
		last, ok = shortTermMemories.m[lastMsgContext]
		shortTermMemories.Unlock()
		if ok && ts.Sub(last.timestamp) < keepListeningDuration {
			bot.msg = last.memory
			messageMatched = bot.checkPluginMatchersAndRun(plugCommand)
		} else {
			messageMatched = true
			r.Say("Yes?")
		}
	}
	if !messageMatched && bot.isCommand {
		// See if a command matches (and runs)
		messageMatched = bot.checkPluginMatchersAndRun(plugCommand)
	}
	// See if the robot was waiting on a reply
	var waiters []replyWaiter
	waitingForReply := false
	if !messageMatched {
		matcher := replyMatcher{bot.User, bot.Channel}
		Log(Trace, fmt.Sprintf("Checking replies for matcher: %q", matcher))
		replies.Lock()
		waiters, waitingForReply = replies.m[matcher]
		if !waitingForReply {
			replies.Unlock()
		} else {
			delete(replies.m, matcher)
			replies.Unlock()
			// if the robot was waiting on a reply, we don't want to check for
			// ambient message matches - the plugin will handle it.
			messageMatched = true
			for i, rep := range waiters {
				if i == 0 {
					matched := rep.re.MatchString(bot.msg)
					Log(Debug, fmt.Sprintf("Found replyWaiter for user '%s' in channel '%s', checking if message '%s' matches '%s': %t", bot.User, bot.Channel, bot.msg, rep.re.String(), matched))
					rep.replyChannel <- reply{matched, replied, bot.msg}
				} else {
					Log(Debug, "Sending retry to next reply waiter")
					rep.replyChannel <- reply{false, retryPrompt, ""}
				}
			}
		}
	}
	// Direct commands were checked above; if a direct command didn't match,
	// and a there wasn't a reply being waited on, then we check ambient
	// MessageMatchers.
	if !messageMatched {
		// check for ambient message matches
		messageMatched = bot.checkPluginMatchersAndRun(plugMessage)
	}
	// Check for job commands
	if !messageMatched {
		messageMatched = bot.checkJobMatchersAndRun()
	}
	if bot.isCommand && !messageMatched { // the robot was spoken to, but nothing matched - call catchAlls
		robot.RLock()
		if !robot.shuttingDown {
			robot.RUnlock()
			r.messageHeard()
			Log(Debug, fmt.Sprintf("Unmatched command sent to robot, calling catchalls: %s", bot.msg))
			emit(CatchAllsRan) // for testing, otherwise noop
			// TODO: should we allow more than 1 catchall?
			catchAllPlugins := make([]interface{}, 0, 0)
			for _, t := range bot.tasks.t {
				if plugin, ok := t.(*botPlugin); ok && plugin.CatchAll {
					catchAllPlugins = append(catchAllPlugins, t)
				}
			}
			if len(catchAllPlugins) > 1 {
				Log(Error, "More than one catch all registered, none will be called")
			} else {
				// Note: if the catchall plugin has configured security, it
				// should still apply.
				bot.startPipeline(catchAllPlugins[0], catchAll, "catchall", bot.msg)
			}
		} else {
			// If the robot is shutting down, just ignore catch-all plugins
			robot.RUnlock()
		}
	}
	if messageMatched || bot.isCommand {
		shortTermMemories.Lock()
		delete(shortTermMemories.m, lastMsgContext)
		shortTermMemories.Unlock()
	} else {
		last = shortTermMemory{bot.msg, ts}
		shortTermMemories.Lock()
		shortTermMemories.m[lastMsgContext] = last
		shortTermMemories.Unlock()
	}
}
<commit_msg>Fix sprintf, add comments<commit_after>package bot

import (
	"fmt"
	"strings"
	"time"
)

const keepListeningDuration = 77 * time.Second

// checkPluginMatchersAndRun checks either command matchers (for messages directed at
// the robot), or message matchers (for ambient commands that need not be
// directed at the robot), and calls the plugin if it matches. Note: this
// function is called under a read lock on the 'b' struct.
func (bot *botContext) checkPluginMatchersAndRun(pipelineType pipelineType) (messageMatched bool) {
	r := bot.makeRobot()
	// un-needed, but more clear
	messageMatched = false
	// If we're checking messages, debugging messages require that the user requested verboseness
	//verboseOnly := !checkCommands
	verboseOnly := false
	if pipelineType == plugMessage {
		verboseOnly = true
	}
	var runTask interface{}
	var matchedMatcher InputMatcher
	var cmdArgs []string
	for _, t := range bot.tasks.t {
		task, plugin, _ := getTask(t)
		if plugin == nil {
			continue
		}
		if task.Disabled {
			msg := fmt.Sprintf("Skipping disabled task '%s', reason: %s", task.name, task.reason)
			Log(Trace, msg)
			bot.debugT(t, msg, false)
			continue
		}
		Log(Trace, fmt.Sprintf("Checking availability of task '%s' in channel '%s' for user '%s', active in %d channels (allchannels: %t)", task.name, bot.Channel, bot.User, len(task.Channels), task.AllChannels))
		ok := bot.taskAvailable(task, false, verboseOnly)
		if !ok {
			Log(Trace, fmt.Sprintf("Task '%s' not available for user '%s' in channel '%s', doesn't meet criteria", task.name, bot.User, bot.Channel))
			continue
		}
		var matchers []InputMatcher
		var ctype string
		switch pipelineType {
		case plugCommand:
			if plugin == nil {
				continue
			}
			if len(plugin.CommandMatchers) == 0 {
				bot.debugT(t, fmt.Sprintf("Plugin has no command matchers, skipping command check"), false)
				continue
			}
			matchers = plugin.CommandMatchers
			ctype = "command"
		case plugMessage:
			if plugin == nil {
				continue
			}
			if len(plugin.MessageMatchers) == 0 {
				bot.debugT(t, fmt.Sprintf("Plugin has no message matchers, skipping message check"), true)
				continue
			}
			matchers = plugin.MessageMatchers
			ctype = "message"
		}
		Log(Trace, fmt.Sprintf("Task '%s' is active, will check for matches", task.name))
		bot.debugT(t, fmt.Sprintf("Checking %d %s matchers against message: '%s'", len(matchers), ctype, bot.msg), verboseOnly)
		for _, matcher := range matchers {
			Log(Trace, fmt.Sprintf("Checking '%s' against '%s'", bot.msg, matcher.Regex))
			matches := matcher.re.FindAllStringSubmatch(bot.msg, -1)
			matched := false
			if matches != nil {
				bot.debugT(t, fmt.Sprintf("Matched %s regex '%s', command: %s", ctype, matcher.Regex, matcher.Command), false)
				matched = true
				Log(Trace, fmt.Sprintf("Message '%s' matches command '%s'", bot.msg, matcher.Command))
				cmdArgs = matches[0][1:]
				if len(matcher.Contexts) > 0 {
					// Resolve & store "it" with short-term memories
					ts := time.Now()
					shortTermMemories.Lock()
					for i, contextLabel := range matcher.Contexts {
						if contextLabel != "" {
							if len(cmdArgs) > i {
								ctx := strings.Split(contextLabel, ":")
								contextName := ctx[0]
								contextMatches := []string{""}
								contextMatches = append(contextMatches, ctx[1:]...)
								key := "context:" + contextName
								c := memoryContext{key, bot.User, bot.Channel}
								// Check if the capture group matches the empty string
								// or one of the generic values (e.g. "it")
								cMatch := false
								for _, cm := range contextMatches {
									if cmdArgs[i] == cm {
										cMatch = true
									}
								}
								if cMatch {
									// If a generic matched, try to recall from short-term memory
									s, ok := shortTermMemories.m[c]
									if ok {
										cmdArgs[i] = s.memory
										// TODO: it would probably be best to substitute the value
										// from "it" back in to the original message and re-check for
										// a match. Failing a match, matched should be set to false.
										s.timestamp = ts
										shortTermMemories.m[c] = s
									} else {
										bot.makeRobot().Say(fmt.Sprintf("Sorry, I don't remember which %s we were talking about - please re-enter your command and be more specific", contextLabel))
										shortTermMemories.Unlock()
										return true
									}
								} else {
									// Didn't match generic, store the value in short-term context memory
									s := shortTermMemory{cmdArgs[i], ts}
									shortTermMemories.m[c] = s
								}
							} else {
								Log(Error, fmt.Sprintf("Plugin '%s', command '%s', has more contexts than match groups", task.name, matcher.Command))
							}
						}
					}
					shortTermMemories.Unlock()
				}
			} else {
				bot.debugT(t, fmt.Sprintf("Not matched: %s", matcher.Regex), verboseOnly)
			}
			if matched {
				if messageMatched {
					prevTask, _, _ := getTask(runTask)
					Log(Error, fmt.Sprintf("Message '%s' matched multiple tasks: %s and %s", bot.msg, prevTask.name, task.name))
					r.Say("Yikes! Your command matched multiple plugins, so I'm not doing ANYTHING")
					emit(MultipleMatchesNoAction)
					return
				}
				messageMatched = true
				runTask = t
				matchedMatcher = matcher
				break
			}
		} // end of matcher checking
	} // end of plugin checking
	if messageMatched {
		task, _, _ := getTask(runTask)
		r.messageHeard()
		matcher := matchedMatcher
		abort := false
		if task.name == "builtInadmin" && matcher.Command == "abort" {
			abort = true
		}
		robot.RLock()
		if robot.shuttingDown && !abort {
			r.Say("Sorry, I'm shutting down and can't start any new tasks")
			robot.RUnlock()
			return
		} else if robot.paused && !abort {
			r.Say("Sorry, I've been paused and can't start any new tasks")
			robot.RUnlock()
			return
		}
		robot.RUnlock()
		// Check to see if user issued a new command when a reply was being
		// waited on
		replyMatcher := replyMatcher{bot.User, bot.Channel}
		replies.Lock()
		waiters, waitingForReply := replies.m[replyMatcher]
		if waitingForReply {
			delete(replies.m, replyMatcher)
			replies.Unlock()
			for i, rep := range waiters {
				if i == 0 {
					rep.replyChannel <- reply{false, replyInterrupted, ""}
				} else {
					rep.replyChannel <- reply{false, retryPrompt, ""}
				}
			}
			Log(Debug, fmt.Sprintf("User '%s' matched a new command while the robot was waiting for a reply in channel '%s'", bot.User, bot.Channel))
		} else {
			replies.Unlock()
		}
		bot.startPipeline(runTask, pipelineType, matcher.Command, cmdArgs...)
	}
	return
}

// handleMessage checks the message against plugin commands and full-message
// matches, then dispatches it to the applicable plugin. If the robot was
// addressed directly but nothing matched, any registered CatchAll plugins are
// called. There Should Be Only One (terminal plugin called).
func (bot *botContext) handleMessage() {
	r := bot.makeRobot()
	defer checkPanic(r, bot.msg)

	if len(bot.Channel) == 0 {
		emit(BotDirectMessage)
		Log(Trace, fmt.Sprintf("Bot received a direct message from %s: %s", bot.User, bot.msg))
	}
	messageMatched := false
	ts := time.Now()
	lastMsgContext := memoryContext{"lastMsg", bot.User, bot.Channel}
	var last shortTermMemory
	var ok bool
	// See if the robot got a blank message, indicating that the last message
	// was meant for it (if it was in the keepListeningDuration)
	if bot.isCommand && bot.msg == "" {
		shortTermMemories.Lock()
		last, ok = shortTermMemories.m[lastMsgContext]
		shortTermMemories.Unlock()
		if ok && ts.Sub(last.timestamp) < keepListeningDuration {
			bot.msg = last.memory
			messageMatched = bot.checkPluginMatchersAndRun(plugCommand)
		} else {
			messageMatched = true
			r.Say("Yes?")
		}
	}
	if !messageMatched && bot.isCommand {
		// See if a command matches (and runs)
		messageMatched = bot.checkPluginMatchersAndRun(plugCommand)
	}
	// See if the robot was waiting on a reply
	var waiters []replyWaiter
	waitingForReply := false
	if !messageMatched {
		matcher := replyMatcher{bot.User, bot.Channel}
		Log(Trace, fmt.Sprintf("Checking replies for matcher: %q", matcher))
		replies.Lock()
		waiters, waitingForReply = replies.m[matcher]
		if !waitingForReply {
			replies.Unlock()
		} else {
			delete(replies.m, matcher)
			replies.Unlock()
			// if the robot was waiting on a reply, we don't want to check for
			// ambient message matches - the plugin will handle it.
			messageMatched = true
			for i, rep := range waiters {
				if i == 0 {
					matched := rep.re.MatchString(bot.msg)
					Log(Debug, fmt.Sprintf("Found replyWaiter for user '%s' in channel '%s', checking if message '%s' matches '%s': %t", bot.User, bot.Channel, bot.msg, rep.re.String(), matched))
					rep.replyChannel <- reply{matched, replied, bot.msg}
				} else {
					Log(Debug, "Sending retry to next reply waiter")
					rep.replyChannel <- reply{false, retryPrompt, ""}
				}
			}
		}
	}
	// Direct commands were checked above; if a direct command didn't match,
	// and a there wasn't a reply being waited on, then we check ambient
	// MessageMatchers.
	if !messageMatched {
		// check for ambient message matches
		messageMatched = bot.checkPluginMatchersAndRun(plugMessage)
	}
	// Check for job commands
	if !messageMatched {
		messageMatched = bot.checkJobMatchersAndRun()
	}
	if bot.isCommand && !messageMatched { // the robot was spoken to, but nothing matched - call catchAlls
		robot.RLock()
		if !robot.shuttingDown {
			robot.RUnlock()
			r.messageHeard()
			Log(Debug, fmt.Sprintf("Unmatched command sent to robot, calling catchalls: %s", bot.msg))
			emit(CatchAllsRan) // for testing, otherwise noop
			// TODO: should we allow more than 1 catchall?
			catchAllPlugins := make([]interface{}, 0, 0)
			for _, t := range bot.tasks.t {
				if plugin, ok := t.(*botPlugin); ok && plugin.CatchAll {
					catchAllPlugins = append(catchAllPlugins, t)
				}
			}
			if len(catchAllPlugins) > 1 {
				Log(Error, "More than one catch all registered, none will be called")
			} else {
				// Note: if the catchall plugin has configured security, it
				// should still apply.
				bot.startPipeline(catchAllPlugins[0], catchAll, "catchall", bot.msg)
			}
		} else {
			// If the robot is shutting down, just ignore catch-all plugins
			robot.RUnlock()
		}
	}
	if messageMatched || bot.isCommand {
		shortTermMemories.Lock()
		delete(shortTermMemories.m, lastMsgContext)
		shortTermMemories.Unlock()
	} else {
		last = shortTermMemory{bot.msg, ts}
		shortTermMemories.Lock()
		shortTermMemories.m[lastMsgContext] = last
		shortTermMemories.Unlock()
	}
}
<|endoftext|>


<commit_before>package container

import (
	"fmt"

	executorpkg "github.com/docker/docker/daemon/cluster/executor"
	"github.com/docker/engine-api/types"
	"github.com/docker/engine-api/types/events"
	"github.com/docker/swarmkit/agent/exec"
	"github.com/docker/swarmkit/api"
	"github.com/docker/swarmkit/log"
	"github.com/pkg/errors"
	"golang.org/x/net/context"
)

// controller implements agent.Controller against docker's API.
//
// Most operations against docker's API are done through the container name,
// which is unique to the task.
type controller struct {
	backend executorpkg.Backend
	task    *api.Task
	adapter *containerAdapter
	closed  chan struct{}
	err     error

	pulled     chan struct{} // closed after pull
	cancelPull func()        // cancels pull context if not nil
	pullErr    error         // pull error, only read after pulled closed
}

var _ exec.Controller = &controller{}

// NewController returns a dockerexec runner for the provided task.
func newController(b executorpkg.Backend, task *api.Task) (*controller, error) {
	adapter, err := newContainerAdapter(b, task)
	if err != nil {
		return nil, err
	}

	return &controller{
		backend: b,
		task:    task,
		adapter: adapter,
		closed:  make(chan struct{}),
	}, nil
}

func (r *controller) Task() (*api.Task, error) {
	return r.task, nil
}

// ContainerStatus returns the container-specific status for the task.
func (r *controller) ContainerStatus(ctx context.Context) (*api.ContainerStatus, error) {
	ctnr, err := r.adapter.inspect(ctx)
	if err != nil {
		if isUnknownContainer(err) {
			return nil, nil
		}
		return nil, err
	}
	return parseContainerStatus(ctnr)
}

// Update tasks a recent task update and applies it to the container.
func (r *controller) Update(ctx context.Context, t *api.Task) error {
	// TODO(stevvooe): While assignment of tasks is idempotent, we do allow
	// updates of metadata, such as labelling, as well as any other properties
	// that make sense.
	return nil
}

// Prepare creates a container and ensures the image is pulled.
//
// If the container has already be created, exec.ErrTaskPrepared is returned.
func (r *controller) Prepare(ctx context.Context) error {
	if err := r.checkClosed(); err != nil {
		return err
	}

	// Make sure all the networks that the task needs are created.
	if err := r.adapter.createNetworks(ctx); err != nil {
		return err
	}

	// Make sure all the volumes that the task needs are created.
	if err := r.adapter.createVolumes(ctx, r.backend); err != nil {
		return err
	}

	if r.pulled == nil {
		// Fork the pull to a different context to allow pull to continue
		// on re-entrant calls to Prepare. This ensures that Prepare can be
		// idempotent and not incur the extra cost of pulling when
		// cancelled on updates.
		var pctx context.Context

		r.pulled = make(chan struct{})
		pctx, r.cancelPull = context.WithCancel(context.Background()) // TODO(stevvooe): Bind a context to the entire controller.

		go func() {
			defer close(r.pulled)
			r.pullErr = r.adapter.pullImage(pctx) // protected by closing r.pulled
		}()
	}

	select {
	case <-ctx.Done():
		return ctx.Err()
	case <-r.pulled:
		if r.pullErr != nil {
			// NOTE(stevvooe): We always try to pull the image to make sure we have
			// the most up to date version. This will return an error, but we only
			// log it. If the image truly doesn't exist, the create below will
			// error out.
			//
			// This gives us some nice behavior where we use up to date versions of
			// mutable tags, but will still run if the old image is available but a
			// registry is down.
			//
			// If you don't want this behavior, lock down your image to an
			// immutable tag or digest.
			log.G(ctx).WithError(r.pullErr).Error("pulling image failed")
		}
	}

	if err := r.adapter.create(ctx, r.backend); err != nil {
		if isContainerCreateNameConflict(err) {
			if _, err := r.adapter.inspect(ctx); err != nil {
				return err
			}

			// container is already created. success!
			return exec.ErrTaskPrepared
		}

		return err
	}

	return nil
}

// Start the container. An error will be returned if the container is already started.
func (r *controller) Start(ctx context.Context) error {
	if err := r.checkClosed(); err != nil {
		return err
	}

	ctnr, err := r.adapter.inspect(ctx)
	if err != nil {
		return err
	}

	// Detect whether the container has *ever* been started. If so, we don't
	// issue the start.
	//
	// TODO(stevvooe): This is very racy. While reading inspect, another could
	// start the process and we could end up starting it twice.
	if ctnr.State.Status != "created" {
		return exec.ErrTaskStarted
	}

	if err := r.adapter.start(ctx); err != nil {
		return errors.Wrap(err, "starting container failed")
	}

	// no health check
	if ctnr.Config == nil || ctnr.Config.Healthcheck == nil {
		return nil
	}

	healthCmd := ctnr.Config.Healthcheck.Test

	if len(healthCmd) == 0 || healthCmd[0] == "NONE" {
		return nil
	}

	// wait for container to be healthy
	eventq := r.adapter.events(ctx)

	var healthErr error
	for {
		select {
		case event := <-eventq:
			if !r.matchevent(event) {
				continue
			}

			switch event.Action {
			case "die": // exit on terminal events
				ctnr, err := r.adapter.inspect(ctx)
				if err != nil {
					return errors.Wrap(err, "die event received")
				} else if ctnr.State.ExitCode != 0 {
					return &exitError{code: ctnr.State.ExitCode, cause: healthErr}
				}

				return nil
			case "destroy":
				// If we get here, something has gone wrong but we want to exit
				// and report anyways.
				return ErrContainerDestroyed
			case "health_status: unhealthy":
				// in this case, we stop the container and report unhealthy status
				if err := r.Shutdown(ctx); err != nil {
					return errors.Wrap(err, "unhealthy container shutdown failed")
				}
				// set health check error, and wait for container to fully exit ("die" event)
				healthErr = ErrContainerUnhealthy
			case "health_status: healthy":
				return nil
			}
		case <-ctx.Done():
			return ctx.Err()
		case <-r.closed:
			return r.err
		}
	}
}

// Wait on the container to exit.
func (r *controller) Wait(pctx context.Context) error {
	if err := r.checkClosed(); err != nil {
		return err
	}

	ctx, cancel := context.WithCancel(pctx)
	defer cancel()

	healthErr := make(chan error, 1)
	go func() {
		ectx, cancel := context.WithCancel(ctx) // cancel event context on first event
		defer cancel()
		if err := r.checkHealth(ectx); err == ErrContainerUnhealthy {
			healthErr <- ErrContainerUnhealthy
			if err := r.Shutdown(ectx); err != nil {
				log.G(ectx).WithError(err).Debug("shutdown failed on unhealthy")
			}
		}
	}()

	err := r.adapter.wait(ctx)
	if ctx.Err() != nil {
		return ctx.Err()
	}

	if err != nil {
		ee := &exitError{}
		if ec, ok := err.(exec.ExitCoder); ok {
			ee.code = ec.ExitCode()
		}
		select {
		case e := <-healthErr:
			ee.cause = e
		default:
			if err.Error() != "" {
				ee.cause = err
			}
		}
		return ee
	}

	return nil
}

// Shutdown the container cleanly.
func (r *controller) Shutdown(ctx context.Context) error {
	if err := r.checkClosed(); err != nil {
		return err
	}

	if r.cancelPull != nil {
		r.cancelPull()
	}

	if err := r.adapter.shutdown(ctx); err != nil {
		if isUnknownContainer(err) || isStoppedContainer(err) {
			return nil
		}

		return err
	}

	return nil
}

// Terminate the container, with force.
func (r *controller) Terminate(ctx context.Context) error {
	if err := r.checkClosed(); err != nil {
		return err
	}

	if r.cancelPull != nil {
		r.cancelPull()
	}

	if err := r.adapter.terminate(ctx); err != nil {
		if isUnknownContainer(err) {
			return nil
		}

		return err
	}

	return nil
}

// Remove the container and its resources.
func (r *controller) Remove(ctx context.Context) error {
	if err := r.checkClosed(); err != nil {
		return err
	}

	if r.cancelPull != nil {
		r.cancelPull()
	}

	// It may be necessary to shut down the task before removing it.
	if err := r.Shutdown(ctx); err != nil {
		if isUnknownContainer(err) {
			return nil
		}
		// This may fail if the task was already shut down.
		log.G(ctx).WithError(err).Debug("shutdown failed on removal")
	}

	// Try removing networks referenced in this task in case this
	// task is the last one referencing it
	if err := r.adapter.removeNetworks(ctx); err != nil {
		if isUnknownContainer(err) {
			return nil
		}
		return err
	}

	if err := r.adapter.remove(ctx); err != nil {
		if isUnknownContainer(err) {
			return nil
		}

		return err
	}
	return nil
}

// Close the runner and clean up any ephemeral resources.
func (r *controller) Close() error {
	select {
	case <-r.closed:
		return r.err
	default:
		if r.cancelPull != nil {
			r.cancelPull()
		}

		r.err = exec.ErrControllerClosed
		close(r.closed)
	}
	return nil
}

func (r *controller) matchevent(event events.Message) bool {
	if event.Type != events.ContainerEventType {
		return false
	}

	// TODO(stevvooe): Filter based on ID matching, in addition to name.

	// Make sure the events are for this container.
	if event.Actor.Attributes["name"] != r.adapter.container.name() {
		return false
	}

	return true
}

func (r *controller) checkClosed() error {
	select {
	case <-r.closed:
		return r.err
	default:
		return nil
	}
}

func parseContainerStatus(ctnr types.ContainerJSON) (*api.ContainerStatus, error) {
	status := &api.ContainerStatus{
		ContainerID: ctnr.ID,
		PID:         int32(ctnr.State.Pid),
		ExitCode:    int32(ctnr.State.ExitCode),
	}

	return status, nil
}

type exitError struct {
	code  int
	cause error
}

func (e *exitError) Error() string {
	if e.cause != nil {
		return fmt.Sprintf("task: non-zero exit (%v): %v", e.code, e.cause)
	}

	return fmt.Sprintf("task: non-zero exit (%v)", e.code)
}

func (e *exitError) ExitCode() int {
	return int(e.code)
}

func (e *exitError) Cause() error {
	return e.cause
}

// checkHealth blocks until unhealthy container is detected or ctx exits
func (r *controller) checkHealth(ctx context.Context) error {
	eventq := r.adapter.events(ctx)

	for {
		select {
		case <-ctx.Done():
			return nil
		case <-r.closed:
			return nil
		case event := <-eventq:
			if !r.matchevent(event) {
				continue
			}

			switch event.Action {
			case "health_status: unhealthy":
				return ErrContainerUnhealthy
			}
		}
	}
}
<commit_msg>Retry creating dynamic networks if not found<commit_after>package container

import (
	"fmt"

	executorpkg "github.com/docker/docker/daemon/cluster/executor"
	"github.com/docker/engine-api/types"
	"github.com/docker/engine-api/types/events"
	"github.com/docker/libnetwork"
	"github.com/docker/swarmkit/agent/exec"
	"github.com/docker/swarmkit/api"
	"github.com/docker/swarmkit/log"
	"github.com/pkg/errors"
	"golang.org/x/net/context"
)

// controller implements agent.Controller against docker's API.
//
// Most operations against docker's API are done through the container name,
// which is unique to the task.
type controller struct {
	backend executorpkg.Backend
	task    *api.Task
	adapter *containerAdapter
	closed  chan struct{}
	err     error

	pulled     chan struct{} // closed after pull
	cancelPull func()        // cancels pull context if not nil
	pullErr    error         // pull error, only read after pulled closed
}

var _ exec.Controller = &controller{}

// NewController returns a dockerexec runner for the provided task.
func newController(b executorpkg.Backend, task *api.Task) (*controller, error) {
	adapter, err := newContainerAdapter(b, task)
	if err != nil {
		return nil, err
	}

	return &controller{
		backend: b,
		task:    task,
		adapter: adapter,
		closed:  make(chan struct{}),
	}, nil
}

func (r *controller) Task() (*api.Task, error) {
	return r.task, nil
}

// ContainerStatus returns the container-specific status for the task.
func (r *controller) ContainerStatus(ctx context.Context) (*api.ContainerStatus, error) {
	ctnr, err := r.adapter.inspect(ctx)
	if err != nil {
		if isUnknownContainer(err) {
			return nil, nil
		}
		return nil, err
	}
	return parseContainerStatus(ctnr)
}

// Update tasks a recent task update and applies it to the container.
func (r *controller) Update(ctx context.Context, t *api.Task) error {
	// TODO(stevvooe): While assignment of tasks is idempotent, we do allow
	// updates of metadata, such as labelling, as well as any other properties
	// that make sense.
	return nil
}

// Prepare creates a container and ensures the image is pulled.
//
// If the container has already be created, exec.ErrTaskPrepared is returned.
func (r *controller) Prepare(ctx context.Context) error {
	if err := r.checkClosed(); err != nil {
		return err
	}

	// Make sure all the networks that the task needs are created.
	if err := r.adapter.createNetworks(ctx); err != nil {
		return err
	}

	// Make sure all the volumes that the task needs are created.
	if err := r.adapter.createVolumes(ctx, r.backend); err != nil {
		return err
	}

	if r.pulled == nil {
		// Fork the pull to a different context to allow pull to continue
		// on re-entrant calls to Prepare. This ensures that Prepare can be
		// idempotent and not incur the extra cost of pulling when
		// cancelled on updates.
		var pctx context.Context

		r.pulled = make(chan struct{})
		pctx, r.cancelPull = context.WithCancel(context.Background()) // TODO(stevvooe): Bind a context to the entire controller.

		go func() {
			defer close(r.pulled)
			r.pullErr = r.adapter.pullImage(pctx) // protected by closing r.pulled
		}()
	}

	select {
	case <-ctx.Done():
		return ctx.Err()
	case <-r.pulled:
		if r.pullErr != nil {
			// NOTE(stevvooe): We always try to pull the image to make sure we have
			// the most up to date version. This will return an error, but we only
			// log it. If the image truly doesn't exist, the create below will
			// error out.
			//
			// This gives us some nice behavior where we use up to date versions of
			// mutable tags, but will still run if the old image is available but a
			// registry is down.
			//
			// If you don't want this behavior, lock down your image to an
			// immutable tag or digest.
			log.G(ctx).WithError(r.pullErr).Error("pulling image failed")
		}
	}

	if err := r.adapter.create(ctx, r.backend); err != nil {
		if isContainerCreateNameConflict(err) {
			if _, err := r.adapter.inspect(ctx); err != nil {
				return err
			}

			// container is already created. success!
			return exec.ErrTaskPrepared
		}

		return err
	}

	return nil
}

// Start the container. An error will be returned if the container is already started.
func (r *controller) Start(ctx context.Context) error {
	if err := r.checkClosed(); err != nil {
		return err
	}

	ctnr, err := r.adapter.inspect(ctx)
	if err != nil {
		return err
	}

	// Detect whether the container has *ever* been started. If so, we don't
	// issue the start.
	//
	// TODO(stevvooe): This is very racy. While reading inspect, another could
	// start the process and we could end up starting it twice.
	if ctnr.State.Status != "created" {
		return exec.ErrTaskStarted
	}

	for {
		if err := r.adapter.start(ctx); err != nil {
			if _, ok := err.(libnetwork.ErrNoSuchNetwork); ok {
				// Retry network creation again if we
				// failed because some of the networks
				// were not found.
				if err := r.adapter.createNetworks(ctx); err != nil {
					return err
				}

				continue
			}

			return errors.Wrap(err, "starting container failed")
		}

		break
	}

	// no health check
	if ctnr.Config == nil || ctnr.Config.Healthcheck == nil {
		return nil
	}

	healthCmd := ctnr.Config.Healthcheck.Test

	if len(healthCmd) == 0 || healthCmd[0] == "NONE" {
		return nil
	}

	// wait for container to be healthy
	eventq := r.adapter.events(ctx)

	var healthErr error
	for {
		select {
		case event := <-eventq:
			if !r.matchevent(event) {
				continue
			}

			switch event.Action {
			case "die": // exit on terminal events
				ctnr, err := r.adapter.inspect(ctx)
				if err != nil {
					return errors.Wrap(err, "die event received")
				} else if ctnr.State.ExitCode != 0 {
					return &exitError{code: ctnr.State.ExitCode, cause: healthErr}
				}

				return nil
			case "destroy":
				// If we get here, something has gone wrong but we want to exit
				// and report anyways.
				return ErrContainerDestroyed
			case "health_status: unhealthy":
				// in this case, we stop the container and report unhealthy status
				if err := r.Shutdown(ctx); err != nil {
					return errors.Wrap(err, "unhealthy container shutdown failed")
				}
				// set health check error, and wait for container to fully exit ("die" event)
				healthErr = ErrContainerUnhealthy
			case "health_status: healthy":
				return nil
			}
		case <-ctx.Done():
			return ctx.Err()
		case <-r.closed:
			return r.err
		}
	}
}

// Wait on the container to exit.
func (r *controller) Wait(pctx context.Context) error {
	if err := r.checkClosed(); err != nil {
		return err
	}

	ctx, cancel := context.WithCancel(pctx)
	defer cancel()

	healthErr := make(chan error, 1)
	go func() {
		ectx, cancel := context.WithCancel(ctx) // cancel event context on first event
		defer cancel()
		if err := r.checkHealth(ectx); err == ErrContainerUnhealthy {
			healthErr <- ErrContainerUnhealthy
			if err := r.Shutdown(ectx); err != nil {
				log.G(ectx).WithError(err).Debug("shutdown failed on unhealthy")
			}
		}
	}()

	err := r.adapter.wait(ctx)
	if ctx.Err() != nil {
		return ctx.Err()
	}

	if err != nil {
		ee := &exitError{}
		if ec, ok := err.(exec.ExitCoder); ok {
			ee.code = ec.ExitCode()
		}
		select {
		case e := <-healthErr:
			ee.cause = e
		default:
			if err.Error() != "" {
				ee.cause = err
			}
		}
		return ee
	}

	return nil
}

// Shutdown the container cleanly.
func (r *controller) Shutdown(ctx context.Context) error {
	if err := r.checkClosed(); err != nil {
		return err
	}

	if r.cancelPull != nil {
		r.cancelPull()
	}

	if err := r.adapter.shutdown(ctx); err != nil {
		if isUnknownContainer(err) || isStoppedContainer(err) {
			return nil
		}

		return err
	}

	return nil
}

// Terminate the container, with force.
func (r *controller) Terminate(ctx context.Context) error {
	if err := r.checkClosed(); err != nil {
		return err
	}

	if r.cancelPull != nil {
		r.cancelPull()
	}

	if err := r.adapter.terminate(ctx); err != nil {
		if isUnknownContainer(err) {
			return nil
		}

		return err
	}

	return nil
}

// Remove the container and its resources.
func (r *controller) Remove(ctx context.Context) error {
	if err := r.checkClosed(); err != nil {
		return err
	}

	if r.cancelPull != nil {
		r.cancelPull()
	}

	// It may be necessary to shut down the task before removing it.
	if err := r.Shutdown(ctx); err != nil {
		if isUnknownContainer(err) {
			return nil
		}
		// This may fail if the task was already shut down.
		log.G(ctx).WithError(err).Debug("shutdown failed on removal")
	}

	// Try removing networks referenced in this task in case this
	// task is the last one referencing it
	if err := r.adapter.removeNetworks(ctx); err != nil {
		if isUnknownContainer(err) {
			return nil
		}
		return err
	}

	if err := r.adapter.remove(ctx); err != nil {
		if isUnknownContainer(err) {
			return nil
		}

		return err
	}
	return nil
}

// Close the runner and clean up any ephemeral resources.
func (r *controller) Close() error {
	select {
	case <-r.closed:
		return r.err
	default:
		if r.cancelPull != nil {
			r.cancelPull()
		}

		r.err = exec.ErrControllerClosed
		close(r.closed)
	}
	return nil
}

func (r *controller) matchevent(event events.Message) bool {
	if event.Type != events.ContainerEventType {
		return false
	}

	// TODO(stevvooe): Filter based on ID matching, in addition to name.

	// Make sure the events are for this container.
	if event.Actor.Attributes["name"] != r.adapter.container.name() {
		return false
	}

	return true
}

func (r *controller) checkClosed() error {
	select {
	case <-r.closed:
		return r.err
	default:
		return nil
	}
}

func parseContainerStatus(ctnr types.ContainerJSON) (*api.ContainerStatus, error) {
	status := &api.ContainerStatus{
		ContainerID: ctnr.ID,
		PID:         int32(ctnr.State.Pid),
		ExitCode:    int32(ctnr.State.ExitCode),
	}

	return status, nil
}

type exitError struct {
	code  int
	cause error
}

func (e *exitError) Error() string {
	if e.cause != nil {
		return fmt.Sprintf("task: non-zero exit (%v): %v", e.code, e.cause)
	}

	return fmt.Sprintf("task: non-zero exit (%v)", e.code)
}

func (e *exitError) ExitCode() int {
	return int(e.code)
}

func (e *exitError) Cause() error {
	return e.cause
}

// checkHealth blocks until unhealthy container is detected or ctx exits
func (r *controller) checkHealth(ctx context.Context) error {
	eventq := r.adapter.events(ctx)

	for {
		select {
		case <-ctx.Done():
			return nil
		case <-r.closed:
			return nil
		case event := <-eventq:
			if !r.matchevent(event) {
				continue
			}

			switch event.Action {
			case "health_status: unhealthy":
				return ErrContainerUnhealthy
			}
		}
	}
}
<|endoftext|>


<commit_before>package golf

import (
	"testing"
)

func assertStringEqual(t *testing.T, expected, got string) {
	if expected != got {
		t.Errorf("Expected %v, got %v", expected, got)
	}
}

func assertSliceEqual(t *testing.T, expected, got []string) {
	if len(expected) != len(got) {
		t.Errorf("Slice length not equal, expected: %v, got %v", expected, got)
	}
	for i := 0; i < len(expected); i++ {
		if expected[i] != got[i] {
			t.Errorf("Slice not equal, expected: %v, got %v", expected, got)
		}
	}
}

type route struct {
	method   string
	path     string
	testPath string
	params   map[string]string
}

var githubAPI = []route{
	// OAuth Authorizations
	{"GET", "/authorizations", "/authorizations", map[string]string{}},
	{"GET", "/auth", "/auth", map[string]string{}},
	{"GET", "/authorizations/:id", "/authorizations/12345", map[string]string{"id": "12345"}},
	{"POST", "/authorizations", "/authorizations", map[string]string{}},
	{"DELETE", "/authorizations/:id", "/authorizations/12345", map[string]string{"id": "12345"}},
	{"GET", "/applications/:client_id/tokens/:access_token", "/applications/12345/tokens/67890", map[string]string{"client_id": "12345", "access_token": "67890"}},
	{"DELETE", "/applications/:client_id/tokens", "/applications/12345/tokens", map[string]string{"client_id": "12345"}},
	{"DELETE", "/applications/:client_id/tokens/:access_token", "/applications/12345/tokens/67890", map[string]string{"client_id": "12345", "access_token": "67890"}},

	// Activity
	{"GET", "/events", "/events", nil},
	{"GET", "/repos/:owner/:repo/events", "/repos/dinever/golf/events", map[string]string{"owner": "dinever", "repo": "golf"}},
	{"GET", "/networks/:owner/:repo/events", "/networks/dinever/golf/events", map[string]string{"owner": "dinever", "repo": "golf"}},
	{"GET", "/orgs/:org/events", "/orgs/golf/events", map[string]string{"org": "golf"}},
	{"GET", "/users/:user/received_events", "/users/dinever/received_events", nil},
	{"GET", "/users/:user/received_events/public", "/users/dinever/received_events/public", nil},
}

func handler(ctx *Context) {
}

func TestRouter(t *testing.T) {
	router := newRouter()
	for _, route := range githubAPI {
		router.AddRoute(route.method, route.path, handler)
	}

	for _, route := range githubAPI {
		_, param, err := router.FindRoute(route.method, route.testPath)
		if err != nil {
			t.Errorf("Can not find route: %v", route.testPath)
		}

		for key, expected := range route.params {
			val, err := param.ByName(key)
			if err != nil {
				t.Errorf("Can not retrieve parameter from route %v: %v", route.testPath, key)
			} else {
				assertStringEqual(t, expected, val)
			}
			val, err = param.ByName(key)
			if err != nil {
				t.Errorf("Can not retrieve parameter from route %v: %v", route.testPath, key)
			} else {
				assertStringEqual(t, expected, val)
			}
		}
	}
}

func TestSplitURLPath(t *testing.T) {

	var table = map[string][2][]string{
		"/users/:name":                         {{"/users/", ":"}, {"name"}},
		"/users/:name/put":                     {{"/users/", ":", "/put"}, {"name"}},
		"/users/:name/put/:section":            {{"/users/", ":", "/put/", ":"}, {"name", "section"}},
		"/customers/:name/put/:section":        {{"/customers/", ":", "/put/", ":"}, {"name", "section"}},
		"/customers/groups/:name/put/:section": {{"/customers/groups/", ":", "/put/", ":"}, {"name", "section"}},
	}

	for path, result := range table {
		parts, _ := splitURLpath(path)
		assertSliceEqual(t, parts, result[0])
	}
}

func TestIncorrectPath(t *testing.T) {
	path := "/users/foo:name/"
	defer func() {
		if err := recover(); err != nil {
		}
	}()
	router := newRouter()
	router.AddRoute("GET", path, handler)
	t.Errorf("Incorrect path should raise an error.")
}
<commit_msg>[test] Improve test coverage when path is not found<commit_after>package golf

import (
	"testing"
)

func assertStringEqual(t *testing.T, expected, got string) {
	if expected != got {
		t.Errorf("Expected %v, got %v", expected, got)
	}
}

func assertSliceEqual(t *testing.T, expected, got []string) {
	if len(expected) != len(got) {
		t.Errorf("Slice length not equal, expected: %v, got %v", expected, got)
	}
	for i := 0; i < len(expected); i++ {
		if expected[i] != got[i] {
			t.Errorf("Slice not equal, expected: %v, got %v", expected, got)
		}
	}
}

type route struct {
	method   string
	path     string
	testPath string
	params   map[string]string
}

var githubAPI = []route{
	// OAuth Authorizations
	{"GET", "/authorizations", "/authorizations", map[string]string{}},
	{"GET", "/auth", "/auth", map[string]string{}},
	{"GET", "/authorizations/:id", "/authorizations/12345", map[string]string{"id": "12345"}},
	{"POST", "/authorizations", "/authorizations", map[string]string{}},
	{"DELETE", "/authorizations/:id", "/authorizations/12345", map[string]string{"id": "12345"}},
	{"GET", "/applications/:client_id/tokens/:access_token", "/applications/12345/tokens/67890", map[string]string{"client_id": "12345", "access_token": "67890"}},
	{"DELETE", "/applications/:client_id/tokens", "/applications/12345/tokens", map[string]string{"client_id": "12345"}},
	{"DELETE", "/applications/:client_id/tokens/:access_token", "/applications/12345/tokens/67890", map[string]string{"client_id": "12345", "access_token": "67890"}},

	// Activity
	{"GET", "/events", "/events", nil},
	{"GET", "/repos/:owner/:repo/events", "/repos/dinever/golf/events", map[string]string{"owner": "dinever", "repo": "golf"}},
	{"GET", "/networks/:owner/:repo/events", "/networks/dinever/golf/events", map[string]string{"owner": "dinever", "repo": "golf"}},
	{"GET", "/orgs/:org/events", "/orgs/golf/events", map[string]string{"org": "golf"}},
	{"GET", "/users/:user/received_events", "/users/dinever/received_events", nil},
	{"GET", "/users/:user/received_events/public", "/users/dinever/received_events/public", nil},
}

func handler(ctx *Context) {
}

func TestRouter(t *testing.T) {
	router := newRouter()
	for _, route := range githubAPI {
		router.AddRoute(route.method, route.path, handler)
	}

	for _, route := range githubAPI {
		_, param, err := router.FindRoute(route.method, route.testPath)
		if err != nil {
			t.Errorf("Can not find route: %v", route.testPath)
		}

		for key, expected := range route.params {
			val, err := param.ByName(key)
			if err != nil {
				t.Errorf("Can not retrieve parameter from route %v: %v", route.testPath, key)
			} else {
				assertStringEqual(t, expected, val)
			}
			val, err = param.ByName(key)
			if err != nil {
				t.Errorf("Can not retrieve parameter from route %v: %v", route.testPath, key)
			} else {
				assertStringEqual(t, expected, val)
			}
		}
	}
}

func TestSplitURLPath(t *testing.T) {

	var table = map[string][2][]string{
		"/users/:name":                         {{"/users/", ":"}, {"name"}},
		"/users/:name/put":                     {{"/users/", ":", "/put"}, {"name"}},
		"/users/:name/put/:section":            {{"/users/", ":", "/put/", ":"}, {"name", "section"}},
		"/customers/:name/put/:section":        {{"/customers/", ":", "/put/", ":"}, {"name", "section"}},
		"/customers/groups/:name/put/:section": {{"/customers/groups/", ":", "/put/", ":"}, {"name", "section"}},
	}

	for path, result := range table {
		parts, _ := splitURLpath(path)
		assertSliceEqual(t, parts, result[0])
	}
}

func TestIncorrectPath(t *testing.T) {
	path := "/users/foo:name/"
	defer func() {
		if err := recover(); err != nil {
		}
	}()
	router := newRouter()
	router.AddRoute("GET", path, handler)
	t.Errorf("Incorrect path should raise an error.")
}

func TestPathNotFound(t *testing.T) {
	path := map[string]string {
		"/users/name/": "/users/name/dinever/",
	}
	defer func() {
		if err := recover(); err != nil {
		}
	}()
	router := newRouter()
	for route, wrongPath := range path {
		router.AddRoute("GET", route, handler)
		h, p, err := router.FindRoute("GET", wrongPath)
		if h != nil {
			t.Errorf("Should return nil handler when path not found.")
		}
		if p.Len() != 0 {
			t.Errorf("Should return nil parameter when path not found.")
		}
		if err == nil {
			t.Errorf("Should rasie an error when path not found.")
		}
	}
}
<|endoftext|>


<commit_before>package rest

import (
	"fmt"
	"strings"
	"testing"
)

var urls = []string{
	"///user/:id/param1/param2/:id/param3//",
	"/user/:id/param",
	"/user/:id",
	"/user/test",
	"/user/vova/:param",
	"/user/:vova/param3",
	"/user/:id/param2",
	"/user",
}

func TestSplit(t *testing.T) {
	for _, url := range urls {
		splitted := split(url)
		fmt.Printf("%q\n", splitted)
		if strings.Join(splitted, "/") != strings.Trim(url, "/") {
			t.Error(url, splitted)
		}
	}
}

func TestRouter(t *testing.T) {
	var r router
	for _, url := range urls {
		if err := r.add(url, url); err != nil {
			t.Error(err)
		}
	}
	for _, url := range urls {
		handler, params := r.lookup(url)
		if handler == nil {
			t.Error("Nil handler:", url)
		}
		fmt.Println(handler, params)
	}
	url := "/user/:id/param1/"
	handler, params := r.lookup(url)
	if handler != nil {
		t.Error("Bad handler:", url)
	}
	fmt.Println(handler, params)
	handler, params = r.lookup("/user/test/mama/1/2/3/4/5/6/7/8/9/0/")
	if handler != nil {
		t.Error("Bad handler:", url)
	}
}

func TestLongRouter(t *testing.T) {
	var r router
	url := `1/2/3/4/5/6/7/8/9/0/1/2/3/4/5/6/7/8/9/0/1/2/3/4/5/6/7/8/9/0/1/2/3/4/5/6/7/8/9/0/1/2/3/4/5/6/7/8/9/0/` +
		`1/2/3/4/5/6/7/8/9/0/1/2/3/4/5/6/7/8/9/0/1/2/3/4/5/6/7/8/9/0/1/2/3/4/5/6/7/8/9/0/1/2/3/4/5/6/7/8/9/0/` +
		`1/2/3/4/5/6/7/8/9/0/1/2/3/4/5/6/7/8/9/0/1/2/3/4/5/6/7/8/9/0/1/2/3/4/5/6/7/8/9/0/1/2/3/4/5/6/7/8/9/0/` +
		`1/2/3/4/5/6/7/8/9/0/1/2/3/4/5/6/7/8/9/0/1/2/3/4/5/6/7/8/9/0/1/2/3/4/5/6/7/8/9/0/1/2/3/4/5/6/7/8/9/0/` +
		`1/2/3/4/5/6/7/8/9/0/1/2/3/4/5/6/7/8/9/0/1/2/3/4/5/6/7/8/9/0/1/2/3/4/5/6/7/8/9/0/1/2/3/4/5/6/7/8/9/0/` +
		`1/2/3/4/5/6/7/8/9/0/1/2/3/4/5/6/7/8/9/0/1/2/3/4/5/6/7/8/9/0/1/2/3/4/5/6/7/8/9/0/1/2/3/4/5/6/7/8/9/0/`
	if err := r.add(url, "long"); err == nil {
		t.Error("must be error")
	}
}

func TestOnlyStaticRouter(t *testing.T) {
	var r router
	var urls = []string{
		"test/url",
		"test2/url",
		"test2/add",
		"test/add",
		"test",
	}
	for _, url := range urls {
		if err := r.add(url, "long"); err != nil {
			t.Error(err)
		}
	}
	handler, _ := r.lookup("/test")
	if handler == nil {
		t.Error("Bad handler:", "/test")
	}
	handler, _ = r.lookup("/test2")
	if handler != nil {
		t.Error("Bad handler:", "/test2")
	}
}
<commit_msg>tests<commit_after>package rest

import (
	"fmt"
	"strings"
	"testing"
)

var urls = []string{
	"///user/:id/param1/param2/:id/param3//",
	"/user/:id/param",
	"/user/:id",
	"/user/test",
	"/user/vova/:param",
	"/user/:vova/param3",
	"/user/:id/param2",
	"/user",
}

func TestSplit(t *testing.T) {
	for _, url := range urls {
		splitted := split(url)
		fmt.Printf("%q\n", splitted)
		if strings.Join(splitted, "/") != strings.Trim(url, "/") {
			t.Error(url, splitted)
		}
	}
}

func TestRouter(t *testing.T) {
	var r router
	for _, url := range urls {
		if err := r.add(url, url); err != nil {
			t.Error(err)
		}
	}
	for _, url := range urls {
		handler, params := r.lookup(url)
		if handler == nil {
			t.Error("Nil handler:", url)
		}
		fmt.Println(handler, params)
	}
	url := "/user/:id/param1/"
	handler, params := r.lookup(url)
	if handler != nil {
		t.Error("Bad handler:", url)
	}
	fmt.Println(handler, params)
	handler, params = r.lookup("/user/test/mama/1/2/3/4/5/6/7/8/9/0/")
	if handler != nil {
		t.Error("Bad handler:", url)
	}
}

func TestLongRouter(t *testing.T) {
	var r router
	url := `1/2/3/4/5/6/7/8/9/0/1/2/3/4/5/6/7/8/9/0/1/2/3/4/5/6/7/8/9/0/1/2/3/4/5/6/7/8/9/0/1/2/3/4/5/6/7/8/9/0/` +
		`1/2/3/4/5/6/7/8/9/0/1/2/3/4/5/6/7/8/9/0/1/2/3/4/5/6/7/8/9/0/1/2/3/4/5/6/7/8/9/0/1/2/3/4/5/6/7/8/9/0/` +
		`1/2/3/4/5/6/7/8/9/0/1/2/3/4/5/6/7/8/9/0/1/2/3/4/5/6/7/8/9/0/1/2/3/4/5/6/7/8/9/0/1/2/3/4/5/6/7/8/9/0/` +
		`1/2/3/4/5/6/7/8/9/0/1/2/3/4/5/6/7/8/9/0/1/2/3/4/5/6/7/8/9/0/1/2/3/4/5/6/7/8/9/0/1/2/3/4/5/6/7/8/9/0/` +
		`1/2/3/4/5/6/7/8/9/0/1/2/3/4/5/6/7/8/9/0/1/2/3/4/5/6/7/8/9/0/1/2/3/4/5/6/7/8/9/0/1/2/3/4/5/6/7/8/9/0/` +
		`1/2/3/4/5/6/7/8/9/0/1/2/3/4/5/6/7/8/9/0/1/2/3/4/5/6/7/8/9/0/1/2/3/4/5/6/7/8/9/0/1/2/3/4/5/6/7/8/9/0/`
	if err := r.add(url, "long"); err == nil {
		t.Error("must be error")
	}
}

func TestOnlyStaticRouter(t *testing.T) {
	var r router
	var urls = []string{
		"test/url",
		"test2/url",
		"test2/add",
		"test/add",
		"test",
	}
	for _, url := range urls {
		if err := r.add(url, "long"); err != nil {
			t.Error(err)
		}
	}
	handler, _ := r.lookup("/test")
	if handler == nil {
		t.Error("Bad handler:", "/test")
	}
	handler, _ = r.lookup("/test2")
	if handler != nil {
		t.Error("Bad handler:", "/test2")
	}
}

func TestRouterSort(t *testing.T) {
	var r router
	var urls = []string{
		"/1/2/3/",
		"/:1/2/3/",
		"/1/:2/3/",
		"/1/2/:3/",
		"/:1/:2/3/",
		"/:1/2/:3/",
		"/1/:2/:3/",
	}
	for _, url := range urls {
		if err := r.add(url, "long"); err != nil {
			t.Error(err)
		}
	}
}
<|endoftext|>


<commit_before>// +build !goji_router_simple

package goji

import (
	"net/http"
	"sort"
	"strings"

	"goji.io/internal"
	"golang.org/x/net/context"
)

type router struct {
	routes   []route
	methods  map[string]*trieNode
	wildcard trieNode
}

type route struct {
	Pattern
	Handler
}

type child struct {
	prefix string
	node   *trieNode
}

type trieNode struct {
	routes   []int
	children []child
}

func (rt *router) add(p Pattern, h Handler) {
	i := len(rt.routes)
	rt.routes = append(rt.routes, route{p, h})

	var prefix string
	if pp, ok := p.(pathPrefix); ok {
		prefix = pp.PathPrefix()
	}

	var methods map[string]struct{}
	if hm, ok := p.(httpMethods); ok {
		methods = hm.HTTPMethods()
	}
	if methods == nil {
		rt.wildcard.add(prefix, i)
		for _, sub := range rt.methods {
			sub.add(prefix, i)
		}
	} else {
		if rt.methods == nil {
			rt.methods = make(map[string]*trieNode)
		}

		for method := range methods {
			if _, ok := rt.methods[method]; !ok {
				rt.methods[method] = rt.wildcard.clone()
			}
			rt.methods[method].add(prefix, i)
		}
	}
}

func (rt *router) route(ctx context.Context, r *http.Request) context.Context {
	tn := &rt.wildcard
	if tn2, ok := rt.methods[r.Method]; ok {
		tn = tn2
	}

	path := ctx.Value(internal.Path).(string)
	for path != "" {
		i := sort.Search(len(tn.children), func(i int) bool {
			return path[0] <= tn.children[i].prefix[0]
		})
		if i == len(tn.children) || !strings.HasPrefix(path, tn.children[i].prefix) {
			break
		}

		path = path[len(tn.children[i].prefix):]
		tn = tn.children[i].node
	}
	for _, i := range tn.routes {
		if ctx := rt.routes[i].Match(ctx, r); ctx != nil {
			return &match{ctx, rt.routes[i].Pattern, rt.routes[i].Handler}
		}
	}
	return &match{Context: ctx}
}

// We can be a teensy bit more efficient here: we're maintaining a sorted list,
// so we know exactly where to insert the new element. But since that involves
// more bookkeeping and makes the code messier, let's cross that bridge when we
// come to it.
type byPrefix []child

func (b byPrefix) Len() int {
	return len(b)
}
func (b byPrefix) Less(i, j int) bool {
	return b[i].prefix < b[j].prefix
}
func (b byPrefix) Swap(i, j int) {
	b[i], b[j] = b[j], b[i]
}

func longestPrefix(a, b string) string {
	mlen := len(a)
	if len(b) < mlen {
		mlen = len(b)
	}
	for i := 0; i < mlen; i++ {
		if a[i] != b[i] {
			return a[:i]
		}
	}
	return a[:mlen]
}

func (tn *trieNode) add(prefix string, idx int) {
	if len(prefix) == 0 {
		tn.routes = append(tn.routes, idx)
		for i := range tn.children {
			tn.children[i].node.add(prefix, idx)
		}
		return
	}

	ch := prefix[0]
	i := sort.Search(len(tn.children), func(i int) bool {
		return ch <= tn.children[i].prefix[0]
	})

	for ; i < len(tn.children); i++ {
		if tn.children[i].prefix[0] > ch {
			break
		}

		lp := longestPrefix(prefix, tn.children[i].prefix)

		if tn.children[i].prefix == lp {
			tn.children[i].node.add(prefix[len(lp):], idx)
			return
		}

		split := new(trieNode)
		split.children = []child{
			{tn.children[i].prefix[len(lp):], tn.children[i].node},
		}
		split.routes = append([]int(nil), tn.routes...)
		split.add(prefix[len(lp):], idx)

		tn.children[i].prefix = lp
		tn.children[i].node = split
		sort.Sort(byPrefix(tn.children))
		return
	}

	routes := append([]int(nil), tn.routes...)
	tn.children = append(tn.children, child{
		prefix: prefix,
		node:   &trieNode{routes: append(routes, idx)},
	})
	sort.Sort(byPrefix(tn.children))
}

func (tn *trieNode) clone() *trieNode {
	clone := new(trieNode)
	clone.routes = append(clone.routes, tn.routes...)
	clone.children = append(clone.children, tn.children...)
	for i := range clone.children {
		clone.children[i].node = tn.children[i].node.clone()
	}
	return clone
}
<commit_msg>goji: clarify route addition control flow<commit_after>// +build !goji_router_simple

package goji

import (
	"net/http"
	"sort"
	"strings"

	"goji.io/internal"
	"golang.org/x/net/context"
)

type router struct {
	routes   []route
	methods  map[string]*trieNode
	wildcard trieNode
}

type route struct {
	Pattern
	Handler
}

type child struct {
	prefix string
	node   *trieNode
}

type trieNode struct {
	routes   []int
	children []child
}

func (rt *router) add(p Pattern, h Handler) {
	i := len(rt.routes)
	rt.routes = append(rt.routes, route{p, h})

	var prefix string
	if pp, ok := p.(pathPrefix); ok {
		prefix = pp.PathPrefix()
	}

	var methods map[string]struct{}
	if hm, ok := p.(httpMethods); ok {
		methods = hm.HTTPMethods()
	}
	if methods == nil {
		rt.wildcard.add(prefix, i)
		for _, sub := range rt.methods {
			sub.add(prefix, i)
		}
	} else {
		if rt.methods == nil {
			rt.methods = make(map[string]*trieNode)
		}

		for method := range methods {
			if _, ok := rt.methods[method]; !ok {
				rt.methods[method] = rt.wildcard.clone()
			}
			rt.methods[method].add(prefix, i)
		}
	}
}

func (rt *router) route(ctx context.Context, r *http.Request) context.Context {
	tn := &rt.wildcard
	if tn2, ok := rt.methods[r.Method]; ok {
		tn = tn2
	}

	path := ctx.Value(internal.Path).(string)
	for path != "" {
		i := sort.Search(len(tn.children), func(i int) bool {
			return path[0] <= tn.children[i].prefix[0]
		})
		if i == len(tn.children) || !strings.HasPrefix(path, tn.children[i].prefix) {
			break
		}

		path = path[len(tn.children[i].prefix):]
		tn = tn.children[i].node
	}
	for _, i := range tn.routes {
		if ctx := rt.routes[i].Match(ctx, r); ctx != nil {
			return &match{ctx, rt.routes[i].Pattern, rt.routes[i].Handler}
		}
	}
	return &match{Context: ctx}
}

// We can be a teensy bit more efficient here: we're maintaining a sorted list,
// so we know exactly where to insert the new element. But since that involves
// more bookkeeping and makes the code messier, let's cross that bridge when we
// come to it.
type byPrefix []child

func (b byPrefix) Len() int {
	return len(b)
}
func (b byPrefix) Less(i, j int) bool {
	return b[i].prefix < b[j].prefix
}
func (b byPrefix) Swap(i, j int) {
	b[i], b[j] = b[j], b[i]
}

func longestPrefix(a, b string) string {
	mlen := len(a)
	if len(b) < mlen {
		mlen = len(b)
	}
	for i := 0; i < mlen; i++ {
		if a[i] != b[i] {
			return a[:i]
		}
	}
	return a[:mlen]
}

func (tn *trieNode) add(prefix string, idx int) {
	if len(prefix) == 0 {
		tn.routes = append(tn.routes, idx)
		for i := range tn.children {
			tn.children[i].node.add(prefix, idx)
		}
		return
	}

	ch := prefix[0]
	i := sort.Search(len(tn.children), func(i int) bool {
		return ch <= tn.children[i].prefix[0]
	})

	if i == len(tn.children) || ch != tn.children[i].prefix[0] {
		routes := append([]int(nil), tn.routes...)
		tn.children = append(tn.children, child{
			prefix: prefix,
			node:   &trieNode{routes: append(routes, idx)},
		})
	} else {
		lp := longestPrefix(prefix, tn.children[i].prefix)

		if tn.children[i].prefix == lp {
			tn.children[i].node.add(prefix[len(lp):], idx)
			return
		}

		split := new(trieNode)
		split.children = []child{
			{tn.children[i].prefix[len(lp):], tn.children[i].node},
		}
		split.routes = append([]int(nil), tn.routes...)
		split.add(prefix[len(lp):], idx)

		tn.children[i].prefix = lp
		tn.children[i].node = split
	}

	sort.Sort(byPrefix(tn.children))
}

func (tn *trieNode) clone() *trieNode {
	clone := new(trieNode)
	clone.routes = append(clone.routes, tn.routes...)
	clone.children = append(clone.children, tn.children...)
	for i := range clone.children {
		clone.children[i].node = tn.children[i].node.clone()
	}
	return clone
}
<|endoftext|>


<commit_before>package drivers

import (
	"fmt"
)

// ErrNotImplemented is the "Not implemented" error.
var ErrNotImplemented = fmt.Errorf("Not implemented")

// ErrInvalidFunction is the "Invalid function" error.
var ErrInvalidFunction = fmt.Errorf("Invalid function")

// ErrUnknownDriver is the "Unknown driver" error.
var ErrUnknownDriver = fmt.Errorf("Unknown driver")

// ErrWatchExists is the "Watch already exists" error.
var ErrWatchExists = fmt.Errorf("Watch already exists")

// ErrInvalidPath is the "Invalid path" error.
type ErrInvalidPath struct {
	PrefixPath string
}

// Error returns the error string.
func (e *ErrInvalidPath) Error() string {
	return fmt.Sprintf("Path needs to be in %s", e.PrefixPath)
}
<commit_msg>lxd/fsmonitor/drivers/errors: Removes unused variable ErrNotImplemented<commit_after>package drivers

import (
	"fmt"
)

// ErrInvalidFunction is the "Invalid function" error.
var ErrInvalidFunction = fmt.Errorf("Invalid function")

// ErrUnknownDriver is the "Unknown driver" error.
var ErrUnknownDriver = fmt.Errorf("Unknown driver")

// ErrWatchExists is the "Watch already exists" error.
var ErrWatchExists = fmt.Errorf("Watch already exists")

// ErrInvalidPath is the "Invalid path" error.
type ErrInvalidPath struct {
	PrefixPath string
}

// Error returns the error string.
func (e *ErrInvalidPath) Error() string {
	return fmt.Sprintf("Path needs to be in %s", e.PrefixPath)
}
<|endoftext|>