<commit_before>/* Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 clownfish

/*

#include "charmony.h"

#include "Clownfish/Obj.h"
#include "Clownfish/Err.h"
#include "Clownfish/Class.h"
#include "Clownfish/String.h"
#include "Clownfish/Hash.h"
#include "Clownfish/Vector.h"
#include "Clownfish/String.h"
#include "Clownfish/Util/Memory.h"
#include "Clownfish/Method.h"

extern void
GoCfish_PanicErr_internal(cfish_Err *error);
typedef void
(*cfish_Err_do_throw_t)(cfish_Err *error);
extern cfish_Err_do_throw_t GoCfish_PanicErr;

extern cfish_Err*
GoCfish_TrapErr_internal(CFISH_Err_Attempt_t routine, void *context);
typedef cfish_Err*
(*cfish_Err_trap_t)(CFISH_Err_Attempt_t routine, void *context);
extern cfish_Err_trap_t GoCfish_TrapErr;

// C symbols linked into a Go-built package archive are not visible to
// external C code -- but internal code *can* see symbols from outside.
// This allows us to fake up symbol export by assigning values only known
// interally to external symbols during Go package initialization.
static CHY_INLINE void
GoCfish_glue_exported_symbols() {
	GoCfish_PanicErr = GoCfish_PanicErr_internal;
	GoCfish_TrapErr  = GoCfish_TrapErr_internal;
}

static CHY_INLINE void
GoCfish_RunRoutine(CFISH_Err_Attempt_t routine, void *context) {
	routine(context);
}

*/
import "C"
import "runtime"
import "unsafe"

func init() {
	C.GoCfish_glue_exported_symbols()
	C.cfish_bootstrap_parcel()
}

type ObjIMP struct {
	ref uintptr
}

func NewString(goString string) String {
	str := C.CString(goString)
	len := C.size_t(len(goString))
	cfObj := C.cfish_Str_new_steal_utf8(str, len)
	return WRAPString(unsafe.Pointer(cfObj))
}

func (o *ObjIMP) INITOBJ(ptr unsafe.Pointer) {
	o.ref = uintptr(ptr)
	runtime.SetFinalizer(o, ClearRef)
}

func ClearRef (o *ObjIMP) {
	C.cfish_dec_refcount(unsafe.Pointer(o.ref))
	o.ref = 0
}

func (o *ObjIMP) TOPTR() uintptr {
	return o.ref
}

func CFStringToGo(ptr unsafe.Pointer) string {
	cfString := (*C.cfish_String)(ptr)
	if cfString == nil {
		return ""
	}
	if !C.cfish_Str_is_a(cfString, C.CFISH_STRING) {
		cfString := C.CFISH_Str_To_String(cfString)
		defer C.cfish_dec_refcount(unsafe.Pointer(cfString))
	}
	data := C.CFISH_Str_Get_Ptr8(cfString)
	size := C.int(C.CFISH_Str_Get_Size(cfString))
	return C.GoStringN(data, size)
}

func (e *ErrIMP) Error() string {
	mess := C.CFISH_Err_Get_Mess((*C.cfish_Err)(unsafe.Pointer(e.ref)))
	return CFStringToGo(unsafe.Pointer(mess))
}

//export GoCfish_PanicErr_internal
func GoCfish_PanicErr_internal(cfErr *C.cfish_Err) {
	goErr := WRAPErr(unsafe.Pointer(cfErr))
	panic(goErr)
}

//export GoCfish_TrapErr_internal
func GoCfish_TrapErr_internal(routine C.CFISH_Err_Attempt_t,
	context unsafe.Pointer) *C.cfish_Err {
	err := TrapErr(func() { C.GoCfish_RunRoutine(routine, context) })
	if err != nil {
		ptr := (err.(Err)).TOPTR()
		return ((*C.cfish_Err)(unsafe.Pointer(ptr)))
	}
	return nil
}

// Run the supplied routine, and if it panics with a clownfish.Err, trap and
// return it.
func TrapErr(routine func()) (trapped error) {
	defer func() {
		if r := recover(); r != nil {
			// TODO: pass whitelist of Err types to trap.
			myErr, ok := r.(Err)
			if ok {
				trapped = myErr
			} else {
				// re-panic
				panic(r)
			}
		}
	}()
	routine()
	return trapped
}

func (s *StringIMP) CodePointAt(tick uintptr) rune {
	self := ((*C.cfish_String)(unsafe.Pointer(s.TOPTR())))
	retvalCF := C.CFISH_Str_Code_Point_At(self, C.size_t(tick))
	return rune(retvalCF)
}

func (s *StringIMP) CodePointFrom(tick uintptr) rune {
	self := ((*C.cfish_String)(unsafe.Pointer(s.TOPTR())))
	retvalCF := C.CFISH_Str_Code_Point_From(self, C.size_t(tick))
	return rune(retvalCF)
}

func (s *StringIMP) SwapChars(match, replacement rune) string {
	self := ((*C.cfish_String)(unsafe.Pointer(s.TOPTR())))
	retvalCF := C.CFISH_Str_Swap_Chars(self, C.int32_t(match), C.int32_t(replacement))
	defer C.cfish_dec_refcount(unsafe.Pointer(retvalCF))
	return CFStringToGo(unsafe.Pointer(retvalCF))
}
<commit_msg>Add Go bindings for Boolean and Blob constructors.<commit_after>/* Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 clownfish

/*

#include "charmony.h"

#include "Clownfish/Obj.h"
#include "Clownfish/Err.h"
#include "Clownfish/Class.h"
#include "Clownfish/String.h"
#include "Clownfish/Blob.h"
#include "Clownfish/Hash.h"
#include "Clownfish/Vector.h"
#include "Clownfish/Boolean.h"
#include "Clownfish/Util/Memory.h"
#include "Clownfish/Method.h"

extern void
GoCfish_PanicErr_internal(cfish_Err *error);
typedef void
(*cfish_Err_do_throw_t)(cfish_Err *error);
extern cfish_Err_do_throw_t GoCfish_PanicErr;

extern cfish_Err*
GoCfish_TrapErr_internal(CFISH_Err_Attempt_t routine, void *context);
typedef cfish_Err*
(*cfish_Err_trap_t)(CFISH_Err_Attempt_t routine, void *context);
extern cfish_Err_trap_t GoCfish_TrapErr;

// C symbols linked into a Go-built package archive are not visible to
// external C code -- but internal code *can* see symbols from outside.
// This allows us to fake up symbol export by assigning values only known
// interally to external symbols during Go package initialization.
static CHY_INLINE void
GoCfish_glue_exported_symbols() {
	GoCfish_PanicErr = GoCfish_PanicErr_internal;
	GoCfish_TrapErr  = GoCfish_TrapErr_internal;
}

static CHY_INLINE void
GoCfish_RunRoutine(CFISH_Err_Attempt_t routine, void *context) {
	routine(context);
}

*/
import "C"
import "runtime"
import "unsafe"

func init() {
	C.GoCfish_glue_exported_symbols()
	C.cfish_bootstrap_parcel()
}

type ObjIMP struct {
	ref uintptr
}

func NewString(goString string) String {
	str := C.CString(goString)
	len := C.size_t(len(goString))
	cfObj := C.cfish_Str_new_steal_utf8(str, len)
	return WRAPString(unsafe.Pointer(cfObj))
}

func (o *ObjIMP) INITOBJ(ptr unsafe.Pointer) {
	o.ref = uintptr(ptr)
	runtime.SetFinalizer(o, ClearRef)
}

func ClearRef (o *ObjIMP) {
	C.cfish_dec_refcount(unsafe.Pointer(o.ref))
	o.ref = 0
}

func (o *ObjIMP) TOPTR() uintptr {
	return o.ref
}

func CFStringToGo(ptr unsafe.Pointer) string {
	cfString := (*C.cfish_String)(ptr)
	if cfString == nil {
		return ""
	}
	if !C.cfish_Str_is_a(cfString, C.CFISH_STRING) {
		cfString := C.CFISH_Str_To_String(cfString)
		defer C.cfish_dec_refcount(unsafe.Pointer(cfString))
	}
	data := C.CFISH_Str_Get_Ptr8(cfString)
	size := C.int(C.CFISH_Str_Get_Size(cfString))
	return C.GoStringN(data, size)
}

func (e *ErrIMP) Error() string {
	mess := C.CFISH_Err_Get_Mess((*C.cfish_Err)(unsafe.Pointer(e.ref)))
	return CFStringToGo(unsafe.Pointer(mess))
}

//export GoCfish_PanicErr_internal
func GoCfish_PanicErr_internal(cfErr *C.cfish_Err) {
	goErr := WRAPErr(unsafe.Pointer(cfErr))
	panic(goErr)
}

//export GoCfish_TrapErr_internal
func GoCfish_TrapErr_internal(routine C.CFISH_Err_Attempt_t,
	context unsafe.Pointer) *C.cfish_Err {
	err := TrapErr(func() { C.GoCfish_RunRoutine(routine, context) })
	if err != nil {
		ptr := (err.(Err)).TOPTR()
		return ((*C.cfish_Err)(unsafe.Pointer(ptr)))
	}
	return nil
}

// Run the supplied routine, and if it panics with a clownfish.Err, trap and
// return it.
func TrapErr(routine func()) (trapped error) {
	defer func() {
		if r := recover(); r != nil {
			// TODO: pass whitelist of Err types to trap.
			myErr, ok := r.(Err)
			if ok {
				trapped = myErr
			} else {
				// re-panic
				panic(r)
			}
		}
	}()
	routine()
	return trapped
}

func (s *StringIMP) CodePointAt(tick uintptr) rune {
	self := ((*C.cfish_String)(unsafe.Pointer(s.TOPTR())))
	retvalCF := C.CFISH_Str_Code_Point_At(self, C.size_t(tick))
	return rune(retvalCF)
}

func (s *StringIMP) CodePointFrom(tick uintptr) rune {
	self := ((*C.cfish_String)(unsafe.Pointer(s.TOPTR())))
	retvalCF := C.CFISH_Str_Code_Point_From(self, C.size_t(tick))
	return rune(retvalCF)
}

func (s *StringIMP) SwapChars(match, replacement rune) string {
	self := ((*C.cfish_String)(unsafe.Pointer(s.TOPTR())))
	retvalCF := C.CFISH_Str_Swap_Chars(self, C.int32_t(match), C.int32_t(replacement))
	defer C.cfish_dec_refcount(unsafe.Pointer(retvalCF))
	return CFStringToGo(unsafe.Pointer(retvalCF))
}

func NewBoolean(val bool) Boolean {
	if val {
		return WRAPBoolean(unsafe.Pointer(C.cfish_inc_refcount(unsafe.Pointer(C.CFISH_TRUE))))
	} else {
		return WRAPBoolean(unsafe.Pointer(C.cfish_inc_refcount(unsafe.Pointer(C.CFISH_FALSE))))
	}
}

func NewBlob(content []byte) Blob {
	size := C.size_t(len(content))
	var buf *C.char = nil
	if size > 0 {
		buf = ((*C.char)(unsafe.Pointer(&content[0])))
	}
	obj := C.cfish_Blob_new(buf, size)
	return WRAPBlob(unsafe.Pointer(obj))
}
<|endoftext|>


<commit_before>package trustmanager

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
)

const visible os.FileMode = 0755
const private os.FileMode = 0700

// FileStore is the interface for all FileStores
type FileStore interface {
	Add(fileName string, data []byte) error
	Remove(fileName string) error
	RemoveGUN(gun string) error
	GetData(fileName string) ([]byte, error)
	GetPath(fileName string) string
	List() []string
	ListGUN(gun string) []string
}

type fileStore struct {
	baseDir string
	fileExt string
	perms   os.FileMode
}

func NewFileStore(baseDir string, fileExt string) (FileStore, error) {
	if err := CreateDirectory(baseDir); err != nil {
		return nil, err
	}

	return &fileStore{
		baseDir: baseDir,
		fileExt: fileExt,
		perms:   visible,
	}, nil
}

func NewPrivateFileStore(baseDir string, fileExt string) (FileStore, error) {
	if err := CreatePrivateDirectory(baseDir); err != nil {
		return nil, err
	}

	return &fileStore{
		baseDir: baseDir,
		fileExt: fileExt,
		perms:   private,
	}, nil
}

func (f *fileStore) Add(name string, data []byte) error {
	filePath := f.genFilePath(name)
	createDirectory(filepath.Dir(filePath), f.perms)
	if err := ioutil.WriteFile(filePath, data, f.perms); err != nil {
		return err
	}

	return nil
}

func (f *fileStore) Remove(name string) error {
	filePath := f.genFilePath(name)
	if err := os.Remove(filePath); err != nil {
		return err
	}

	return nil
}

