<commit_before>package parser

import (
	. "github.com/smartystreets/goconvey/convey"
	"pfi/sensorbee/sensorbee/data"
	"testing"
)

func TestAssembleSourceSinkSpecs(t *testing.T) {
	Convey("Given a parseStack", t, func() {
		ps := parseStack{}

		Convey("When the stack contains only SourceSinkParams in the given range", func() {
			ps.PushComponent(0, 6, Raw{"PRE"})
			ps.PushComponent(6, 7, SourceSinkParamAST{"key", data.String("val")})
			ps.PushComponent(7, 8, SourceSinkParamAST{"a", data.String("b")})
			ps.AssembleSourceSinkSpecs(6, 8)

			Convey("Then AssembleSourceSinkSpecs transforms them into one item", func() {
				So(ps.Len(), ShouldEqual, 2)

				Convey("And that item is a SourceSinkSpecsAST", func() {
					top := ps.Peek()
					So(top, ShouldNotBeNil)
					So(top.begin, ShouldEqual, 6)
					So(top.end, ShouldEqual, 8)
					So(top.comp, ShouldHaveSameTypeAs, SourceSinkSpecsAST{})

					Convey("And it contains the previously pushed data", func() {
						comp := top.comp.(SourceSinkSpecsAST)
						So(len(comp.Params), ShouldEqual, 2)
						So(comp.Params[0].Key, ShouldEqual, "key")
						So(comp.Params[0].Value, ShouldEqual, data.String("val"))
						So(comp.Params[1].Key, ShouldEqual, "a")
						So(comp.Params[1].Value, ShouldEqual, data.String("b"))
					})
				})
			})
		})

		Convey("When the stack contains no elements in the given range", func() {
			ps.PushComponent(0, 6, Raw{"PRE"})
			ps.AssembleSourceSinkSpecs(6, 8)

			Convey("Then AssembleSourceSinkSpecs pushes one item onto the stack", func() {
				So(ps.Len(), ShouldEqual, 2)

				Convey("And that item is a SourceSinkSpecsAST", func() {
					top := ps.Peek()
					So(top, ShouldNotBeNil)
					So(top.begin, ShouldEqual, 6)
					So(top.end, ShouldEqual, 8)
					So(top.comp, ShouldHaveSameTypeAs, SourceSinkSpecsAST{})

					Convey("And it contains an empty list", func() {
						comp := top.comp.(SourceSinkSpecsAST)
						So(len(comp.Params), ShouldEqual, 0)
					})
				})
			})
		})

		Convey("When the given range is empty", func() {
			ps.PushComponent(0, 6, Raw{"PRE"})
			ps.AssembleSourceSinkSpecs(6, 6)

			Convey("Then AssembleSourceSinkSpecs pushes one item onto the stack", func() {
				So(ps.Len(), ShouldEqual, 2)

				Convey("And that item is a SourceSinkSpecsAST", func() {
					top := ps.Peek()
					So(top, ShouldNotBeNil)
					So(top.begin, ShouldEqual, 6)
					So(top.end, ShouldEqual, 6)
					So(top.comp, ShouldHaveSameTypeAs, SourceSinkSpecsAST{})

					Convey("And it contains an empty list", func() {
						comp := top.comp.(SourceSinkSpecsAST)
						So(len(comp.Params), ShouldEqual, 0)
					})
				})
			})
		})

		Convey("When the stack contains non-SourceSinkParams in the given range", func() {
			ps.PushComponent(0, 6, Raw{"PRE"})
			f := func() {
				ps.AssembleSourceSinkSpecs(0, 8)
			}

			Convey("Then AssembleSourceSinkSpecs panics", func() {
				So(f, ShouldPanic)
			})
		})
	})

	Convey("Given a parser", t, func() {
		p := &bqlPeg{}

		Convey("When creating a source without a WITH", func() {
			p.Buffer = "CREATE SOURCE a TYPE b"
			p.Init()

			Convey("Then the statement should be parsed correctly", func() {
				err := p.Parse()
				So(err, ShouldEqual, nil)
				p.Execute()

				ps := p.parseStack
				So(ps.Len(), ShouldEqual, 1)
				top := ps.Peek().comp
				So(top, ShouldHaveSameTypeAs, CreateSourceStmt{})
				s := top.(CreateSourceStmt)
				So(s.Params, ShouldBeNil)
			})
		})

		Convey("When creating a source with a WITH", func() {
			p.Buffer = `CREATE SOURCE a TYPE b WITH port=8080, proto='http'`
			p.Init()

			Convey("Then the statement should be parsed correctly", func() {
				err := p.Parse()
				So(err, ShouldEqual, nil)
				p.Execute()

				ps := p.parseStack
				So(ps.Len(), ShouldEqual, 1)
				top := ps.Peek().comp
				So(top, ShouldHaveSameTypeAs, CreateSourceStmt{})
				s := top.(CreateSourceStmt)
				So(s.Params, ShouldNotBeNil)
				So(len(s.Params), ShouldEqual, 2)
				So(s.Params[0], ShouldResemble,
					SourceSinkParamAST{"port", data.Int(8080)})
				So(s.Params[1], ShouldResemble,
					SourceSinkParamAST{"proto", data.String("http")})
			})
		})
	})
}
<commit_msg>Add string conversion test for CREATE SOURCE<commit_after>package parser

import (
	. "github.com/smartystreets/goconvey/convey"
	"pfi/sensorbee/sensorbee/data"
	"testing"
)

func TestAssembleSourceSinkSpecs(t *testing.T) {
	Convey("Given a parseStack", t, func() {
		ps := parseStack{}

		Convey("When the stack contains only SourceSinkParams in the given range", func() {
			ps.PushComponent(0, 6, Raw{"PRE"})
			ps.PushComponent(6, 7, SourceSinkParamAST{"key", data.String("val")})
			ps.PushComponent(7, 8, SourceSinkParamAST{"a", data.String("b")})
			ps.AssembleSourceSinkSpecs(6, 8)

			Convey("Then AssembleSourceSinkSpecs transforms them into one item", func() {
				So(ps.Len(), ShouldEqual, 2)

				Convey("And that item is a SourceSinkSpecsAST", func() {
					top := ps.Peek()
					So(top, ShouldNotBeNil)
					So(top.begin, ShouldEqual, 6)
					So(top.end, ShouldEqual, 8)
					So(top.comp, ShouldHaveSameTypeAs, SourceSinkSpecsAST{})

					Convey("And it contains the previously pushed data", func() {
						comp := top.comp.(SourceSinkSpecsAST)
						So(len(comp.Params), ShouldEqual, 2)
						So(comp.Params[0].Key, ShouldEqual, "key")
						So(comp.Params[0].Value, ShouldEqual, data.String("val"))
						So(comp.Params[1].Key, ShouldEqual, "a")
						So(comp.Params[1].Value, ShouldEqual, data.String("b"))
					})
				})
			})
		})

		Convey("When the stack contains no elements in the given range", func() {
			ps.PushComponent(0, 6, Raw{"PRE"})
			ps.AssembleSourceSinkSpecs(6, 8)

			Convey("Then AssembleSourceSinkSpecs pushes one item onto the stack", func() {
				So(ps.Len(), ShouldEqual, 2)

				Convey("And that item is a SourceSinkSpecsAST", func() {
					top := ps.Peek()
					So(top, ShouldNotBeNil)
					So(top.begin, ShouldEqual, 6)
					So(top.end, ShouldEqual, 8)
					So(top.comp, ShouldHaveSameTypeAs, SourceSinkSpecsAST{})

					Convey("And it contains an empty list", func() {
						comp := top.comp.(SourceSinkSpecsAST)
						So(len(comp.Params), ShouldEqual, 0)
					})
				})
			})
		})

		Convey("When the given range is empty", func() {
			ps.PushComponent(0, 6, Raw{"PRE"})
			ps.AssembleSourceSinkSpecs(6, 6)

			Convey("Then AssembleSourceSinkSpecs pushes one item onto the stack", func() {
				So(ps.Len(), ShouldEqual, 2)

				Convey("And that item is a SourceSinkSpecsAST", func() {
					top := ps.Peek()
					So(top, ShouldNotBeNil)
					So(top.begin, ShouldEqual, 6)
					So(top.end, ShouldEqual, 6)
					So(top.comp, ShouldHaveSameTypeAs, SourceSinkSpecsAST{})

					Convey("And it contains an empty list", func() {
						comp := top.comp.(SourceSinkSpecsAST)
						So(len(comp.Params), ShouldEqual, 0)
					})
				})
			})
		})

		Convey("When the stack contains non-SourceSinkParams in the given range", func() {
			ps.PushComponent(0, 6, Raw{"PRE"})
			f := func() {
				ps.AssembleSourceSinkSpecs(0, 8)
			}

			Convey("Then AssembleSourceSinkSpecs panics", func() {
				So(f, ShouldPanic)
			})
		})
	})

	Convey("Given a parser", t, func() {
		p := &bqlPeg{}

		Convey("When creating a source without a WITH", func() {
			p.Buffer = "CREATE SOURCE a TYPE b"
			p.Init()

			Convey("Then the statement should be parsed correctly", func() {
				err := p.Parse()
				So(err, ShouldEqual, nil)
				p.Execute()

				ps := p.parseStack
				So(ps.Len(), ShouldEqual, 1)
				top := ps.Peek().comp
				So(top, ShouldHaveSameTypeAs, CreateSourceStmt{})
				s := top.(CreateSourceStmt)
				So(s.Params, ShouldBeNil)

				Convey("And String() should return the original statement", func() {
					So(s.String(), ShouldEqual, p.Buffer)
				})
			})
		})

		Convey("When creating a source with a WITH", func() {
			p.Buffer = `CREATE SOURCE a TYPE b WITH port=8080, proto='http'`
			p.Init()

			Convey("Then the statement should be parsed correctly", func() {
				err := p.Parse()
				So(err, ShouldEqual, nil)
				p.Execute()

				ps := p.parseStack
				So(ps.Len(), ShouldEqual, 1)
				top := ps.Peek().comp
				So(top, ShouldHaveSameTypeAs, CreateSourceStmt{})
				s := top.(CreateSourceStmt)
				So(s.Params, ShouldNotBeNil)
				So(len(s.Params), ShouldEqual, 2)
				So(s.Params[0], ShouldResemble,
					SourceSinkParamAST{"port", data.Int(8080)})
				So(s.Params[1], ShouldResemble,
					SourceSinkParamAST{"proto", data.String("http")})

				Convey("And String() should return the original statement", func() {
					So(s.String(), ShouldEqual, p.Buffer)
				})
			})
		})
	})
}
<|endoftext|>


<commit_before>// package fsync keeps two files or directories in sync.
//
//         err := fsync.Sync("~/dst", ".")
//
// After the above code, if err is nil, you can be sure that everything that is
// at the current directory will also be at ~/dst. Consequent calls will only
// copy changed or new files. You can use SyncDel to also delete extra files in
// the destination:
//
//         err := fsync.SyncDel("~/dst", ".")
//
package fsync

import (
	"bytes"
	"errors"
	"io"
	"io/ioutil"
	"path"
	"runtime"
	"os"
)

var (
	ErrFileOverDir = errors.New(
		"fsync: trying to overwrite a non-empty directory with a file")
)

// Sync updates dst to contain everything that is available in src.
func Sync(dst, src string) error {
	// return error instead of replacing a non-empty directory with a file
	if b, err := checkDir(dst, src); err != nil {
		return err
	} else if b {
		return ErrFileOverDir
	}

	return syncRecover(false, dst, src)
}

// SyncDel makes sure dst is a copy of src. It's only difference with Sync is in
// deleting files in dst that are not found in src.
func SyncDel(dst, src string) error {
	// return error instead of replacing a non-empty directory with a file
	if b, err := checkDir(dst, src); err != nil {
		return err
	} else if b {
		return ErrFileOverDir
	}

	return syncRecover(true, dst, src)
}

// SyncTo syncs srcs files or directories **into** to directory. Calling
//
//         SyncTo("a", "b", "c/d")
//
// is equivalent to calling
//
//         Sync("a/b", "b")
//         Sync("a/d", "c/d")
//
// Actually, this is also implementation of SyncTo.
func SyncTo(to string, srcs ...string) error {
	for _, src := range srcs {
		dst := path.Join(to, path.Base(src))
		if err := Sync(dst, src); err != nil {
			return err
		}
	}
	return nil
}

// SyncDelTo syncs srcs files or directories **into** to directory. It differs
// with SyncDelTo in using SyncDel instead of Sync.
func SyncDelTo(to string, srcs ...string) error {
	for _, src := range srcs {
		dst := path.Join(to, path.Base(src))
		if err := SyncDel(dst, src); err != nil {
			return err
		}
	}
	return nil
}

// syncRecover handles errors and calls sync
func syncRecover(del bool, dst, src string) (err error) {
	defer func() {
		if r := recover(); r != nil {
			if _, ok := r.(runtime.Error); ok {
				panic(r)
			}
			err = r.(error)
		}
	}()

	sync(del, dst, src)
	return nil
}