func (f *fileStore) RemoveGUN(gun string) error {
	dirPath := filepath.Join(f.baseDir, gun)

	// Check to see if file exists
	fi, err := os.Stat(dirPath)
	if err != nil {
		return err
	}

	// Check to see if it is a directory
	if !fi.IsDir() {
		return fmt.Errorf("GUN not found: %s", gun)
	}

	if err := os.RemoveAll(dirPath); err != nil {
		return err
	}

	return nil
}

func (f *fileStore) GetData(name string) ([]byte, error) {
	filePath := f.genFilePath(name)
	data, err := ioutil.ReadFile(filePath)
	if err != nil {
		return nil, err
	}

	return data, nil
}

func (f *fileStore) GetPath(name string) string {
	return f.genFilePath(name)
}

func (f *fileStore) List() []string {
	files := make([]string, 0, 0)
	filepath.Walk(f.baseDir, func(fp string, fi os.FileInfo, err error) error {
		// If there are errors, ignore this particular file
		if err != nil {
			return nil
		}
		// Ignore if it is a directory
		if fi.IsDir() {
			return nil
		}
		// Only allow matches that end with our certificate extension (e.g. *.crt)
		matched, _ := filepath.Match("*"+f.fileExt, fi.Name())

		if matched {
			files = append(files, fp)
		}
		return nil
	})
	return files
}

func (f *fileStore) ListGUN(gun string) []string {
	files := make([]string, 0, 0)
	// This prevents someone passing /path/to/dir and 'dir' not being included
	// If two '//' exist, Walk deals it with correctly
	gunPath := filepath.Join(f.baseDir, gun) + "/"
	filepath.Walk(gunPath, func(fp string, fi os.FileInfo, err error) error {
		// If there are errors, ignore this particular file
		if err != nil {
			return nil
		}
		// Ignore if it is a directory
		if fi.IsDir() {
			return nil
		}
		// Only allow matches that end with our certificate extension (e.g. *.crt)
		matched, _ := filepath.Match("*"+f.fileExt, fi.Name())

		if matched {
			files = append(files, fp)
		}
		return nil
	})
	return files
}

func (f *fileStore) genFilePath(name string) string {
	fileName := fmt.Sprintf("%s.%s", name, f.fileExt)
	filePath := filepath.Join(f.baseDir, fileName)
	return filePath
}

func CreateDirectory(dir string) error {
	return createDirectory(dir, visible)
}

func CreatePrivateDirectory(dir string) error {
	return createDirectory(dir, private)
}

// createDirectory receives a string of the path to a directory.
// It does not support passing files, so the caller has to remove
// the filename by doing filepath.Dir(full_path_to_file)
func createDirectory(dir string, perms os.FileMode) error {
	// This prevents someone passing /path/to/dir and 'dir' not being created
	// If two '//' exist, MkdirAll deals it with correctly
	dir = dir + "/"
	if err := os.MkdirAll(dir, perms); err != nil {
		return err
	}
	return nil
}
<commit_msg>Making ListGUN and List DRY<commit_after>package trustmanager

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
)

const visible os.FileMode = 0755
const private os.FileMode = 0700

// FileStore is the interface for all FileStores
type FileStore interface {
	Add(fileName string, data []byte) error
	Remove(fileName string) error
	RemoveGUN(gun string) error
	GetData(fileName string) ([]byte, error)
	GetPath(fileName string) string
	List() []string
	ListGUN(gun string) []string
}

type fileStore struct {
	baseDir string
	fileExt string
	perms   os.FileMode
}

func NewFileStore(baseDir string, fileExt string) (FileStore, error) {
	if err := CreateDirectory(baseDir); err != nil {
		return nil, err
	}

	return &fileStore{
		baseDir: baseDir,
		fileExt: fileExt,
		perms:   visible,
	}, nil
}

func NewPrivateFileStore(baseDir string, fileExt string) (FileStore, error) {
	if err := CreatePrivateDirectory(baseDir); err != nil {
		return nil, err
	}

	return &fileStore{
		baseDir: baseDir,
		fileExt: fileExt,
		perms:   private,
	}, nil
}

func (f *fileStore) Add(name string, data []byte) error {
	filePath := f.genFilePath(name)
	createDirectory(filepath.Dir(filePath), f.perms)
	if err := ioutil.WriteFile(filePath, data, f.perms); err != nil {
		return err
	}

	return nil
}

func (f *fileStore) Remove(name string) error {
	filePath := f.genFilePath(name)
	if err := os.Remove(filePath); err != nil {
		return err
	}

	return nil
}

func (f *fileStore) RemoveGUN(gun string) error {
	dirPath := filepath.Join(f.baseDir, gun)

	// Check to see if file exists
	fi, err := os.Stat(dirPath)
	if err != nil {
		return err
	}

	// Check to see if it is a directory
	if !fi.IsDir() {
		return fmt.Errorf("GUN not found: %s", gun)
	}

	if err := os.RemoveAll(dirPath); err != nil {
		return err
	}

	return nil
}

func (f *fileStore) GetData(name string) ([]byte, error) {
	filePath := f.genFilePath(name)
	data, err := ioutil.ReadFile(filePath)
	if err != nil {
		return nil, err
	}

	return data, nil
}

func (f *fileStore) GetPath(name string) string {
	return f.genFilePath(name)
}

func (f *fileStore) List() []string {
	return f.listGUN(f.baseDir)
}

func (f *fileStore) ListGUN(gun string) []string {
	gunPath := filepath.Join(f.baseDir, gun)
	return f.listGUN(gunPath)
}

func (f *fileStore) listGUN(gunPath string) []string {
	files := make([]string, 0, 0)
	filepath.Walk(gunPath, func(fp string, fi os.FileInfo, err error) error {
		// If there are errors, ignore this particular file
		if err != nil {
			return nil
		}
		// Ignore if it is a directory
		if fi.IsDir() {
			return nil
		}
		// Only allow matches that end with our certificate extension (e.g. *.crt)
		matched, _ := filepath.Match("*"+f.fileExt, fi.Name())

		if matched {
			files = append(files, fp)
		}
		return nil
	})
	return files
}

func (f *fileStore) genFilePath(name string) string {
	fileName := fmt.Sprintf("%s.%s", name, f.fileExt)
	filePath := filepath.Join(f.baseDir, fileName)
	return filePath
}

func CreateDirectory(dir string) error {
	return createDirectory(dir, visible)
}

func CreatePrivateDirectory(dir string) error {
	return createDirectory(dir, private)
}