// sync updates dst to match with src, handling both files and directories.
func sync(del bool, dst, src string) {
	// sync permissions after handling content
	defer syncperms(dst, src)

	// read files info
	d, err := os.Stat(dst)
	if err != nil && !os.IsNotExist(err) {
		panic(err)
	}
	s, err := os.Stat(src); check(err)

	if !s.IsDir() {
		// src is a file
		// delete dst if its a directory
		if d != nil && d.IsDir() {
			check(os.RemoveAll(dst))
		}
		if !equal(dst, src) {
			// perform copy
			df, err := os.Create(dst); check(err)
			defer df.Close()
			sf, err := os.Open(src); check(err)
			defer sf.Close()
			_, err = io.Copy(df, sf); check(err)
		}
		return
	}

	// src is a directory
	// make dst if necessary
	if d == nil {
		// dst does not exist; create directory
		check(os.MkdirAll(dst, 0755)) // permissions will be synced later
	} else if !d.IsDir() {
		// dst is a file; remove and create directory
		check(os.Remove(dst))
		check(os.MkdirAll(dst, 0755)) // permissions will be synced later
	}

	// go through sf files and sync them
	files, err := ioutil.ReadDir(src); check(err)
	// make a map of filenames for quick lookup; used in deletion
	// deletion below
	m := make(map[string]bool, len(files))
	for _, file := range files {
		dst2 := path.Join(dst, file.Name())
		src2 := path.Join(src, file.Name())
		sync(del, dst2, src2)
		m[file.Name()] = true
	}

	// delete files from dst that does not exist in src
	if del {
		files, err = ioutil.ReadDir(dst); check(err)
		for _, file := range files {
			if !m[file.Name()] {
				check(os.RemoveAll(path.Join(dst, file.Name())))
			}
		}
	}
}

// syncperms makes sure dst has the same pemissions as src
func syncperms(dst, src string) {
	// get file infos; return if not exist and panic if error
	d, err1 := os.Stat(dst)
	s, err2 := os.Stat(src)
	if os.IsNotExist(err1) || os.IsNotExist(err2) {
		return
	}
	check(err1)
	check(err2)

	// return if they are already the same
	if d.Mode().Perm() == s.Mode().Perm() {
		return
	}

	// update dst's permission bits
	check(os.Chmod(dst, s.Mode().Perm()))
}

// equal returns true if both files are equal
func equal(a, b string) bool {
	// get file infos
	info1, err1 := os.Stat(a)
	info2, err2 := os.Stat(b)
	if os.IsNotExist(err1) || os.IsNotExist(err2) {
		return false
	}
	check(err1)
	check(err2)

	// check sizes
	if info1.Size() != info2.Size() {
		return false
	}

	// both have the same size, check the contents
	f1, err := os.Open(a); check(err)
	f2, err := os.Open(b); check(err)
	buf1 := make([]byte, 1000)
	buf2 := make([]byte, 1000)
	for {
		// read from both
		n1, err := f1.Read(buf1)
		if err != nil && err != io.EOF {
			panic(err)
		}
		n2, err := f2.Read(buf2)
		if err != nil && err != io.EOF {
			panic(err)
		}

		// compare read bytes
		if !bytes.Equal(buf1[:n1], buf2[:n2]) {
			return false
		}

		// end of both files
		if n1 == 0 && n2 == 0 {
			break
		}
	}

	return true
}

// checkDir returns true if dst is a non-empty directory and src is a file
func checkDir(dst, src string) (b bool, err error) {
	// read file info
	d, err := os.Stat(dst)
	if os.IsNotExist(err) {
		return false, nil
	} else if err != nil {
		return false, err
	}
	s, err := os.Stat(src)
	if err != nil {
		return false, err
	}

	// return false is dst is not a directory or src is a directory
	if !d.IsDir() || s.IsDir() {
		return false, nil
	}

	// dst is a directory and src is a file
	// check if dst is non-empty
	// read dst directory
	files, err := ioutil.ReadDir(dst)
	if err != nil {
		return false, err
	}
	if len(files) > 0 {
		return true, nil
	}
	return false, nil
}

func check(err error) {
	if err != nil {
		panic(err)
	}
}<commit_msg>Add forgotten Close call for openned files<commit_after>// package fsync keeps two files or directories in sync.
//
//         err := fsync.Sync("~/dst", ".")
//
// After the above code, if err is nil, you can be sure that everything that is
// at the current directory will also be at ~/dst. Consequent calls will only
// copy changed or new files. You can use SyncDel to also delete extra files in
// the destination:
//
//         err := fsync.SyncDel("~/dst", ".")
//
package fsync

import (
	"bytes"
	"errors"
	"io"
	"io/ioutil"
	"path"
	"runtime"
	"os"
)

var (
	ErrFileOverDir = errors.New(
		"fsync: trying to overwrite a non-empty directory with a file")
)

// Sync updates dst to contain everything that is available in src.
func Sync(dst, src string) error {
	// return error instead of replacing a non-empty directory with a file
	if b, err := checkDir(dst, src); err != nil {
		return err
	} else if b {
		return ErrFileOverDir
	}

	return syncRecover(false, dst, src)
}

// SyncDel makes sure dst is a copy of src. It's only difference with Sync is in
// deleting files in dst that are not found in src.
func SyncDel(dst, src string) error {
	// return error instead of replacing a non-empty directory with a file
	if b, err := checkDir(dst, src); err != nil {
		return err
	} else if b {
		return ErrFileOverDir
	}

	return syncRecover(true, dst, src)
}

// SyncTo syncs srcs files or directories **into** to directory. Calling
//
//         SyncTo("a", "b", "c/d")
//
// is equivalent to calling
//
//         Sync("a/b", "b")
//         Sync("a/d", "c/d")
//
// Actually, this is also implementation of SyncTo.
func SyncTo(to string, srcs ...string) error {
	for _, src := range srcs {
		dst := path.Join(to, path.Base(src))
		if err := Sync(dst, src); err != nil {
			return err
		}
	}
	return nil
}

// SyncDelTo syncs srcs files or directories **into** to directory. It differs
// with SyncDelTo in using SyncDel instead of Sync.
func SyncDelTo(to string, srcs ...string) error {
	for _, src := range srcs {
		dst := path.Join(to, path.Base(src))
		if err := SyncDel(dst, src); err != nil {
			return err
		}
	}
	return nil
}

// syncRecover handles errors and calls sync
func syncRecover(del bool, dst, src string) (err error) {
	defer func() {
		if r := recover(); r != nil {
			if _, ok := r.(runtime.Error); ok {
				panic(r)
			}
			err = r.(error)
		}
	}()

	sync(del, dst, src)
	return nil
}

// sync updates dst to match with src, handling both files and directories.
func sync(del bool, dst, src string) {
	// sync permissions after handling content
	defer syncperms(dst, src)

	// read files info
	d, err := os.Stat(dst)
	if err != nil && !os.IsNotExist(err) {
		panic(err)
	}
	s, err := os.Stat(src); check(err)

	if !s.IsDir() {
		// src is a file
		// delete dst if its a directory
		if d != nil && d.IsDir() {
			check(os.RemoveAll(dst))
		}
		if !equal(dst, src) {
			// perform copy
			df, err := os.Create(dst); check(err)
			defer df.Close()
			sf, err := os.Open(src); check(err)
			defer sf.Close()
			_, err = io.Copy(df, sf); check(err)
		}
		return
	}

	// src is a directory
	// make dst if necessary
	if d == nil {
		// dst does not exist; create directory
		check(os.MkdirAll(dst, 0755)) // permissions will be synced later
	} else if !d.IsDir() {
		// dst is a file; remove and create directory
		check(os.Remove(dst))
		check(os.MkdirAll(dst, 0755)) // permissions will be synced later
	}

	// go through sf files and sync them
	files, err := ioutil.ReadDir(src); check(err)
	// make a map of filenames for quick lookup; used in deletion
	// deletion below
	m := make(map[string]bool, len(files))
	for _, file := range files {
		dst2 := path.Join(dst, file.Name())
		src2 := path.Join(src, file.Name())
		sync(del, dst2, src2)
		m[file.Name()] = true
	}

	// delete files from dst that does not exist in src
	if del {
		files, err = ioutil.ReadDir(dst); check(err)
		for _, file := range files {
			if !m[file.Name()] {
				check(os.RemoveAll(path.Join(dst, file.Name())))
			}
		}
	}
}

// syncperms makes sure dst has the same pemissions as src
func syncperms(dst, src string) {
	// get file infos; return if not exist and panic if error
	d, err1 := os.Stat(dst)
	s, err2 := os.Stat(src)
	if os.IsNotExist(err1) || os.IsNotExist(err2) {
		return
	}
	check(err1)
	check(err2)

	// return if they are already the same
	if d.Mode().Perm() == s.Mode().Perm() {
		return
	}

	// update dst's permission bits
	check(os.Chmod(dst, s.Mode().Perm()))
}

// equal returns true if both files are equal
func equal(a, b string) bool {
	// get file infos
	info1, err1 := os.Stat(a)
	info2, err2 := os.Stat(b)
	if os.IsNotExist(err1) || os.IsNotExist(err2) {
		return false
	}
	check(err1)
	check(err2)

	// check sizes
	if info1.Size() != info2.Size() {
		return false
	}

	// both have the same size, check the contents
	f1, err := os.Open(a); check(err)
	defer f1.Close()
	f2, err := os.Open(b); check(err)
	defer f2.Close()
	buf1 := make([]byte, 1000)
	buf2 := make([]byte, 1000)
	for {
		// read from both
		n1, err := f1.Read(buf1)
		if err != nil && err != io.EOF {
			panic(err)
		}
		n2, err := f2.Read(buf2)
		if err != nil && err != io.EOF {
			panic(err)
		}

		// compare read bytes
		if !bytes.Equal(buf1[:n1], buf2[:n2]) {
			return false
		}

		// end of both files
		if n1 == 0 && n2 == 0 {
			break
		}
	}

	return true
}

// checkDir returns true if dst is a non-empty directory and src is a file
func checkDir(dst, src string) (b bool, err error) {
	// read file info
	d, err := os.Stat(dst)
	if os.IsNotExist(err) {
		return false, nil
	} else if err != nil {
		return false, err
	}
	s, err := os.Stat(src)
	if err != nil {
		return false, err
	}

	// return false is dst is not a directory or src is a directory
	if !d.IsDir() || s.IsDir() {
		return false, nil
	}

	// dst is a directory and src is a file
	// check if dst is non-empty
	// read dst directory
	files, err := ioutil.ReadDir(dst)
	if err != nil {
		return false, err
	}
	if len(files) > 0 {
		return true, nil
	}
	return false, nil
}

func check(err error) {
	if err != nil {
		panic(err)
	}
}<|endoftext|>


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

package orm

import (
	"context"
	"fmt"
	"reflect"
	"strings"

	"github.com/astaxie/beego/orm"
	"github.com/goharbor/harbor/src/lib/q"
)

// QuerySetter generates the query setter according to the provided model and query.
// e.g.
// type Foo struct{
//   Field1 string `orm:"-"`                         // can not filter/sort
//   Field2 string `orm:"column(customized_field2)"` // support filter by "Field2", "customized_field2"
//   Field3 string `sort:"false"`                    // cannot be sorted
//   Field4 string `sort:"default:desc"`             // the default field/order(asc/desc) to sort if no sorting specified in query.
//   Field5 string `filter:"false"`                  // cannot be filtered
// }
// // support filter by "Field6", "field6"
// func (f *Foo) FilterByField6(ctx context.Context, qs orm.QuerySetter, key string, value interface{}) orm.QuerySetter {
//   ...
//	 return qs
// }
//
// Defining the method "GetDefaultSorts() []*q.Sort" for the model whose default sorting contains more than one fields
// type Bar struct{
//   Field1 string
//   Field2 string
// }
// // Sort by "Field1" desc, "Field2"
// func (b *Bar) GetDefaultSorts() []*q.Sort {
//	return []*q.Sort{
//		{
//			Key:  "Field1",
//			DESC: true,
//		},
//		{
//			Key:  "Field2",
//			DESC: false,
//		},
//	 }
// }
func QuerySetter(ctx context.Context, model interface{}, query *q.Query) (orm.QuerySeter, error) {
	t := reflect.TypeOf(model)
	if t.Kind() != reflect.Ptr {
		return nil, fmt.Errorf("<orm.QuerySetter> cannot use non-ptr model struct `%s`", getFullName(t.Elem()))
	}
	ormer, err := FromContext(ctx)
	if err != nil {
		return nil, err
	}
	qs := ormer.QueryTable(model)
	if query == nil {
		return qs, nil
	}

	metadata := parseModel(model)
	// set filters
	qs = setFilters(ctx, qs, query, metadata)

	// sorting
	qs = setSorts(qs, query, metadata)

	// pagination
	if query.PageSize > 0 {
		qs = qs.Limit(query.PageSize)
		if query.PageNumber > 0 {
			qs = qs.Offset(query.PageSize * (query.PageNumber - 1))
		}
	}

	return qs, nil
}

// PaginationOnRawSQL append page information to the raw sql
// It should be called after the order by
// e.g.
// select a, b, c from mytable order by a limit ? offset ?
// it appends the " limit ? offset ? " to sql,
// and appends the limit value and offset value to the params of this query
func PaginationOnRawSQL(query *q.Query, sql string, params []interface{}) (string, []interface{}) {
	if query != nil && query.PageSize > 0 {
		sql += ` limit ?`
		params = append(params, query.PageSize)

		if query.PageNumber > 0 {
			sql += ` offset ?`
			params = append(params, (query.PageNumber-1)*query.PageSize)
		}
	}
	return sql, params
}

// QuerySetterForCount creates the query setter used for count with the sort and pagination information ignored
func QuerySetterForCount(ctx context.Context, model interface{}, query *q.Query, ignoredCols ...string) (orm.QuerySeter, error) {
	query = q.MustClone(query)
	query.Sorts = nil
	query.PageSize = 0
	query.PageNumber = 0
	return QuerySetter(ctx, model, query)
}

// set filters according to the query
func setFilters(ctx context.Context, qs orm.QuerySeter, query *q.Query, meta *metadata) orm.QuerySeter {
	for key, value := range query.Keywords {
		// The "strings.SplitN()" here is a workaround for the incorrect usage of query which should be avoided
		// e.g. use the query with the knowledge of underlying ORM implementation, the "OrList" should be used instead:
		// https://github.com/goharbor/harbor/blob/v2.2.0/src/controller/project/controller.go#L348
		k := strings.SplitN(key, orm.ExprSep, 2)[0]
		mk, filterable := meta.Filterable(k)
		if !filterable {
			// This is a workaround for the unsuitable usage of query, the keyword format for field and method should be consistent
			// e.g. "ArtifactDigest" or the snake case format "artifact_digest" should be used instead:
			// https://github.com/goharbor/harbor/blob/v2.2.0/src/controller/blob/controller.go#L233
			mk, filterable = meta.Filterable(snakeCase(k))
			if !filterable {
				continue
			}
		}
		// filter function defined, use it directly
		if mk.FilterFunc != nil {
			qs = mk.FilterFunc(ctx, qs, key, value)
			continue
		}
		// fuzzy match
		if f, ok := value.(*q.FuzzyMatchValue); ok {
			qs = qs.Filter(key+"__icontains", Escape(f.Value))
			continue
		}
		// range
		if r, ok := value.(*q.Range); ok {
			if r.Min != nil {
				qs = qs.Filter(key+"__gte", r.Min)
			}
			if r.Max != nil {
				qs = qs.Filter(key+"__lte", r.Max)
			}
			continue
		}
		// or list
		if ol, ok := value.(*q.OrList); ok {
			if len(ol.Values) > 0 {
				qs = qs.Filter(key+"__in", ol.Values...)
			}
			continue
		}
		// and list
		if _, ok := value.(*q.AndList); ok {
			// do nothing as and list needs to be handled by the logic of DAO
			continue
		}
		// exact match
		qs = qs.Filter(key, value)
	}
	return qs
}

// set sorts according to the query
func setSorts(qs orm.QuerySeter, query *q.Query, meta *metadata) orm.QuerySeter {
	var sortings []string
	for _, sort := range query.Sorts {
		if !meta.Sortable(sort.Key) {
			continue
		}
		sorting := sort.Key
		if sort.DESC {
			sorting = fmt.Sprintf("-%s", sorting)
		}
		sortings = append(sortings, sorting)
	}
	// if no sorts are specified, apply the default sort setting if exists
	if len(sortings) == 0 {
		for _, ds := range meta.DefaultSorts {
			sorting := ds.Key
			if ds.DESC {
				sorting = fmt.Sprintf("-%s", sorting)
			}
			sortings = append(sortings, sorting)
		}
	}
	if len(sortings) > 0 {
		qs = qs.OrderBy(sortings...)
	}
	return qs
}