// createDirectory receives a string of the path to a directory.
// It does not support passing files, so the caller has to remove
// the filename by doing filepath.Dir(full_path_to_file)
func createDirectory(dir string, perms os.FileMode) error {
	// This prevents someone passing /path/to/dir and 'dir' not being created
	// If two '//' exist, MkdirAll deals it with correctly
	dir = dir + "/"
	if err := os.MkdirAll(dir, perms); err != nil {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>/* walter: a deployment pipeline template
 * Copyright (C) 2014 Recruit Technologies Co., Ltd. and contributors
 * (see CONTRIBUTORS.md)
 *
 * 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 config

import (
	"container/list"
	"fmt"
	"reflect"
	"strings"
	"strconv"

	"github.com/recruit-tech/walter/log"
	"github.com/recruit-tech/walter/messengers"
	"github.com/recruit-tech/walter/pipelines"
	"github.com/recruit-tech/walter/services"
	"github.com/recruit-tech/walter/stages"
)

type Parser struct {
	ConfigData   *map[interface{}]interface{}
	EnvVariables *EnvVariables
}

// Parse reads the specified configuration and create the pipeline.Resource.
func (self *Parser) Parse() (*pipelines.Resources, error) {
	// parse require block
	requires, ok := (*self.ConfigData)["require"].([]interface{})
	if ok == true {
		log.Info("found \"require\" block")
		self.mapRequires(requires)
	} else {
		log.Info("not found \"require\" block")
	}

	// parse service block
	serviceOps, ok := (*self.ConfigData)["service"].(map[interface{}]interface{})
	var repoService services.Service
	var err error
	if ok == true {
		log.Info("found \"service\" block")
		repoService, err = self.mapService(serviceOps)
		if err != nil {
			return nil, err
		}
	} else {
		log.Info("not found \"service\" block")
		repoService, err = services.InitService("local")
		if err != nil {
			return nil, err
		}
	}

	// parse messenger block
	messengerOps, ok := (*self.ConfigData)["messenger"].(map[interface{}]interface{})
	var messenger messengers.Messenger
	if ok == true {
		log.Info("found messenger block")
		messenger, err = self.mapMessenger(messengerOps)
		if err != nil {
			return nil, err
		}
	} else {
		log.Info("not found messenger block")
		messenger, err = messengers.InitMessenger("fake")
		if err != nil {
			return nil, err
		}
	}

	// parse cleanup block
	var cleanup *pipelines.Pipeline = &pipelines.Pipeline{}
	cleanupData, ok := (*self.ConfigData)["cleanup"].([]interface{})
	if ok == true {
		log.Info("found cleanup block")
		cleanupList, err := self.convertYamlMapToStages(cleanupData)
		if err != nil {
			return nil, err
		}
		for stageItem := cleanupList.Front(); stageItem != nil; stageItem = stageItem.Next() {
			cleanup.AddStage(stageItem.Value.(stages.Stage))
		}
	} else {
		log.Info("not found cleanup block in the input file")
	}

	// parse pipeline block
	var pipeline *pipelines.Pipeline = &pipelines.Pipeline{}

	pipelineData, ok := (*self.ConfigData)["pipeline"].([]interface{})
	if ok == false {
		return nil, fmt.Errorf("no pipeline block in the input file")
	}
	stageList, err := self.convertYamlMapToStages(pipelineData)
	if err != nil {
		return nil, err
	}
	for stageItem := stageList.Front(); stageItem != nil; stageItem = stageItem.Next() {
		pipeline.AddStage(stageItem.Value.(stages.Stage))
	}
	var resources = &pipelines.Resources{Pipeline: pipeline, Cleanup: cleanup, Reporter: messenger, RepoService: repoService}

	return resources, nil
}

func (self *Parser) mapRequires(requireList []interface{}) (map[string]interface{}, error) {
	requires := make(map[string]interface{})
	for _, requireFile := range requireList {
		log.Info("register require file: " + requireFile.(string))
		requireData := ReadConfig(requireFile.(string))
		self.mapRequire(*requireData, requires)
	}
	return requires, nil
}

func (self *Parser) mapRequire(requireData map[interface{}]interface{}, requries map[string]interface{}) {
	// load namespace
	namespace := requireData["namespace"].(string)
	log.Info("detect namespace: " + namespace)

	// load stages
	stages := requireData["stages"].([]interface{})
	log.Info("Number of detected stages: " + strconv.Itoa(len(stages)))
}

func (self *Parser) mapMessenger(messengerMap map[interface{}]interface{}) (messengers.Messenger, error) {
	messengerType := messengerMap["type"].(string)
	log.Info("type of reporter is " + messengerType)
	messenger, err := messengers.InitMessenger(messengerType)
	if err != nil {
		return nil, err
	}
	newMessengerValue := reflect.ValueOf(messenger).Elem()
	newMessengerType := reflect.TypeOf(messenger).Elem()
	for i := 0; i < newMessengerType.NumField(); i++ {
		tagName := newMessengerType.Field(i).Tag.Get("config")
		for messengerOptKey, messengerOptVal := range messengerMap {
			if tagName == messengerOptKey {
				fieldVal := newMessengerValue.Field(i)
				if fieldVal.Type() == reflect.ValueOf("string").Type() {
					fieldVal.SetString(self.EnvVariables.Replace(messengerOptVal.(string)))
				}
			}
		}
	}

	return messenger, nil
}

func (self *Parser) mapService(serviceMap map[interface{}]interface{}) (services.Service, error) {
	serviceType := serviceMap["type"].(string)
	log.Info("type of service is " + serviceType)
	service, err := services.InitService(serviceType)
	if err != nil {
		return nil, err
	}

	newServiceValue := reflect.ValueOf(service).Elem()
	newServiceType := reflect.TypeOf(service).Elem()
	for i := 0; i < newServiceType.NumField(); i++ {
		tagName := newServiceType.Field(i).Tag.Get("config")
		for serviceOptKey, serviceOptVal := range serviceMap {
			if tagName == serviceOptKey {
				fieldVal := newServiceValue.Field(i)
				if fieldVal.Type() == reflect.ValueOf("string").Type() {
					fieldVal.SetString(self.EnvVariables.Replace(serviceOptVal.(string)))
				}
			}
		}
	}
	return service, nil
}

func (self *Parser) convertYamlMapToStages(yamlStageList []interface{}) (*list.List, error) {
	stages := list.New()
	for _, stageDetail := range yamlStageList {
		stage, err := self.mapStage(stageDetail.(map[interface{}]interface{}))
		if err != nil {
			return nil, err
		}
		stages.PushBack(stage)
	}
	return stages, nil
}

func (self *Parser) mapStage(stageMap map[interface{}]interface{}) (stages.Stage, error) {
	log.Debugf("%v", stageMap["run_after"])

	var stageType string = "command"
	if stageMap["type"] != nil {
		stageType = stageMap["type"].(string)
	} else if stageMap["stage_type"] != nil {
		log.Warn("found property \"stage_type\"")
		log.Warn("property \"stage_type\" is deprecated. please use \"type\" instead.")
		stageType = stageMap["stage_type"].(string)
	}
	stage, err := stages.InitStage(stageType)
	if err != nil {
		return nil, err
	}
	newStageValue := reflect.ValueOf(stage).Elem()
	newStageType := reflect.TypeOf(stage).Elem()

	if stageName := stageMap["name"]; stageName != nil {
		stage.SetStageName(stageMap["name"].(string))
	} else if stageName := stageMap["stage_name"]; stageName != nil {
		log.Warn("found property \"stage_name\"")
		log.Warn("property \"stage_name\" is deprecated. please use \"stage\" instead.")
		stage.SetStageName(stageMap["stage_name"].(string))
	}

	stageOpts := stages.NewStageOpts()

	if reportingFullOutput := stageMap["report_full_output"]; reportingFullOutput != nil {
		stageOpts.ReportingFullOutput = true
	}

	stage.SetStageOpts(*stageOpts)

	for i := 0; i < newStageType.NumField(); i++ {
		tagName := newStageType.Field(i).Tag.Get("config")
		is_replace := newStageType.Field(i).Tag.Get("is_replace")
		for stageOptKey, stageOptVal := range stageMap {
			if tagName == stageOptKey {
				if stageOptVal == nil {
					log.Warnf("stage option \"%s\" is not specified", stageOptKey)
				} else {
					self.setFieldVal(newStageValue.Field(i), stageOptVal, is_replace)
				}
			}
		}
	}

	parallelStages := stageMap["parallel"]
	if parallelStages == nil {
		if parallelStages = stageMap["run_after"]; parallelStages != nil {
			log.Warn("`run_after' will be obsoleted in near future. Use `parallel' instead.")
		}
	}

	if parallelStages != nil {
		for _, parallelStages := range parallelStages.([]interface{}) {
			childStage, err := self.mapStage(parallelStages.(map[interface{}]interface{}))
			if err != nil {
				return nil, err
			}
			stage.AddChildStage(childStage)
		}
	}
	return stage, nil
}

func (self *Parser) setFieldVal(fieldVal reflect.Value, stageOptVal interface{}, is_replace string) {
	if fieldVal.Type() == reflect.ValueOf("string").Type() {
		if is_replace == "true" {
			fieldVal.SetString(self.EnvVariables.Replace(stageOptVal.(string)))
		} else {
			fieldVal.SetString(stageOptVal.(string))
		}
	}
}

func getStageTypeModuleName(stageType string) string {
	return strings.ToLower(stageType)
}
<commit_msg>Fix format<commit_after>/* walter: a deployment pipeline template
 * Copyright (C) 2014 Recruit Technologies Co., Ltd. and contributors
 * (see CONTRIBUTORS.md)
 *
 * 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 config

import (
	"container/list"
	"fmt"
	"reflect"
	"strconv"
	"strings"

	"github.com/recruit-tech/walter/log"
	"github.com/recruit-tech/walter/messengers"
	"github.com/recruit-tech/walter/pipelines"
	"github.com/recruit-tech/walter/services"
	"github.com/recruit-tech/walter/stages"
)

type Parser struct {
	ConfigData   *map[interface{}]interface{}
	EnvVariables *EnvVariables
}

// Parse reads the specified configuration and create the pipeline.Resource.
func (self *Parser) Parse() (*pipelines.Resources, error) {
	// parse require block
	requires, ok := (*self.ConfigData)["require"].([]interface{})
	if ok == true {
		log.Info("found \"require\" block")
		self.mapRequires(requires)
	} else {
		log.Info("not found \"require\" block")
	}

	// parse service block
	serviceOps, ok := (*self.ConfigData)["service"].(map[interface{}]interface{})
	var repoService services.Service
	var err error
	if ok == true {
		log.Info("found \"service\" block")
		repoService, err = self.mapService(serviceOps)
		if err != nil {
			return nil, err
		}
	} else {
		log.Info("not found \"service\" block")
		repoService, err = services.InitService("local")
		if err != nil {
			return nil, err
		}
	}

	// parse messenger block
	messengerOps, ok := (*self.ConfigData)["messenger"].(map[interface{}]interface{})
	var messenger messengers.Messenger
	if ok == true {
		log.Info("found messenger block")
		messenger, err = self.mapMessenger(messengerOps)
		if err != nil {
			return nil, err
		}
	} else {
		log.Info("not found messenger block")
		messenger, err = messengers.InitMessenger("fake")
		if err != nil {
			return nil, err
		}
	}

	// parse cleanup block
	var cleanup *pipelines.Pipeline = &pipelines.Pipeline{}
	cleanupData, ok := (*self.ConfigData)["cleanup"].([]interface{})
	if ok == true {
		log.Info("found cleanup block")
		cleanupList, err := self.convertYamlMapToStages(cleanupData)
		if err != nil {
			return nil, err
		}
		for stageItem := cleanupList.Front(); stageItem != nil; stageItem = stageItem.Next() {
			cleanup.AddStage(stageItem.Value.(stages.Stage))
		}
	} else {
		log.Info("not found cleanup block in the input file")
	}

	// parse pipeline block
	var pipeline *pipelines.Pipeline = &pipelines.Pipeline{}

	pipelineData, ok := (*self.ConfigData)["pipeline"].([]interface{})
	if ok == false {
		return nil, fmt.Errorf("no pipeline block in the input file")
	}
	stageList, err := self.convertYamlMapToStages(pipelineData)
	if err != nil {
		return nil, err
	}
	for stageItem := stageList.Front(); stageItem != nil; stageItem = stageItem.Next() {
		pipeline.AddStage(stageItem.Value.(stages.Stage))
	}
	var resources = &pipelines.Resources{Pipeline: pipeline, Cleanup: cleanup, Reporter: messenger, RepoService: repoService}

	return resources, nil
}

func (self *Parser) mapRequires(requireList []interface{}) (map[string]interface{}, error) {
	requires := make(map[string]interface{})
	for _, requireFile := range requireList {
		log.Info("register require file: " + requireFile.(string))
		requireData := ReadConfig(requireFile.(string))
		self.mapRequire(*requireData, requires)
	}
	return requires, nil
}

func (self *Parser) mapRequire(requireData map[interface{}]interface{}, requries map[string]interface{}) {
	// load namespace
	namespace := requireData["namespace"].(string)
	log.Info("detect namespace: " + namespace)

	// load stages
	stages := requireData["stages"].([]interface{})
	log.Info("Number of detected stages: " + strconv.Itoa(len(stages)))
}

func (self *Parser) mapMessenger(messengerMap map[interface{}]interface{}) (messengers.Messenger, error) {
	messengerType := messengerMap["type"].(string)
	log.Info("type of reporter is " + messengerType)
	messenger, err := messengers.InitMessenger(messengerType)
	if err != nil {
		return nil, err
	}
	newMessengerValue := reflect.ValueOf(messenger).Elem()
	newMessengerType := reflect.TypeOf(messenger).Elem()
	for i := 0; i < newMessengerType.NumField(); i++ {
		tagName := newMessengerType.Field(i).Tag.Get("config")
		for messengerOptKey, messengerOptVal := range messengerMap {
			if tagName == messengerOptKey {
				fieldVal := newMessengerValue.Field(i)
				if fieldVal.Type() == reflect.ValueOf("string").Type() {
					fieldVal.SetString(self.EnvVariables.Replace(messengerOptVal.(string)))
				}
			}
		}
	}

	return messenger, nil
}

func (self *Parser) mapService(serviceMap map[interface{}]interface{}) (services.Service, error) {
	serviceType := serviceMap["type"].(string)
	log.Info("type of service is " + serviceType)
	service, err := services.InitService(serviceType)
	if err != nil {
		return nil, err
	}

	newServiceValue := reflect.ValueOf(service).Elem()
	newServiceType := reflect.TypeOf(service).Elem()
	for i := 0; i < newServiceType.NumField(); i++ {
		tagName := newServiceType.Field(i).Tag.Get("config")
		for serviceOptKey, serviceOptVal := range serviceMap {
			if tagName == serviceOptKey {
				fieldVal := newServiceValue.Field(i)
				if fieldVal.Type() == reflect.ValueOf("string").Type() {
					fieldVal.SetString(self.EnvVariables.Replace(serviceOptVal.(string)))
				}
			}
		}
	}
	return service, nil
}

func (self *Parser) convertYamlMapToStages(yamlStageList []interface{}) (*list.List, error) {
	stages := list.New()
	for _, stageDetail := range yamlStageList {
		stage, err := self.mapStage(stageDetail.(map[interface{}]interface{}))
		if err != nil {
			return nil, err
		}
		stages.PushBack(stage)
	}
	return stages, nil
}

func (self *Parser) mapStage(stageMap map[interface{}]interface{}) (stages.Stage, error) {
	log.Debugf("%v", stageMap["run_after"])

	var stageType string = "command"
	if stageMap["type"] != nil {
		stageType = stageMap["type"].(string)
	} else if stageMap["stage_type"] != nil {
		log.Warn("found property \"stage_type\"")
		log.Warn("property \"stage_type\" is deprecated. please use \"type\" instead.")
		stageType = stageMap["stage_type"].(string)
	}
	stage, err := stages.InitStage(stageType)
	if err != nil {
		return nil, err
	}
	newStageValue := reflect.ValueOf(stage).Elem()
	newStageType := reflect.TypeOf(stage).Elem()

	if stageName := stageMap["name"]; stageName != nil {
		stage.SetStageName(stageMap["name"].(string))
	} else if stageName := stageMap["stage_name"]; stageName != nil {
		log.Warn("found property \"stage_name\"")
		log.Warn("property \"stage_name\" is deprecated. please use \"stage\" instead.")
		stage.SetStageName(stageMap["stage_name"].(string))
	}

	stageOpts := stages.NewStageOpts()

	if reportingFullOutput := stageMap["report_full_output"]; reportingFullOutput != nil {
		stageOpts.ReportingFullOutput = true
	}

	stage.SetStageOpts(*stageOpts)

	for i := 0; i < newStageType.NumField(); i++ {
		tagName := newStageType.Field(i).Tag.Get("config")
		is_replace := newStageType.Field(i).Tag.Get("is_replace")
		for stageOptKey, stageOptVal := range stageMap {
			if tagName == stageOptKey {
				if stageOptVal == nil {
					log.Warnf("stage option \"%s\" is not specified", stageOptKey)
				} else {
					self.setFieldVal(newStageValue.Field(i), stageOptVal, is_replace)
				}
			}
		}
	}

	parallelStages := stageMap["parallel"]
	if parallelStages == nil {
		if parallelStages = stageMap["run_after"]; parallelStages != nil {
			log.Warn("`run_after' will be obsoleted in near future. Use `parallel' instead.")
		}
	}

	if parallelStages != nil {
		for _, parallelStages := range parallelStages.([]interface{}) {
			childStage, err := self.mapStage(parallelStages.(map[interface{}]interface{}))
			if err != nil {
				return nil, err
			}
			stage.AddChildStage(childStage)
		}
	}
	return stage, nil
}

func (self *Parser) setFieldVal(fieldVal reflect.Value, stageOptVal interface{}, is_replace string) {
	if fieldVal.Type() == reflect.ValueOf("string").Type() {
		if is_replace == "true" {
			fieldVal.SetString(self.EnvVariables.Replace(stageOptVal.(string)))
		} else {
			fieldVal.SetString(stageOptVal.(string))
		}
	}
}

func getStageTypeModuleName(stageType string) string {
	return strings.ToLower(stageType)
}
<|endoftext|>


<commit_before>package apns

import (
	"bytes"
	"crypto"
	"crypto/ecdsa"
	"crypto/rand"
	"crypto/x509"
	"encoding/asn1"
	"encoding/base64"
	"encoding/json"
	"encoding/pem"
	"io"
	"io/ioutil"
	"math/big"
	"time"
)

// https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CommunicatingwithAPNs.html#//apple_ref/doc/uid/TP40008194-CH11-SW1

type jwtHeader struct {
	Alg string `json:"alg"`
	Kid string `json:"kid"`
}

type jwtClaim struct {
	Iss string `json:"iss"`
	Iat int64  `json:"iat"`
}

type ecdsaSignature struct {
	R, S *big.Int
}

func CreateJWT(keyFile string, kid string, teamID string, now time.Time) (string, error) {

	var b bytes.Buffer

	header := jwtHeader{
		Alg: "ES256",
		Kid: kid,
	}
	headerJSON, err := json.Marshal(&header)
	if err != nil {
		return "", err
	}
	if err := writeAsBase64(&b, headerJSON); err != nil {
		return "", err
	}
	b.WriteString(".")

	claim := jwtClaim{
		Iss: teamID,
		Iat: now.Unix(),
	}
	claimJSON, err := json.Marshal(&claim)
	if err != nil {
		return "", err
	}
	if err := writeAsBase64(&b, claimJSON); err != nil {
		return "", err
	}

	sig, err := createSignature(b.Bytes(), keyFile)
	if err != nil {
		return "", err
	}
	b.WriteString(".")

	if err := writeAsBase64(&b, sig); err != nil {
		return "", err
	}

	return b.String(), nil
}

func writeAsBase64(w io.Writer, byt []byte) error {
	enc := base64.NewEncoder(base64.RawURLEncoding, w)
	defer enc.Close()

	if _, err := enc.Write(byt); err != nil {
		return err
	}
	return nil
}

func createSignature(payload []byte, keyFile string) ([]byte, error) {
	h := crypto.SHA256.New()
	if _, err := h.Write(payload); err != nil {
		return nil, err
	}
	msg := h.Sum(nil)

	data, err := ioutil.ReadFile(keyFile)
	if err != nil {
		return nil, err
	}
	block, _ := pem.Decode(data)
	key, err := x509.ParsePKCS8PrivateKey(block.Bytes)
	if err != nil {
		return nil, err
	}

	r, s, err := ecdsa.Sign(rand.Reader, key.(*ecdsa.PrivateKey), msg)
	if err != nil {
		return nil, err
	}

	sig, err := asn1.Marshal(ecdsaSignature{r, s})
	if err != nil {
		return nil, err
	}

	return sig, nil
}
<commit_msg>grow bytes.Buffer and use WriteByte<commit_after>package apns

import (
	"bytes"
	"crypto"
	"crypto/ecdsa"
	"crypto/rand"
	"crypto/x509"
	"encoding/asn1"
	"encoding/base64"
	"encoding/json"
	"encoding/pem"
	"io"
	"io/ioutil"
	"math/big"
	"time"
)

// https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CommunicatingwithAPNs.html#//apple_ref/doc/uid/TP40008194-CH11-SW1

const jwtDefaultGrowSize = 256

type jwtHeader struct {
	Alg string `json:"alg"`
	Kid string `json:"kid"`
}

type jwtClaim struct {
	Iss string `json:"iss"`
	Iat int64  `json:"iat"`
}

type ecdsaSignature struct {
	R, S *big.Int
}

func CreateJWT(keyFile string, kid string, teamID string, now time.Time) (string, error) {
	var b bytes.Buffer
	b.Grow(jwtDefaultGrowSize)

	header := jwtHeader{
		Alg: "ES256",
		Kid: kid,
	}
	headerJSON, err := json.Marshal(&header)
	if err != nil {
		return "", err
	}
	if err := writeAsBase64(&b, headerJSON); err != nil {
		return "", err
	}
	b.WriteByte(byte('.'))

	claim := jwtClaim{
		Iss: teamID,
		Iat: now.Unix(),
	}
	claimJSON, err := json.Marshal(&claim)
	if err != nil {
		return "", err
	}
	if err := writeAsBase64(&b, claimJSON); err != nil {
		return "", err
	}

	sig, err := createSignature(b.Bytes(), keyFile)
	if err != nil {
		return "", err
	}
	b.WriteByte(byte('.'))

	if err := writeAsBase64(&b, sig); err != nil {
		return "", err
	}

	return b.String(), nil
}

func writeAsBase64(w io.Writer, byt []byte) error {
	enc := base64.NewEncoder(base64.RawURLEncoding, w)
	defer enc.Close()

	if _, err := enc.Write(byt); err != nil {
		return err
	}
	return nil
}

func createSignature(payload []byte, keyFile string) ([]byte, error) {
	h := crypto.SHA256.New()
	if _, err := h.Write(payload); err != nil {
		return nil, err
	}
	msg := h.Sum(nil)

	data, err := ioutil.ReadFile(keyFile)
	if err != nil {
		return nil, err
	}
	block, _ := pem.Decode(data)
	key, err := x509.ParsePKCS8PrivateKey(block.Bytes)
	if err != nil {
		return nil, err
	}

	r, s, err := ecdsa.Sign(rand.Reader, key.(*ecdsa.PrivateKey), msg)
	if err != nil {
		return nil, err
	}

	sig, err := asn1.Marshal(ecdsaSignature{r, s})
	if err != nil {
		return nil, err
	}

	return sig, nil
}
<|endoftext|>


<commit_before>/*
 * Copyright ©1998-2022 by Richard A. Wilkes. All rights reserved.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, version 2.0. If a copy of the MPL was not distributed with
 * this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This Source Code Form is "Incompatible With Secondary Licenses", as
 * defined by the Mozilla Public License, version 2.0.
 */

package about

import (
	_ "embed"
	"fmt"

	"github.com/richardwilkes/gcs/v5/setup/trampolines"
	"github.com/richardwilkes/toolbox/cmdline"
	"github.com/richardwilkes/toolbox/errs"
	"github.com/richardwilkes/toolbox/i18n"
	"github.com/richardwilkes/toolbox/log/jot"
	"github.com/richardwilkes/toolbox/xmath"
	"github.com/richardwilkes/unison"
)

var (
	//go:embed "about-1200x820.png"
	aboutImageData []byte
	aboutWnd       = &aboutWindow{}
)

type aboutWindow struct {
	*unison.Window
	img *unison.Image
}

// Show the about box.
func Show(_ unison.MenuItem) {
	if aboutWnd.Window == nil {
		if err := aboutWnd.prepare(); err != nil {
			jot.Error(err)
			return
		}
	}
	aboutWnd.ToFront()
}

func (w *aboutWindow) prepare() error {
	var err error
	if w.img == nil {
		if w.img, err = unison.NewImageFromBytes(aboutImageData, 0.5); err != nil {
			return errs.NewWithCause("unable to load about image", err)
		}
	}
	if w.Window, err = unison.NewWindow(fmt.Sprintf(i18n.Text("About %s"), cmdline.AppName),
		unison.NotResizableWindowOption()); err != nil {
		return errs.NewWithCause("unable to create about window", err)
	}
	trampolines.CallMenuSetup(w.Window)
	content := w.Content()
	content.SetSizer(func(hint unison.Size) (min, pref, max unison.Size) {
		pref = w.img.LogicalSize()
		return pref, pref, pref
	})
	content.SetLayout(nil)
	content.DrawCallback = w.drawContentBackground
	w.Pack()
	r := w.ContentRect()
	usable := unison.PrimaryDisplay().Usable
	r.X = usable.X + (usable.Width-r.Width)/2
	r.Y = usable.Y + (usable.Height-r.Height)/2
	r.Point.Align()
	w.SetContentRect(r)
	return nil
}

func (w *aboutWindow) drawContentBackground(gc *unison.Canvas, _ unison.Rect) {
	r := w.Content().ContentRect(true)
	gc.DrawImageInRect(w.img, r, nil, nil)
	gc.DrawRect(r, unison.NewEvenlySpacedGradient(unison.Point{Y: 0.25}, unison.Point{Y: 1}, 0, 0,
		unison.Transparent, unison.Black).Paint(gc, r, unison.Fill))

	face := unison.MatchFontFace(unison.DefaultSystemFamilyName, unison.NormalFontWeight, unison.StandardSpacing, unison.NoSlant)
	boldFace := unison.MatchFontFace(unison.DefaultSystemFamilyName, unison.BlackFontWeight, unison.StandardSpacing, unison.NoSlant)
	paint := unison.Gray.Paint(gc, unison.Rect{}, unison.Fill)
	dec := &unison.TextDecoration{
		Font:  face.Font(7),
		Paint: paint,
	}
	text := unison.NewText(i18n.Text("This product includes copyrighted material from the "), dec)
	text.AddString("GURPS", &unison.TextDecoration{
		Font:  boldFace.Font(7),
		Paint: paint,
	})
	text.AddString(i18n.Text(" game, which is used by permission of Steve Jackson Games."), dec)
	y := r.Height - 10
	text.Draw(gc, (r.Width-text.Width())/2, y)
	y -= text.Height()

	font := face.Font(8)
	dec = &unison.TextDecoration{
		Font:  font,
		Paint: paint,
	}
	text = unison.NewText("GURPS", &unison.TextDecoration{
		Font:  boldFace.Font(8),
		Paint: paint,
	})
	text.AddString(i18n.Text(" is a trademark of Steve Jackson Games, used by permission. All rights reserved."), dec)
	text.Draw(gc, (r.Width-text.Width())/2, y)
	lineHeight := text.Height()
	y -= lineHeight * 1.5

	paint = unison.RGB(204, 204, 204).Paint(gc, unison.Rect{}, unison.Fill)
	text = unison.NewText(cmdline.Copyright(), &unison.TextDecoration{
		Font:  font,
		Paint: paint,
	})
	text.Draw(gc, (r.Width-text.Width())/2, y)

	buildText := unison.NewText(i18n.Text("Build ")+cmdline.BuildNumber, &unison.TextDecoration{
		Font:  font,
		Paint: paint,
	})
	var t string
	if cmdline.AppVersion != "" && cmdline.AppVersion != "0.0" {
		t = i18n.Text("Version ") + cmdline.AppVersion
	} else {
		t = i18n.Text("Development")
	}
	versionText := unison.NewText(t, &unison.TextDecoration{
		Font: unison.MatchFontFace(unison.DefaultSystemFamilyName, unison.BlackFontWeight,
			unison.StandardSpacing, unison.NoSlant).Font(10),
		Paint: unison.White.Paint(gc, unison.Rect{}, unison.Fill),
	})

	const (
		hMargin = 8
		vMargin = 4
	)
	var backing unison.Rect
	backing.Width = xmath.Max(versionText.Width(), buildText.Width()) + hMargin*2
	backing.Height = versionText.Height() + buildText.Height() + vMargin*2
	backing.X = (r.Width - backing.Width) / 2
	backing.Y = 65
	gc.DrawRoundedRect(backing, 8, 8, unison.Black.SetAlphaIntensity(0.7).Paint(gc, backing, unison.Fill))
	p := unison.Black.Paint(gc, backing, unison.Stroke)
	p.SetStrokeWidth(2)
	gc.DrawRoundedRect(backing, 8, 8, p)

	versionText.Draw(gc, (r.Width-versionText.Width())/2, backing.Y+vMargin+versionText.Baseline())
	buildText.Draw(gc, (r.Width-buildText.Width())/2, backing.Y+vMargin+versionText.Height()+buildText.Baseline())
}
<commit_msg>Fix inability to open the About box more than once<commit_after>/*
 * Copyright ©1998-2022 by Richard A. Wilkes. All rights reserved.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, version 2.0. If a copy of the MPL was not distributed with
 * this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This Source Code Form is "Incompatible With Secondary Licenses", as
 * defined by the Mozilla Public License, version 2.0.
 */

package about

import (
	_ "embed"
	"fmt"

	"github.com/richardwilkes/gcs/v5/setup/trampolines"
	"github.com/richardwilkes/toolbox/cmdline"
	"github.com/richardwilkes/toolbox/errs"
	"github.com/richardwilkes/toolbox/i18n"
	"github.com/richardwilkes/toolbox/log/jot"
	"github.com/richardwilkes/toolbox/xmath"
	"github.com/richardwilkes/unison"
)

var (
	//go:embed "about-1200x820.png"
	aboutImageData []byte
	aboutWnd       = &aboutWindow{}
)

type aboutWindow struct {
	*unison.Window
	img *unison.Image
}

// Show the about box.
func Show(_ unison.MenuItem) {
	if aboutWnd.Window == nil {
		if err := aboutWnd.prepare(); err != nil {
			jot.Error(err)
			return
		}
	}
	aboutWnd.ToFront()
}

func (w *aboutWindow) prepare() error {
	var err error
	if w.img == nil {
		if w.img, err = unison.NewImageFromBytes(aboutImageData, 0.5); err != nil {
			return errs.NewWithCause("unable to load about image", err)
		}
	}
	if w.Window, err = unison.NewWindow(fmt.Sprintf(i18n.Text("About %s"), cmdline.AppName),
		unison.NotResizableWindowOption()); err != nil {
		return errs.NewWithCause("unable to create about window", err)
	}
	trampolines.CallMenuSetup(w.Window)
	content := w.Content()
	content.SetSizer(func(hint unison.Size) (min, pref, max unison.Size) {
		pref = w.img.LogicalSize()
		return pref, pref, pref
	})
	content.SetLayout(nil)
	content.DrawCallback = w.drawContentBackground
	w.WillCloseCallback = func() {
		aboutWnd.Window = nil
	}
	w.Pack()
	r := w.ContentRect()
	usable := unison.PrimaryDisplay().Usable
	r.X = usable.X + (usable.Width-r.Width)/2
	r.Y = usable.Y + (usable.Height-r.Height)/2
	r.Point.Align()
	w.SetContentRect(r)
	return nil
}

func (w *aboutWindow) drawContentBackground(gc *unison.Canvas, _ unison.Rect) {
	r := w.Content().ContentRect(true)
	gc.DrawImageInRect(w.img, r, nil, nil)
	gc.DrawRect(r, unison.NewEvenlySpacedGradient(unison.Point{Y: 0.25}, unison.Point{Y: 1}, 0, 0,
		unison.Transparent, unison.Black).Paint(gc, r, unison.Fill))

	face := unison.MatchFontFace(unison.DefaultSystemFamilyName, unison.NormalFontWeight, unison.StandardSpacing, unison.NoSlant)
	boldFace := unison.MatchFontFace(unison.DefaultSystemFamilyName, unison.BlackFontWeight, unison.StandardSpacing, unison.NoSlant)
	paint := unison.Gray.Paint(gc, unison.Rect{}, unison.Fill)
	dec := &unison.TextDecoration{
		Font:  face.Font(7),
		Paint: paint,
	}
	text := unison.NewText(i18n.Text("This product includes copyrighted material from the "), dec)
	text.AddString("GURPS", &unison.TextDecoration{
		Font:  boldFace.Font(7),
		Paint: paint,
	})
	text.AddString(i18n.Text(" game, which is used by permission of Steve Jackson Games."), dec)
	y := r.Height - 10
	text.Draw(gc, (r.Width-text.Width())/2, y)
	y -= text.Height()

	font := face.Font(8)
	dec = &unison.TextDecoration{
		Font:  font,
		Paint: paint,
	}
	text = unison.NewText("GURPS", &unison.TextDecoration{
		Font:  boldFace.Font(8),
		Paint: paint,
	})
	text.AddString(i18n.Text(" is a trademark of Steve Jackson Games, used by permission. All rights reserved."), dec)
	text.Draw(gc, (r.Width-text.Width())/2, y)
	lineHeight := text.Height()
	y -= lineHeight * 1.5

	paint = unison.RGB(204, 204, 204).Paint(gc, unison.Rect{}, unison.Fill)
	text = unison.NewText(cmdline.Copyright(), &unison.TextDecoration{
		Font:  font,
		Paint: paint,
	})
	text.Draw(gc, (r.Width-text.Width())/2, y)

	buildText := unison.NewText(i18n.Text("Build ")+cmdline.BuildNumber, &unison.TextDecoration{
		Font:  font,
		Paint: paint,
	})
	var t string
	if cmdline.AppVersion != "" && cmdline.AppVersion != "0.0" {
		t = i18n.Text("Version ") + cmdline.AppVersion
	} else {
		t = i18n.Text("Development")
	}
	versionText := unison.NewText(t, &unison.TextDecoration{
		Font: unison.MatchFontFace(unison.DefaultSystemFamilyName, unison.BlackFontWeight,
			unison.StandardSpacing, unison.NoSlant).Font(10),
		Paint: unison.White.Paint(gc, unison.Rect{}, unison.Fill),
	})

	const (
		hMargin = 8
		vMargin = 4
	)
	var backing unison.Rect
	backing.Width = xmath.Max(versionText.Width(), buildText.Width()) + hMargin*2
	backing.Height = versionText.Height() + buildText.Height() + vMargin*2
	backing.X = (r.Width - backing.Width) / 2
	backing.Y = 65
	gc.DrawRoundedRect(backing, 8, 8, unison.Black.SetAlphaIntensity(0.7).Paint(gc, backing, unison.Fill))
	p := unison.Black.Paint(gc, backing, unison.Stroke)
	p.SetStrokeWidth(2)
	gc.DrawRoundedRect(backing, 8, 8, p)

	versionText.Draw(gc, (r.Width-versionText.Width())/2, backing.Y+vMargin+versionText.Baseline())
	buildText.Draw(gc, (r.Width-buildText.Width())/2, backing.Y+vMargin+versionText.Height()+buildText.Baseline())
}
<|endoftext|>


<commit_before>package app

import "github.com/revel/revel"

func init() {
	// Filters is the default set of global filters.
	revel.Filters = []revel.Filter{
		SecureOriginProdFilter,        // Enforce access only via TLS/SSL in production mode
		revel.PanicFilter,             // Recover from panics and display an error page instead.
		revel.RouterFilter,            // Use the routing table to select the right Action
		revel.FilterConfiguringFilter, // A hook for adding or removing per-Action filters.
		revel.ParamsFilter,            // Parse parameters into Controller.Params.
		revel.SessionFilter,           // Restore and write the session cookie.
		revel.FlashFilter,             // Restore and write the flash cookie.
		revel.ValidationFilter,        // Restore kept validation errors and save new ones from cookie.
		revel.I18nFilter,              // Resolve the requested language
		HeaderFilter,                  // Add some security based headers
		revel.InterceptorFilter,       // Run interceptors around the action.
		revel.CompressFilter,          // Compress the result.
		revel.ActionInvoker,           // Invoke the action.
	}
}

var SecureOriginProdFilter = func(c *revel.Controller, fc []revel.Filter) {
	// Reject the request if is not served on a non-HTTPS origin.
	//
	// This is *important* because BaseApp deals with usernames and passwords
	// that could be man-in-the-middled without proper transport-level security
	if revel.RunMode == "prod" && c.Request.TLS == nil {
		c.Response.Out.WriteHeader(500)
		c.Response.Out.Write([]byte("BaseApp must be deployed to production on a secure HTTP origin!"))
		return
	}

	fc[0](c, fc[1:]) // Execute the next filter stage.
}

var HeaderFilter = func(c *revel.Controller, fc []revel.Filter) {
	// Add some common security headers
	c.Response.Out.Header().Add("X-Frame-Options", "SAMEORIGIN")
	c.Response.Out.Header().Add("X-XSS-Protection", "1; mode=block")
	c.Response.Out.Header().Add("X-Content-Type-Options", "nosniff")

	fc[0](c, fc[1:]) // Execute the next filter stage.
}
<commit_msg>Remove mandatory SSL requirement from production since it makes it too hard to test<commit_after>package app

import "github.com/revel/revel"

func init() {
	// Filters is the default set of global filters.
	revel.Filters = []revel.Filter{
		revel.PanicFilter,             // Recover from panics and display an error page instead.
		revel.RouterFilter,            // Use the routing table to select the right Action
		revel.FilterConfiguringFilter, // A hook for adding or removing per-Action filters.
		revel.ParamsFilter,            // Parse parameters into Controller.Params.
		revel.SessionFilter,           // Restore and write the session cookie.
		revel.FlashFilter,             // Restore and write the flash cookie.
		revel.ValidationFilter,        // Restore kept validation errors and save new ones from cookie.
		revel.I18nFilter,              // Resolve the requested language
		HeaderFilter,                  // Add some security based headers
		revel.InterceptorFilter,       // Run interceptors around the action.
		revel.CompressFilter,          // Compress the result.
		revel.ActionInvoker,           // Invoke the action.
	}
}

var HeaderFilter = func(c *revel.Controller, fc []revel.Filter) {
	// Add some common security headers
	c.Response.Out.Header().Add("X-Frame-Options", "SAMEORIGIN")
	c.Response.Out.Header().Add("X-XSS-Protection", "1; mode=block")
	c.Response.Out.Header().Add("X-Content-Type-Options", "nosniff")

	fc[0](c, fc[1:]) // Execute the next filter stage.
}
<|endoftext|>


<commit_before>package main

import (
	"./content"
	"./db"
	"fmt"
	"github.com/ChimeraCoder/anaconda"
	"github.com/jsgoecke/go-wit"
	"github.com/robfig/cron"
	"math/rand"
	"time"
)

var api *anaconda.TwitterApi
var witclient *wit.Client

func main() {
	// Init Twitter API
	anaconda.SetConsumerKey(CONSUMER_KEY)
	anaconda.SetConsumerSecret(CONSUMER_SECRET)
	api = anaconda.NewTwitterApi(TOKEN, TOKEN_SECRET)

	// Init DB
	database, err := db.Init(MYSQL_USER, MYSQL_PASSWORD, MYSQL_SCHEMA)
	if err != nil {
		panic(err.Error())
	}

	defer database.Close()

	// Init Content
	content.Init(HASHTAGS, T_CO_URL_LENGTH)

	for _, kimonoDataSourcesUrl := range KIMONO_DATA_SOURCES {
		content.RegisterAPI(content.KimonoContent{Url: kimonoDataSourcesUrl})
	}

	// Init WIT api
	witclient = wit.NewClient(WIT_ACCESS_TOKEN)

	// Init cron
	c := cron.New()
	c.AddFunc(ACTIONS_INTERVAL, bot)
	c.Start()

	// Init random
	rand.Seed(time.Now().UnixNano())

	fmt.Println("Hello world")

	bot()

	select {} // block forever
}

func bot() {
	fmt.Println("----------- Waking up!")

	hour := time.Now().Hour()
	if hour >= WAKE_UP_HOUR || hour < GO_TO_BED_HOUR {
		performDailyAction()
	} else {
		performNightlyAction()
	}

	fmt.Println("----------- Goes to sleep")
}
<commit_msg>Fix nightly actions not being triggered on certain config<commit_after>package main

import (
	"./content"
	"./db"
	"fmt"
	"github.com/ChimeraCoder/anaconda"
	"github.com/jsgoecke/go-wit"
	"github.com/robfig/cron"
	"math/rand"
	"time"
)

var api *anaconda.TwitterApi
var witclient *wit.Client

func main() {
	// Init Twitter API
	anaconda.SetConsumerKey(CONSUMER_KEY)
	anaconda.SetConsumerSecret(CONSUMER_SECRET)
	api = anaconda.NewTwitterApi(TOKEN, TOKEN_SECRET)

	// Init DB
	database, err := db.Init(MYSQL_USER, MYSQL_PASSWORD, MYSQL_SCHEMA)
	if err != nil {
		panic(err.Error())
	}

	defer database.Close()

	// Init Content
	content.Init(HASHTAGS, T_CO_URL_LENGTH)

	for _, kimonoDataSourcesUrl := range KIMONO_DATA_SOURCES {
		content.RegisterAPI(content.KimonoContent{Url: kimonoDataSourcesUrl})
	}

	// Init WIT api
	witclient = wit.NewClient(WIT_ACCESS_TOKEN)

	// Init cron
	c := cron.New()
	c.AddFunc(ACTIONS_INTERVAL, bot)
	c.Start()

	// Init random
	rand.Seed(time.Now().UnixNano())

	fmt.Println("Hello world")

	bot()

	select {} // block forever
}

func bot() {
	fmt.Println("----------- Waking up!")

	hour := time.Now().Hour()

	if GO_TO_BED_HOUR < WAKE_UP_HOUR {
		if hour >= WAKE_UP_HOUR || hour < GO_TO_BED_HOUR {
			performDailyAction()
		} else {
			performNightlyAction()
		}
	} else {
		if hour >= WAKE_UP_HOUR && hour < GO_TO_BED_HOUR {
			performDailyAction()
		} else {
			performNightlyAction()
		}
	}

	fmt.Println("----------- Goes to sleep")
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/wfleming/go-timecard/timecard"
	"os"
	"sort"
	"time"
)

const (
	csvDate   = "2006-01-02"
	humanDate = "Monday, 02 January 2006"
)

func runSummary(config *appConfig, args []string) {
	if len(args) > 0 && args[0] != "--csv" {
		printSummaryHelp()
		return
	}

	var entries, err = config.log.AllEntries()

	if err != nil {
		fmt.Printf("Error parsing entries: %s\n", err)
		os.Exit(1)
	}

	if len(entries) > 0 && entries[len(entries)-1].TimeOut.IsZero() {
		// exclude final entry if it has not been checked out
		entries = entries[:len(entries)]
	}

	exitIfNoEntries(entries)

	summary := timecard.NewSummary(entries)
	daySummaries := summary.GetSummaries()

	if len(args) > 0 && args[0] == "--csv" {
		printSummariesCsv(daySummaries)
	} else {
		printSummariesStd(daySummaries)
	}
}

func exitIfNoEntries(entries []*timecard.Entry) {
	if len(entries) == 0 {
		fmt.Println("No entries to summarize.")
		os.Exit(0)
	}
}

// do the standard printing of the summary data
func printSummariesStd(summaries []timecard.DaySummary) {
	for _, daySummary := range summaries {
		fmt.Println(daySummary.Date.Format(humanDate))

		for _, projHours := range daySummary.Hours {
			fmt.Printf("\t%s: %.2f\n", projHours.Project, projHours.Hours)
		}
		fmt.Println("")
	}
}

// printing the summary data as CSV
func printSummariesCsv(summaries []timecard.DaySummary) {
	var allProjects = make([]string, 0)

	indexStr := func(arr []string, needle string) int {
		for idx, str := range arr {
			if str == needle {
				return idx
			}
		}
		return -1
	}

	hoursForProjDate := func(project string, date time.Time) float64 {
		for _, daySummary := range summaries {
			if !daySummary.Date.Equal(date) {
				continue
			}
			for _, projHours := range daySummary.Hours {
				if projHours.Project == project {
					return projHours.Hours
				}
			}
		}
		return 0
	}

	// iterate once to get all project names
	for _, daySummary := range summaries {
		for _, projHours := range daySummary.Hours {
			if indexStr(allProjects, projHours.Project) < 0 {
				allProjects = append(allProjects, projHours.Project)
			}
		}
	}

	sort.Strings(allProjects)

	//////// print the CSV data ///////
	// first line is just dates
	fmt.Print("Project,")
	for idx, daySummary := range summaries {
		var comma = ""
		if idx < (len(summaries) - 1) {
			comma = ","
		}
		fmt.Printf("%s%s",
			daySummary.Date.Format(csvDate), comma)
	}
	fmt.Print("\n")
	// now print a row for each project
	for _, project := range allProjects {
		fmt.Printf("%s,", project)
		for idx, daySummary := range summaries {
			var comma = ""
			if idx < (len(summaries) - 1) {
				comma = ","
			}
			hours := hoursForProjDate(project, daySummary.Date)
			fmt.Printf("%.2f%s", hours, comma)
		}
		fmt.Print("\n")
	}
}

func printSummaryHelp() {
	fmt.Println("usage: punch summary [--csv]")
}
<commit_msg>summary: fix dropping of open entries<commit_after>package main

import (
	"fmt"
	"github.com/wfleming/go-timecard/timecard"
	"os"
	"sort"
	"time"
)

const (
	csvDate   = "2006-01-02"
	humanDate = "Monday, 02 January 2006"
)

func runSummary(config *appConfig, args []string) {
	if len(args) > 0 && args[0] != "--csv" {
		printSummaryHelp()
		return
	}

	var entries, err = config.log.AllEntries()

	if err != nil {
		fmt.Printf("Error parsing entries: %s\n", err)
		os.Exit(1)
	}

	if len(entries) > 0 && entries[len(entries)-1].TimeOut.IsZero() {
		// exclude final entry if it has not been checked out
		entries = entries[:(len(entries) - 1)]
	}

	exitIfNoEntries(entries)

	summary := timecard.NewSummary(entries)
	daySummaries := summary.GetSummaries()

	if len(args) > 0 && args[0] == "--csv" {
		printSummariesCsv(daySummaries)
	} else {
		printSummariesStd(daySummaries)
	}
}

func exitIfNoEntries(entries []*timecard.Entry) {
	if len(entries) == 0 {
		fmt.Println("No entries to summarize.")
		os.Exit(0)
	}
}

// do the standard printing of the summary data
func printSummariesStd(summaries []timecard.DaySummary) {
	for _, daySummary := range summaries {
		fmt.Println(daySummary.Date.Format(humanDate))

		for _, projHours := range daySummary.Hours {
			fmt.Printf("\t%s: %.2f\n", projHours.Project, projHours.Hours)
		}
		fmt.Println("")
	}
}

// printing the summary data as CSV
func printSummariesCsv(summaries []timecard.DaySummary) {
	var allProjects = make([]string, 0)

	indexStr := func(arr []string, needle string) int {
		for idx, str := range arr {
			if str == needle {
				return idx
			}
		}
		return -1
	}

	hoursForProjDate := func(project string, date time.Time) float64 {
		for _, daySummary := range summaries {
			if !daySummary.Date.Equal(date) {
				continue
			}
			for _, projHours := range daySummary.Hours {
				if projHours.Project == project {
					return projHours.Hours
				}
			}
		}
		return 0
	}

	// iterate once to get all project names
	for _, daySummary := range summaries {
		for _, projHours := range daySummary.Hours {
			if indexStr(allProjects, projHours.Project) < 0 {
				allProjects = append(allProjects, projHours.Project)
			}
		}
	}

	sort.Strings(allProjects)

	//////// print the CSV data ///////
	// first line is just dates
	fmt.Print("Project,")
	for idx, daySummary := range summaries {
		var comma = ""
		if idx < (len(summaries) - 1) {
			comma = ","
		}
		fmt.Printf("%s%s",
			daySummary.Date.Format(csvDate), comma)
	}
	fmt.Print("\n")
	// now print a row for each project
	for _, project := range allProjects {
		fmt.Printf("%s,", project)
		for idx, daySummary := range summaries {
			var comma = ""
			if idx < (len(summaries) - 1) {
				comma = ","
			}
			hours := hoursForProjDate(project, daySummary.Date)
			fmt.Printf("%.2f%s", hours, comma)
		}
		fmt.Print("\n")
	}
}

func printSummaryHelp() {
	fmt.Println("usage: punch summary [--csv]")
}
<|endoftext|>


<commit_before>package cairo

// #cgo pkg-config: cairo cairo-gobject
// #include <stdlib.h>
// #include <cairo.h>
// #include <cairo-gobject.h>
import "C"

import (
	"runtime"
	"unsafe"
)

// TODO(jrick) SetUserData (depends on UserDataKey and DestroyFunc)

// TODO(jrick) GetUserData (depends on UserDataKey)

/*
 * cairo_surface_t
 */

// Surface is a representation of Cairo's cairo_surface_t.
type Surface struct {
	surface *C.cairo_surface_t
}

func NewSurfaceFromPNG(fileName string) (*Surface, error) {

	cstr := C.CString(fileName)
	defer C.free(unsafe.Pointer(cstr))

	surfaceNative := C.cairo_image_surface_create_from_png(cstr)

	status := Status(C.cairo_surface_status(surfaceNative))
	if status != STATUS_SUCCESS {
		return nil, ErrorStatus(status)
	}

	return &Surface{surfaceNative}, nil
}

// CreateImageSurface is a wrapper around cairo_image_surface_create().
func CreateImageSurface(format Format, width, height int) *Surface {
	c := C.cairo_image_surface_create(C.cairo_format_t(format),
		C.int(width), C.int(height))
	s := wrapSurface(c)
	runtime.SetFinalizer(s, (*Surface).destroy)
	return s
}

// native returns a pointer to the underlying cairo_surface_t.
func (v *Surface) native() *C.cairo_surface_t {
	if v == nil {
		return nil
	}
	return v.surface
}

// Native returns a pointer to the underlying cairo_surface_t.
func (v *Surface) Native() uintptr {
	return uintptr(unsafe.Pointer(v.native()))
}

func marshalSurface(p uintptr) (interface{}, error) {
	c := C.g_value_get_boxed((*C.GValue)(unsafe.Pointer(p)))
	surface := (*C.cairo_surface_t)(unsafe.Pointer(c))
	return wrapSurface(surface), nil
}

func wrapSurface(surface *C.cairo_surface_t) *Surface {
	return &Surface{surface}
}

// NewSurface creates a gotk3 cairo Surface from a pointer to a
// C cairo_surface_t.  This is primarily designed for use with other
// gotk3 packages and should be avoided by applications.
func NewSurface(s uintptr, needsRef bool) *Surface {
	ptr := (*C.cairo_surface_t)(unsafe.Pointer(s))
	surface := wrapSurface(ptr)
	if needsRef {
		surface.reference()
	}
	runtime.SetFinalizer(surface, (*Surface).destroy)
	return surface
}

// CreateSimilar is a wrapper around cairo_surface_create_similar().
func (v *Surface) CreateSimilar(content Content, width, height int) *Surface {
	c := C.cairo_surface_create_similar(v.native(),
		C.cairo_content_t(content), C.int(width), C.int(height))
	s := wrapSurface(c)
	runtime.SetFinalizer(s, (*Surface).destroy)
	return s
}

// TODO cairo_surface_create_similar_image (since 1.12)

// CreateForRectangle is a wrapper around cairo_surface_create_for_rectangle().
func (v *Surface) CreateForRectangle(x, y, width, height float64) *Surface {
	c := C.cairo_surface_create_for_rectangle(v.native(), C.double(x),
		C.double(y), C.double(width), C.double(height))
	s := wrapSurface(c)
	runtime.SetFinalizer(s, (*Surface).destroy)
	return s
}

// reference is a wrapper around cairo_surface_reference().
func (v *Surface) reference() {
	v.surface = C.cairo_surface_reference(v.native())
}

// destroy is a wrapper around cairo_surface_destroy().
func (v *Surface) destroy() {
	C.cairo_surface_destroy(v.native())
}

// Status is a wrapper around cairo_surface_status().
func (v *Surface) Status() Status {
	c := C.cairo_surface_status(v.native())
	return Status(c)
}

// Flush is a wrapper around cairo_surface_flush().
func (v *Surface) Flush() {
	C.cairo_surface_flush(v.native())
}

// TODO(jrick) GetDevice (requires Device bindings)

// TODO(jrick) GetFontOptions (require FontOptions bindings)

// TODO(jrick) GetContent (requires Content bindings)

// MarkDirty is a wrapper around cairo_surface_mark_dirty().
func (v *Surface) MarkDirty() {
	C.cairo_surface_mark_dirty(v.native())
}

// MarkDirtyRectangle is a wrapper around cairo_surface_mark_dirty_rectangle().
func (v *Surface) MarkDirtyRectangle(x, y, width, height int) {
	C.cairo_surface_mark_dirty_rectangle(v.native(), C.int(x), C.int(y),
		C.int(width), C.int(height))
}

// SetDeviceOffset is a wrapper around cairo_surface_set_device_offset().
func (v *Surface) SetDeviceOffset(x, y float64) {
	C.cairo_surface_set_device_offset(v.native(), C.double(x), C.double(y))
}

// GetDeviceOffset is a wrapper around cairo_surface_get_device_offset().
func (v *Surface) GetDeviceOffset() (x, y float64) {
	var xOffset, yOffset C.double
	C.cairo_surface_get_device_offset(v.native(), &xOffset, &yOffset)
	return float64(xOffset), float64(yOffset)
}

// SetFallbackResolution is a wrapper around
// cairo_surface_set_fallback_resolution().
func (v *Surface) SetFallbackResolution(xPPI, yPPI float64) {
	C.cairo_surface_set_fallback_resolution(v.native(), C.double(xPPI),
		C.double(yPPI))
}

// GetFallbackResolution is a wrapper around
// cairo_surface_get_fallback_resolution().
func (v *Surface) GetFallbackResolution() (xPPI, yPPI float64) {
	var x, y C.double
	C.cairo_surface_get_fallback_resolution(v.native(), &x, &y)
	return float64(x), float64(y)
}

// GetType is a wrapper around cairo_surface_get_type().
func (v *Surface) GetType() SurfaceType {
	c := C.cairo_surface_get_type(v.native())
	return SurfaceType(c)
}

// TODO(jrick) SetUserData (depends on UserDataKey and DestroyFunc)

// TODO(jrick) GetUserData (depends on UserDataKey)

// CopyPage is a wrapper around cairo_surface_copy_page().
func (v *Surface) CopyPage() {
	C.cairo_surface_copy_page(v.native())
}

// ShowPage is a wrapper around cairo_surface_show_page().
func (v *Surface) ShowPage() {
	C.cairo_surface_show_page(v.native())
}

// HasShowTextGlyphs is a wrapper around cairo_surface_has_show_text_glyphs().
func (v *Surface) HasShowTextGlyphs() bool {
	c := C.cairo_surface_has_show_text_glyphs(v.native())
	return gobool(c)
}

// TODO(jrick) SetMimeData (depends on DestroyFunc)

// GetMimeData is a wrapper around cairo_surface_get_mime_data().  The
// returned mimetype data is returned as a Go byte slice.
func (v *Surface) GetMimeData(mimeType MimeType) []byte {
	cstr := C.CString(string(mimeType))
	defer C.free(unsafe.Pointer(cstr))
	var data *C.uchar
	var length C.ulong
	C.cairo_surface_get_mime_data(v.native(), cstr, &data, &length)
	return C.GoBytes(unsafe.Pointer(data), C.int(length))
}

// TODO(jrick) SupportsMimeType (since 1.12)

// TODO(jrick) MapToImage (since 1.12)

// TODO(jrick) UnmapImage (since 1.12)
<commit_msg>Add a wrapper around cairo_surface_write_to_png.<commit_after>package cairo

// #cgo pkg-config: cairo cairo-gobject
// #include <stdlib.h>
// #include <cairo.h>
// #include <cairo-gobject.h>
import "C"

import (
	"runtime"
	"unsafe"
)

// TODO(jrick) SetUserData (depends on UserDataKey and DestroyFunc)

// TODO(jrick) GetUserData (depends on UserDataKey)

/*
 * cairo_surface_t
 */

// Surface is a representation of Cairo's cairo_surface_t.
type Surface struct {
	surface *C.cairo_surface_t
}

func NewSurfaceFromPNG(fileName string) (*Surface, error) {

	cstr := C.CString(fileName)
	defer C.free(unsafe.Pointer(cstr))

	surfaceNative := C.cairo_image_surface_create_from_png(cstr)

	status := Status(C.cairo_surface_status(surfaceNative))
	if status != STATUS_SUCCESS {
		return nil, ErrorStatus(status)
	}

	return &Surface{surfaceNative}, nil
}

// CreateImageSurface is a wrapper around cairo_image_surface_create().
func CreateImageSurface(format Format, width, height int) *Surface {
	c := C.cairo_image_surface_create(C.cairo_format_t(format),
		C.int(width), C.int(height))
	s := wrapSurface(c)
	runtime.SetFinalizer(s, (*Surface).destroy)
	return s
}

// native returns a pointer to the underlying cairo_surface_t.
func (v *Surface) native() *C.cairo_surface_t {
	if v == nil {
		return nil
	}
	return v.surface
}

// Native returns a pointer to the underlying cairo_surface_t.
func (v *Surface) Native() uintptr {
	return uintptr(unsafe.Pointer(v.native()))
}

func marshalSurface(p uintptr) (interface{}, error) {
	c := C.g_value_get_boxed((*C.GValue)(unsafe.Pointer(p)))
	surface := (*C.cairo_surface_t)(unsafe.Pointer(c))
	return wrapSurface(surface), nil
}

func wrapSurface(surface *C.cairo_surface_t) *Surface {
	return &Surface{surface}
}

// NewSurface creates a gotk3 cairo Surface from a pointer to a
// C cairo_surface_t.  This is primarily designed for use with other
// gotk3 packages and should be avoided by applications.
func NewSurface(s uintptr, needsRef bool) *Surface {
	ptr := (*C.cairo_surface_t)(unsafe.Pointer(s))
	surface := wrapSurface(ptr)
	if needsRef {
		surface.reference()
	}
	runtime.SetFinalizer(surface, (*Surface).destroy)
	return surface
}

// CreateSimilar is a wrapper around cairo_surface_create_similar().
func (v *Surface) CreateSimilar(content Content, width, height int) *Surface {
	c := C.cairo_surface_create_similar(v.native(),
		C.cairo_content_t(content), C.int(width), C.int(height))
	s := wrapSurface(c)
	runtime.SetFinalizer(s, (*Surface).destroy)
	return s
}

// TODO cairo_surface_create_similar_image (since 1.12)

// CreateForRectangle is a wrapper around cairo_surface_create_for_rectangle().
func (v *Surface) CreateForRectangle(x, y, width, height float64) *Surface {
	c := C.cairo_surface_create_for_rectangle(v.native(), C.double(x),
		C.double(y), C.double(width), C.double(height))
	s := wrapSurface(c)
	runtime.SetFinalizer(s, (*Surface).destroy)
	return s
}

// reference is a wrapper around cairo_surface_reference().
func (v *Surface) reference() {
	v.surface = C.cairo_surface_reference(v.native())
}

// destroy is a wrapper around cairo_surface_destroy().
func (v *Surface) destroy() {
	C.cairo_surface_destroy(v.native())
}

// Status is a wrapper around cairo_surface_status().
func (v *Surface) Status() Status {
	c := C.cairo_surface_status(v.native())
	return Status(c)
}

// Flush is a wrapper around cairo_surface_flush().
func (v *Surface) Flush() {
	C.cairo_surface_flush(v.native())
}

// TODO(jrick) GetDevice (requires Device bindings)

// TODO(jrick) GetFontOptions (require FontOptions bindings)

// TODO(jrick) GetContent (requires Content bindings)

// MarkDirty is a wrapper around cairo_surface_mark_dirty().
func (v *Surface) MarkDirty() {
	C.cairo_surface_mark_dirty(v.native())
}

// MarkDirtyRectangle is a wrapper around cairo_surface_mark_dirty_rectangle().
func (v *Surface) MarkDirtyRectangle(x, y, width, height int) {
	C.cairo_surface_mark_dirty_rectangle(v.native(), C.int(x), C.int(y),
		C.int(width), C.int(height))
}

// SetDeviceOffset is a wrapper around cairo_surface_set_device_offset().
func (v *Surface) SetDeviceOffset(x, y float64) {
	C.cairo_surface_set_device_offset(v.native(), C.double(x), C.double(y))
}

// GetDeviceOffset is a wrapper around cairo_surface_get_device_offset().
func (v *Surface) GetDeviceOffset() (x, y float64) {
	var xOffset, yOffset C.double
	C.cairo_surface_get_device_offset(v.native(), &xOffset, &yOffset)
	return float64(xOffset), float64(yOffset)
}

// SetFallbackResolution is a wrapper around
// cairo_surface_set_fallback_resolution().
func (v *Surface) SetFallbackResolution(xPPI, yPPI float64) {
	C.cairo_surface_set_fallback_resolution(v.native(), C.double(xPPI),
		C.double(yPPI))
}

// GetFallbackResolution is a wrapper around
// cairo_surface_get_fallback_resolution().
func (v *Surface) GetFallbackResolution() (xPPI, yPPI float64) {
	var x, y C.double
	C.cairo_surface_get_fallback_resolution(v.native(), &x, &y)
	return float64(x), float64(y)
}

// GetType is a wrapper around cairo_surface_get_type().
func (v *Surface) GetType() SurfaceType {
	c := C.cairo_surface_get_type(v.native())
	return SurfaceType(c)
}

// TODO(jrick) SetUserData (depends on UserDataKey and DestroyFunc)

// TODO(jrick) GetUserData (depends on UserDataKey)

// CopyPage is a wrapper around cairo_surface_copy_page().
func (v *Surface) CopyPage() {
	C.cairo_surface_copy_page(v.native())
}

// ShowPage is a wrapper around cairo_surface_show_page().
func (v *Surface) ShowPage() {
	C.cairo_surface_show_page(v.native())
}

// HasShowTextGlyphs is a wrapper around cairo_surface_has_show_text_glyphs().
func (v *Surface) HasShowTextGlyphs() bool {
	c := C.cairo_surface_has_show_text_glyphs(v.native())
	return gobool(c)
}

// TODO(jrick) SetMimeData (depends on DestroyFunc)

// GetMimeData is a wrapper around cairo_surface_get_mime_data().  The
// returned mimetype data is returned as a Go byte slice.
func (v *Surface) GetMimeData(mimeType MimeType) []byte {
	cstr := C.CString(string(mimeType))
	defer C.free(unsafe.Pointer(cstr))
	var data *C.uchar
	var length C.ulong
	C.cairo_surface_get_mime_data(v.native(), cstr, &data, &length)
	return C.GoBytes(unsafe.Pointer(data), C.int(length))
}

// WriteToPNG is a wrapper around cairo_surface_write_png(). It writes the Cairo
// surface to the given file in PNG format.
func (v *Surface) WriteToPNG(fileName string) error {
	cstr := C.CString(fileName)
	defer C.free(unsafe.Pointer(cstr))

	status := Status(C.cairo_surface_write_to_png(v.surface, cstr))

	if status != STATUS_SUCCESS {
		return ErrorStatus(status)
	}

	return nil
}

// TODO(jrick) SupportsMimeType (since 1.12)

// TODO(jrick) MapToImage (since 1.12)

// TODO(jrick) UnmapImage (since 1.12)
<|endoftext|>


<commit_before>package client

import (
	"errors"
	"fmt"
	"time"

	"strconv"

	"sourcegraph.com/sourcegraph/api_router"
	"sourcegraph.com/sourcegraph/srcgraph/db_common"
	"sourcegraph.com/sourcegraph/srcgraph/repo"
	"sourcegraph.com/sourcegraph/srcgraph/task2"
)

// BuildsService communicates with the build-related endpoints in the
// Sourcegraph API.
type BuildsService interface {
	// Get fetches a build.
	Get(build BuildSpec, opt *BuildGetOptions) (*Build, Response, error)

	// List builds.
	List(opt *BuildListOptions) ([]*Build, Response, error)

	// ListByRepository lists builds for a repository.
	ListByRepository(repo RepositorySpec, opt *BuildListByRepositoryOptions) ([]*Build, Response, error)

	// Create a new build. The build will run asynchronously (Create does not
	// wait for it to return. To monitor the build's status, use Get.)
	Create(repo RepositorySpec, conf BuildConfig) (*Build, Response, error)

	// ListBuildTasks lists the tasks associated with a build.
	ListBuildTasks(build BuildSpec, opt *BuildTaskListOptions) ([]*BuildTask, Response, error)
}

type buildsService struct {
	client *Client
}

var _ BuildsService = &buildsService{}

type BuildSpec struct {
	BID int64
}

func (s *BuildSpec) RouteVars() map[string]string {
	return map[string]string{"BID": fmt.Sprintf("%d", s.BID)}
}

// A Build represents a scheduled, completed, or failed repository analysis and
// import job.
type Build struct {
	BID       int64
	Repo      repo.RID
	CommitID  string             `db:"commit_id"`
	CreatedAt time.Time          `db:"created_at"`
	StartedAt db_common.NullTime `db:"started_at"`
	EndedAt   db_common.NullTime `db:"ended_at"`
	Success   bool
	Failure   bool

	// Host is the hostname of the machine that is working on this build.
	Host string

	BuildConfig

	// RepoURI is populated (as a convenience) in results by Get and List but
	// should not be set when creating builds (it will be ignored).
	RepoURI repo.URI `db:"repo_uri" json:",omitempty"`
}

// IDString returns a succinct string that uniquely identifies this build.
func (b *Build) IDString() string { return buildIDString(b.BID) }

func buildIDString(bid int64) string { return "B" + strconv.FormatInt(bid, 36) }

// LogURL is the URL to the logs for this build.
func (b *Build) LogURL() string {
	return task2.LogURLForTag(b.IDString())
}

// A BuildTask represents an individual step of a build.
type BuildTask struct {
	TID int64

	// BID is the build that this task is a part of.
	BID int64

	UnitType string
	Unit     string

	Title string

	StartedAt db_common.NullTime `db:"started_at"`
	EndedAt   db_common.NullTime `db:"ended_at"`

	Success bool
	Failure bool
}

// IDString returns a succinct string that uniquely identifies this build task.
func (t *BuildTask) IDString() string {
	return buildIDString(t.BID) + "-T" + strconv.FormatInt(t.TID, 36)
}

// LogURL is the URL to the logs for this task.
func (t *BuildTask) LogURL() string {
	return task2.LogURLForTag(t.IDString())
}

// BuildConfig configures a repository build.
type BuildConfig struct {
	// Import is whether to import the build data into the database when the
	// build is complete. The data must be imported for Sourcegraph's web app or
	// API to use it, except that unimported build data is available through the
	// BuildData service. (TODO(sqs): BuildData isn't yet implemented.)
	Import bool

	// Queue is whether this build should be enqueued. If enqueued, any worker
	// may begin running this build. If not enqueued, it is up to the client to
	// run the build and update it accordingly.
	Queue bool
}

var ErrBuildNotFound = errors.New("build not found")

type BuildGetOptions struct{}

func (s *buildsService) Get(build BuildSpec, opt *BuildGetOptions) (*Build, Response, error) {
	url, err := s.client.url(api_router.Build, build.RouteVars(), opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", url.String(), nil)
	if err != nil {
		return nil, nil, err
	}

	var build_ *Build
	resp, err := s.client.Do(req, &build_)
	if err != nil {
		return nil, resp, err
	}

	return build_, nil, nil
}

type BuildListOptions struct {
	Queued    bool `url:",omitempty"`
	Ended     bool `url:",omitempty"`
	Succeeded bool `url:",omitempty"`
	Failed    bool `url:",omitempty"`

	ListOptions
}

func (s *buildsService) List(opt *BuildListOptions) ([]*Build, Response, error) {
	url, err := s.client.url(api_router.Builds, nil, opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", url.String(), nil)
	if err != nil {
		return nil, nil, err
	}

	var builds []*Build
	resp, err := s.client.Do(req, &builds)
	if err != nil {
		return nil, resp, err
	}

	return builds, resp, nil
}

type BuildListByRepositoryOptions struct {
	BuildListOptions
	Rev string `url:",omitempty"`
}

func (s *buildsService) ListByRepository(repo RepositorySpec, opt *BuildListByRepositoryOptions) ([]*Build, Response, error) {
	url, err := s.client.url(api_router.RepositoryBuilds, map[string]string{"RepoURI": repo.URI}, opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", url.String(), nil)
	if err != nil {
		return nil, nil, err
	}

	var builds []*Build
	resp, err := s.client.Do(req, &builds)
	if err != nil {
		return nil, resp, err
	}

	return builds, resp, nil
}

func (s *buildsService) Create(repo RepositorySpec, conf BuildConfig) (*Build, Response, error) {
	url, err := s.client.url(api_router.RepositoryBuildsCreate, repo.RouteVars(), nil)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("POST", url.String(), conf)
	if err != nil {
		return nil, nil, err
	}

	var build *Build
	resp, err := s.client.Do(req, &build)
	if err != nil {
		return nil, resp, err
	}

	return build, resp, nil
}

type BuildTaskListOptions struct{ ListOptions }

func (s *buildsService) ListBuildTasks(build BuildSpec, opt *BuildTaskListOptions) ([]*BuildTask, Response, error) {
	url, err := s.client.url(api_router.BuildTasks, build.RouteVars(), opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", url.String(), nil)
	if err != nil {
		return nil, nil, err
	}

	var tasks []*BuildTask
	resp, err := s.client.Do(req, &tasks)
	if err != nil {
		return nil, resp, err
	}

	return tasks, resp, nil
}

type MockBuildsService struct {
	Get_              func(build BuildSpec, opt *BuildGetOptions) (*Build, Response, error)
	List_             func(opt *BuildListOptions) ([]*Build, Response, error)
	ListByRepository_ func(repo RepositorySpec, opt *BuildListByRepositoryOptions) ([]*Build, Response, error)
	Create_           func(repo RepositorySpec, conf BuildConfig) (*Build, Response, error)
	ListBuildTasks_   func(build BuildSpec, opt *BuildTaskListOptions) ([]*BuildTask, Response, error)
}

var _ BuildsService = MockBuildsService{}

func (s MockBuildsService) Get(build BuildSpec, opt *BuildGetOptions) (*Build, Response, error) {
	if s.Get_ == nil {
		return nil, &HTTPResponse{}, nil
	}
	return s.Get_(build, opt)
}

func (s MockBuildsService) List(opt *BuildListOptions) ([]*Build, Response, error) {
	if s.List_ == nil {
		return nil, nil, nil
	}
	return s.List_(opt)
}

func (s MockBuildsService) ListByRepository(repo RepositorySpec, opt *BuildListByRepositoryOptions) ([]*Build, Response, error) {
	if s.ListByRepository_ == nil {
		return nil, &HTTPResponse{}, nil
	}
	return s.ListByRepository_(repo, opt)
}

func (s MockBuildsService) Create(repo RepositorySpec, conf BuildConfig) (*Build, Response, error) {
	if s.Create_ == nil {
		return nil, nil, nil
	}
	return s.Create_(repo, conf)
}

func (s MockBuildsService) ListBuildTasks(build BuildSpec, opt *BuildTaskListOptions) ([]*BuildTask, Response, error) {
	if s.ListBuildTasks_ == nil {
		return nil, nil, nil
	}
	return s.ListBuildTasks_(build, opt)
}
<commit_msg>active builds<commit_after>package client

import (
	"errors"
	"fmt"
	"time"

	"strconv"

	"sourcegraph.com/sourcegraph/api_router"
	"sourcegraph.com/sourcegraph/srcgraph/db_common"
	"sourcegraph.com/sourcegraph/srcgraph/repo"
	"sourcegraph.com/sourcegraph/srcgraph/task2"
)

// BuildsService communicates with the build-related endpoints in the
// Sourcegraph API.
type BuildsService interface {
	// Get fetches a build.
	Get(build BuildSpec, opt *BuildGetOptions) (*Build, Response, error)

	// List builds.
	List(opt *BuildListOptions) ([]*Build, Response, error)

	// ListByRepository lists builds for a repository.
	ListByRepository(repo RepositorySpec, opt *BuildListByRepositoryOptions) ([]*Build, Response, error)

	// Create a new build. The build will run asynchronously (Create does not
	// wait for it to return. To monitor the build's status, use Get.)
	Create(repo RepositorySpec, conf BuildConfig) (*Build, Response, error)

	// ListBuildTasks lists the tasks associated with a build.
	ListBuildTasks(build BuildSpec, opt *BuildTaskListOptions) ([]*BuildTask, Response, error)
}

type buildsService struct {
	client *Client
}

var _ BuildsService = &buildsService{}

type BuildSpec struct {
	BID int64
}

func (s *BuildSpec) RouteVars() map[string]string {
	return map[string]string{"BID": fmt.Sprintf("%d", s.BID)}
}

// A Build represents a scheduled, completed, or failed repository analysis and
// import job.
type Build struct {
	BID       int64
	Repo      repo.RID
	CommitID  string             `db:"commit_id"`
	CreatedAt time.Time          `db:"created_at"`
	StartedAt db_common.NullTime `db:"started_at"`
	EndedAt   db_common.NullTime `db:"ended_at"`
	Success   bool
	Failure   bool

	// Host is the hostname of the machine that is working on this build.
	Host string

	// Tries is the number of times that this build has started to run. Builds
	// may be retried after a failure or timeout, in which case Tries > 1.
	Tries int

	BuildConfig

	// RepoURI is populated (as a convenience) in results by Get and List but
	// should not be set when creating builds (it will be ignored).
	RepoURI repo.URI `db:"repo_uri" json:",omitempty"`
}

// IDString returns a succinct string that uniquely identifies this build.
func (b *Build) IDString() string { return buildIDString(b.BID) }

func buildIDString(bid int64) string { return "B" + strconv.FormatInt(bid, 36) }

// LogURL is the URL to the logs for this build.
func (b *Build) LogURL() string {
	return task2.LogURLForTag(b.IDString())
}

// A BuildTask represents an individual step of a build.
type BuildTask struct {
	TID int64

	// BID is the build that this task is a part of.
	BID int64

	UnitType string
	Unit     string

	Title string

	StartedAt db_common.NullTime `db:"started_at"`
	EndedAt   db_common.NullTime `db:"ended_at"`

	Success bool
	Failure bool
}

// IDString returns a succinct string that uniquely identifies this build task.
func (t *BuildTask) IDString() string {
	return buildIDString(t.BID) + "-T" + strconv.FormatInt(t.TID, 36)
}

// LogURL is the URL to the logs for this task.
func (t *BuildTask) LogURL() string {
	return task2.LogURLForTag(t.IDString())
}

// BuildConfig configures a repository build.
type BuildConfig struct {
	// Import is whether to import the build data into the database when the
	// build is complete. The data must be imported for Sourcegraph's web app or
	// API to use it, except that unimported build data is available through the
	// BuildData service. (TODO(sqs): BuildData isn't yet implemented.)
	Import bool

	// Queue is whether this build should be enqueued. If enqueued, any worker
	// may begin running this build. If not enqueued, it is up to the client to
	// run the build and update it accordingly.
	Queue bool
}

var ErrBuildNotFound = errors.New("build not found")

type BuildGetOptions struct{}

func (s *buildsService) Get(build BuildSpec, opt *BuildGetOptions) (*Build, Response, error) {
	url, err := s.client.url(api_router.Build, build.RouteVars(), opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", url.String(), nil)
	if err != nil {
		return nil, nil, err
	}

	var build_ *Build
	resp, err := s.client.Do(req, &build_)
	if err != nil {
		return nil, resp, err
	}

	return build_, nil, nil
}

type BuildListOptions struct {
	Queued    bool `url:",omitempty"`
	Active    bool `url:",omitempty"`
	Ended     bool `url:",omitempty"`
	Succeeded bool `url:",omitempty"`
	Failed    bool `url:",omitempty"`

	ListOptions
}

func (s *buildsService) List(opt *BuildListOptions) ([]*Build, Response, error) {
	url, err := s.client.url(api_router.Builds, nil, opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", url.String(), nil)
	if err != nil {
		return nil, nil, err
	}

	var builds []*Build
	resp, err := s.client.Do(req, &builds)
	if err != nil {
		return nil, resp, err
	}

	return builds, resp, nil
}

type BuildListByRepositoryOptions struct {
	BuildListOptions
	Rev string `url:",omitempty"`
}

func (s *buildsService) ListByRepository(repo RepositorySpec, opt *BuildListByRepositoryOptions) ([]*Build, Response, error) {
	url, err := s.client.url(api_router.RepositoryBuilds, map[string]string{"RepoURI": repo.URI}, opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", url.String(), nil)
	if err != nil {
		return nil, nil, err
	}

	var builds []*Build
	resp, err := s.client.Do(req, &builds)
	if err != nil {
		return nil, resp, err
	}

	return builds, resp, nil
}

func (s *buildsService) Create(repo RepositorySpec, conf BuildConfig) (*Build, Response, error) {
	url, err := s.client.url(api_router.RepositoryBuildsCreate, repo.RouteVars(), nil)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("POST", url.String(), conf)
	if err != nil {
		return nil, nil, err
	}

	var build *Build
	resp, err := s.client.Do(req, &build)
	if err != nil {
		return nil, resp, err
	}

	return build, resp, nil
}

type BuildTaskListOptions struct{ ListOptions }

func (s *buildsService) ListBuildTasks(build BuildSpec, opt *BuildTaskListOptions) ([]*BuildTask, Response, error) {
	url, err := s.client.url(api_router.BuildTasks, build.RouteVars(), opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", url.String(), nil)
	if err != nil {
		return nil, nil, err
	}

	var tasks []*BuildTask
	resp, err := s.client.Do(req, &tasks)
	if err != nil {
		return nil, resp, err
	}

	return tasks, resp, nil
}

type MockBuildsService struct {
	Get_              func(build BuildSpec, opt *BuildGetOptions) (*Build, Response, error)
	List_             func(opt *BuildListOptions) ([]*Build, Response, error)
	ListByRepository_ func(repo RepositorySpec, opt *BuildListByRepositoryOptions) ([]*Build, Response, error)
	Create_           func(repo RepositorySpec, conf BuildConfig) (*Build, Response, error)
	ListBuildTasks_   func(build BuildSpec, opt *BuildTaskListOptions) ([]*BuildTask, Response, error)
}

var _ BuildsService = MockBuildsService{}

func (s MockBuildsService) Get(build BuildSpec, opt *BuildGetOptions) (*Build, Response, error) {
	if s.Get_ == nil {
		return nil, &HTTPResponse{}, nil
	}
	return s.Get_(build, opt)
}

func (s MockBuildsService) List(opt *BuildListOptions) ([]*Build, Response, error) {
	if s.List_ == nil {
		return nil, nil, nil
	}
	return s.List_(opt)
}

func (s MockBuildsService) ListByRepository(repo RepositorySpec, opt *BuildListByRepositoryOptions) ([]*Build, Response, error) {
	if s.ListByRepository_ == nil {
		return nil, &HTTPResponse{}, nil
	}
	return s.ListByRepository_(repo, opt)
}

func (s MockBuildsService) Create(repo RepositorySpec, conf BuildConfig) (*Build, Response, error) {
	if s.Create_ == nil {
		return nil, nil, nil
	}
	return s.Create_(repo, conf)
}

func (s MockBuildsService) ListBuildTasks(build BuildSpec, opt *BuildTaskListOptions) ([]*BuildTask, Response, error) {
	if s.ListBuildTasks_ == nil {
		return nil, nil, nil
	}
	return s.ListBuildTasks_(build, opt)
}
<|endoftext|>