// get reflect.Type name with package path.
func getFullName(typ reflect.Type) string {
	return typ.PkgPath() + "." + typ.Name()
}
<commit_msg>Set null list when or list is nil in query (#14941)<commit_after>// Copyright Project Harbor Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package orm

import (
	"context"
	"fmt"
	"reflect"
	"strings"

	"github.com/astaxie/beego/orm"
	"github.com/goharbor/harbor/src/lib/q"
)

// QuerySetter generates the query setter according to the provided model and query.
// e.g.
// type Foo struct{
//   Field1 string `orm:"-"`                         // can not filter/sort
//   Field2 string `orm:"column(customized_field2)"` // support filter by "Field2", "customized_field2"
//   Field3 string `sort:"false"`                    // cannot be sorted
//   Field4 string `sort:"default:desc"`             // the default field/order(asc/desc) to sort if no sorting specified in query.
//   Field5 string `filter:"false"`                  // cannot be filtered
// }
// // support filter by "Field6", "field6"
// func (f *Foo) FilterByField6(ctx context.Context, qs orm.QuerySetter, key string, value interface{}) orm.QuerySetter {
//   ...
//	 return qs
// }
//
// Defining the method "GetDefaultSorts() []*q.Sort" for the model whose default sorting contains more than one fields
// type Bar struct{
//   Field1 string
//   Field2 string
// }
// // Sort by "Field1" desc, "Field2"
// func (b *Bar) GetDefaultSorts() []*q.Sort {
//	return []*q.Sort{
//		{
//			Key:  "Field1",
//			DESC: true,
//		},
//		{
//			Key:  "Field2",
//			DESC: false,
//		},
//	 }
// }
func QuerySetter(ctx context.Context, model interface{}, query *q.Query) (orm.QuerySeter, error) {
	t := reflect.TypeOf(model)
	if t.Kind() != reflect.Ptr {
		return nil, fmt.Errorf("<orm.QuerySetter> cannot use non-ptr model struct `%s`", getFullName(t.Elem()))
	}
	ormer, err := FromContext(ctx)
	if err != nil {
		return nil, err
	}
	qs := ormer.QueryTable(model)
	if query == nil {
		return qs, nil
	}

	metadata := parseModel(model)
	// set filters
	qs = setFilters(ctx, qs, query, metadata)

	// sorting
	qs = setSorts(qs, query, metadata)

	// pagination
	if query.PageSize > 0 {
		qs = qs.Limit(query.PageSize)
		if query.PageNumber > 0 {
			qs = qs.Offset(query.PageSize * (query.PageNumber - 1))
		}
	}

	return qs, nil
}

// PaginationOnRawSQL append page information to the raw sql
// It should be called after the order by
// e.g.
// select a, b, c from mytable order by a limit ? offset ?
// it appends the " limit ? offset ? " to sql,
// and appends the limit value and offset value to the params of this query
func PaginationOnRawSQL(query *q.Query, sql string, params []interface{}) (string, []interface{}) {
	if query != nil && query.PageSize > 0 {
		sql += ` limit ?`
		params = append(params, query.PageSize)

		if query.PageNumber > 0 {
			sql += ` offset ?`
			params = append(params, (query.PageNumber-1)*query.PageSize)
		}
	}
	return sql, params
}

// QuerySetterForCount creates the query setter used for count with the sort and pagination information ignored
func QuerySetterForCount(ctx context.Context, model interface{}, query *q.Query, ignoredCols ...string) (orm.QuerySeter, error) {
	query = q.MustClone(query)
	query.Sorts = nil
	query.PageSize = 0
	query.PageNumber = 0
	return QuerySetter(ctx, model, query)
}

// set filters according to the query
func setFilters(ctx context.Context, qs orm.QuerySeter, query *q.Query, meta *metadata) orm.QuerySeter {
	for key, value := range query.Keywords {
		// The "strings.SplitN()" here is a workaround for the incorrect usage of query which should be avoided
		// e.g. use the query with the knowledge of underlying ORM implementation, the "OrList" should be used instead:
		// https://github.com/goharbor/harbor/blob/v2.2.0/src/controller/project/controller.go#L348
		k := strings.SplitN(key, orm.ExprSep, 2)[0]
		mk, filterable := meta.Filterable(k)
		if !filterable {
			// This is a workaround for the unsuitable usage of query, the keyword format for field and method should be consistent
			// e.g. "ArtifactDigest" or the snake case format "artifact_digest" should be used instead:
			// https://github.com/goharbor/harbor/blob/v2.2.0/src/controller/blob/controller.go#L233
			mk, filterable = meta.Filterable(snakeCase(k))
			if !filterable {
				continue
			}
		}
		// filter function defined, use it directly
		if mk.FilterFunc != nil {
			qs = mk.FilterFunc(ctx, qs, key, value)
			continue
		}
		// fuzzy match
		if f, ok := value.(*q.FuzzyMatchValue); ok {
			qs = qs.Filter(key+"__icontains", Escape(f.Value))
			continue
		}
		// range
		if r, ok := value.(*q.Range); ok {
			if r.Min != nil {
				qs = qs.Filter(key+"__gte", r.Min)
			}
			if r.Max != nil {
				qs = qs.Filter(key+"__lte", r.Max)
			}
			continue
		}
		// or list
		if ol, ok := value.(*q.OrList); ok {
			if ol == nil || len(ol.Values) == 0 {
				qs = qs.Filter(key+"__in", nil)
			} else {
				qs = qs.Filter(key+"__in", ol.Values...)
			}
			continue
		}
		// and list
		if _, ok := value.(*q.AndList); ok {
			// do nothing as and list needs to be handled by the logic of DAO
			continue
		}
		// exact match
		qs = qs.Filter(key, value)
	}
	return qs
}

// set sorts according to the query
func setSorts(qs orm.QuerySeter, query *q.Query, meta *metadata) orm.QuerySeter {
	var sortings []string
	for _, sort := range query.Sorts {
		if !meta.Sortable(sort.Key) {
			continue
		}
		sorting := sort.Key
		if sort.DESC {
			sorting = fmt.Sprintf("-%s", sorting)
		}
		sortings = append(sortings, sorting)
	}
	// if no sorts are specified, apply the default sort setting if exists
	if len(sortings) == 0 {
		for _, ds := range meta.DefaultSorts {
			sorting := ds.Key
			if ds.DESC {
				sorting = fmt.Sprintf("-%s", sorting)
			}
			sortings = append(sortings, sorting)
		}
	}
	if len(sortings) > 0 {
		qs = qs.OrderBy(sortings...)
	}
	return qs
}

// get reflect.Type name with package path.
func getFullName(typ reflect.Type) string {
	return typ.PkgPath() + "." + typ.Name()
}
<|endoftext|>


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

package rpmutils

import "sort"

type NEVRA struct {
	Name    string
	Epoch   string
	Version string
	Release string
	Arch    string
}

func (nevra *NEVRA) String() string {
	return fmt.Sprintf("%s-%s:%s-%s.%s.rpm", nevra.Name, nevra.Epoch, nevra.Version, nevra.Release, nevra.Archi)
}

func NEVRAcmp(a NEVRA, b NEVRA) int {
	if res := Vercmp(a.Epoch, b.Epoch); res != 0 {
		return res
	}
	if res := Vercmp(a.Version, b.Version); res != 0 {
		return res
	}
	if res := Vercmp(a.Release, b.Release); res != 0 {
		return res
	}
	return 0
}

type NEVRASlice []NEVRA

func (s NEVRASlice) Len() int {
	return len(s)
}

func (s NEVRASlice) Less(i, j int) bool {
	return NEVRAcmp(s[i], s[j]) == -1
}

func (s NEVRASlice) Swap(i, j int) {
	n := s[i]
	s[i] = s[j]
	s[j] = n
}

func (s NEVRASlice) Sort() {
	sort.Sort(s)
}
<commit_msg>fix typo<commit_after>/*
 * Copyright (c) SAS Institute, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package rpmutils

import (
	"fmt"
	"sort"
)

type NEVRA struct {
	Name    string
	Epoch   string
	Version string
	Release string
	Arch    string
}

func (nevra *NEVRA) String() string {
	return fmt.Sprintf("%s-%s:%s-%s.%s.rpm", nevra.Name, nevra.Epoch, nevra.Version, nevra.Release, nevra.Arch)
}

func NEVRAcmp(a NEVRA, b NEVRA) int {
	if res := Vercmp(a.Epoch, b.Epoch); res != 0 {
		return res
	}
	if res := Vercmp(a.Version, b.Version); res != 0 {
		return res
	}
	if res := Vercmp(a.Release, b.Release); res != 0 {
		return res
	}
	return 0
}

type NEVRASlice []NEVRA

func (s NEVRASlice) Len() int {
	return len(s)
}

func (s NEVRASlice) Less(i, j int) bool {
	return NEVRAcmp(s[i], s[j]) == -1
}

func (s NEVRASlice) Swap(i, j int) {
	n := s[i]
	s[i] = s[j]
	s[j] = n
}

func (s NEVRASlice) Sort() {
	sort.Sort(s)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
	"syscall"
	"time"
	"unicode/utf16"
	"unsafe"

	"golang.org/x/sys/windows/registry"

	"github.com/jessevdk/go-flags"
	"github.com/mackerelio/checkers"
	"github.com/mackerelio/go-check-plugins/check-event-log/internal/eventlog"
)

const (
	errorInvalidParameter = syscall.Errno(87)
)

type logOpts struct {
	Log            string `long:"log" description:"Event Names (comma separated)"`
	ID             string `long:"id" description:"Event IDs (comma separated)"`
	Type           string `long:"type" description:"Event Types (comma separated)"`
	SourcePattern  string `long:"source-pattern" description:"Event Source (regexp pattern)"`
	MessagePattern string `long:"message-pattern" description:"Message Pattern (regexp pattern)"`
	WarnOver       int64  `short:"w" long:"warning-over" description:"Trigger a warning if matched lines is over a number"`
	CritOver       int64  `short:"c" long:"critical-over" description:"Trigger a critical if matched lines is over a number"`
	ReturnContent  bool   `short:"r" long:"return" description:"Return matched line"`
	StateDir       string `short:"s" long:"state-dir" default:"/var/mackerel-cache/check-event-log" value-name:"DIR" description:"Dir to keep state files under"`
	NoState        bool   `long:"no-state" description:"Don't use state file and read whole logs"`
	FailFirst      bool   `long:"fail-first" description:"Count errors on first seek"`
	Verbose        bool   `long:"verbose" description:"Verbose output"`

	logList        []string
	idList         []int64
	typeList       []string
	sourcePattern  *regexp.Regexp
	messagePattern *regexp.Regexp
}

func stringList(s string) []string {
	l := strings.Split(s, ",")
	if len(l) == 0 || l[0] == "" {
		return []string{}
	}
	return l
}

func (opts *logOpts) prepare() error {
	opts.logList = stringList(opts.Log)
	if len(opts.logList) == 0 || opts.logList[0] == "" {
		opts.logList = []string{"Application"}
	}
	for _, id := range stringList(opts.ID) {
		negate := int64(1)
		if id != "" && id[0] == '!' {
			negate = -1
			id = id[1:]
		}
		i, err := strconv.Atoi(id)
		if err != nil {
			return err
		}
		opts.idList = append(opts.idList, int64(i)*negate)
	}
	opts.typeList = stringList(opts.Type)

	var err error
	opts.sourcePattern, err = regexp.Compile(opts.SourcePattern)
	if err != nil {
		return err
	}
	opts.messagePattern, err = regexp.Compile(opts.MessagePattern)
	if err != nil {
		return err
	}
	return nil
}

func main() {
	ckr := run(os.Args[1:])
	ckr.Name = "Event Log"
	ckr.Exit()
}

func parseArgs(args []string) (*logOpts, error) {
	opts := &logOpts{}
	_, err := flags.ParseArgs(opts, args)
	return opts, err
}

func run(args []string) *checkers.Checker {
	opts, err := parseArgs(args)
	if err != nil {
		os.Exit(1)
	}

	err = opts.prepare()
	if err != nil {
		return checkers.Unknown(err.Error())
	}

	checkSt := checkers.OK
	warnNum := int64(0)
	critNum := int64(0)
	errorOverall := ""

	for _, f := range opts.logList {
		w, c, errLines, err := opts.searchLog(f)
		if err != nil {
			return checkers.Unknown(err.Error())
		}
		warnNum += w
		critNum += c
		if opts.ReturnContent {
			errorOverall += errLines
		}
	}
	msg := fmt.Sprintf("%d warnings, %d criticals.", warnNum, critNum)
	if errorOverall != "" {
		msg += "\n" + errorOverall
	}
	if warnNum > opts.WarnOver {
		checkSt = checkers.WARNING
	}
	if critNum > opts.CritOver {
		checkSt = checkers.CRITICAL
	}
	return checkers.NewChecker(checkSt, msg)
}

func bytesToString(b []byte) (string, uint32) {
	var i int
	s := make([]uint16, len(b)/2)
	for i = range s {
		s[i] = uint16(b[i*2]) + uint16(b[(i*2)+1])<<8
		if s[i] == 0 {
			s = s[0:i]
			break
		}
	}
	return string(utf16.Decode(s)), uint32(i * 2)
}

func getResourceMessage(providerName, sourceName string, eventID uint32, argsptr uintptr) (string, error) {
	regkey := fmt.Sprintf(
		"SYSTEM\\CurrentControlSet\\Services\\EventLog\\%s\\%s",
		providerName, sourceName)
	key, err := registry.OpenKey(registry.LOCAL_MACHINE, regkey, registry.QUERY_VALUE)
	if err != nil {
		return "", err
	}
	defer key.Close()

	val, _, err := key.GetStringValue("EventMessageFile")
	if err != nil {
		return "", err
	}
	val, err = registry.ExpandString(val)
	if err != nil {
		return "", err
	}

	handle, err := eventlog.LoadLibraryEx(syscall.StringToUTF16Ptr(val), 0,
		eventlog.DONT_RESOLVE_DLL_REFERENCES|eventlog.LOAD_LIBRARY_AS_DATAFILE)
	if err != nil {
		return "", err
	}
	defer syscall.CloseHandle(handle)

	msgbuf := make([]byte, 1<<16)
	numChars, err := eventlog.FormatMessage(
		syscall.FORMAT_MESSAGE_FROM_SYSTEM|
			syscall.FORMAT_MESSAGE_FROM_HMODULE|
			syscall.FORMAT_MESSAGE_ARGUMENT_ARRAY,
		handle,
		eventID,
		0,
		&msgbuf[0],
		uint32(len(msgbuf)),
		argsptr)
	if err != nil {
		return "", err
	}
	message, _ := bytesToString(msgbuf[:numChars*2])
	message = strings.Replace(message, "\r", "", -1)
	message = strings.TrimSuffix(message, "\n")
	return message, nil
}

func (opts *logOpts) searchLog(eventName string) (warnNum, critNum int64, errLines string, err error) {
	stateFile := getStateFile(opts.StateDir, eventName)
	recordNumber := uint32(0)
	if !opts.NoState {
		s, err := getLastOffset(stateFile)
		if err != nil && !os.IsNotExist(err) {
			return 0, 0, "", err
		}
		recordNumber = uint32(s)
	}

	ptr := syscall.StringToUTF16Ptr(eventName)
	h, err := eventlog.OpenEventLog(nil, ptr)
	if err != nil {
		log.Fatal(err)
	}
	defer eventlog.CloseEventLog(h)

	var num, oldnum, lastNumber uint32

	eventlog.GetNumberOfEventLogRecords(h, &num)
	if err != nil {
		log.Fatal(err)
	}
	eventlog.GetOldestEventLogRecord(h, &oldnum)
	if err != nil {
		log.Fatal(err)
	}

	if recordNumber == 0 {
		if !opts.NoState {
			err = writeLastOffset(stateFile, int64(oldnum+num-1))
			return 0, 0, "", err
		}
	}

	if oldnum <= recordNumber {
		if recordNumber == oldnum+num-1 {
			return 0, 0, "", nil
		}
		lastNumber = recordNumber
		recordNumber++
	} else {
		recordNumber = oldnum
	}

	size := uint32(1)
	buf := []byte{0}

	var readBytes uint32
	var nextSize uint32
	for i := recordNumber; i < oldnum+num; i++ {
		flags := eventlog.EVENTLOG_FORWARDS_READ | eventlog.EVENTLOG_SEEK_READ
		if i == 0 {
			flags = eventlog.EVENTLOG_FORWARDS_READ | eventlog.EVENTLOG_SEQUENTIAL_READ
		}

		err = eventlog.ReadEventLog(
			h,
			flags,
			i,
			&buf[0],
			size,
			&readBytes,
			&nextSize)
		if err != nil {
			if err != syscall.ERROR_INSUFFICIENT_BUFFER {
				if err != errorInvalidParameter {
					return 0, 0, "", err
				}
				break
			}
			buf = make([]byte, nextSize)
			size = nextSize
			err = eventlog.ReadEventLog(
				h,
				flags,
				i,
				&buf[0],
				size,
				&readBytes,
				&nextSize)
			if err != nil {
				log.Printf("eventlog.ReadEventLog: %v", err)
				break
			}
		}

		r := *(*eventlog.EVENTLOGRECORD)(unsafe.Pointer(&buf[0]))
		if opts.Verbose {
			log.Printf("RecordNumber=%v", r.RecordNumber)
			log.Printf("TimeGenerated=%v", time.Unix(int64(r.TimeGenerated), 0).String())
			log.Printf("TimeWritten=%v", time.Unix(int64(r.TimeWritten), 0).String())
			log.Printf("EventID=%v", r.EventID)
		}
		lastNumber = r.RecordNumber

		if len(opts.idList) > 0 {
			found := false
			for _, id := range opts.idList {
				if id > 0 && uint32(id) == r.EventID {
					found = true
					break
				} else if id <= 0 && uint32(-id) != r.EventID {
					found = true
					break
				}
			}
			if !found {
				continue
			}
		}

		tn := eventlog.EventType(r.EventType).String()
		if opts.Verbose {
			log.Printf("EventType=%v", tn)
		}
		tn = strings.ToLower(tn)
		if len(opts.typeList) > 0 {
			found := false
			for _, typ := range opts.typeList {
				if typ == tn {
					found = true
					break
				}
			}
			if !found {
				continue
			}
		}

		sourceName, sourceNameOff := bytesToString(buf[unsafe.Sizeof(eventlog.EVENTLOGRECORD{}):])
		computerName, _ := bytesToString(buf[unsafe.Sizeof(eventlog.EVENTLOGRECORD{})+uintptr(sourceNameOff+2):])
		if opts.Verbose {
			log.Printf("SourceName=%v", sourceName)
			log.Printf("ComputerName=%v", computerName)
		}

		if opts.sourcePattern != nil {
			if !opts.sourcePattern.MatchString(sourceName) {
				continue
			}
		}

		off := uint32(0)
		args := make([]*byte, uintptr(r.NumStrings)*unsafe.Sizeof((*uint16)(nil)))
		for n := 0; n < int(r.NumStrings); n++ {
			args[n] = &buf[r.StringOffset+off]
			_, boff := bytesToString(buf[r.StringOffset+off:])
			off += boff + 2
		}

		var argsptr uintptr
		if r.NumStrings > 0 {
			argsptr = uintptr(unsafe.Pointer(&args[0]))
		}
		message, err := getResourceMessage(eventName, sourceName, r.EventID, argsptr)
		if err == nil {
			if opts.Verbose {
				log.Printf("Message=%v", message)
			}
			if opts.messagePattern != nil {
				if !opts.messagePattern.MatchString(message) {
					continue
				}
			}
		}
		if opts.ReturnContent {
			errLines += sourceName + ":" + strings.Replace(message, "\n", "", -1) + "\n"
		}
		switch tn {
		case "error":
			critNum++
		case "audit failure":
			critNum++
		case "warning":
			warnNum++
		}
	}

	if !opts.NoState {
		err = writeLastOffset(stateFile, int64(lastNumber))
		if err != nil {
			log.Printf("writeLastOffset failed: %s\n", err.Error())
		}
	}

	if recordNumber == 0 && !opts.FailFirst {
		return 0, 0, "", nil
	}
	return warnNum, critNum, errLines, nil
}

var stateRe = regexp.MustCompile(`^([A-Z]):[/\\]`)

func getStateFile(stateDir, f string) string {
	return filepath.ToSlash(filepath.Join(stateDir, stateRe.ReplaceAllString(f, `$1`+string(filepath.Separator))))
}

func getLastOffset(f string) (int64, error) {
	_, err := os.Stat(f)
	if err != nil {
		return 0, err
	}
	b, err := ioutil.ReadFile(f)
	if err != nil {
		return 0, err
	}
	i, err := strconv.ParseInt(strings.Trim(string(b), " \r\n"), 10, 64)
	if err != nil {
		return 0, err
	}
	return i, nil
}

func writeLastOffset(f string, num int64) error {
	err := os.MkdirAll(filepath.Dir(f), 0755)
	if err != nil {
		return err
	}
	return ioutil.WriteFile(f, []byte(fmt.Sprintf("%d", num)), 0644)
}
<commit_msg>remove idList because checking IDs is not useful<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
	"syscall"
	"time"
	"unicode/utf16"
	"unsafe"

	"golang.org/x/sys/windows/registry"

	"github.com/jessevdk/go-flags"
	"github.com/mackerelio/checkers"
	"github.com/mackerelio/go-check-plugins/check-event-log/internal/eventlog"
)

const (
	errorInvalidParameter = syscall.Errno(87)
)

type logOpts struct {
	Log            string `long:"log" description:"Event Names (comma separated)"`
	Type           string `long:"type" description:"Event Types (comma separated)"`
	SourcePattern  string `long:"source-pattern" description:"Event Source (regexp pattern)"`
	MessagePattern string `long:"message-pattern" description:"Message Pattern (regexp pattern)"`
	WarnOver       int64  `short:"w" long:"warning-over" description:"Trigger a warning if matched lines is over a number"`
	CritOver       int64  `short:"c" long:"critical-over" description:"Trigger a critical if matched lines is over a number"`
	ReturnContent  bool   `short:"r" long:"return" description:"Return matched line"`
	StateDir       string `short:"s" long:"state-dir" default:"/var/mackerel-cache/check-event-log" value-name:"DIR" description:"Dir to keep state files under"`
	NoState        bool   `long:"no-state" description:"Don't use state file and read whole logs"`
	FailFirst      bool   `long:"fail-first" description:"Count errors on first seek"`
	Verbose        bool   `long:"verbose" description:"Verbose output"`

	logList        []string
	typeList       []string
	sourcePattern  *regexp.Regexp
	messagePattern *regexp.Regexp
}

func stringList(s string) []string {
	l := strings.Split(s, ",")
	if len(l) == 0 || l[0] == "" {
		return []string{}
	}
	return l
}

func (opts *logOpts) prepare() error {
	opts.logList = stringList(opts.Log)
	if len(opts.logList) == 0 || opts.logList[0] == "" {
		opts.logList = []string{"Application"}
	}
	opts.typeList = stringList(opts.Type)

	var err error
	opts.sourcePattern, err = regexp.Compile(opts.SourcePattern)
	if err != nil {
		return err
	}
	opts.messagePattern, err = regexp.Compile(opts.MessagePattern)
	if err != nil {
		return err
	}
	return nil
}

func main() {
	ckr := run(os.Args[1:])
	ckr.Name = "Event Log"
	ckr.Exit()
}

func parseArgs(args []string) (*logOpts, error) {
	opts := &logOpts{}
	_, err := flags.ParseArgs(opts, args)
	return opts, err
}

func run(args []string) *checkers.Checker {
	opts, err := parseArgs(args)
	if err != nil {
		os.Exit(1)
	}

	err = opts.prepare()
	if err != nil {
		return checkers.Unknown(err.Error())
	}

	checkSt := checkers.OK
	warnNum := int64(0)
	critNum := int64(0)
	errorOverall := ""

	for _, f := range opts.logList {
		w, c, errLines, err := opts.searchLog(f)
		if err != nil {
			return checkers.Unknown(err.Error())
		}
		warnNum += w
		critNum += c
		if opts.ReturnContent {
			errorOverall += errLines
		}
	}
	msg := fmt.Sprintf("%d warnings, %d criticals.", warnNum, critNum)
	if errorOverall != "" {
		msg += "\n" + errorOverall
	}
	if warnNum > opts.WarnOver {
		checkSt = checkers.WARNING
	}
	if critNum > opts.CritOver {
		checkSt = checkers.CRITICAL
	}
	return checkers.NewChecker(checkSt, msg)
}

func bytesToString(b []byte) (string, uint32) {
	var i int
	s := make([]uint16, len(b)/2)
	for i = range s {
		s[i] = uint16(b[i*2]) + uint16(b[(i*2)+1])<<8
		if s[i] == 0 {
			s = s[0:i]
			break
		}
	}
	return string(utf16.Decode(s)), uint32(i * 2)
}

func getResourceMessage(providerName, sourceName string, eventID uint32, argsptr uintptr) (string, error) {
	regkey := fmt.Sprintf(
		"SYSTEM\\CurrentControlSet\\Services\\EventLog\\%s\\%s",
		providerName, sourceName)
	key, err := registry.OpenKey(registry.LOCAL_MACHINE, regkey, registry.QUERY_VALUE)
	if err != nil {
		return "", err
	}
	defer key.Close()

	val, _, err := key.GetStringValue("EventMessageFile")
	if err != nil {
		return "", err
	}
	val, err = registry.ExpandString(val)
	if err != nil {
		return "", err
	}

	handle, err := eventlog.LoadLibraryEx(syscall.StringToUTF16Ptr(val), 0,
		eventlog.DONT_RESOLVE_DLL_REFERENCES|eventlog.LOAD_LIBRARY_AS_DATAFILE)
	if err != nil {
		return "", err
	}
	defer syscall.CloseHandle(handle)

	msgbuf := make([]byte, 1<<16)
	numChars, err := eventlog.FormatMessage(
		syscall.FORMAT_MESSAGE_FROM_SYSTEM|
			syscall.FORMAT_MESSAGE_FROM_HMODULE|
			syscall.FORMAT_MESSAGE_ARGUMENT_ARRAY,
		handle,
		eventID,
		0,
		&msgbuf[0],
		uint32(len(msgbuf)),
		argsptr)
	if err != nil {
		return "", err
	}
	message, _ := bytesToString(msgbuf[:numChars*2])
	message = strings.Replace(message, "\r", "", -1)
	message = strings.TrimSuffix(message, "\n")
	return message, nil
}

func (opts *logOpts) searchLog(eventName string) (warnNum, critNum int64, errLines string, err error) {
	stateFile := getStateFile(opts.StateDir, eventName)
	recordNumber := uint32(0)
	if !opts.NoState {
		s, err := getLastOffset(stateFile)
		if err != nil && !os.IsNotExist(err) {
			return 0, 0, "", err
		}
		recordNumber = uint32(s)
	}

	ptr := syscall.StringToUTF16Ptr(eventName)
	h, err := eventlog.OpenEventLog(nil, ptr)
	if err != nil {
		log.Fatal(err)
	}
	defer eventlog.CloseEventLog(h)

	var num, oldnum, lastNumber uint32

	eventlog.GetNumberOfEventLogRecords(h, &num)
	if err != nil {
		log.Fatal(err)
	}
	eventlog.GetOldestEventLogRecord(h, &oldnum)
	if err != nil {
		log.Fatal(err)
	}

	if recordNumber == 0 {
		if !opts.NoState {
			err = writeLastOffset(stateFile, int64(oldnum+num-1))
			return 0, 0, "", err
		}
	}

	if oldnum <= recordNumber {
		if recordNumber == oldnum+num-1 {
			return 0, 0, "", nil
		}
		lastNumber = recordNumber
		recordNumber++
	} else {
		recordNumber = oldnum
	}

	size := uint32(1)
	buf := []byte{0}

	var readBytes uint32
	var nextSize uint32
	for i := recordNumber; i < oldnum+num; i++ {
		flags := eventlog.EVENTLOG_FORWARDS_READ | eventlog.EVENTLOG_SEEK_READ
		if i == 0 {
			flags = eventlog.EVENTLOG_FORWARDS_READ | eventlog.EVENTLOG_SEQUENTIAL_READ
		}

		err = eventlog.ReadEventLog(
			h,
			flags,
			i,
			&buf[0],
			size,
			&readBytes,
			&nextSize)
		if err != nil {
			if err != syscall.ERROR_INSUFFICIENT_BUFFER {
				if err != errorInvalidParameter {
					return 0, 0, "", err
				}
				break
			}
			buf = make([]byte, nextSize)
			size = nextSize
			err = eventlog.ReadEventLog(
				h,
				flags,
				i,
				&buf[0],
				size,
				&readBytes,
				&nextSize)
			if err != nil {
				log.Printf("eventlog.ReadEventLog: %v", err)
				break
			}
		}

		r := *(*eventlog.EVENTLOGRECORD)(unsafe.Pointer(&buf[0]))
		if opts.Verbose {
			log.Printf("RecordNumber=%v", r.RecordNumber)
			log.Printf("TimeGenerated=%v", time.Unix(int64(r.TimeGenerated), 0).String())
			log.Printf("TimeWritten=%v", time.Unix(int64(r.TimeWritten), 0).String())
			log.Printf("EventID=%v", r.EventID)
		}
		lastNumber = r.RecordNumber

		tn := eventlog.EventType(r.EventType).String()
		if opts.Verbose {
			log.Printf("EventType=%v", tn)
		}
		tn = strings.ToLower(tn)
		if len(opts.typeList) > 0 {
			found := false
			for _, typ := range opts.typeList {
				if typ == tn {
					found = true
					break
				}
			}
			if !found {
				continue
			}
		}

		sourceName, sourceNameOff := bytesToString(buf[unsafe.Sizeof(eventlog.EVENTLOGRECORD{}):])
		computerName, _ := bytesToString(buf[unsafe.Sizeof(eventlog.EVENTLOGRECORD{})+uintptr(sourceNameOff+2):])
		if opts.Verbose {
			log.Printf("SourceName=%v", sourceName)
			log.Printf("ComputerName=%v", computerName)
		}

		if opts.sourcePattern != nil {
			if !opts.sourcePattern.MatchString(sourceName) {
				continue
			}
		}

		off := uint32(0)
		args := make([]*byte, uintptr(r.NumStrings)*unsafe.Sizeof((*uint16)(nil)))
		for n := 0; n < int(r.NumStrings); n++ {
			args[n] = &buf[r.StringOffset+off]
			_, boff := bytesToString(buf[r.StringOffset+off:])
			off += boff + 2
		}

		var argsptr uintptr
		if r.NumStrings > 0 {
			argsptr = uintptr(unsafe.Pointer(&args[0]))
		}
		message, err := getResourceMessage(eventName, sourceName, r.EventID, argsptr)
		if err == nil {
			if opts.Verbose {
				log.Printf("Message=%v", message)
			}
			if opts.messagePattern != nil {
				if !opts.messagePattern.MatchString(message) {
					continue
				}
			}
		}
		if opts.ReturnContent {
			errLines += sourceName + ":" + strings.Replace(message, "\n", "", -1) + "\n"
		}
		switch tn {
		case "error":
			critNum++
		case "audit failure":
			critNum++
		case "warning":
			warnNum++
		}
	}

	if !opts.NoState {
		err = writeLastOffset(stateFile, int64(lastNumber))
		if err != nil {
			log.Printf("writeLastOffset failed: %s\n", err.Error())
		}
	}

	if recordNumber == 0 && !opts.FailFirst {
		return 0, 0, "", nil
	}
	return warnNum, critNum, errLines, nil
}

var stateRe = regexp.MustCompile(`^([A-Z]):[/\\]`)

func getStateFile(stateDir, f string) string {
	return filepath.ToSlash(filepath.Join(stateDir, stateRe.ReplaceAllString(f, `$1`+string(filepath.Separator))))
}

func getLastOffset(f string) (int64, error) {
	_, err := os.Stat(f)
	if err != nil {
		return 0, err
	}
	b, err := ioutil.ReadFile(f)
	if err != nil {
		return 0, err
	}
	i, err := strconv.ParseInt(strings.Trim(string(b), " \r\n"), 10, 64)
	if err != nil {
		return 0, err
	}
	return i, nil
}

func writeLastOffset(f string, num int64) error {
	err := os.MkdirAll(filepath.Dir(f), 0755)
	if err != nil {
		return err
	}
	return ioutil.WriteFile(f, []byte(fmt.Sprintf("%d", num)), 0644)
}
<|endoftext|>


<commit_before>package main

import (
  "fmt"
  "log"
  "io/ioutil"
  "flag"
  "path/filepath"
  "regexp"
  "os"
  sass "github.com/moovweb/gosass"
  "github.com/kylelemons/go-gypsy/yaml"
  "github.com/howeyc/fsnotify"
)

var (
  file = flag.String("f", "config.yml", "YAML config file (defaults to config.yml)")
)

func main() {
  compileFiles := []string{}
  watchings := map[string]string{}
  watchDirs := []string{}

  flag.Parse()

  // parse the yaml yo
  yml, err := yaml.ReadFile(*file)
  if err != nil {
    log.Fatal("Error reading config file")
  }

  count, err := yml.Count("config")

  for i:=0; i<count; i++ {
    s, err := yml.Get(fmt.Sprintf("config[%d].source", i))
    if err != nil {
      panic(err)
    }
    d, err := yml.Get(fmt.Sprintf("config[%d].dest", i))
    if err != nil {
      panic(err)
    }
    s = filepath.Clean(s)
    d = filepath.Clean(d)
    watchDirs = append(watchDirs, s)

    _, compileFiles = getFiles(s)

    for z:=0; z<len(compileFiles); z++ {
      compile(compileFiles[z], d)
      watchings[compileFiles[z]] = d
    }
  }

  params := flag.Args()
  for _, param := range params {
    if param == "build" || param == "b" { // "gassy build"
      fmt.Println("Built. Come again soon.")
    } else if param == "watch" || param == "w" { // "gassy watch"
      watcher, err := fsnotify.NewWatcher()
      if err != nil {
          log.Fatal(err)
      }

      done := make(chan bool)

      go func() {
        for {
          select {
          case ev := <-watcher.Event:
            // log.Println("event:", ev)
            if ev.IsCreate() {
              if finfo, err := os.Stat(ev.Name); err == nil && finfo.IsDir() {
                watcher.Watch(ev.Name)
                log.Println("Added Watch: ", ev.Name)
              }
            } else if ev.IsModify() {
              if finfo, err := os.Stat(ev.Name); err == nil {
                filename := finfo.Name()
                extension := filepath.Ext(filename)
                if (extension == ".scss" || extension == ".sass" || extension == ".css") {
                  // compile everything for now
                  for k, v := range watchings {
                    fmt.Println(k, v)
                    compile(k, v)
                  }
                }
              }
            }
          case err := <-watcher.Error:
            log.Println("error:", err)
          }
        }
        done <- true
      }()

      for i:=0; i<len(watchDirs); i++ {
        err = watchAllDirs(watcher, watchDirs[i])
        if err != nil {
          log.Fatal(err)
        }
      }

      <-done

      watcher.Close()
    }
  }
}

func watchAllDirs(watcher *fsnotify.Watcher, root string) (err error) {
  walkFn := func(path string, info os.FileInfo, err error) error {
    if info.IsDir() {
      watcher.Watch(path)
      log.Println("Watching: ", path)
    }
    return nil
  }

  return filepath.Walk(root, walkFn)
}

func getFiles(s string) ([]string, []string) {
  watchFiles := []string{}
  compileFiles := []string{}

  dirList, err := ioutil.ReadDir(s)
  if err != nil {
    log.Fatal("error reading specified directory")
  }

  for x:=0; x<len(dirList); x++ {
    if dirList[x].IsDir() {
      subdirsWatch, subdirsCompile := getFiles(filepath.Join(s, dirList[x].Name()))
      for y:=0; y<len(subdirsWatch); y++ {
        watchFiles = append(watchFiles, subdirsWatch[y])
      }
      for y:=0; y<len(subdirsCompile); y++ {
        compileFiles = append(compileFiles, subdirsCompile[y])
      }
    } else {
      filename := dirList[x].Name()
      extension := filepath.Ext(filename)
      // first find the files we need to compile
      if !(filename[0] == 95) { // ignore files starting with an underscore
        if (extension == ".scss" || extension == ".sass") {
          compileFiles = append(compileFiles, filepath.Join(s, dirList[x].Name()))
        }
      }
      // then find all the files we need to watch for changes
      if (extension == ".scss" || extension == ".sass" || extension == ".css") {
        watchFiles = append(watchFiles, filepath.Join(s, dirList[x].Name()))
      }
    }
  }
  return watchFiles, compileFiles
}

func compile(s string, d string) {
  // compile the sass yo
  ctx := sass.FileContext {
    Options: sass.Options {
      OutputStyle: sass.NESTED_STYLE,
      IncludePaths: make([]string, 0),
    },
    InputPath:    s,
    OutputString: "",
    ErrorStatus:  0,
    ErrorMessage: "",
  }

  // minified version
  ctxMin := sass.FileContext {
    Options: sass.Options {
      OutputStyle: sass.COMPRESSED_STYLE,
      IncludePaths: make([]string, 0),
    },
    InputPath:    s,
    OutputString: "",
    ErrorStatus:  0,
    ErrorMessage: "",
  }

  sass.CompileFile(&ctx)
  sass.CompileFile(&ctxMin)

  if ctx.ErrorStatus != 0 {
    if ctx.ErrorMessage != "" {
      fmt.Print(ctx.ErrorMessage)
    } else {
      fmt.Println("An error occured; no error message available.")
    }
  } else {
    re := regexp.MustCompile("scss|sass")
    name := re.ReplaceAllString(filepath.Base(s), "css")
    nameMin := re.ReplaceAllString(filepath.Base(s), "min.css")
    // write out un-minified file
    err := ioutil.WriteFile(filepath.Join(d, name), []byte(ctx.OutputString), 0644)
    if err != nil {
      panic(err)
    }
    // write out minified file
    err = ioutil.WriteFile(filepath.Join(d, nameMin), []byte(ctxMin.OutputString), 0644)
    if err != nil {
      panic(err)
    }
  }
}<commit_msg>formatting<commit_after>package main

import (
	"flag"
	"fmt"
	"github.com/howeyc/fsnotify"
	"github.com/kylelemons/go-gypsy/yaml"
	sass "github.com/moovweb/gosass"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"regexp"
)

var (
	file = flag.String("f", "config.yml", "YAML config file (defaults to config.yml)")
)

func main() {
	compileFiles := []string{}
	watchings := map[string]string{}
	watchDirs := []string{}

	flag.Parse()

	// parse the yaml yo
	yml, err := yaml.ReadFile(*file)
	if err != nil {
		log.Fatal("Error reading config file")
	}

	count, err := yml.Count("config")

	for i := 0; i < count; i++ {
		s, err := yml.Get(fmt.Sprintf("config[%d].source", i))
		if err != nil {
			panic(err)
		}
		d, err := yml.Get(fmt.Sprintf("config[%d].dest", i))
		if err != nil {
			panic(err)
		}
		s = filepath.Clean(s)
		d = filepath.Clean(d)
		watchDirs = append(watchDirs, s)

		_, compileFiles = getFiles(s)

		for z := 0; z < len(compileFiles); z++ {
			compile(compileFiles[z], d)
			watchings[compileFiles[z]] = d
		}
	}

	params := flag.Args()
	for _, param := range params {
		if param == "build" || param == "b" { // "gassy build"
			fmt.Println("Built. Come again soon.")
		} else if param == "watch" || param == "w" { // "gassy watch"
			watcher, err := fsnotify.NewWatcher()
			if err != nil {
				log.Fatal(err)
			}

			done := make(chan bool)

			go func() {
				for {
					select {
					case ev := <-watcher.Event:
						// log.Println("event:", ev)
						if ev.IsCreate() {
							if finfo, err := os.Stat(ev.Name); err == nil && finfo.IsDir() {
								watcher.Watch(ev.Name)
								log.Println("Added Watch: ", ev.Name)
							}
						} else if ev.IsModify() {
							if finfo, err := os.Stat(ev.Name); err == nil {
								filename := finfo.Name()
								extension := filepath.Ext(filename)
								if extension == ".scss" || extension == ".sass" || extension == ".css" {
									// compile everything for now
									for k, v := range watchings {
										fmt.Println(k, v)
										compile(k, v)
									}
								}
							}
						}
					case err := <-watcher.Error:
						log.Println("error:", err)
					}
				}
				done <- true
			}()

			for i := 0; i < len(watchDirs); i++ {
				err = watchAllDirs(watcher, watchDirs[i])
				if err != nil {
					log.Fatal(err)
				}
			}

			<-done

			watcher.Close()
		}
	}
}

func watchAllDirs(watcher *fsnotify.Watcher, root string) (err error) {
	walkFn := func(path string, info os.FileInfo, err error) error {
		if info.IsDir() {
			watcher.Watch(path)
			log.Println("Watching: ", path)
		}
		return nil
	}

	return filepath.Walk(root, walkFn)
}

func getFiles(s string) ([]string, []string) {
	watchFiles := []string{}
	compileFiles := []string{}

	dirList, err := ioutil.ReadDir(s)
	if err != nil {
		log.Fatal("error reading specified directory")
	}

	for x := 0; x < len(dirList); x++ {
		if dirList[x].IsDir() {
			subdirsWatch, subdirsCompile := getFiles(filepath.Join(s, dirList[x].Name()))
			for y := 0; y < len(subdirsWatch); y++ {
				watchFiles = append(watchFiles, subdirsWatch[y])
			}
			for y := 0; y < len(subdirsCompile); y++ {
				compileFiles = append(compileFiles, subdirsCompile[y])
			}
		} else {
			filename := dirList[x].Name()
			extension := filepath.Ext(filename)
			// first find the files we need to compile
			if !(filename[0] == 95) { // ignore files starting with an underscore
				if extension == ".scss" || extension == ".sass" {
					compileFiles = append(compileFiles, filepath.Join(s, dirList[x].Name()))
				}
			}
			// then find all the files we need to watch for changes
			if extension == ".scss" || extension == ".sass" || extension == ".css" {
				watchFiles = append(watchFiles, filepath.Join(s, dirList[x].Name()))
			}
		}
	}
	return watchFiles, compileFiles
}

func compile(s string, d string) {
	// compile the sass yo
	ctx := sass.FileContext{
		Options: sass.Options{
			OutputStyle:  sass.NESTED_STYLE,
			IncludePaths: make([]string, 0),
		},
		InputPath:    s,
		OutputString: "",
		ErrorStatus:  0,
		ErrorMessage: "",
	}

	// minified version
	ctxMin := sass.FileContext{
		Options: sass.Options{
			OutputStyle:  sass.COMPRESSED_STYLE,
			IncludePaths: make([]string, 0),
		},
		InputPath:    s,
		OutputString: "",
		ErrorStatus:  0,
		ErrorMessage: "",
	}

	sass.CompileFile(&ctx)
	sass.CompileFile(&ctxMin)

	if ctx.ErrorStatus != 0 {
		if ctx.ErrorMessage != "" {
			fmt.Print(ctx.ErrorMessage)
		} else {
			fmt.Println("An error occured; no error message available.")
		}
	} else {
		re := regexp.MustCompile("scss|sass")
		name := re.ReplaceAllString(filepath.Base(s), "css")
		nameMin := re.ReplaceAllString(filepath.Base(s), "min.css")
		// write out un-minified file
		err := ioutil.WriteFile(filepath.Join(d, name), []byte(ctx.OutputString), 0644)
		if err != nil {
			panic(err)
		}
		// write out minified file
		err = ioutil.WriteFile(filepath.Join(d, nameMin), []byte(ctxMin.OutputString), 0644)
		if err != nil {
			panic(err)
		}
	}
}
<|endoftext|>


<commit_before>// Test database access under Travis
// +build travis

package experiment

import (
	"os"
	"path/filepath"
	"testing"

	"github.com/lawrencewoodman/ddataset"
	"github.com/lawrencewoodman/ddataset/dcsv"
	"github.com/vlifesystems/rulehunter/config"
	"github.com/vlifesystems/rulehunter/internal/testhelpers"
)

func TestMakeDataset_travis(t *testing.T) {
	cases := []struct {
		desc   *datasetDesc
		fields []string
		want   ddataset.Dataset
	}{
		{desc: &datasetDesc{
			SQL: &sqlDesc{
				DriverName:     "mysql",
				DataSourceName: "travis@/master",
				Query:          "select * from flow",
			},
		},
			fields: []string{"grp", "district", "height", "flow"},
			want: dcsv.New(
				filepath.Join("fixtures", "flow.csv"),
				true,
				rune(','),
				[]string{"grp", "district", "height", "flow"},
			),
		},
		{desc: &datasetDesc{
			SQL: &sqlDesc{
				DriverName:     "mysql",
				DataSourceName: "travis@/master",
				Query:          "select grp,district,flow from flow",
			},
		},
			fields: []string{"grp", "district", "flow"},
			want: dcsv.New(
				filepath.Join("fixtures", "flow_three_columns.csv"),
				true,
				rune(','),
				[]string{"grp", "district", "flow"},
			),
		},
		{desc: &datasetDesc{
			SQL: &sqlDesc{
				DriverName:     "postgres",
				DataSourceName: "user=postgres dbname=master",
				Query:          "select * from \"master\".\"flow\"",
			},
		},
			fields: []string{"grp", "district", "height", "flow"},
			want: dcsv.New(
				filepath.Join("fixtures", "flow.csv"),
				true,
				rune(','),
				[]string{"grp", "district", "height", "flow"},
			),
		},
		{desc: &datasetDesc{
			SQL: &sqlDesc{
				DriverName:     "postgres",
				DataSourceName: "user=postgres dbname=master",
				Query:          "select grp,district,flow from \"master\".\"flow\"",
			},
		},
			fields: []string{"grp", "district", "flow"},
			want: dcsv.New(
				filepath.Join("fixtures", "flow_three_columns.csv"),
				true,
				rune(','),
				[]string{"grp", "district", "flow"},
			),
		},
	}
	tmpDir := testhelpers.BuildConfigDirs(t, true)
	defer os.RemoveAll(tmpDir)
	cfg := &config.Config{
		MaxNumRecords: -1,
		BuildDir:      filepath.Join(tmpDir, "build"),
	}
	for i, c := range cases {
		got, err := makeDataset("trainDataset", cfg, c.fields, c.desc)
		if err != nil {
			t.Errorf("(%d) makeDataset: %s", i, err)
		} else if err := checkDatasetsEqual(got, c.want); err != nil {
			t.Errorf("checkDatasetsEqual: err: %s", err)
		}
	}
}
<commit_msg>Remove database name from postgres test<commit_after>// Test database access under Travis
// +build travis

package experiment

import (
	"os"
	"path/filepath"
	"testing"

	"github.com/lawrencewoodman/ddataset"
	"github.com/lawrencewoodman/ddataset/dcsv"
	"github.com/vlifesystems/rulehunter/config"
	"github.com/vlifesystems/rulehunter/internal/testhelpers"
)

func TestMakeDataset_travis(t *testing.T) {
	cases := []struct {
		desc   *datasetDesc
		fields []string
		want   ddataset.Dataset
	}{
		{desc: &datasetDesc{
			SQL: &sqlDesc{
				DriverName:     "mysql",
				DataSourceName: "travis@/master",
				Query:          "select * from flow",
			},
		},
			fields: []string{"grp", "district", "height", "flow"},
			want: dcsv.New(
				filepath.Join("fixtures", "flow.csv"),
				true,
				rune(','),
				[]string{"grp", "district", "height", "flow"},
			),
		},
		{desc: &datasetDesc{
			SQL: &sqlDesc{
				DriverName:     "mysql",
				DataSourceName: "travis@/master",
				Query:          "select grp,district,flow from flow",
			},
		},
			fields: []string{"grp", "district", "flow"},
			want: dcsv.New(
				filepath.Join("fixtures", "flow_three_columns.csv"),
				true,
				rune(','),
				[]string{"grp", "district", "flow"},
			),
		},
		{desc: &datasetDesc{
			SQL: &sqlDesc{
				DriverName:     "postgres",
				DataSourceName: "user=postgres dbname=master",
				Query:          "select * from \"flow\"",
			},
		},
			fields: []string{"grp", "district", "height", "flow"},
			want: dcsv.New(
				filepath.Join("fixtures", "flow.csv"),
				true,
				rune(','),
				[]string{"grp", "district", "height", "flow"},
			),
		},
		{desc: &datasetDesc{
			SQL: &sqlDesc{
				DriverName:     "postgres",
				DataSourceName: "user=postgres dbname=master",
				Query:          "select grp,district,flow from \"flow\"",
			},
		},
			fields: []string{"grp", "district", "flow"},
			want: dcsv.New(
				filepath.Join("fixtures", "flow_three_columns.csv"),
				true,
				rune(','),
				[]string{"grp", "district", "flow"},
			),
		},
	}
	tmpDir := testhelpers.BuildConfigDirs(t, true)
	defer os.RemoveAll(tmpDir)
	cfg := &config.Config{
		MaxNumRecords: -1,
		BuildDir:      filepath.Join(tmpDir, "build"),
	}
	for i, c := range cases {
		got, err := makeDataset("trainDataset", cfg, c.fields, c.desc)
		if err != nil {
			t.Errorf("(%d) makeDataset: %s", i, err)
		} else if err := checkDatasetsEqual(got, c.want); err != nil {
			t.Errorf("checkDatasetsEqual: err: %s", err)
		}
	}
}
<|endoftext|>


<commit_before>package godbg

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"os"
	"runtime"
	"strings"
)

// http://stackoverflow.com/a/23554672/6309 https://vividcortex.com/blog/2013/12/03/go-idiom-package-and-object/
// you design a type with methods as usual, and then you also place matching functions at the package level itself.
// These functions simply delegate to a default instance of the type that’s a private package-level variable, created in an init() function.

// Pdbg allows to print debug message with indent and function name added
type Pdbg struct {
	bout     *bytes.Buffer
	berr     *bytes.Buffer
	sout     *bufio.Writer
	serr     *bufio.Writer
	breaks   []string
	excludes []string
}

// Out returns a writer for normal messages.
// By default, os.StdOut
func Out() io.Writer {
	return pdbg.Out()
}

// Out returns a writer for normal messages for a given pdbg instance.
// By default, os.StdOut
func (pdbg *Pdbg) Out() io.Writer {
	if pdbg.sout == nil {
		return os.Stdout
	}
	return pdbg.sout
}

// Err returns a writer for error messages.
// By default, os.StdErr
func Err() io.Writer {
	return pdbg.Err()
}

// Err returns a writer for error messages for a given pdbg instance.
// By default, os.StdErr
func (pdbg *Pdbg) Err() io.Writer {
	if pdbg.serr == nil {
		return os.Stderr
	}
	return pdbg.serr
}

// global pdbg used for printing
var pdbg = NewPdbg()

// Option set an option for a Pdbg
// http://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis
type Option func(*Pdbg)

// SetBuffers is an option for replacing stdout and stderr by
// bytes buffers (in a bufio.Writer).
// If apdbg is nil, set for the global pdbg instance
func SetBuffers(apdbg *Pdbg) {
	if apdbg == nil {
		apdbg = pdbg
	}
	apdbg.bout = bytes.NewBuffer(nil)
	apdbg.sout = bufio.NewWriter(apdbg.bout)
	apdbg.berr = bytes.NewBuffer(nil)
	apdbg.serr = bufio.NewWriter(apdbg.berr)
}

// SetExcludes set excludes on a pdbg (nil for global pdbg)
func (pdbg *Pdbg) SetExcludes(excludes []string) {
	pdbg.excludes = excludes
}

// OptExcludes is an option to set excludes at the creation of a pdbg
func OptExcludes(excludes []string) Option {
	return func(apdbg *Pdbg) {
		apdbg.SetExcludes(excludes)
	}
}

// NewPdbg creates a PDbg instance, with options
func NewPdbg(options ...Option) *Pdbg {
	newpdbg := &Pdbg{}
	for _, option := range options {
		option(newpdbg)
	}
	newpdbg.breaks = append(newpdbg.breaks, "smartystreets")
	//newpdbg.breaks = append(newpdbg.breaks, "(*Pdbg).Pdbgf")
	return newpdbg
}

// ResetIOs reset the out and err buffer of global pdbg instance
func ResetIOs() {
	pdbg.ResetIOs()
}

// ResetIOs reset the out and err buffer
// (unless they were the default stdout and stderr,
// in which case it does nothing)
func (pdbg *Pdbg) ResetIOs() {
	if pdbg.sout != nil {
		pdbg.bout = bytes.NewBuffer(nil)
		pdbg.sout.Reset(pdbg.bout)
		pdbg.berr = bytes.NewBuffer(nil)
		pdbg.serr.Reset(pdbg.berr)
	}
}

// OutString returns the string for out messages for the global pdbg instance.
// It flushes the out buffer.
// If out is set to os.Stdout, returns an empty string
func OutString() string {
	return pdbg.OutString()
}

// OutString returns the string for out messages for a given pdbg instance.
// It flushes the out buffer.
// If out is set to os.Stdout, returns an empty string
func (pdbg *Pdbg) OutString() string {
	if pdbg.sout == nil {
		return ""
	}
	pdbg.sout.Flush()
	return pdbg.bout.String()
}

// ErrString returns the string for error messages for the global pdbg instance.
// It flushes the err buffer.
// If err is set to os.StdErr, returns an empty string
func ErrString() string {
	return pdbg.ErrString()
}

// ErrString returns the string for error messages for a given pdbg instance.
// It flushes the err buffer.
// If err is set to os.StdErr, returns an empty string
func (pdbg *Pdbg) ErrString() string {
	if pdbg.serr == nil {
		return ""
	}
	pdbg.serr.Flush()
	return pdbg.berr.String()
}

func (pdbg *Pdbg) pdbgExcluded(dbg string) bool {
	for _, e := range pdbg.excludes {
		if strings.Contains(dbg, e) {
			fmt.Printf("EXCLUDE over '%v' including '%v'\n", dbg, e)
			return true
		}
	}
	return false
}

func (pdbg *Pdbg) pdbgBreak(dbg string) bool {
	for _, b := range pdbg.breaks {
		if strings.Contains(dbg, b) {
			fmt.Printf("BREAK over '%v' including '%v'\n", dbg, b)
			return true
		}
	}
	return false
}

// Pdbgf uses global Pdbg variable for printing strings, with indent and function name
func Pdbgf(format string, args ...interface{}) string {
	return pdbg.Pdbgf(format, args...)
}

// Pdbgf uses custom Pdbg variable for printing strings, with indent and function name
func (pdbg *Pdbg) Pdbgf(format string, args ...interface{}) string {
	msg := fmt.Sprintf(format+"\n", args...)
	msg = strings.TrimSpace(msg)

	pmsg := ""
	depth := 0
	for ok := true; ok; {
		pc, file, line, ok := runtime.Caller(depth)
		if !ok {
			break
		}
		fname := runtime.FuncForPC(pc).Name()
		fmt.Printf("Name of function: '%v' (line %v): file '%v'\n", fname, line, file)
		if pdbg.pdbgBreak(fname) {
			break
		}
		dbg := fname + ":" + fmt.Sprintf("%d", line)
		if depth == 1 {
			if pdbg.pdbgExcluded(dbg) {
				return ""
			}
			pmsg = "[" + dbg + "]"
		} else {
			pmsg = pmsg + " (" + dbg + ")"
		}
		depth = depth + 1
	}
	depth = depth - 1

	spaces := ""
	if depth >= 2 {
		spaces = strings.Repeat(" ", depth-2)
	}
	// fmt.Printf("spaces '%s', depth '%d'\n", spaces, depth)
	res := pmsg
	pmsg = spaces + pmsg
	msg = pmsg + "\n" + spaces + "  " + msg + "\n"
	// fmt.Printf("MSG '%v'\n", msg)
	fmt.Fprint(pdbg.Err(), fmt.Sprint(msg))
	return res
}
<commit_msg>Add skip for skipping gogdb.go lines<commit_after>package godbg

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"os"
	"runtime"
	"strings"
)

// http://stackoverflow.com/a/23554672/6309 https://vividcortex.com/blog/2013/12/03/go-idiom-package-and-object/
// you design a type with methods as usual, and then you also place matching functions at the package level itself.
// These functions simply delegate to a default instance of the type that’s a private package-level variable, created in an init() function.

// Pdbg allows to print debug message with indent and function name added
type Pdbg struct {
	bout     *bytes.Buffer
	berr     *bytes.Buffer
	sout     *bufio.Writer
	serr     *bufio.Writer
	breaks   []string
	excludes []string
	skips    []string
}

// Out returns a writer for normal messages.
// By default, os.StdOut
func Out() io.Writer {
	return pdbg.Out()
}

// Out returns a writer for normal messages for a given pdbg instance.
// By default, os.StdOut
func (pdbg *Pdbg) Out() io.Writer {
	if pdbg.sout == nil {
		return os.Stdout
	}
	return pdbg.sout
}

// Err returns a writer for error messages.
// By default, os.StdErr
func Err() io.Writer {
	return pdbg.Err()
}

// Err returns a writer for error messages for a given pdbg instance.
// By default, os.StdErr
func (pdbg *Pdbg) Err() io.Writer {
	if pdbg.serr == nil {
		return os.Stderr
	}
	return pdbg.serr
}

// global pdbg used for printing
var pdbg = NewPdbg()

// Option set an option for a Pdbg
// http://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis
type Option func(*Pdbg)

// SetBuffers is an option for replacing stdout and stderr by
// bytes buffers (in a bufio.Writer).
// If apdbg is nil, set for the global pdbg instance
func SetBuffers(apdbg *Pdbg) {
	if apdbg == nil {
		apdbg = pdbg
	}
	apdbg.bout = bytes.NewBuffer(nil)
	apdbg.sout = bufio.NewWriter(apdbg.bout)
	apdbg.berr = bytes.NewBuffer(nil)
	apdbg.serr = bufio.NewWriter(apdbg.berr)
}

// SetExcludes set excludes on a pdbg (nil for global pdbg)
func (pdbg *Pdbg) SetExcludes(excludes []string) {
	pdbg.excludes = excludes
}

// OptExcludes is an option to set excludes at the creation of a pdbg
func OptExcludes(excludes []string) Option {
	return func(apdbg *Pdbg) {
		apdbg.SetExcludes(excludes)
	}
}

// NewPdbg creates a PDbg instance, with options
func NewPdbg(options ...Option) *Pdbg {
	newpdbg := &Pdbg{}
	for _, option := range options {
		option(newpdbg)
	}
	newpdbg.breaks = append(newpdbg.breaks, "smartystreets")
	//newpdbg.breaks = append(newpdbg.breaks, "(*Pdbg).Pdbgf")
	newpdbg.skips = append(newpdbg.breaks, "/gogdb.go'")
	return newpdbg
}

// ResetIOs reset the out and err buffer of global pdbg instance
func ResetIOs() {
	pdbg.ResetIOs()
}

// ResetIOs reset the out and err buffer
// (unless they were the default stdout and stderr,
// in which case it does nothing)
func (pdbg *Pdbg) ResetIOs() {
	if pdbg.sout != nil {
		pdbg.bout = bytes.NewBuffer(nil)
		pdbg.sout.Reset(pdbg.bout)
		pdbg.berr = bytes.NewBuffer(nil)
		pdbg.serr.Reset(pdbg.berr)
	}
}

// OutString returns the string for out messages for the global pdbg instance.
// It flushes the out buffer.
// If out is set to os.Stdout, returns an empty string
func OutString() string {
	return pdbg.OutString()
}

// OutString returns the string for out messages for a given pdbg instance.
// It flushes the out buffer.
// If out is set to os.Stdout, returns an empty string
func (pdbg *Pdbg) OutString() string {
	if pdbg.sout == nil {
		return ""
	}
	pdbg.sout.Flush()
	return pdbg.bout.String()
}

// ErrString returns the string for error messages for the global pdbg instance.
// It flushes the err buffer.
// If err is set to os.StdErr, returns an empty string
func ErrString() string {
	return pdbg.ErrString()
}

// ErrString returns the string for error messages for a given pdbg instance.
// It flushes the err buffer.
// If err is set to os.StdErr, returns an empty string
func (pdbg *Pdbg) ErrString() string {
	if pdbg.serr == nil {
		return ""
	}
	pdbg.serr.Flush()
	return pdbg.berr.String()
}

func (pdbg *Pdbg) pdbgExcluded(dbg string) bool {
	for _, e := range pdbg.excludes {
		if strings.Contains(dbg, e) {
			fmt.Printf("EXCLUDE over '%v' including '%v'\n", dbg, e)
			return true
		}
	}
	return false
}

func (pdbg *Pdbg) pdbgBreak(dbg string) bool {
	for _, b := range pdbg.breaks {
		if strings.Contains(dbg, b) {
			fmt.Printf("BREAK over '%v' including '%v'\n", dbg, b)
			return true
		}
	}
	return false
}

func (pdbg *Pdbg) pdbgSkip(dbg string) bool {
	for _, s := range pdbg.skips {
		if strings.Contains(dbg, s) {
			fmt.Printf("SKIP over '%v' including '%v'\n", dbg, s)
			return true
		}
	}
	return false
}

// Pdbgf uses global Pdbg variable for printing strings, with indent and function name
func Pdbgf(format string, args ...interface{}) string {
	return pdbg.Pdbgf(format, args...)
}

// Pdbgf uses custom Pdbg variable for printing strings, with indent and function name
func (pdbg *Pdbg) Pdbgf(format string, args ...interface{}) string {
	msg := fmt.Sprintf(format+"\n", args...)
	msg = strings.TrimSpace(msg)

	pmsg := ""
	depth := 0
	nbskip := 0
	for ok := true; ok; {
		pc, file, line, ok := runtime.Caller(depth)
		if !ok {
			break
		}
		fname := runtime.FuncForPC(pc).Name()
		fline := fmt.Sprintf("Name of function: '%v': '%+x' (line %v): file '%v'\n", fname, fname, line, file)
		fmt.Println(fline)
		if pdbg.pdbgBreak(fline) {
			break
		}
		if pdbg.pdbgSkip(fline) {
			depth = depth + 1
			nbskip = nbskip + 1
			continue
		}
		dbg := fname + ":" + fmt.Sprintf("%d", line)
		if depth == 1 {
			if pdbg.pdbgExcluded(dbg) {
				return ""
			}
			pmsg = "[" + dbg + "]"
		} else {
			pmsg = pmsg + " (" + dbg + ")"
		}
		depth = depth + 1
	}
	depth = depth - nbskip

	spaces := ""
	if depth >= 2 {
		spaces = strings.Repeat(" ", depth-2)
	}
	// fmt.Printf("spaces '%s', depth '%d'\n", spaces, depth)
	res := pmsg
	pmsg = spaces + pmsg
	msg = pmsg + "\n" + spaces + "  " + msg + "\n"
	// fmt.Printf("MSG '%v'\n", msg)
	fmt.Fprint(pdbg.Err(), fmt.Sprint(msg))
	return res
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/defeated/going/matcher"
	"github.com/defeated/going/reader"
	"os"
)

func main() {
	lines := reader.Read("data.json")
	input := os.Args[1]
	matches := matcher.Match(input, lines)
	fmt.Println(matches)
}
<commit_msg>return first matching directory (TODO ranking/scoring)<commit_after>package main

import (
	"fmt"
	"github.com/defeated/going/matcher"
	"github.com/defeated/going/reader"
	"os"
)

func main() {
	lines := reader.Read("data.json")
	input := os.Args[1]
	matches := matcher.Match(input, lines)
	directory := matches[0]

	fmt.Println(directory)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"golang.org/x/net/ipv4"
	"golang.org/x/net/ipv6"
	"log"
	"net"
	"os"
	"strings"
)

var iMap map[string]int
var flagList bool

func parseInterfaces() {
	if flagList {
		fmt.Println("Available interfaces")
	}
	ifaces, err := net.Interfaces()
	if err != nil {
		fmt.Println(err)
		return
	}
	for _, i := range ifaces {
		addrs, err := i.Addrs()
		if err != nil {
			fmt.Println(err)
			continue
		}
		for _, a := range addrs {
			switch v := a.(type) {
			//windows
			case *net.IPAddr:
				iMap[v.String()] = i.Index
				if flagList {
					fmt.Printf("%v) %v : %s\n", i.Index, i.Name, v.String())
				}
			//linux
			case *net.IPNet:
				iMap[v.String()] = i.Index
				if flagList {
					fmt.Printf("%v) %v : %s\n", i.Index, i.Name, v.String())
				}
			}

		}
	}
}

func main() {
	var flagGroup, flagIP string
	var flagIndex int
	var c net.PacketConn
	var p6 *ipv6.PacketConn
	var p4 *ipv4.PacketConn

	iMap = make(map[string]int)

	flag.BoolVar(&flagList, "li", false, "show available interfaces")
	flag.IntVar(&flagIndex, "interface", 0, "interface to listen on (number)")
	flag.StringVar(&flagGroup, "group", "ff02::42:1 239.42.42.1", "multicast groups to join (space seperated)")
	flag.StringVar(&flagIP, "ip", "", "use interface where the specified ip is bound on")
	flag.Parse()
	if flag.NFlag() < 1 {
		flag.PrintDefaults()
		os.Exit(1)
	}
	if flagList {
		parseInterfaces()
		os.Exit(1)
	}

	parseInterfaces()
	if flagIndex == 0 {
		fmt.Print("searching interface for ip ", flagIP)
		for k, v := range iMap {
			if strings.HasPrefix(k, flagIP) {
				fmt.Println(" using interface", v, "with ip", k)
				flagIndex = v
				break
			}
		}
	}

	fmt.Println("listening on index", flagIndex)
	iface, err := net.InterfaceByIndex(flagIndex)
	if err != nil {
		log.Fatal(err)
	}

	groups := strings.Fields(flagGroup)

	if strings.Contains(flagGroup, ":") {
		c, err = net.ListenPacket("udp6", "[::]:1024")
		if err != nil {
			log.Fatal(err)
		}
		defer c.Close()
		p6 = ipv6.NewPacketConn(c)
	}
	if strings.Contains(flagGroup, ".") {
		c, err = net.ListenPacket("udp4", ":1024")
		if err != nil {
			log.Fatal(err)
		}
		defer c.Close()
		p4 = ipv4.NewPacketConn(c)
	}

	for _, group := range groups {
		IPgroup := net.ParseIP(group)
		if strings.Contains(group, ":") {
			fmt.Println("joining ipv6 group", group)
			if err := p6.JoinGroup(iface, &net.UDPAddr{IP: IPgroup}); err != nil {
				log.Fatal(err)
			}
		} else {
			fmt.Println("joining ipv4 group", group)
			if err := p4.JoinGroup(iface, &net.UDPAddr{IP: IPgroup}); err != nil {
				log.Fatal(err)
			}
		}
	}
	select {}
}
<commit_msg>Udate to go modules<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"net"
	"os"
	"strings"

	"golang.org/x/net/ipv4"
	"golang.org/x/net/ipv6"
)

var iMap map[string]int
var flagList bool

func parseInterfaces() {
	if flagList {
		fmt.Println("Available interfaces")
	}
	ifaces, err := net.Interfaces()
	if err != nil {
		fmt.Println(err)
		return
	}
	for _, i := range ifaces {
		addrs, err := i.Addrs()
		if err != nil {
			fmt.Println(err)
			continue
		}
		for _, a := range addrs {
			switch v := a.(type) {
			//windows
			case *net.IPAddr:
				iMap[v.String()] = i.Index
				if flagList {
					fmt.Printf("%v) %v : %s\n", i.Index, i.Name, v.String())
				}
			//linux
			case *net.IPNet:
				iMap[v.String()] = i.Index
				if flagList {
					fmt.Printf("%v) %v : %s\n", i.Index, i.Name, v.String())
				}
			}

		}
	}
}

func main() {
	var flagGroup, flagIP string
	var flagIndex int
	var c net.PacketConn
	var p6 *ipv6.PacketConn
	var p4 *ipv4.PacketConn

	iMap = make(map[string]int)

	flag.BoolVar(&flagList, "li", false, "show available interfaces")
	flag.IntVar(&flagIndex, "interface", 0, "interface to listen on (number)")
	flag.StringVar(&flagGroup, "group", "ff02::42:1 239.42.42.1", "multicast groups to join (space seperated)")
	flag.StringVar(&flagIP, "ip", "", "use interface where the specified ip is bound on")
	flag.Parse()
	if flag.NFlag() < 1 {
		flag.PrintDefaults()
		os.Exit(1)
	}
	if flagList {
		parseInterfaces()
		os.Exit(1)
	}

	parseInterfaces()
	if flagIndex == 0 {
		fmt.Print("searching interface for ip ", flagIP)
		for k, v := range iMap {
			if strings.HasPrefix(k, flagIP) {
				fmt.Println(" using interface", v, "with ip", k)
				flagIndex = v
				break
			}
		}
	}

	fmt.Println("listening on index", flagIndex)
	iface, err := net.InterfaceByIndex(flagIndex)
	if err != nil {
		log.Fatal(err)
	}

	groups := strings.Fields(flagGroup)

	if strings.Contains(flagGroup, ":") {
		c, err = net.ListenPacket("udp6", "[::]:1024")
		if err != nil {
			log.Fatal(err)
		}
		defer c.Close()
		p6 = ipv6.NewPacketConn(c)
	}
	if strings.Contains(flagGroup, ".") {
		c, err = net.ListenPacket("udp4", ":1024")
		if err != nil {
			log.Fatal(err)
		}
		defer c.Close()
		p4 = ipv4.NewPacketConn(c)
	}

	for _, group := range groups {
		IPgroup := net.ParseIP(group)
		if strings.Contains(group, ":") {
			fmt.Println("joining ipv6 group", group)
			if err := p6.JoinGroup(iface, &net.UDPAddr{IP: IPgroup}); err != nil {
				log.Fatal(err)
			}
		} else {
			fmt.Println("joining ipv4 group", group)
			if err := p4.JoinGroup(iface, &net.UDPAddr{IP: IPgroup}); err != nil {
				log.Fatal(err)
			}
		}
	}
	select {}
}
<|endoftext|>


<commit_before>package main

import (
    "io"
    "io/ioutil"
    "os"
    "fmt"
    "flag"
    "path/filepath"
    "strings"

    "bitbucket.org/lmika/goseq/seqdiagram"
)

// Name of the output file
var flagOut = flag.String("o", "", "Output file")

// Die with error
func die(msg string) {
    fmt.Fprintf(os.Stderr, "goseq: %s\n", msg)
    os.Exit(1)
}

// Processes a md file
func processMdFile(inFilename string, outFilename string, renderer Renderer) error {
    srcFile, err := openSourceFile(inFilename)
    if err != nil {
        return err
    }
    defer srcFile.Close()

    targetFile := ioutil.Discard

    mf := &MarkdownFilter{srcFile, targetFile, func(codeblock string, output io.Writer) error {
        fmt.Fprint(output, codeblock)
        err := processSeqDiagram(strings.NewReader(codeblock), inFilename, "/dev/null", renderer)
        if err != nil {
            fmt.Fprintf(os.Stderr, "goseq: %s:embedded block - %s\n", inFilename, err.Error())
        }
        return nil
    }}
    return mf.Scan()
}

// Processes a seq file
func processSeqFile(inFilename string, outFilename string, renderer Renderer) error {
    srcFile, err := openSourceFile(inFilename)
    if err != nil {
        return err
    }
    defer srcFile.Close()

    return processSeqDiagram(srcFile, inFilename, outFilename, renderer)
}

// Processes a sequence diagram
func processSeqDiagram(infile io.Reader, inFilename string, outFilename string, renderer Renderer) error {
    diagram, err := seqdiagram.ParseDiagram(infile, inFilename)
    if err != nil {
        return err
    }

    // If there's a process instruction, use it as the target of the diagram
    // TODO: be a little smarter with the process instructions
    if diagram.ProcessInstr != "" {
        outFilename = diagram.ProcessInstr
    }

    if renderer == nil {
        renderer, err = chooseRendererBaseOnOutfile(outFilename)
        if err != nil {
            return err
        }
    }

    err = renderer(diagram, outFilename)
    if err != nil {
        return err
    }

    return nil
}

// Processes a file.  This switches based on the file extension
func processFile(inFilename string, outFilename string, renderer Renderer) error {
    ext := filepath.Ext(inFilename)
    if ext == ".md" {
        return processMdFile(inFilename, outFilename, renderer)
    } else {
        return processSeqFile(inFilename, outFilename, renderer)
    }
}

func main() {
    var err error

    renderer := SvgRenderer
    outFile := ""

    flag.Parse()

    // Select a suitable renderer (based on the suffix of the output file, if there is one)
    if *flagOut != "" {
        renderer, err = chooseRendererBaseOnOutfile(*flagOut)
        if err != nil {
            die(err.Error())
        }
        outFile = *flagOut
    }

    // Process each file (or stdin)
    if flag.NArg() == 0 {
        err := processFile("-", outFile, renderer)
        if err != nil {
            die("stdin - " + err.Error())
        }
    } else {
        for _, inFile := range flag.Args() {
            err := processFile(inFile, outFile, renderer)
            if err != nil {
                die(inFile + " - " + err.Error())
            }
        }
    }
}<commit_msg>Fixed the embedded processing again<commit_after>package main

import (
    "io"
    "io/ioutil"
    "os"
    "fmt"
    "flag"
    "path/filepath"
    "strings"

    "bitbucket.org/lmika/goseq/seqdiagram"
)

// Name of the output file
var flagOut = flag.String("o", "", "Output file")

// Die with error
func die(msg string) {
    fmt.Fprintf(os.Stderr, "goseq: %s\n", msg)
    os.Exit(1)
}

// Processes a md file
func processMdFile(inFilename string, outFilename string, renderer Renderer) error {
    srcFile, err := openSourceFile(inFilename)
    if err != nil {
        return err
    }
    defer srcFile.Close()

    targetFile := ioutil.Discard

    mf := &MarkdownFilter{srcFile, targetFile, func(codeblock string, output io.Writer) error {
        fmt.Fprint(output, codeblock)
        err := processSeqDiagram(strings.NewReader(codeblock), inFilename, "/dev/null", nil)
        if err != nil {
            fmt.Fprintf(os.Stderr, "goseq: %s:embedded block - %s\n", inFilename, err.Error())
        }
        return nil
    }}
    return mf.Scan()
}

// Processes a seq file
func processSeqFile(inFilename string, outFilename string, renderer Renderer) error {
    srcFile, err := openSourceFile(inFilename)
    if err != nil {
        return err
    }
    defer srcFile.Close()

    return processSeqDiagram(srcFile, inFilename, outFilename, renderer)
}

// Processes a sequence diagram
func processSeqDiagram(infile io.Reader, inFilename string, outFilename string, renderer Renderer) error {
    diagram, err := seqdiagram.ParseDiagram(infile, inFilename)
    if err != nil {
        return err
    }

    // If there's a process instruction, use it as the target of the diagram
    // TODO: be a little smarter with the process instructions
    if diagram.ProcessInstr != "" {
        outFilename = diagram.ProcessInstr
    }

    if renderer == nil {
        renderer, err = chooseRendererBaseOnOutfile(outFilename)
        if err != nil {
            return err
        }
    }

    err = renderer(diagram, outFilename)
    if err != nil {
        return err
    }

    return nil
}

// Processes a file.  This switches based on the file extension
func processFile(inFilename string, outFilename string, renderer Renderer) error {
    ext := filepath.Ext(inFilename)
    if ext == ".md" {
        return processMdFile(inFilename, outFilename, renderer)
    } else {
        return processSeqFile(inFilename, outFilename, renderer)
    }
}

func main() {
    var err error

    renderer := SvgRenderer
    outFile := ""

    flag.Parse()

    // Select a suitable renderer (based on the suffix of the output file, if there is one)
    if *flagOut != "" {
        renderer, err = chooseRendererBaseOnOutfile(*flagOut)
        if err != nil {
            die(err.Error())
        }
        outFile = *flagOut
    }

    // Process each file (or stdin)
    if flag.NArg() == 0 {
        err := processFile("-", outFile, renderer)
        if err != nil {
            die("stdin - " + err.Error())
        }
    } else {
        for _, inFile := range flag.Args() {
            err := processFile(inFile, outFile, renderer)
            if err != nil {
                die(inFile + " - " + err.Error())
            }
        }
    }
}<|endoftext|>