<commit_before>package browse

import (
	"errors"
	"github.com/scritch007/ShareMinatorApiGenerator/api"
	"github.com/scritch007/go-tools"
	"github.com/scritch007/shareit/auth"
	"github.com/scritch007/shareit/thumbnail"
	"github.com/scritch007/shareit/types"
	"io/ioutil"
	"mime"
	"net/http"
	"net/url"
	"os"
	"path"
	"path/filepath"
	"time"
)

type BrowseHandler struct {
	config    *types.Configuration
	thumbnail *thumbnail.ThumbnailGenerator
}

func NewBrowseHandler(config *types.Configuration) (handler *BrowseHandler) {
	handler = &BrowseHandler{config: config, thumbnail: thumbnail.NewThumbnailGenerator(config)}
	return handler
}

func (b *BrowseHandler) Handle(context *types.CommandContext, resp chan<- types.EnumCommandHandlerStatus) *types.HttpError {
	command := context.Command
	tools.LOG_DEBUG.Println("Got this command ", command.ApiCommand.Name)
	if nil == command.ApiCommand.Browser {
		return &types.HttpError{Err: errors.New("Missing browse command body"), Status: http.StatusBadRequest}
	}
	if command.ApiCommand.Name == api.EnumBrowserList {
		go b.browseCommand(context, resp)
	} else if command.ApiCommand.Name == api.EnumBrowserCreateFolder {
		go b.createFolderCommand(context, resp)
	} else if command.ApiCommand.Name == api.EnumBrowserDelete {
		go b.deleteItemCommand(context, resp)
	} else if command.ApiCommand.Name == api.EnumBrowserDownloadLink {
		go b.downloadLink(context, resp)
	} else if command.ApiCommand.Name == api.EnumBrowserUploadFile {
		go b.uploadFile(context, resp)
	} else if command.ApiCommand.Name == api.EnumBrowserThumbnail {
		go b.thumbnailCommand(context, resp)
	} else {
		return &types.HttpError{Err: errors.New("Unknown Browse command"), Status: http.StatusBadRequest}
	}
	return nil
}

func (b *BrowseHandler) downloadLink(context *types.CommandContext, resp chan<- types.EnumCommandHandlerStatus) {
	command := context.Command.ApiCommand
	if nil == command.Browser.DownloadLink {
		tools.LOG_DEBUG.Println("Missing input configuration")
		command.State.ErrorCode = api.ERROR_MISSING_COMMAND_BODY
		resp <- types.EnumCommandHandlerError
		return
	}

	accessPath, _ := auth.GetAccessAndPath(b.config, context, command.Browser.DownloadLink.Input.Path, false)
	if !accessPath.Exists {
		tools.LOG_DEBUG.Println("Couldn't find this path")
		command.State.ErrorCode = api.ERROR_INVALID_PATH
		resp <- types.EnumCommandHandlerError
		return
	}

	file_path := accessPath.RealPath
	result := tools.ComputeHmac256Html(*file_path, b.config.PrivateKey)
	dLink := types.DownloadLink{Link: result, Path: command.Browser.DownloadLink.Input.Path, RealPath: file_path}
	b.config.Db.AddDownloadLink(&dLink)
	command.Browser.DownloadLink.Output.DownloadLink = url.QueryEscape(result)
	resp <- types.EnumCommandHandlerDone
}

//Handle removal of an item
func (b *BrowseHandler) deleteItemCommand(context *types.CommandContext, resp chan<- types.EnumCommandHandlerStatus) {
	command := context.Command.ApiCommand
	if nil == command.Browser.Delete {
		tools.LOG_DEBUG.Println("Missing input configuration")
		command.State.ErrorCode = api.ERROR_MISSING_COMMAND_BODY
		resp <- types.EnumCommandHandlerError
		return
	}
	asUser := nil == context.Account || !context.Account.IsAdmin

	accessPath, _ := auth.GetAccessAndPath(b.config, context, command.Browser.Delete.Input.Path, asUser)

	if api.ERROR_NO_ERROR != accessPath.Error {
		command.State.ErrorCode = accessPath.Error
		resp <- types.EnumCommandHandlerError
		return
	}

	if api.READ_WRITE != accessPath.Access {
		command.State.ErrorCode = api.ERROR_NOT_ALLOWED
		resp <- types.EnumCommandHandlerError
		return
	}

	item_path := accessPath.RealPath
	if nil == item_path {
		command.State.ErrorCode = api.ERROR_INVALID_PATH
		resp <- types.EnumCommandHandlerError
		return
	}

	if !accessPath.Exists {
		command.State.ErrorCode = api.ERROR_INVALID_PATH
		resp <- types.EnumCommandHandlerError
		return
	}
	if accessPath.IsDir {
		tools.LOG_DEBUG.Println("Item is a directory")
		//We are going to make something nice with a progress
		fileList, err := ioutil.ReadDir(*item_path)
		if nil != err {
			tools.LOG_DEBUG.Println("Couldn't list directory")
			command.State.ErrorCode = api.ERROR_FILE_SYSTEM
			resp <- types.EnumCommandHandlerError
			return
		}
		nbElements := len(fileList)
		success := types.EnumCommandHandlerDone
		for i, element := range fileList {
			element_path := path.Join(*item_path, element.Name())
			tools.LOG_DEBUG.Println("Trying to remove " + element_path)
			err = os.RemoveAll(element_path)
			if nil != err {
				tools.LOG_ERROR.Println("Failed to remove entry " + err.Error())
				success = types.EnumCommandHandlerError
				command.State.ErrorCode = api.ERROR_FILE_SYSTEM
			}
			command.State.Progress = i * 100 / nbElements
		}
		if nil != os.RemoveAll(*item_path) {
			success = types.EnumCommandHandlerError
		}
		resp <- success
	} else {
		err := os.Remove(*item_path)
		if nil == err {
			resp <- types.EnumCommandHandlerDone
		} else {
			resp <- types.EnumCommandHandlerError
		}
	}

}

//Handle the creation of a folder
func (b *BrowseHandler) createFolderCommand(context *types.CommandContext, resp chan<- types.EnumCommandHandlerStatus) {
	command := context.Command.ApiCommand
	if nil == command.Browser.CreateFolder {
		tools.LOG_ERROR.Println("Missing configuration")
		command.State.ErrorCode = api.ERROR_MISSING_COMMAND_BODY
		resp <- types.EnumCommandHandlerError
		return
	}
	asUser := nil == context.Account || !context.Account.IsAdmin
	accessPath, _ := auth.GetAccessAndPath(b.config, context, command.Browser.CreateFolder.Input.Path, asUser)

	if api.ERROR_NO_ERROR != accessPath.Error {
		command.State.ErrorCode = accessPath.Error
		resp <- types.EnumCommandHandlerError
		return
	}

	if api.READ_WRITE != accessPath.Access {
		command.State.ErrorCode = api.ERROR_NOT_ALLOWED
		resp <- types.EnumCommandHandlerError
		return
	}

	item_path := accessPath.RealPath
	if nil == item_path {
		command.State.ErrorCode = api.ERROR_INVALID_PATH
		resp <- types.EnumCommandHandlerError
		return
	}

	if accessPath.Exists {
		command.State.ErrorCode = api.ERROR_INVALID_PATH
		resp <- types.EnumCommandHandlerError
		return
	}

	error := os.Mkdir(*item_path, os.ModePerm)
	if nil != error {
		resp <- types.EnumCommandHandlerError
	} else {
		resp <- types.EnumCommandHandlerDone
	}
}

func (b *BrowseHandler) uploadFile(context *types.CommandContext, resp chan<- types.EnumCommandHandlerStatus) {
	command := context.Command.ApiCommand
	if nil == command.Browser.UploadFile {
		tools.LOG_ERROR.Println("Missing configuration")
		command.State.ErrorCode = api.ERROR_MISSING_COMMAND_BODY
		resp <- types.EnumCommandHandlerError
		return
	}

	asUser := nil == context.Account || !context.Account.IsAdmin

	accessPath, _ := auth.GetAccessAndPath(b.config, context, command.Browser.UploadFile.Input.Path, asUser)

	if api.ERROR_NO_ERROR != accessPath.Error {
		command.State.ErrorCode = accessPath.Error
		resp <- types.EnumCommandHandlerError
		return
	}

	item_path := accessPath.RealPath
	if nil == item_path {
		command.State.ErrorCode = api.ERROR_INVALID_PATH
		resp <- types.EnumCommandHandlerError
		return
	}

	//If write access has been removed, then we should respond false!!
	if api.READ_WRITE != accessPath.Access {
		command.State.ErrorCode = api.ERROR_NOT_ALLOWED
		resp <- types.EnumCommandHandlerError
		return
	}

	if accessPath.Exists {
		tools.LOG_DEBUG.Println("Truncating file")
		os.Truncate(*item_path, command.Browser.UploadFile.Input.Size)
		return
	}
	resp <- types.EnumCommandHandlerPostponed
}

func (b *BrowseHandler) thumbnailCommand(context *types.CommandContext, resp chan<- types.EnumCommandHandlerStatus) {
	command := context.Command.ApiCommand
	if nil == command.Browser.Thumbnail {
		tools.LOG_ERROR.Println("Missing configuration")
		command.State.ErrorCode = api.ERROR_MISSING_COMMAND_BODY
		resp <- types.EnumCommandHandlerError
		return
	}

	asUser := nil == context.Account || !context.Account.IsAdmin

	accessPath, _ := auth.GetAccessAndPath(b.config, context, command.Browser.Thumbnail.Input.Path, asUser)

	if api.ERROR_NO_ERROR != accessPath.Error {
		command.State.ErrorCode = accessPath.Error
		resp <- types.EnumCommandHandlerError
		return
	}

	item_path := accessPath.RealPath
	if nil == item_path {
		command.State.ErrorCode = api.ERROR_INVALID_PATH
		resp <- types.EnumCommandHandlerError
		return
	}

	//If write access has been removed, then we should respond false!!
	if api.NONE == accessPath.Access {
		command.State.ErrorCode = api.ERROR_NOT_ALLOWED
		resp <- types.EnumCommandHandlerError
		return
	}
	responseChan := make(chan string)
	thumbnailRequest := thumbnail.ThumbnailRequest{Path: *accessPath.RealPath, Response: responseChan}
	b.thumbnail.GetThumbnail(&thumbnailRequest)
	value := <-responseChan
	command.Browser.Thumbnail.Output.Content = value
	if 0 == len(value) {
		resp <- types.EnumCommandHandlerError
	} else {
		resp <- types.EnumCommandHandlerDone
	}
}

//Handle the browsing of a folder
func (b *BrowseHandler) browseCommand(context *types.CommandContext, resp chan<- types.EnumCommandHandlerStatus) {
	command := context.Command.ApiCommand
	if nil == command.Browser.List || 0 == len(command.Browser.List.Input.Path) {
		tools.LOG_ERROR.Println("Missing input configuration")
		command.State.ErrorCode = api.ERROR_MISSING_COMMAND_BODY
		resp <- types.EnumCommandHandlerError
		return
	}
	asUser := true
	if nil != context.Account && context.Account.IsAdmin {
		//TODO checkt he asUser request header
		asUser = false
	}
	tools.LOG_DEBUG.Println("Retrieving access")
	accessPath, _ := auth.GetAccessAndPath(b.config, context, command.Browser.List.Input.Path, asUser)

	if api.ERROR_NO_ERROR != accessPath.Error {
		command.State.ErrorCode = accessPath.Error
		resp <- types.EnumCommandHandlerError
		return
	}

	if !accessPath.Exists {
		command.State.ErrorCode = api.ERROR_INVALID_PATH
		resp <- types.EnumCommandHandlerError
		return
	}

	tools.LOG_DEBUG.Println("Browsing path ", accessPath.RealPath)
	counter := 0
	var result []api.StorageItem

	command.Browser.List.Output.CurrentItem = api.StorageItem{Name: filepath.Base(command.Browser.List.Input.Path), IsDir: accessPath.IsDir, MDate: accessPath.FileInfo.ModTime().Unix(), Access: accessPath.Access, ShareAccess: accessPath.Access, Kind: filepath.Ext(accessPath.FileInfo.Name()), Size: accessPath.FileInfo.Size(), Mimetype: mime.TypeByExtension(filepath.Ext(accessPath.FileInfo.Name()))}
	if accessPath.IsDir {
		fileList, err := ioutil.ReadDir(*accessPath.RealPath)
		if nil != err {
			tools.LOG_ERROR.Println("Failed to read path with error code " + err.Error())
			resp <- types.EnumCommandHandlerError
		}
		result = make([]api.StorageItem, len(fileList))

		var access api.AccessType
		for _, file := range fileList {
			s := api.StorageItem{Name: file.Name(), IsDir: file.IsDir(), MDate: file.ModTime().Unix()}
			if "." == string(file.Name()[0]) && (nil == command.Browser.List.Input.ShowHiddenFiles || !*command.Browser.List.Input.ShowHiddenFiles) {
				continue
			}
			if !file.IsDir() {
				s.Size = file.Size()
				s.Kind = filepath.Ext(file.Name())
				s.Mimetype = mime.TypeByExtension(filepath.Ext(file.Name()))
				access = accessPath.Access
			} else {
				s.Kind = "folder"
				s.Mimetype = ""
				accessPath2, _ := auth.GetAccessAndPath(b.config, context, path.Join(command.Browser.List.Input.Path, s.Name), asUser)
				if api.ERROR_NO_ERROR != accessPath2.Error {
					err = errors.New("Couldn't get infos about this")
				} else {
					err = nil
				}
				access = accessPath2.Access
			}
			if nil != err {
				continue
			} else if api.NONE == access && asUser {
				continue
			}
			s.Access = access
			s.ShareAccess = s.Access
			result[counter] = s
			counter++
		}
	} else {
		//Force the name for the display
		command.Browser.List.Output.CurrentItem.Name = accessPath.FileInfo.Name()
	}
	command.Browser.List.Output.Children = result[:counter]
	time.Sleep(2)
	resp <- types.EnumCommandHandlerDone
}

func (b *BrowseHandler) GetUploadPath(context *types.CommandContext) (path *string, size int64, hErr *types.HttpError) {
	command := context.Command.ApiCommand
	if api.EnumBrowserUploadFile != command.Name {
		return nil, 0, &types.HttpError{errors.New("Not Allowed for this command type"), http.StatusBadRequest}
	}

	accessPath, _ := auth.GetAccessAndPath(b.config, context, command.Browser.UploadFile.Input.Path, false)

	if api.ERROR_NO_ERROR != accessPath.Error {
		return nil, 0, &types.HttpError{errors.New("Access Error"), http.StatusUnauthorized}
	}
	if api.READ_WRITE != accessPath.Access {
		return nil, 0, &types.HttpError{errors.New("Access Error"), http.StatusUnauthorized}
	}

	return accessPath.RealPath, command.Browser.UploadFile.Input.Size, nil
}
<commit_msg>Some more Go<commit_after>package browse

import (
	"errors"
	"io/ioutil"
	"mime"
	"net/http"
	"net/url"
	"os"
	"path"
	"path/filepath"
	"time"

	"github.com/scritch007/ShareMinatorApiGenerator/api"
	"github.com/scritch007/go-tools"
	"github.com/scritch007/shareit/auth"
	"github.com/scritch007/shareit/thumbnail"
	"github.com/scritch007/shareit/types"
)

//BrowseHandler export browse structure
type BrowseHandler struct {
	config    *types.Configuration
	thumbnail *thumbnail.ThumbnailGenerator
}

//NewBrowseHandler instantiate handler
func NewBrowseHandler(config *types.Configuration) (handler *BrowseHandler) {
	handler = &BrowseHandler{config: config, thumbnail: thumbnail.NewThumbnailGenerator(config)}
	return handler
}

//Handle main method to handle commands
func (b *BrowseHandler) Handle(context *types.CommandContext, resp chan<- types.EnumCommandHandlerStatus) *types.HttpError {
	command := context.Command
	tools.LOG_DEBUG.Println("Got this command ", command.ApiCommand.Name)
	if nil == command.ApiCommand.Browser {
		return &types.HttpError{Err: errors.New("Missing browse command body"), Status: http.StatusBadRequest}
	}
	if command.ApiCommand.Name == api.EnumBrowserList {
		go b.browseCommand(context, resp)
	} else if command.ApiCommand.Name == api.EnumBrowserCreateFolder {
		go b.createFolderCommand(context, resp)
	} else if command.ApiCommand.Name == api.EnumBrowserDelete {
		go b.deleteItemCommand(context, resp)
	} else if command.ApiCommand.Name == api.EnumBrowserDownloadLink {
		go b.downloadLink(context, resp)
	} else if command.ApiCommand.Name == api.EnumBrowserUploadFile {
		go b.uploadFile(context, resp)
	} else if command.ApiCommand.Name == api.EnumBrowserThumbnail {
		go b.thumbnailCommand(context, resp)
	} else {
		return &types.HttpError{Err: errors.New("Unknown Browse command"), Status: http.StatusBadRequest}
	}
	return nil
}

func (b *BrowseHandler) downloadLink(context *types.CommandContext, resp chan<- types.EnumCommandHandlerStatus) {
	command := context.Command.ApiCommand
	if nil == command.Browser.DownloadLink {
		tools.LOG_DEBUG.Println("Missing input configuration")
		command.State.ErrorCode = api.ERROR_MISSING_COMMAND_BODY
		resp <- types.EnumCommandHandlerError
		return
	}

	accessPath, _ := auth.GetAccessAndPath(b.config, context, command.Browser.DownloadLink.Input.Path, false)
	if !accessPath.Exists {
		tools.LOG_DEBUG.Println("Couldn't find this path")
		command.State.ErrorCode = api.ERROR_INVALID_PATH
		resp <- types.EnumCommandHandlerError
		return
	}

	filePath := accessPath.RealPath
	result := tools.ComputeHmac256Html(*filePath, b.config.PrivateKey)
	dLink := types.DownloadLink{Link: result, Path: command.Browser.DownloadLink.Input.Path, RealPath: filePath}
	b.config.Db.AddDownloadLink(&dLink)
	command.Browser.DownloadLink.Output.DownloadLink = url.QueryEscape(result)
	resp <- types.EnumCommandHandlerDone
}

//Handle removal of an item
func (b *BrowseHandler) deleteItemCommand(context *types.CommandContext, resp chan<- types.EnumCommandHandlerStatus) {
	command := context.Command.ApiCommand
	if nil == command.Browser.Delete {
		tools.LOG_DEBUG.Println("Missing input configuration")
		command.State.ErrorCode = api.ERROR_MISSING_COMMAND_BODY
		resp <- types.EnumCommandHandlerError
		return
	}
	asUser := nil == context.Account || !context.Account.IsAdmin

	accessPath, _ := auth.GetAccessAndPath(b.config, context, command.Browser.Delete.Input.Path, asUser)

	if api.ERROR_NO_ERROR != accessPath.Error {
		command.State.ErrorCode = accessPath.Error
		resp <- types.EnumCommandHandlerError
		return
	}

	if api.READ_WRITE != accessPath.Access {
		command.State.ErrorCode = api.ERROR_NOT_ALLOWED
		resp <- types.EnumCommandHandlerError
		return
	}

	itemPath := accessPath.RealPath
	if nil == itemPath {
		command.State.ErrorCode = api.ERROR_INVALID_PATH
		resp <- types.EnumCommandHandlerError
		return
	}

	if !accessPath.Exists {
		command.State.ErrorCode = api.ERROR_INVALID_PATH
		resp <- types.EnumCommandHandlerError
		return
	}
	if accessPath.IsDir {
		tools.LOG_DEBUG.Println("Item is a directory")
		//We are going to make something nice with a progress
		fileList, err := ioutil.ReadDir(*itemPath)
		if nil != err {
			tools.LOG_DEBUG.Println("Couldn't list directory")
			command.State.ErrorCode = api.ERROR_FILE_SYSTEM
			resp <- types.EnumCommandHandlerError
			return
		}
		nbElements := len(fileList)
		success := types.EnumCommandHandlerDone
		for i, element := range fileList {
			elementPath := path.Join(*itemPath, element.Name())
			tools.LOG_DEBUG.Println("Trying to remove " + elementPath)
			err = os.RemoveAll(elementPath)
			if nil != err {
				tools.LOG_ERROR.Println("Failed to remove entry " + err.Error())
				success = types.EnumCommandHandlerError
				command.State.ErrorCode = api.ERROR_FILE_SYSTEM
			}
			command.State.Progress = i * 100 / nbElements
		}
		if nil != os.RemoveAll(*itemPath) {
			success = types.EnumCommandHandlerError
		}
		resp <- success
	} else {
		err := os.Remove(*itemPath)
		if nil == err {
			resp <- types.EnumCommandHandlerDone
		} else {
			resp <- types.EnumCommandHandlerError
		}
	}

}

//Handle the creation of a folder
func (b *BrowseHandler) createFolderCommand(context *types.CommandContext, resp chan<- types.EnumCommandHandlerStatus) {
	command := context.Command.ApiCommand
	if nil == command.Browser.CreateFolder {
		tools.LOG_ERROR.Println("Missing configuration")
		command.State.ErrorCode = api.ERROR_MISSING_COMMAND_BODY
		resp <- types.EnumCommandHandlerError
		return
	}
	asUser := nil == context.Account || !context.Account.IsAdmin
	accessPath, _ := auth.GetAccessAndPath(b.config, context, command.Browser.CreateFolder.Input.Path, asUser)

	if api.ERROR_NO_ERROR != accessPath.Error {
		command.State.ErrorCode = accessPath.Error
		resp <- types.EnumCommandHandlerError
		return
	}

	if api.READ_WRITE != accessPath.Access {
		command.State.ErrorCode = api.ERROR_NOT_ALLOWED
		resp <- types.EnumCommandHandlerError
		return
	}

	itemPath := accessPath.RealPath
	if nil == itemPath {
		command.State.ErrorCode = api.ERROR_INVALID_PATH
		resp <- types.EnumCommandHandlerError
		return
	}

	if accessPath.Exists {
		command.State.ErrorCode = api.ERROR_INVALID_PATH
		resp <- types.EnumCommandHandlerError
		return
	}

	error := os.Mkdir(*itemPath, os.ModePerm)
	if nil != error {
		resp <- types.EnumCommandHandlerError
	} else {
		resp <- types.EnumCommandHandlerDone
	}
}

func (b *BrowseHandler) uploadFile(context *types.CommandContext, resp chan<- types.EnumCommandHandlerStatus) {
	command := context.Command.ApiCommand
	if nil == command.Browser.UploadFile {
		tools.LOG_ERROR.Println("Missing configuration")
		command.State.ErrorCode = api.ERROR_MISSING_COMMAND_BODY
		resp <- types.EnumCommandHandlerError
		return
	}

	asUser := nil == context.Account || !context.Account.IsAdmin

	accessPath, _ := auth.GetAccessAndPath(b.config, context, command.Browser.UploadFile.Input.Path, asUser)

	if api.ERROR_NO_ERROR != accessPath.Error {
		command.State.ErrorCode = accessPath.Error
		resp <- types.EnumCommandHandlerError
		return
	}

	itemPath := accessPath.RealPath
	if nil == itemPath {
		command.State.ErrorCode = api.ERROR_INVALID_PATH
		resp <- types.EnumCommandHandlerError
		return
	}

	//If write access has been removed, then we should respond false!!
	if api.READ_WRITE != accessPath.Access {
		command.State.ErrorCode = api.ERROR_NOT_ALLOWED
		resp <- types.EnumCommandHandlerError
		return
	}

	if accessPath.Exists {
		tools.LOG_DEBUG.Println("Truncating file")
		os.Truncate(*itemPath, command.Browser.UploadFile.Input.Size)
		return
	}
	resp <- types.EnumCommandHandlerPostponed
}

func (b *BrowseHandler) thumbnailCommand(context *types.CommandContext, resp chan<- types.EnumCommandHandlerStatus) {
	command := context.Command.ApiCommand
	if nil == command.Browser.Thumbnail {
		tools.LOG_ERROR.Println("Missing configuration")
		command.State.ErrorCode = api.ERROR_MISSING_COMMAND_BODY
		resp <- types.EnumCommandHandlerError
		return
	}

	asUser := nil == context.Account || !context.Account.IsAdmin

	accessPath, _ := auth.GetAccessAndPath(b.config, context, command.Browser.Thumbnail.Input.Path, asUser)

	if api.ERROR_NO_ERROR != accessPath.Error {
		command.State.ErrorCode = accessPath.Error
		resp <- types.EnumCommandHandlerError
		return
	}

	itemPath := accessPath.RealPath
	if nil == itemPath {
		command.State.ErrorCode = api.ERROR_INVALID_PATH
		resp <- types.EnumCommandHandlerError
		return
	}

	//If write access has been removed, then we should respond false!!
	if api.NONE == accessPath.Access {
		command.State.ErrorCode = api.ERROR_NOT_ALLOWED
		resp <- types.EnumCommandHandlerError
		return
	}
	responseChan := make(chan string)
	thumbnailRequest := thumbnail.ThumbnailRequest{Path: *accessPath.RealPath, Response: responseChan}
	b.thumbnail.GetThumbnail(&thumbnailRequest)
	value := <-responseChan
	command.Browser.Thumbnail.Output.Content = value
	if 0 == len(value) {
		resp <- types.EnumCommandHandlerError
	} else {
		resp <- types.EnumCommandHandlerDone
	}
}

//Handle the browsing of a folder
func (b *BrowseHandler) browseCommand(context *types.CommandContext, resp chan<- types.EnumCommandHandlerStatus) {
	command := context.Command.ApiCommand
	if nil == command.Browser.List || 0 == len(command.Browser.List.Input.Path) {
		tools.LOG_ERROR.Println("Missing input configuration")
		command.State.ErrorCode = api.ERROR_MISSING_COMMAND_BODY
		resp <- types.EnumCommandHandlerError
		return
	}
	asUser := true
	if nil != context.Account && context.Account.IsAdmin {
		//TODO checkt he asUser request header
		asUser = false
	}
	tools.LOG_DEBUG.Println("Retrieving access")
	accessPath, _ := auth.GetAccessAndPath(b.config, context, command.Browser.List.Input.Path, asUser)

	if api.ERROR_NO_ERROR != accessPath.Error {
		command.State.ErrorCode = accessPath.Error
		resp <- types.EnumCommandHandlerError
		return
	}

	if !accessPath.Exists {
		command.State.ErrorCode = api.ERROR_INVALID_PATH
		resp <- types.EnumCommandHandlerError
		return
	}

	tools.LOG_DEBUG.Println("Browsing path ", accessPath.RealPath)
	counter := 0
	var result []api.StorageItem

	command.Browser.List.Output.CurrentItem = api.StorageItem{Name: filepath.Base(command.Browser.List.Input.Path), IsDir: accessPath.IsDir, MDate: accessPath.FileInfo.ModTime().Unix(), Access: accessPath.Access, ShareAccess: accessPath.Access, Kind: filepath.Ext(accessPath.FileInfo.Name()), Size: accessPath.FileInfo.Size(), Mimetype: mime.TypeByExtension(filepath.Ext(accessPath.FileInfo.Name()))}
	if accessPath.IsDir {
		fileList, err := ioutil.ReadDir(*accessPath.RealPath)
		if nil != err {
			tools.LOG_ERROR.Println("Failed to read path with error code " + err.Error())
			resp <- types.EnumCommandHandlerError
		}
		result = make([]api.StorageItem, len(fileList))

		var access api.AccessType
		for _, file := range fileList {
			s := api.StorageItem{Name: file.Name(), IsDir: file.IsDir(), MDate: file.ModTime().Unix()}
			if "." == string(file.Name()[0]) && (nil == command.Browser.List.Input.ShowHiddenFiles || !*command.Browser.List.Input.ShowHiddenFiles) {
				continue
			}
			if !file.IsDir() {
				s.Size = file.Size()
				s.Kind = filepath.Ext(file.Name())
				s.Mimetype = mime.TypeByExtension(filepath.Ext(file.Name()))
				access = accessPath.Access
			} else {
				s.Kind = "folder"
				s.Mimetype = ""
				accessPath2, _ := auth.GetAccessAndPath(b.config, context, path.Join(command.Browser.List.Input.Path, s.Name), asUser)
				if api.ERROR_NO_ERROR != accessPath2.Error {
					err = errors.New("Couldn't get infos about this")
				} else {
					err = nil
				}
				access = accessPath2.Access
			}
			if nil != err {
				continue
			} else if api.NONE == access && asUser {
				continue
			}
			s.Access = access
			s.ShareAccess = s.Access
			result[counter] = s
			counter++
		}
	} else {
		//Force the name for the display
		command.Browser.List.Output.CurrentItem.Name = accessPath.FileInfo.Name()
	}
	command.Browser.List.Output.Children = result[:counter]
	time.Sleep(2)
	resp <- types.EnumCommandHandlerDone
}

//GetUploadPath return uploadPath
func (b *BrowseHandler) GetUploadPath(context *types.CommandContext) (path *string, size int64, hErr *types.HttpError) {
	command := context.Command.ApiCommand
	if api.EnumBrowserUploadFile != command.Name {
		return nil, 0, &types.HttpError{errors.New("Not Allowed for this command type"), http.StatusBadRequest}
	}

	accessPath, _ := auth.GetAccessAndPath(b.config, context, command.Browser.UploadFile.Input.Path, false)

	if api.ERROR_NO_ERROR != accessPath.Error {
		return nil, 0, &types.HttpError{errors.New("Access Error"), http.StatusUnauthorized}
	}
	if api.READ_WRITE != accessPath.Access {
		return nil, 0, &types.HttpError{errors.New("Access Error"), http.StatusUnauthorized}
	}

	return accessPath.RealPath, command.Browser.UploadFile.Input.Size, nil
}
<|endoftext|>


<commit_before>package gocb

import (
	"encoding/json"
	"github.com/couchbase/gocb/gocbcore"
)

type subDocResult struct {
	path string
	data []byte
	err  error
}

type DocumentFragment struct {
	cas      Cas
	mt       MutationToken
	contents []subDocResult
	pathMap  map[string]int
}

func (frag *DocumentFragment) Cas() Cas {
	return frag.cas
}

func (frag *DocumentFragment) ContentByIndex(idx int, valuePtr interface{}) error {
	res := frag.contents[idx]
	if res.err != nil {
		return res.err
	}
	if valuePtr == nil {
		return nil
	}
	return json.Unmarshal(res.data, valuePtr)
}

func (frag *DocumentFragment) Content(path string, valuePtr interface{}) error {
	if frag.pathMap == nil {
		frag.pathMap = make(map[string]int)
		for i, v := range frag.contents {
			frag.pathMap[v.path] = i
		}
	}
	return frag.ContentByIndex(frag.pathMap[path], valuePtr)
}

func (frag *DocumentFragment) Exists(path string) bool {
	err := frag.Content(path, nil)
	return err == nil
}

type LookupInBuilder struct {
	bucket *Bucket
	name   string
	ops    []gocbcore.SubDocOp
}

func (set *LookupInBuilder) Get(path string) *LookupInBuilder {
	op := gocbcore.SubDocOp{
		Op:   gocbcore.SubDocOpGet,
		Path: path,
	}
	set.ops = append(set.ops, op)
	return set
}

func (set *LookupInBuilder) Exists(path string) *LookupInBuilder {
	op := gocbcore.SubDocOp{
		Op:   gocbcore.SubDocOpExists,
		Path: path,
	}
	set.ops = append(set.ops, op)
	return set
}

func (set *LookupInBuilder) Do() (*DocumentFragment, error) {
	return set.bucket.lookupIn(set)
}

func (b *Bucket) lookupIn(set *LookupInBuilder) (resOut *DocumentFragment, errOut error) {
	signal := make(chan bool, 1)
	op, err := b.client.SubDocLookup([]byte(set.name), set.ops,
		func(results []gocbcore.SubDocResult, cas gocbcore.Cas, err error) {
			errOut = err

			{
				resSet := &DocumentFragment{}
				resSet.contents = make([]subDocResult, len(results))

				for i, _ := range results {
					resSet.contents[i].path = set.ops[i].Path
					resSet.contents[i].err = results[i].Err
					if results[i].Value != nil {
						resSet.contents[i].data = append([]byte(nil), results[i].Value...)
					}
				}

				resOut = resSet
			}

			signal <- true
		})
	if err != nil {
		return nil, err
	}

	timeoutTmr := gocbcore.AcquireTimer(b.opTimeout)
	select {
	case <-signal:
		gocbcore.ReleaseTimer(timeoutTmr, false)
		return
	case <-timeoutTmr.C:
		gocbcore.ReleaseTimer(timeoutTmr, true)
		if !op.Cancel() {
			<-signal
			return
		}
		return nil, ErrTimeout
	}
}

func (b *Bucket) LookupIn(key string) *LookupInBuilder {
	return &LookupInBuilder{
		bucket: b,
		name:   key,
	}
}

type MutateInBuilder struct {
	bucket *Bucket
	name   string
	cas    gocbcore.Cas
	expiry uint32
	ops    []gocbcore.SubDocOp
}

func (set *MutateInBuilder) Do() (*DocumentFragment, error) {
	return set.bucket.mutateIn(set)
}

func (set *MutateInBuilder) Insert(path string, value interface{}, createParents bool) *MutateInBuilder {
	op := gocbcore.SubDocOp{
		Op:   gocbcore.SubDocOpDictAdd,
		Path: path,
	}
	op.Value, _ = json.Marshal(value)
	if createParents {
		op.Flags &= gocbcore.SubDocFlagMkDirP
	}
	set.ops = append(set.ops, op)
	return set
}

func (set *MutateInBuilder) Upsert(path string, value interface{}, createParents bool) *MutateInBuilder {
	op := gocbcore.SubDocOp{
		Op:   gocbcore.SubDocOpDictSet,
		Path: path,
	}
	op.Value, _ = json.Marshal(value)
	if createParents {
		op.Flags &= gocbcore.SubDocFlagMkDirP
	}
	set.ops = append(set.ops, op)
	return set
}

func (set *MutateInBuilder) Replace(path string, value interface{}) *MutateInBuilder {
	op := gocbcore.SubDocOp{
		Op:   gocbcore.SubDocOpReplace,
		Path: path,
	}
	op.Value, _ = json.Marshal(value)
	set.ops = append(set.ops, op)
	return set
}

func (set *MutateInBuilder) Remove(path string) *MutateInBuilder {
	op := gocbcore.SubDocOp{
		Op:   gocbcore.SubDocOpDelete,
		Path: path,
	}
	set.ops = append(set.ops, op)
	return set
}

func (set *MutateInBuilder) PushFront(path string, value interface{}, createParents bool) *MutateInBuilder {
	op := gocbcore.SubDocOp{
		Op:   gocbcore.SubDocOpArrayPushFirst,
		Path: path,
	}
	op.Value, _ = json.Marshal(value)
	if createParents {
		op.Flags &= gocbcore.SubDocFlagMkDirP
	}
	set.ops = append(set.ops, op)
	return set
}

func (set *MutateInBuilder) PushBack(path string, value interface{}, createParents bool) *MutateInBuilder {
	op := gocbcore.SubDocOp{
		Op:   gocbcore.SubDocOpArrayPushLast,
		Path: path,
	}
	op.Value, _ = json.Marshal(value)
	if createParents {
		op.Flags &= gocbcore.SubDocFlagMkDirP
	}
	set.ops = append(set.ops, op)
	return set
}

func (set *MutateInBuilder) ArrayInsert(path string, value interface{}) *MutateInBuilder {
	op := gocbcore.SubDocOp{
		Op:   gocbcore.SubDocOpArrayInsert,
		Path: path,
	}
	op.Value, _ = json.Marshal(value)
	set.ops = append(set.ops, op)
	return set
}

func (set *MutateInBuilder) AddUnique(path string, value interface{}, createParents bool) *MutateInBuilder {
	op := gocbcore.SubDocOp{
		Op:   gocbcore.SubDocOpArrayAddUnique,
		Path: path,
	}
	op.Value, _ = json.Marshal(value)
	if createParents {
		op.Flags &= gocbcore.SubDocFlagMkDirP
	}
	set.ops = append(set.ops, op)
	return set
}

func (set *MutateInBuilder) Counter(path string, delta int64, createParents bool) *MutateInBuilder {
	op := gocbcore.SubDocOp{
		Op:   gocbcore.SubDocOpCounter,
		Path: path,
	}
	op.Value, _ = json.Marshal(delta)
	if createParents {
		op.Flags &= gocbcore.SubDocFlagMkDirP
	}
	set.ops = append(set.ops, op)
	return set
}

func (b *Bucket) mutateIn(set *MutateInBuilder) (resOut *DocumentFragment, errOut error) {
	signal := make(chan bool, 1)
	op, err := b.client.SubDocMutate([]byte(set.name), set.ops, set.cas, set.expiry,
		func(results []gocbcore.SubDocResult, cas gocbcore.Cas, mt gocbcore.MutationToken, err error) {
			errOut = err
			if errOut == nil {
				resSet := &DocumentFragment{}
				resSet.contents = make([]subDocResult, len(results))

				for i, _ := range results {
					resSet.contents[i].path = set.ops[i].Path
					resSet.contents[i].err = results[i].Err
					if results[i].Value != nil {
						resSet.contents[i].data = append([]byte(nil), results[i].Value...)
					}
				}

				resOut = resSet
			}
			signal <- true
		})
	if err != nil {
		return nil, err
	}

	timeoutTmr := gocbcore.AcquireTimer(b.opTimeout)
	select {
	case <-signal:
		gocbcore.ReleaseTimer(timeoutTmr, false)
		return
	case <-timeoutTmr.C:
		gocbcore.ReleaseTimer(timeoutTmr, true)
		if !op.Cancel() {
			<-signal
			return
		}
		return nil, ErrTimeout
	}
}

func (b *Bucket) MutateIn(key string, cas Cas, expiry uint32) *MutateInBuilder {
	return &MutateInBuilder{
		bucket: b,
		name:   key,
		cas:    gocbcore.Cas(cas),
		expiry: expiry,
	}
}
<commit_msg>Minor fixes for the Sub-Document APIs.<commit_after>package gocb

import (
	"encoding/json"
	"github.com/couchbase/gocb/gocbcore"
)

type subDocResult struct {
	path string
	data []byte
	err  error
}

type DocumentFragment struct {
	cas      Cas
	mt       MutationToken
	contents []subDocResult
	pathMap  map[string]int
}

func (frag *DocumentFragment) Cas() Cas {
	return frag.cas
}

func (frag *DocumentFragment) MutationToken() MutationToken {
	return frag.mt
}

func (frag *DocumentFragment) ContentByIndex(idx int, valuePtr interface{}) error {
	res := frag.contents[idx]
	if res.err != nil {
		return res.err
	}
	if valuePtr == nil {
		return nil
	}
	return json.Unmarshal(res.data, valuePtr)
}

func (frag *DocumentFragment) Content(path string, valuePtr interface{}) error {
	if frag.pathMap == nil {
		frag.pathMap = make(map[string]int)
		for i, v := range frag.contents {
			frag.pathMap[v.path] = i
		}
	}
	return frag.ContentByIndex(frag.pathMap[path], valuePtr)
}

func (frag *DocumentFragment) Exists(path string) bool {
	err := frag.Content(path, nil)
	return err == nil
}

type LookupInBuilder struct {
	bucket *Bucket
	name   string
	ops    []gocbcore.SubDocOp
}

func (set *LookupInBuilder) Execute() (*DocumentFragment, error) {
	return set.bucket.lookupIn(set)
}

func (set *LookupInBuilder) Get(path string) *LookupInBuilder {
	op := gocbcore.SubDocOp{
		Op:   gocbcore.SubDocOpGet,
		Path: path,
	}
	set.ops = append(set.ops, op)
	return set
}

func (set *LookupInBuilder) Exists(path string) *LookupInBuilder {
	op := gocbcore.SubDocOp{
		Op:   gocbcore.SubDocOpExists,
		Path: path,
	}
	set.ops = append(set.ops, op)
	return set
}

func (b *Bucket) lookupIn(set *LookupInBuilder) (resOut *DocumentFragment, errOut error) {
	signal := make(chan bool, 1)
	op, err := b.client.SubDocLookup([]byte(set.name), set.ops,
		func(results []gocbcore.SubDocResult, cas gocbcore.Cas, err error) {
			errOut = err

			{
				resSet := &DocumentFragment{}
				resSet.contents = make([]subDocResult, len(results))

				for i, _ := range results {
					resSet.contents[i].path = set.ops[i].Path
					resSet.contents[i].err = results[i].Err
					if results[i].Value != nil {
						resSet.contents[i].data = append([]byte(nil), results[i].Value...)
					}
				}

				resOut = resSet
			}

			signal <- true
		})
	if err != nil {
		return nil, err
	}

	timeoutTmr := gocbcore.AcquireTimer(b.opTimeout)
	select {
	case <-signal:
		gocbcore.ReleaseTimer(timeoutTmr, false)
		return
	case <-timeoutTmr.C:
		gocbcore.ReleaseTimer(timeoutTmr, true)
		if !op.Cancel() {
			<-signal
			return
		}
		return nil, ErrTimeout
	}
}

func (b *Bucket) LookupIn(key string) *LookupInBuilder {
	return &LookupInBuilder{
		bucket: b,
		name:   key,
	}
}

type MutateInBuilder struct {
	bucket *Bucket
	name   string
	cas    gocbcore.Cas
	expiry uint32
	ops    []gocbcore.SubDocOp
}

func (set *MutateInBuilder) Execute() (*DocumentFragment, error) {
	return set.bucket.mutateIn(set)
}

func (set *MutateInBuilder) Insert(path string, value interface{}, createParents bool) *MutateInBuilder {
	op := gocbcore.SubDocOp{
		Op:   gocbcore.SubDocOpDictAdd,
		Path: path,
	}
	op.Value, _ = json.Marshal(value)
	if createParents {
		op.Flags &= gocbcore.SubDocFlagMkDirP
	}
	set.ops = append(set.ops, op)
	return set
}

func (set *MutateInBuilder) Upsert(path string, value interface{}, createParents bool) *MutateInBuilder {
	op := gocbcore.SubDocOp{
		Op:   gocbcore.SubDocOpDictSet,
		Path: path,
	}
	op.Value, _ = json.Marshal(value)
	if createParents {
		op.Flags &= gocbcore.SubDocFlagMkDirP
	}
	set.ops = append(set.ops, op)
	return set
}

func (set *MutateInBuilder) Replace(path string, value interface{}) *MutateInBuilder {
	op := gocbcore.SubDocOp{
		Op:   gocbcore.SubDocOpReplace,
		Path: path,
	}
	op.Value, _ = json.Marshal(value)
	set.ops = append(set.ops, op)
	return set
}

func (set *MutateInBuilder) Remove(path string) *MutateInBuilder {
	op := gocbcore.SubDocOp{
		Op:   gocbcore.SubDocOpDelete,
		Path: path,
	}
	set.ops = append(set.ops, op)
	return set
}

func (set *MutateInBuilder) PushFront(path string, value interface{}, createParents bool) *MutateInBuilder {
	op := gocbcore.SubDocOp{
		Op:   gocbcore.SubDocOpArrayPushFirst,
		Path: path,
	}
	op.Value, _ = json.Marshal(value)
	if createParents {
		op.Flags &= gocbcore.SubDocFlagMkDirP
	}
	set.ops = append(set.ops, op)
	return set
}

func (set *MutateInBuilder) PushBack(path string, value interface{}, createParents bool) *MutateInBuilder {
	op := gocbcore.SubDocOp{
		Op:   gocbcore.SubDocOpArrayPushLast,
		Path: path,
	}
	op.Value, _ = json.Marshal(value)
	if createParents {
		op.Flags &= gocbcore.SubDocFlagMkDirP
	}
	set.ops = append(set.ops, op)
	return set
}

func (set *MutateInBuilder) ArrayInsert(path string, value interface{}) *MutateInBuilder {
	op := gocbcore.SubDocOp{
		Op:   gocbcore.SubDocOpArrayInsert,
		Path: path,
	}
	op.Value, _ = json.Marshal(value)
	set.ops = append(set.ops, op)
	return set
}

func (set *MutateInBuilder) AddUnique(path string, value interface{}, createParents bool) *MutateInBuilder {
	op := gocbcore.SubDocOp{
		Op:   gocbcore.SubDocOpArrayAddUnique,
		Path: path,
	}
	op.Value, _ = json.Marshal(value)
	if createParents {
		op.Flags &= gocbcore.SubDocFlagMkDirP
	}
	set.ops = append(set.ops, op)
	return set
}

func (set *MutateInBuilder) Counter(path string, delta int64, createParents bool) *MutateInBuilder {
	op := gocbcore.SubDocOp{
		Op:   gocbcore.SubDocOpCounter,
		Path: path,
	}
	op.Value, _ = json.Marshal(delta)
	if createParents {
		op.Flags &= gocbcore.SubDocFlagMkDirP
	}
	set.ops = append(set.ops, op)
	return set
}

func (b *Bucket) mutateIn(set *MutateInBuilder) (resOut *DocumentFragment, errOut error) {
	signal := make(chan bool, 1)
	op, err := b.client.SubDocMutate([]byte(set.name), set.ops, set.cas, set.expiry,
		func(results []gocbcore.SubDocResult, cas gocbcore.Cas, mt gocbcore.MutationToken, err error) {
			errOut = err
			if errOut == nil {
				resSet := &DocumentFragment{
					cas: cas,
					mt:  mt,
				}
				resSet.contents = make([]subDocResult, len(results))

				for i, _ := range results {
					resSet.contents[i].path = set.ops[i].Path
					resSet.contents[i].err = results[i].Err
					if results[i].Value != nil {
						resSet.contents[i].data = append([]byte(nil), results[i].Value...)
					}
				}

				resOut = resSet
			}
			signal <- true
		})
	if err != nil {
		return nil, err
	}

	timeoutTmr := gocbcore.AcquireTimer(b.opTimeout)
	select {
	case <-signal:
		gocbcore.ReleaseTimer(timeoutTmr, false)
		return
	case <-timeoutTmr.C:
		gocbcore.ReleaseTimer(timeoutTmr, true)
		if !op.Cancel() {
			<-signal
			return
		}
		return nil, ErrTimeout
	}
}

func (b *Bucket) MutateIn(key string, cas Cas, expiry uint32) *MutateInBuilder {
	return &MutateInBuilder{
		bucket: b,
		name:   key,
		cas:    gocbcore.Cas(cas),
		expiry: expiry,
	}
}
<|endoftext|>


<commit_before>package buffer

import (
	"bytes"
	"encoding/base64"
	"encoding/binary"
	"encoding/json"
)

type Buffer []byte

func FromUint(v uint64) Buffer {
	data := make([]byte, 8)
	binary.BigEndian.PutUint64(data, v)
	return Buffer(bytes.TrimLeft(data, "\x00"))
}

func (b Buffer) Bytes() []byte {
	return []byte(b)
}

func (b Buffer) Len() int {
	return len(b)
}

func (b Buffer) Base64Encode() ([]byte, error) {
	enc := base64.RawURLEncoding
	out := make([]byte, enc.EncodedLen(len(b)))
	enc.Encode(out, b)
	return out, nil
}

func (b *Buffer) Base64Decode(v []byte) error {
	enc := base64.RawURLEncoding
	out := make([]byte, enc.DecodedLen(len(v)))
	enc.Decode(out, v)
	*b = Buffer(bytes.TrimRight(out, "\x00"))
	return nil
}

func (b Buffer) MarshalJSON() ([]byte, error) {
	v, err := b.Base64Encode()
	if err != nil {
		return nil, err
	}
	return json.Marshal(string(v))
}

func (b *Buffer) UnmarshalJSON(data []byte) error {
	var x string
	if err := json.Unmarshal(data, &x); err != nil {
		return err
	}
	return b.Base64Decode([]byte(x))
}

// JsonDecode decodes the buffer into interface v
func (b Buffer) JsonDecode(v interface{}) error {
	return json.NewDecoder(bytes.NewBuffer(b)).Decode(v)
}
<commit_msg>Remove unused function<commit_after>package buffer

import (
	"bytes"
	"encoding/base64"
	"encoding/binary"
	"encoding/json"
)

type Buffer []byte

func FromUint(v uint64) Buffer {
	data := make([]byte, 8)
	binary.BigEndian.PutUint64(data, v)
	return Buffer(bytes.TrimLeft(data, "\x00"))
}

func (b Buffer) Bytes() []byte {
	return []byte(b)
}

func (b Buffer) Len() int {
	return len(b)
}

func (b Buffer) Base64Encode() ([]byte, error) {
	enc := base64.RawURLEncoding
	out := make([]byte, enc.EncodedLen(len(b)))
	enc.Encode(out, b)
	return out, nil
}

func (b *Buffer) Base64Decode(v []byte) error {
	enc := base64.RawURLEncoding
	out := make([]byte, enc.DecodedLen(len(v)))
	enc.Decode(out, v)
	*b = Buffer(bytes.TrimRight(out, "\x00"))
	return nil
}

func (b Buffer) MarshalJSON() ([]byte, error) {
	v, err := b.Base64Encode()
	if err != nil {
		return nil, err
	}
	return json.Marshal(string(v))
}

func (b *Buffer) UnmarshalJSON(data []byte) error {
	var x string
	if err := json.Unmarshal(data, &x); err != nil {
		return err
	}
	return b.Base64Decode([]byte(x))
}
<|endoftext|>


<commit_before>package github

import (
	"strings"

	log "github.com/Sirupsen/logrus"
	"github.com/crosbymichael/octokat"
)

func (g GitHub) DcoVerified(prHook *octokat.PullRequestHook) (bool, error) {
	// we only want the prs that are opened/synchronized
	if !prHook.IsOpened() && !prHook.IsSynchronize() {
		return false, nil
	}

	// get the PR
	pr := prHook.PullRequest
	repo := getRepo(prHook.Repo)

	// check if this is a bump branch, then we don't want to check sig
	if pr.Base.Ref == "release" {
		return true, nil
	}

	content, err := g.getContent(repo, prHook.Number, true)
	if err != nil {
		return false, err
	}

	// we only want apply labels
	// to opened pull requests
	var labels []string

	//check if it's a proposal
	isProposal := strings.Contains(strings.ToLower(pr.Title), "proposal")
	switch {
	case isProposal:
		labels = []string{"1-needs-design-review"}
	case content.IsDocsOnly():
		labels = []string{"3-needs-docs-review"}
	default:
		labels = []string{"0-needs-triage"}
	}

	if labelOs(pr, "windows", content.OnlyWindows) {
		labels = append(labels, "os/windows")
	}
	if labelOs(pr, "freebsd", content.OnlyFreebsd) {
		labels = append(labels, "os/freebsd")
	}

	// add labels if there are any
	// only add labels to new PRs not sync
	if len(labels) > 0 && prHook.IsOpened() {
		log.Debugf("Adding labels %#v to pr %d", labels, prHook.Number)

		if err := g.addLabel(repo, prHook.Number, labels...); err != nil {
			return false, err
		}

		log.Infof("Added labels %#v to pr %d", labels, prHook.Number)
	}

	var verified bool

	if content.CommitsSigned() {
		if err := g.removeLabel(repo, prHook.Number, "dco/no"); err != nil {
			return false, err
		}

		if err := g.removeComment(repo, pr, "sign your commits", content); err != nil {
			return false, err
		}

		if err := g.successStatus(repo, pr.Head.Sha, "docker/dco-signed", "All commits signed"); err != nil {
			return false, err
		}

		verified = true
	} else {
		if err := g.addLabel(repo, prHook.Number, "dco/no"); err != nil {
			return false, err
		}

		if err := g.addDCOUnsignedComment(repo, pr, content); err != nil {
			return false, err
		}

		if err := g.failureStatus(repo, pr.Head.Sha, "docker/dco-signed", "Some commits without signature", "https://github.com/docker/docker/blob/master/CONTRIBUTING.md#sign-your-work"); err != nil {
			return false, err
		}
	}

	return verified, nil
}

func getRepo(repo *octokat.Repository) octokat.Repo {
	return octokat.Repo{
		Name:     repo.Name,
		UserName: repo.Owner.Login,
	}
}

func labelOs(pr *octokat.PullRequest, os string, fileChecker func() bool) bool {
	return strings.Contains(strings.ToLower(pr.Title), os) ||
		strings.Contains(strings.ToLower(pr.Body), os) ||
		fileChecker()
}
<commit_msg>Revert "Remove status/ prefix on labels"<commit_after>package github

import (
	"strings"

	log "github.com/Sirupsen/logrus"
	"github.com/crosbymichael/octokat"
)

func (g GitHub) DcoVerified(prHook *octokat.PullRequestHook) (bool, error) {
	// we only want the prs that are opened/synchronized
	if !prHook.IsOpened() && !prHook.IsSynchronize() {
		return false, nil
	}

	// get the PR
	pr := prHook.PullRequest
	repo := getRepo(prHook.Repo)

	// check if this is a bump branch, then we don't want to check sig
	if pr.Base.Ref == "release" {
		return true, nil
	}

	content, err := g.getContent(repo, prHook.Number, true)
	if err != nil {
		return false, err
	}

	// we only want apply labels
	// to opened pull requests
	var labels []string

	//check if it's a proposal
	isProposal := strings.Contains(strings.ToLower(pr.Title), "proposal")
	switch {
	case isProposal:
		labels = []string{"status/1-needs-design-review"}
	case content.IsDocsOnly():
		labels = []string{"status/3-needs-docs-review"}
	default:
		labels = []string{"status/0-needs-triage"}
	}

	if labelOs(pr, "windows", content.OnlyWindows) {
		labels = append(labels, "os/windows")
	}
	if labelOs(pr, "freebsd", content.OnlyFreebsd) {
		labels = append(labels, "os/freebsd")
	}

	// add labels if there are any
	// only add labels to new PRs not sync
	if len(labels) > 0 && prHook.IsOpened() {
		log.Debugf("Adding labels %#v to pr %d", labels, prHook.Number)

		if err := g.addLabel(repo, prHook.Number, labels...); err != nil {
			return false, err
		}

		log.Infof("Added labels %#v to pr %d", labels, prHook.Number)
	}

	var verified bool

	if content.CommitsSigned() {
		if err := g.removeLabel(repo, prHook.Number, "dco/no"); err != nil {
			return false, err
		}

		if err := g.removeComment(repo, pr, "sign your commits", content); err != nil {
			return false, err
		}

		if err := g.successStatus(repo, pr.Head.Sha, "docker/dco-signed", "All commits signed"); err != nil {
			return false, err
		}

		verified = true
	} else {
		if err := g.addLabel(repo, prHook.Number, "dco/no"); err != nil {
			return false, err
		}

		if err := g.addDCOUnsignedComment(repo, pr, content); err != nil {
			return false, err
		}

		if err := g.failureStatus(repo, pr.Head.Sha, "docker/dco-signed", "Some commits without signature", "https://github.com/docker/docker/blob/master/CONTRIBUTING.md#sign-your-work"); err != nil {
			return false, err
		}
	}

	return verified, nil
}

func getRepo(repo *octokat.Repository) octokat.Repo {
	return octokat.Repo{
		Name:     repo.Name,
		UserName: repo.Owner.Login,
	}
}

func labelOs(pr *octokat.PullRequest, os string, fileChecker func() bool) bool {
	return strings.Contains(strings.ToLower(pr.Title), os) ||
		strings.Contains(strings.ToLower(pr.Body), os) ||
		fileChecker()
}
<|endoftext|>


<commit_before>package lib

import (
	"archive/tar"
	"compress/gzip"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"path"
	"strings"
	"time"

	"github.com/google/go-github/github"
	"golang.org/x/oauth2"
)

const (
	githubDownloadTimeoutSecs = 300
)

// CodeFetcher represents an object capable of fetching code and returning a
// gzip-compressed tarball io.Reader
type CodeFetcher interface {
	GetCommitSHA(string, string, string) (string, error)
	Get(string, string, string) (io.Reader, error)
}

// GitHubFetcher represents a github data fetcher
type GitHubFetcher struct {
	c *github.Client
}

// NewGitHubFetcher returns a new github fetcher
func NewGitHubFetcher(token string) *GitHubFetcher {
	ts := oauth2.StaticTokenSource(&oauth2.Token{AccessToken: token})
	tc := oauth2.NewClient(oauth2.NoContext, ts)
	gf := &GitHubFetcher{
		c: github.NewClient(tc),
	}
	return gf
}

// GetCommitSHA returns the commit SHA for a reference
func (gf *GitHubFetcher) GetCommitSHA(owner string, repo string, ref string) (string, error) {
	csha, _, err := gf.c.Repositories.GetCommitSHA1(owner, repo, ref, "")
	return csha, err
}

// Get fetches contents of GitHub repo and returns the processed contents as
// an in-memory io.Reader.
func (gf *GitHubFetcher) Get(owner string, repo string, ref string) (tarball io.Reader, err error) {
	opt := &github.RepositoryContentGetOptions{
		Ref: ref,
	}
	url, resp, err := gf.c.Repositories.GetArchiveLink(owner, repo, github.Tarball, opt)
	if err != nil {
		return nil, fmt.Errorf("error getting archive link: %v", err)
	}
	if resp.StatusCode > 399 {
		return nil, fmt.Errorf("error status when getting archive link: %v", resp.Status)
	}
	if url == nil {
		return nil, fmt.Errorf("url is nil")
	}
	return gf.getArchive(url)
}

func (gf *GitHubFetcher) getArchive(archiveURL *url.URL) (io.Reader, error) {
	hc := http.Client{
		Timeout: githubDownloadTimeoutSecs * time.Second,
	}
	hr, err := http.NewRequest("GET", archiveURL.String(), nil)
	if err != nil {
		return nil, fmt.Errorf("error creating http request: %v", err)
	}
	resp, err := hc.Do(hr)
	if err != nil {
		return nil, fmt.Errorf("error performing archive http request: %v", err)
	}
	if resp == nil {
		return nil, fmt.Errorf("error getting archive: response is nil")
	}
	if resp.StatusCode > 299 {
		return nil, fmt.Errorf("archive http request failed: %v", resp.StatusCode)
	}
	return newTarPrefixStripper(resp.Body), nil
}

func (gf *GitHubFetcher) debugWriteTar(contents []byte) {
	f, err := ioutil.TempFile("", "output-tar")
	defer f.Close()
	log.Printf("debug: saving tar output to %v", f.Name())
	_, err = f.Write(contents)
	if err != nil {
		log.Printf("debug: error writing tar output: %v", err)
	}
}

// tarPrefixStripper removes a random path that Github prefixes its
// archives with.
type tarPrefixStripper struct {
	tarball          io.ReadCloser
	pipeReader       *io.PipeReader
	pipeWriter       *io.PipeWriter
	strippingStarted bool
}

func newTarPrefixStripper(tarball io.ReadCloser) io.Reader {
	reader, writer := io.Pipe()
	return &tarPrefixStripper{
		tarball:    tarball,
		pipeReader: reader,
		pipeWriter: writer,
	}
}

func (t *tarPrefixStripper) Read(p []byte) (n int, err error) {
	if !t.strippingStarted {
		go t.startStrippingPipe()
		t.strippingStarted = true
	}
	return t.pipeReader.Read(p)
}

func (t *tarPrefixStripper) processHeader(h *tar.Header) (bool, error) {
	// metadata file, ignore
	if h.Name == "pax_global_header" {
		return true, nil
	}
	if path.IsAbs(h.Name) {
		return true, fmt.Errorf("archive contains absolute path: %v", h.Name)
	}

	// top-level directory entry
	spath := strings.Split(h.Name, "/")
	if len(spath) == 2 && spath[1] == "" {
		return true, nil
	}
	h.Name = strings.Join(spath[1:len(spath)], "/")

	return false, nil
}

func (t *tarPrefixStripper) startStrippingPipe() {
	gzr, err := gzip.NewReader(t.tarball)
	if err != nil {
		t.pipeWriter.CloseWithError(err)
		return
	}

	tarball := tar.NewReader(gzr)
	outTarball := tar.NewWriter(t.pipeWriter)

	closeFunc := func(e error) {
		outTarball.Close()
		t.pipeWriter.CloseWithError(e)
		t.tarball.Close()
	}

	for {
		header, err := tarball.Next()
		if err == io.EOF {
			closeFunc(nil)
			return
		}
		if err != nil {
			closeFunc(err)
			return
		}

		skip, err := t.processHeader(header)
		if err != nil {
			closeFunc(err)
			return
		}
		if skip {
			continue
		}

		if err := outTarball.WriteHeader(header); err != nil {
			closeFunc(err)
			return
		}
		if _, err := io.Copy(outTarball, tarball); err != nil {
			closeFunc(err)
			return
		}
		if err := outTarball.Flush(); err != nil {
			closeFunc(err)
			return
		}
	}
}
<commit_msg>fix for go-github upgrade<commit_after>package lib

import (
	"archive/tar"
	"compress/gzip"
	"context"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"path"
	"strings"
	"time"

	"github.com/google/go-github/github"
	"golang.org/x/oauth2"
)

const (
	githubDownloadTimeoutSecs = 300
)

// CodeFetcher represents an object capable of fetching code and returning a
// gzip-compressed tarball io.Reader
type CodeFetcher interface {
	GetCommitSHA(string, string, string) (string, error)
	Get(string, string, string) (io.Reader, error)
}

// GitHubFetcher represents a github data fetcher
type GitHubFetcher struct {
	c *github.Client
}

// NewGitHubFetcher returns a new github fetcher
func NewGitHubFetcher(token string) *GitHubFetcher {
	ts := oauth2.StaticTokenSource(&oauth2.Token{AccessToken: token})
	tc := oauth2.NewClient(oauth2.NoContext, ts)
	gf := &GitHubFetcher{
		c: github.NewClient(tc),
	}
	return gf
}

// GetCommitSHA returns the commit SHA for a reference
func (gf *GitHubFetcher) GetCommitSHA(owner string, repo string, ref string) (string, error) {
	ctx, cf := context.WithTimeout(context.Background(), githubDownloadTimeoutSecs*time.Second)
	defer cf()
	csha, _, err := gf.c.Repositories.GetCommitSHA1(ctx, owner, repo, ref, "")
	return csha, err
}

// Get fetches contents of GitHub repo and returns the processed contents as
// an in-memory io.Reader.
func (gf *GitHubFetcher) Get(owner string, repo string, ref string) (tarball io.Reader, err error) {
	opt := &github.RepositoryContentGetOptions{
		Ref: ref,
	}
	ctx, cf := context.WithTimeout(context.Background(), githubDownloadTimeoutSecs*time.Second)
	defer cf()
	url, resp, err := gf.c.Repositories.GetArchiveLink(ctx, owner, repo, github.Tarball, opt)
	if err != nil {
		return nil, fmt.Errorf("error getting archive link: %v", err)
	}
	if resp.StatusCode > 399 {
		return nil, fmt.Errorf("error status when getting archive link: %v", resp.Status)
	}
	if url == nil {
		return nil, fmt.Errorf("url is nil")
	}
	return gf.getArchive(url)
}

func (gf *GitHubFetcher) getArchive(archiveURL *url.URL) (io.Reader, error) {
	hc := http.Client{
		Timeout: githubDownloadTimeoutSecs * time.Second,
	}
	hr, err := http.NewRequest("GET", archiveURL.String(), nil)
	if err != nil {
		return nil, fmt.Errorf("error creating http request: %v", err)
	}
	resp, err := hc.Do(hr)
	if err != nil {
		return nil, fmt.Errorf("error performing archive http request: %v", err)
	}
	if resp == nil {
		return nil, fmt.Errorf("error getting archive: response is nil")
	}
	if resp.StatusCode > 299 {
		return nil, fmt.Errorf("archive http request failed: %v", resp.StatusCode)
	}
	return newTarPrefixStripper(resp.Body), nil
}

func (gf *GitHubFetcher) debugWriteTar(contents []byte) {
	f, err := ioutil.TempFile("", "output-tar")
	defer f.Close()
	log.Printf("debug: saving tar output to %v", f.Name())
	_, err = f.Write(contents)
	if err != nil {
		log.Printf("debug: error writing tar output: %v", err)
	}
}

// tarPrefixStripper removes a random path that Github prefixes its
// archives with.
type tarPrefixStripper struct {
	tarball          io.ReadCloser
	pipeReader       *io.PipeReader
	pipeWriter       *io.PipeWriter
	strippingStarted bool
}

func newTarPrefixStripper(tarball io.ReadCloser) io.Reader {
	reader, writer := io.Pipe()
	return &tarPrefixStripper{
		tarball:    tarball,
		pipeReader: reader,
		pipeWriter: writer,
	}
}

func (t *tarPrefixStripper) Read(p []byte) (n int, err error) {
	if !t.strippingStarted {
		go t.startStrippingPipe()
		t.strippingStarted = true
	}
	return t.pipeReader.Read(p)
}

func (t *tarPrefixStripper) processHeader(h *tar.Header) (bool, error) {
	// metadata file, ignore
	if h.Name == "pax_global_header" {
		return true, nil
	}
	if path.IsAbs(h.Name) {
		return true, fmt.Errorf("archive contains absolute path: %v", h.Name)
	}

	// top-level directory entry
	spath := strings.Split(h.Name, "/")
	if len(spath) == 2 && spath[1] == "" {
		return true, nil
	}
	h.Name = strings.Join(spath[1:len(spath)], "/")

	return false, nil
}

func (t *tarPrefixStripper) startStrippingPipe() {
	gzr, err := gzip.NewReader(t.tarball)
	if err != nil {
		t.pipeWriter.CloseWithError(err)
		return
	}

	tarball := tar.NewReader(gzr)
	outTarball := tar.NewWriter(t.pipeWriter)

	closeFunc := func(e error) {
		outTarball.Close()
		t.pipeWriter.CloseWithError(e)
		t.tarball.Close()
	}

	for {
		header, err := tarball.Next()
		if err == io.EOF {
			closeFunc(nil)
			return
		}
		if err != nil {
			closeFunc(err)
			return
		}

		skip, err := t.processHeader(header)
		if err != nil {
			closeFunc(err)
			return
		}
		if skip {
			continue
		}

		if err := outTarball.WriteHeader(header); err != nil {
			closeFunc(err)
			return
		}
		if _, err := io.Copy(outTarball, tarball); err != nil {
			closeFunc(err)
			return
		}
		if err := outTarball.Flush(); err != nil {
			closeFunc(err)
			return
		}
	}
}
<|endoftext|>


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

package main

/*
*  File: gonew_main.go
*  Author: Bryan Matsuo [bmatsuo@soe.ucsc.edu]
*  Created: Sat Jul  2 19:17:53 PDT 2011
*  Usage: gonew [options]
 */
import (
	"github.com/bmatsuo/gonew/config"
	"github.com/bmatsuo/gonew/project"
	"github.com/bmatsuo/gonew/templates"

	"bufio"
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"reflect"
	"strings"
	"syscall"
	"text/template"
	"time"
	"unicode"
)

// The directory containing Gonew's source code.
var GonewRoot string // The Gonew source directory
func FindGonew() error {
	gopath := os.Getenv("GOPATH")
	if gopath == "" {
		return fmt.Errorf("GOPATH is not set")
	}
	gopath = strings.SplitN(gopath, ":", 2)[0]
	GonewRoot = filepath.Join(gopath, "src", "github.com", "bmatsuo", "gonew")
	stat, err := os.Stat(GonewRoot)
	if err == nil && !stat.IsDir() {
		err = fmt.Errorf("file is not a directory: %s", GonewRoot)
	}
	return err
}

func check(err error, v ...interface{}) error {
	if err != nil {
		if len(v) == 0 {
			fmt.Println(err)
		} else {
			fmt.Printf("%s: %v", fmt.Sprint(v...), err)
		}
	}
	return err
}

func checkFatal(err error, v ...interface{}) {
	if check(err, v...) != nil {
		os.Exit(1)
	}
}

func logJson(v ...interface{}) {
	w := make([]interface{}, 0, len(v))
	w = append(w, v[:len(v)-1]...)
	p, _ := json.MarshalIndent(v[len(v)-1], " ", "\t")
	w = append(w, string(p))
	fmt.Println(w...)
}

func executeHooks(ts templates.Interface, tenv templates.Environment, hooks ...*config.HookConfig) {
	for _, hook := range hooks {
		cwd, err := tenv.RenderTextAsString(ts, "cwd_", hook.Cwd)
		checkFatal(err, "hook cwd template")
		// fmt.Println("cd", cwd)
		for _, _cmd := range hook.Commands {
			cmd, err := tenv.RenderTextAsString(ts, "cmd_", _cmd)
			checkFatal(err, "hook template")
			// fmt.Println("bash", "-c", cmd)
			shell := exec.Command("bash", "-c", cmd)
			shell.Dir = cwd
			shell.Stdin = os.Stdin
			shell.Stdout = os.Stdout
			shell.Stderr = os.Stderr
			checkFatal(shell.Run(), "hook") // TODO clean exit
		}
	}
}

type File struct {
	path    string
	content []byte
}

func funcs(env *config.Environment) template.FuncMap {
	return template.FuncMap{
		"name":  func() string { return env.User.Name },
		"email": func() string { return env.User.Email },

		"year": func() string { return time.Now().Format("2006") },
		"time": func(format ...string) string {
			if len(format) == 0 {
				format = append(format, time.RFC1123)
			}
			return time.Now().Format(format[0])
		},
		"date": func(format ...string) string {
			if len(format) == 0 {
				format = append(format, "Jan 02, 2006")
			}
			return time.Now().Format(format[0])
		},

		"import": func(pkgs ...string) string {
			if len(pkgs) == 0 {
				return `import ()`
			}
			if len(pkgs) == 1 {
				return `import "` + pkgs[0] + `"`
			}
			s := "import (\n"
			for _, pkg := range pkgs {
				s += "\t" + pkg + "\n"
			}
			s += ")"
			return s
		},
		"equal": func(v1, v2 interface{}) bool {
			return reflect.DeepEqual(reflect.ValueOf(v1), reflect.ValueOf(v2))
		},
	}
}

type options struct {
	env     string
	project string
	target  string
	pkg     string
	config  string
}

func parseOptions() *options {
	opts := new(options)
	fs := flag.NewFlagSet(os.Args[0], flag.ExitOnError)
	fs.StringVar(&opts.env, "env", "", "specify a user environment")
	fs.StringVar(&opts.pkg, "pkg", "", "specify a package name")
	fs.StringVar(&opts.config, "config", "", "specify config path")
	fs.Parse(os.Args[1:])

	args := fs.Args()
	if len(args) < 1 {
		fmt.Fprintln(os.Stderr, "usage:", os.Args[0], "[options] [project] target")
		os.Exit(1)
	}
	if len(args) == 1 {
		opts.target = args[0]
	} else {
		opts.project, opts.target = args[0], args[1]
	}
	if opts.pkg == "" {
		opts.pkg = opts.target
	}

	return opts
}

func readLine(r *bufio.Reader) (string, error) {
	fmt.Print("Enter your name: ")
	p, _, err := r.ReadLine()
	line := strings.TrimFunc(string(p), unicode.IsSpace)
	return line, err
}

func initConfig(path string) (conf *config.Gonew, err error) {
	if path == "" {
		home := os.Getenv("HOME")
		path = filepath.Join(home, ".config", "gonew.json")
	}
	conf = new(config.Gonew)
	err = conf.UnmarshalFileJSON(path)
	if err == nil {
		return
	}
	switch perr, ok := err.(*os.PathError); {
	case !ok:
		return
	case perr.Err == syscall.ENOENT || perr.Err == os.ErrNotExist:
		fmt.Fprintln(os.Stderr, "config not found -- generating")

		var name string
		var email string
		var baseImportPath string
		bufr := bufio.NewReader(os.Stdin)
		fmt.Print("Enter your name: ")
		name, err = readLine(bufr)
		checkFatal(err)
		fmt.Print("Enter your email: ")
		email, err = readLine(bufr)
		checkFatal(err)
		fmt.Print("Base import path (e.g. github.com/bmatsuo): ")
		baseImportPath, err = readLine(bufr)
		checkFatal(err)

		examplePath := filepath.Join(GonewRoot, "gonew.json.example")
		checkFatal(conf.UnmarshalFileJSON(examplePath), "example config")
		conf.Environments = config.Environments{
			"default": &config.Environment{
				BaseImportPath: baseImportPath,
				User: &config.EnvironmentUserConfig{
					Name:  name,
					Email: email,
				},
			},
		}
		conf.Default.Environment = "default"
		err = conf.MarshalFileJSON(path)
	}
	return
}

func main() {
	checkFatal(FindGonew(), "root not found")

	// parse command line options/args
	opts := parseOptions()
	// read the config file
	conf, err := initConfig(opts.config)
	checkFatal(err, "config")

	// project metadata
	projectName := opts.target
	packageName := opts.pkg
	envName := opts.env
	if envName == "" {
		envName = conf.Default.Environment
	}
	projType := opts.project
	if projType == "" {
		projType = conf.Default.Project
	}

	// initialize project
	env, err := conf.Environment(envName)
	checkFatal(err)
	project.BaseImportPath = env.BaseImportPath
	proj := project.New(projectName, packageName, env)
	projContext := project.Context("", "", proj)
	projTemplEnv := templates.Env(projContext)
	projConfig, err := conf.Project(projType)
	checkFatal(err)

	// initialize template environment
	ts := templates.New(".t2")
	checkFatal(ts.Funcs(funcs(env)), "templates")

	// read templates
	src := templates.SourceDirectory(filepath.Join(GonewRoot, "templates"))
	checkFatal(ts.Source(src), "templates")
	for i := len(conf.ExternalTemplates) - 1; i >= 0; i-- {
		src := templates.SourceDirectory(conf.ExternalTemplates[i])
		checkFatal(ts.Source(src), "external templates")
	}

	if projConfig.Hooks != nil {
		executeHooks(ts, projTemplEnv, projConfig.Hooks.Pre...)
	}

	// generate files. buffer all output then write.
	files := make([]*File, 0, len(projConfig.Files))
	for name, file := range projConfig.Files {
		_relpath, err := projTemplEnv.RenderTextAsString(ts, "pre_", file.Path)
		checkFatal(err, name)
		relpath := string(_relpath)
		filename := filepath.Base(relpath)
		filetype := file.Type

		fileContext := project.Context(filename, filetype, proj)
		fileTemplEnv := templates.Env(fileContext)
		fileBuf := new(bytes.Buffer)
		for _, t := range file.Templates {
			if nil != check(fileTemplEnv.Render(fileBuf, ts, t)) {
				fileBuf = nil
				break
			}
		}

		if fileBuf != nil {
			f := &File{relpath, fileBuf.Bytes()}
			files = append(files, f)
		} else {
			// TODO clean exit
		}
	}
	for _, file := range files {
		dir := filepath.Dir(file.path)

		// fmt.Println("mkdir", "-p", dir)
		err := os.MkdirAll(dir, 0755|os.ModeDir)
		checkFatal(err, file) // TODO clean exit

		// fmt.Println("cat", ">", file.path)
		// fmt.Println(string(file.content))
		writeMode := os.O_WRONLY|os.O_CREATE|os.O_EXCL // must create
		handle, err := os.OpenFile(file.path, writeMode, 0644)
		checkFatal(err, file) // TODO clean exit
		_, err = handle.Write(file.content)
		checkFatal(err, file) // TODO clean exit
		err = handle.Close()
	}

	if projConfig.Hooks != nil {
		// fmt.Println("POST")
		executeHooks(ts, projTemplEnv, projConfig.Hooks.Post...)
	}
}
<commit_msg>fix issues with initial config building<commit_after>// Copyright 2011, Bryan Matsuo. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

/*
*  File: gonew_main.go
*  Created: Sat Jul  2 19:17:53 PDT 2011
 */
import (
	"github.com/bmatsuo/gonew/config"
	"github.com/bmatsuo/gonew/project"
	"github.com/bmatsuo/gonew/templates"

	"bufio"
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"reflect"
	"strings"
	"syscall"
	"text/template"
	"time"
	"unicode"
)

// The directory containing Gonew's source code.
var GonewRoot string // The Gonew source directory
func FindGonew() error {
	gopath := os.Getenv("GOPATH")
	if gopath == "" {
		return fmt.Errorf("GOPATH is not set")
	}
	gopath = strings.SplitN(gopath, ":", 2)[0]
	GonewRoot = filepath.Join(gopath, "src", "github.com", "bmatsuo", "gonew")
	stat, err := os.Stat(GonewRoot)
	if err == nil && !stat.IsDir() {
		err = fmt.Errorf("file is not a directory: %s", GonewRoot)
	}
	return err
}

func check(err error, v ...interface{}) error {
	if err != nil {
		if len(v) == 0 {
			fmt.Println(err)
		} else {
			fmt.Printf("%s: %v", fmt.Sprint(v...), err)
		}
	}
	return err
}

func checkFatal(err error, v ...interface{}) {
	if check(err, v...) != nil {
		os.Exit(1)
	}
}

func logJson(v ...interface{}) {
	w := make([]interface{}, 0, len(v))
	w = append(w, v[:len(v)-1]...)
	p, _ := json.MarshalIndent(v[len(v)-1], " ", "\t")
	w = append(w, string(p))
	fmt.Println(w...)
}

func executeHooks(ts templates.Interface, tenv templates.Environment, hooks ...*config.HookConfig) {
	for _, hook := range hooks {
		cwd, err := tenv.RenderTextAsString(ts, "cwd_", hook.Cwd)
		checkFatal(err, "hook cwd template")
		// fmt.Println("cd", cwd)
		for _, _cmd := range hook.Commands {
			cmd, err := tenv.RenderTextAsString(ts, "cmd_", _cmd)
			checkFatal(err, "hook template")
			// fmt.Println("bash", "-c", cmd)
			shell := exec.Command("bash", "-c", cmd)
			shell.Dir = cwd
			shell.Stdin = os.Stdin
			shell.Stdout = os.Stdout
			shell.Stderr = os.Stderr
			checkFatal(shell.Run(), "hook") // TODO clean exit
		}
	}
}

type File struct {
	path    string
	content []byte
}

func funcs(env *config.Environment) template.FuncMap {
	return template.FuncMap{
		"name":  func() string { return env.User.Name },
		"email": func() string { return env.User.Email },

		"year": func() string { return time.Now().Format("2006") },
		"time": func(format ...string) string {
			if len(format) == 0 {
				format = append(format, time.RFC1123)
			}
			return time.Now().Format(format[0])
		},
		"date": func(format ...string) string {
			if len(format) == 0 {
				format = append(format, "Jan 02, 2006")
			}
			return time.Now().Format(format[0])
		},

		"import": func(pkgs ...string) string {
			if len(pkgs) == 0 {
				return `import ()`
			}
			if len(pkgs) == 1 {
				return `import "` + pkgs[0] + `"`
			}
			s := "import (\n"
			for _, pkg := range pkgs {
				s += "\t" + pkg + "\n"
			}
			s += ")"
			return s
		},
		"equal": func(v1, v2 interface{}) bool {
			return reflect.DeepEqual(reflect.ValueOf(v1), reflect.ValueOf(v2))
		},
	}
}

type options struct {
	env     string
	project string
	target  string
	pkg     string
	config  string
}

func parseOptions() *options {
	opts := new(options)
	fs := flag.NewFlagSet(os.Args[0], flag.ExitOnError)
	fs.StringVar(&opts.env, "env", "", "specify a user environment")
	fs.StringVar(&opts.pkg, "pkg", "", "specify a package name")
	fs.StringVar(&opts.config, "config", "", "specify config path")
	fs.Parse(os.Args[1:])

	args := fs.Args()
	if len(args) < 1 {
		fmt.Fprintln(os.Stderr, "usage:", os.Args[0], "[options] [project] target")
		os.Exit(1)
	}
	if len(args) == 1 {
		opts.target = args[0]
	} else {
		opts.project, opts.target = args[0], args[1]
	}
	if opts.pkg == "" {
		opts.pkg = opts.target
	}

	return opts
}

func readLine(r *bufio.Reader, prompt string) (string, error) {
	fmt.Print(prompt)
	p, _, err := r.ReadLine()
	line := strings.TrimFunc(string(p), unicode.IsSpace)
	return line, err
}

func initConfig(path string) (conf *config.Gonew, err error) {
	if path == "" {
		home := os.Getenv("HOME")
		path = filepath.Join(home, ".config", "gonew.json")
	}
	conf = new(config.Gonew)
	err = conf.UnmarshalFileJSON(path)
	if err == nil {
		return
	}
	switch perr, ok := err.(*os.PathError); {
	case !ok:
		return
	case perr.Err == syscall.ENOENT || perr.Err == os.ErrNotExist:
		fmt.Fprintf(os.Stderr, "configuration not found at %q\n", path)
		fmt.Fprintln(os.Stderr)
		fmt.Fprintf(os.Stderr, "if you are migrating from an older version of Gonew check out the migration guide\n")
		fmt.Fprintf(os.Stderr, "\thttps://github.com/bmatsuo/gonew/blob/v2/MIGRATION.md\n")
		fmt.Fprintln(os.Stderr)
		fmt.Fprintf(os.Stderr, "otherwise, please take a moment to fill in the user information below\n")
		fmt.Fprintln(os.Stderr)

		var name string
		var email string
		var baseImportPath string
		bufr := bufio.NewReader(os.Stdin)
		name, err = readLine(bufr, "Your name: ")
		checkFatal(err)
		email, err = readLine(bufr, "Your email: ")
		checkFatal(err)
		baseImportPath, err = readLine(bufr, "Base import path (e.g. github.com/bmatsuo): ")
		checkFatal(err)

		examplePath := filepath.Join(GonewRoot, "gonew.json.example")
		checkFatal(conf.UnmarshalFileJSON(examplePath), "example config")
		conf.Environments = config.Environments{
			"default": &config.Environment{
				BaseImportPath: baseImportPath,
				User: &config.EnvironmentUserConfig{
					Name:  name,
					Email: email,
				},
			},
		}
		conf.Default.Environment = "default"
		err = conf.MarshalFileJSON(path)
	}
	return
}

func main() {
	checkFatal(FindGonew(), "root not found")

	// parse command line options/args
	opts := parseOptions()
	// read the config file
	conf, err := initConfig(opts.config)
	checkFatal(err, "config")

	// project metadata
	projectName := opts.target
	packageName := opts.pkg
	envName := opts.env
	if envName == "" {
		envName = conf.Default.Environment
	}
	projType := opts.project
	if projType == "" {
		projType = conf.Default.Project
	}

	// initialize project
	env, err := conf.Environment(envName)
	checkFatal(err)
	project.BaseImportPath = env.BaseImportPath
	proj := project.New(projectName, packageName, env)
	projContext := project.Context("", "", proj)
	projTemplEnv := templates.Env(projContext)
	projConfig, err := conf.Project(projType)
	checkFatal(err)

	// initialize template environment
	ts := templates.New(".t2")
	checkFatal(ts.Funcs(funcs(env)), "templates")

	// read templates
	src := templates.SourceDirectory(filepath.Join(GonewRoot, "templates"))
	checkFatal(ts.Source(src), "templates")
	for i := len(conf.ExternalTemplates) - 1; i >= 0; i-- {
		src := templates.SourceDirectory(conf.ExternalTemplates[i])
		checkFatal(ts.Source(src), "external templates")
	}

	if projConfig.Hooks != nil {
		executeHooks(ts, projTemplEnv, projConfig.Hooks.Pre...)
	}

	// generate files. buffer all output then write.
	files := make([]*File, 0, len(projConfig.Files))
	for name, file := range projConfig.Files {
		_relpath, err := projTemplEnv.RenderTextAsString(ts, "pre_", file.Path)
		checkFatal(err, name)
		relpath := string(_relpath)
		filename := filepath.Base(relpath)
		filetype := file.Type

		fileContext := project.Context(filename, filetype, proj)
		fileTemplEnv := templates.Env(fileContext)
		fileBuf := new(bytes.Buffer)
		for _, t := range file.Templates {
			if nil != check(fileTemplEnv.Render(fileBuf, ts, t)) {
				fileBuf = nil
				break
			}
		}

		if fileBuf != nil {
			f := &File{relpath, fileBuf.Bytes()}
			files = append(files, f)
		} else {
			// TODO clean exit
		}
	}
	for _, file := range files {
		dir := filepath.Dir(file.path)

		// fmt.Println("mkdir", "-p", dir)
		err := os.MkdirAll(dir, 0755|os.ModeDir)
		checkFatal(err, file) // TODO clean exit

		// fmt.Println("cat", ">", file.path)
		// fmt.Println(string(file.content))
		writeMode := os.O_WRONLY | os.O_CREATE | os.O_EXCL // must create
		handle, err := os.OpenFile(file.path, writeMode, 0644)
		checkFatal(err, file) // TODO clean exit
		_, err = handle.Write(file.content)
		checkFatal(err, file) // TODO clean exit
		err = handle.Close()
	}

	if projConfig.Hooks != nil {
		// fmt.Println("POST")
		executeHooks(ts, projTemplEnv, projConfig.Hooks.Post...)
	}
}
<|endoftext|>


<commit_before>package gopdf

import (
	"bytes"
	"errors"
	"io/ioutil"
	"log"
	"os"
	"testing"
)

func BenchmarkPdfWithImageHolder(b *testing.B) {

	err := initTesting()
	if err != nil {
		b.Error(err)
		return
	}

	pdf := GoPdf{}
	pdf.Start(Config{PageSize: Rect{W: 595.28, H: 841.89}}) //595.28, 841.89 = A4
	pdf.AddPage()
	err = pdf.AddTTFFont("LiberationSerif-Regular", "./test/res/LiberationSerif-Regular.ttf")
	if err != nil {
		b.Error(err)
		return
	}

	err = pdf.SetFont("LiberationSerif-Regular", "", 14)
	if err != nil {
		log.Print(err.Error())
		return
	}

	bytesOfImg, err := ioutil.ReadFile("./test/res/chilli.jpg")
	if err != nil {
		b.Error(err)
		return
	}

	imgH, err := ImageHolderByBytes(bytesOfImg)
	if err != nil {
		b.Error(err)
		return
	}
	for i := 0; i < b.N; i++ {
		pdf.ImageByHolder(imgH, 20.0, float64(i)*2.0, nil)
	}

	pdf.SetX(250)
	pdf.SetY(200)
	pdf.Cell(nil, "gopher and gopher")

	pdf.WritePdf("./test/out/image_bench.pdf")
}

func initTesting() error {
	err := os.MkdirAll("./test/out", 0777)
	if err != nil {
		return err
	}
	return nil
}

func TestPdfWithImageHolder(t *testing.T) {
	err := initTesting()
	if err != nil {
		t.Error(err)
		return
	}

	pdf := GoPdf{}
	pdf.Start(Config{PageSize: Rect{W: 595.28, H: 841.89}}) //595.28, 841.89 = A4
	pdf.AddPage()
	err = pdf.AddTTFFont("LiberationSerif-Regular", "./test/res/LiberationSerif-Regular.ttf")
	if err != nil {
		t.Error(err)
		return
	}

	err = pdf.SetFont("LiberationSerif-Regular", "", 14)
	if err != nil {
		log.Print(err.Error())
		return
	}

	bytesOfImg, err := ioutil.ReadFile("./test/res/PNG_transparency_demonstration_1.png")
	if err != nil {
		t.Error(err)
		return
	}

	imgH, err := ImageHolderByBytes(bytesOfImg)
	if err != nil {
		t.Error(err)
		return
	}

	err = pdf.ImageByHolder(imgH, 20.0, 20, nil)
	if err != nil {
		t.Error(err)
		return
	}

	err = pdf.ImageByHolder(imgH, 20.0, 200, nil)
	if err != nil {
		t.Error(err)
		return
	}

	pdf.SetX(250)
	pdf.SetY(200)
	pdf.Cell(nil, "gopher and gopher")

	pdf.WritePdf("./test/out/image_test.pdf")
}

func TestRetrievingNumberOfPdfPage(t *testing.T) {
	pdf := GoPdf{}
	pdf.Start(Config{PageSize: Rect{W: 595.28, H: 841.89}}) //595.28, 841.89 = A4
	if pdf.GetNumberOfPages() != 0 {
		t.Error("Invalid starting number of pages, should be 0")
		return
	}

	pdf.AddPage()
	err := pdf.AddTTFFont("LiberationSerif-Regular", "./test/res/LiberationSerif-Regular.ttf")
	if err != nil {
		t.Error(err)
		return
	}

	err = pdf.SetFont("LiberationSerif-Regular", "", 14)
	if err != nil {
		log.Print(err.Error())
		return
	}

	bytesOfImg, err := ioutil.ReadFile("./test/res/gopher01.jpg")
	if err != nil {
		t.Error(err)
		return
	}

	imgH, err := ImageHolderByBytes(bytesOfImg)
	if err != nil {
		t.Error(err)
		return
	}

	err = pdf.ImageByHolder(imgH, 20.0, 20, nil)
	if err != nil {
		t.Error(err)
		return
	}

	if pdf.GetNumberOfPages() != 1 {
		t.Error(err)
		return
	}

	pdf.SetX(250)
	pdf.SetY(200)
	pdf.Cell(nil, "gopher and gopher")

	pdf.AddPage()

	pdf.SetX(250)
	pdf.SetY(200)
	pdf.Cell(nil, "gopher and gopher again")

	if pdf.GetNumberOfPages() != 2 {
		t.Error(err)
		return
	}

	pdf.WritePdf("./test/out/number_of_pages_test.pdf")
}

func TestImageCrop(t *testing.T) {
	pdf := GoPdf{}
	pdf.Start(Config{PageSize: Rect{W: 595.28, H: 841.89}}) //595.28, 841.89 = A4
	if pdf.GetNumberOfPages() != 0 {
		t.Error("Invalid starting number of pages, should be 0")
		return
	}

	pdf.AddPage()
	err := pdf.AddTTFFont("LiberationSerif-Regular", "./test/res/LiberationSerif-Regular.ttf")
	if err != nil {
		t.Error(err)
		return
	}

	err = pdf.SetFont("LiberationSerif-Regular", "", 14)
	if err != nil {
		log.Print(err.Error())
		return
	}

	bytesOfImg, err := ioutil.ReadFile("./test/res/gopher01.jpg")
	if err != nil {
		t.Error(err)
		return
	}

	imgH, err := ImageHolderByBytes(bytesOfImg)
	if err != nil {
		t.Error(err)
		return
	}

	//err = pdf.ImageByHolder(imgH, 20.0, 20, nil)
	err = pdf.ImageByHolderWithOptions(imgH, ImageOptions{
		//VerticalFlip: true,
		//HorizontalFlip: true,
		Rect: &Rect{
			W: 100,
			H: 100,
		},
		Crop: &CropOptions{
			X:      0,
			Y:      0,
			Width:  10,
			Height: 100,
		},
	})
	if err != nil {
		t.Error(err)
		return
	}

	if pdf.GetNumberOfPages() != 1 {
		t.Error(err)
		return
	}

	pdf.SetX(250)
	pdf.SetY(200)
	pdf.Cell(nil, "gopher and gopher")

	pdf.AddPage()

	pdf.SetX(250)
	pdf.SetY(200)
	pdf.Cell(nil, "gopher and gopher again")

	if pdf.GetNumberOfPages() != 2 {
		t.Error(err)
		return
	}

	pdf.WritePdf("./test/out/image_crop.pdf")
}

/*
func TestBuffer(t *testing.T) {
	b := bytes.NewReader([]byte("ssssssss"))

	b1, err := ioutil.ReadAll(b)
	if err != nil {
		t.Error(err)
		return
	}
	fmt.Printf("->%s\n", string(b1))
	b.Seek(0, 0)
	b2, err := ioutil.ReadAll(b)
	if err != nil {
		t.Error(err)
		return
	}

	fmt.Printf("+>%s\n", string(b2))
}*/

func BenchmarkAddTTFFontByReader(b *testing.B) {
	ttf, err := os.Open("test/res/LiberationSerif-Regular.ttf")
	if err != nil {
		b.Error(err)
		return
	}
	defer ttf.Close()

	fontData, err := ioutil.ReadAll(ttf)
	if err != nil {
		b.Error(err)
		return
	}

	for n := 0; n < b.N; n++ {
		pdf := &GoPdf{}
		pdf.Start(Config{PageSize: Rect{W: 595.28, H: 841.89}}) //595.28, 841.89 = A4
		if err := pdf.AddTTFFontByReader("LiberationSerif-Regular", bytes.NewReader(fontData)); err != nil {
			return
		}
	}
}

func BenchmarkAddTTFFontData(b *testing.B) {
	ttf, err := os.Open("test/res/LiberationSerif-Regular.ttf")
	if err != nil {
		b.Error(err)
		return
	}
	defer ttf.Close()

	fontData, err := ioutil.ReadAll(ttf)
	if err != nil {
		b.Error(err)
		return
	}

	for n := 0; n < b.N; n++ {
		pdf := &GoPdf{}
		pdf.Start(Config{PageSize: Rect{W: 595.28, H: 841.89}}) //595.28, 841.89 = A4
		if err := pdf.AddTTFFontData("LiberationSerif-Regular", fontData); err != nil {
			return
		}
	}
}

func TestReuseFontData(t *testing.T) {
	ttf, err := os.Open("test/res/LiberationSerif-Regular.ttf")
	if err != nil {
		t.Error(err)
		return
	}
	defer ttf.Close()

	fontData, err := ioutil.ReadAll(ttf)
	if err != nil {
		t.Error(err)
		return
	}

	pdf1 := &GoPdf{}
	rst1, err := generatePDFBytesByAddTTFFontData(pdf1, fontData)
	if err != nil {
		t.Error(err)
		return
	}

	// Reuse the parsed font data.
	pdf2 := &GoPdf{}
	rst2, err := generatePDFBytesByAddTTFFontData(pdf2, fontData)
	if err != nil {
		t.Error(err)
		return
	}

	if bytes.Compare(rst1, rst2) != 0 {
		t.Error(errors.New("The generated files must be exactly the same."))
		return
	}

	if err := os.WriteFile("./test/out/result1_by_parsed_ttf_font.pdf", rst1, 0644); err != nil {
		t.Error(err)
		return
	}
	if err := os.WriteFile("./test/out/result2_by_parsed_ttf_font.pdf", rst1, 0644); err != nil {
		t.Error(err)
		return
	}
}

func generatePDFBytesByAddTTFFontData(pdf *GoPdf, fontData []byte) ([]byte, error) {
	pdf.Start(Config{PageSize: Rect{W: 595.28, H: 841.89}}) //595.28, 841.89 = A4
	if pdf.GetNumberOfPages() != 0 {
		return nil, errors.New("Invalid starting number of pages, should be 0")
	}

	if err := pdf.AddTTFFontData("LiberationSerif-Regular", fontData); err != nil {
		return nil, err
	}

	if err := pdf.SetFont("LiberationSerif-Regular", "", 14); err != nil {
		return nil, err
	}

	pdf.AddPage()
	if err := pdf.Text("Test PDF content."); err != nil {
		return nil, err
	}

	return pdf.GetBytesPdfReturnErr()
}

func TestWhiteTransparent(t *testing.T) {
	err := initTesting()
	if err != nil {
		t.Error(err)
		return
	}
	// create pdf.
	pdf := GoPdf{}
	pdf.Start(Config{PageSize: *PageSizeA4})
	pdf.AddPage()

	var glyphNotFoundOfLiberationSerif []rune
	err = pdf.AddTTFFontWithOption("LiberationSerif-Regular", "test/res/LiberationSerif-Regular.ttf", TtfOption{
		OnGlyphNotFound: func(r rune) {
			//log.Printf("glyph not found %c", r)
			glyphNotFoundOfLiberationSerif = append(glyphNotFoundOfLiberationSerif, r)
		},
	})
	if err != nil {
		t.Error(err)
		return
	}
	err = pdf.SetFont("LiberationSerif-Regular", "", 14)
	if err != nil {
		t.Error(err)
		return
	}
	// write text.
	op := CellOption{Align: Left | Middle}
	rect := Rect{W: 20, H: 30}
	pdf.SetX(350)
	pdf.SetY(50)
	err = pdf.Cell(&rect, "あい")
	//err = pdf.CellWithOption(&rect, "あい", op)
	//err = pdf.CellWithOption(&rect, "あ", op)
	//err = pdf.CellWithOption(&rect, "a", op)
	if err != nil {
		t.Error(err)
		return
	}
	pdf.SetY(100)
	err = pdf.CellWithOption(&rect, "abcdef.", op)
	if err != nil {
		t.Error(err)
		return
	}

	//coz あ and い  not contain in "test/res/LiberationSerif-Regular.ttf"
	if len(glyphNotFoundOfLiberationSerif) != 2 {
		t.Error(err)
		return
	}

	//pdf.SetNoCompression()
	err = pdf.WritePdf("./test/out/white_transparent.pdf")
	if err != nil {
		t.Error(err)
		return
	}

}
<commit_msg>comment code<commit_after>package gopdf

import (
	"bytes"
	"errors"
	"io/ioutil"
	"log"
	"os"
	"testing"
)

func BenchmarkPdfWithImageHolder(b *testing.B) {

	err := initTesting()
	if err != nil {
		b.Error(err)
		return
	}

	pdf := GoPdf{}
	pdf.Start(Config{PageSize: Rect{W: 595.28, H: 841.89}}) //595.28, 841.89 = A4
	pdf.AddPage()
	err = pdf.AddTTFFont("LiberationSerif-Regular", "./test/res/LiberationSerif-Regular.ttf")
	if err != nil {
		b.Error(err)
		return
	}

	err = pdf.SetFont("LiberationSerif-Regular", "", 14)
	if err != nil {
		log.Print(err.Error())
		return
	}

	bytesOfImg, err := ioutil.ReadFile("./test/res/chilli.jpg")
	if err != nil {
		b.Error(err)
		return
	}

	imgH, err := ImageHolderByBytes(bytesOfImg)
	if err != nil {
		b.Error(err)
		return
	}
	for i := 0; i < b.N; i++ {
		pdf.ImageByHolder(imgH, 20.0, float64(i)*2.0, nil)
	}

	pdf.SetX(250)
	pdf.SetY(200)
	pdf.Cell(nil, "gopher and gopher")

	pdf.WritePdf("./test/out/image_bench.pdf")
}

func initTesting() error {
	err := os.MkdirAll("./test/out", 0777)
	if err != nil {
		return err
	}
	return nil
}

func TestPdfWithImageHolder(t *testing.T) {
	err := initTesting()
	if err != nil {
		t.Error(err)
		return
	}

	pdf := GoPdf{}
	pdf.Start(Config{PageSize: Rect{W: 595.28, H: 841.89}}) //595.28, 841.89 = A4
	pdf.AddPage()
	err = pdf.AddTTFFont("LiberationSerif-Regular", "./test/res/LiberationSerif-Regular.ttf")
	if err != nil {
		t.Error(err)
		return
	}

	err = pdf.SetFont("LiberationSerif-Regular", "", 14)
	if err != nil {
		log.Print(err.Error())
		return
	}

	bytesOfImg, err := ioutil.ReadFile("./test/res/PNG_transparency_demonstration_1.png")
	if err != nil {
		t.Error(err)
		return
	}

	imgH, err := ImageHolderByBytes(bytesOfImg)
	if err != nil {
		t.Error(err)
		return
	}

	err = pdf.ImageByHolder(imgH, 20.0, 20, nil)
	if err != nil {
		t.Error(err)
		return
	}

	err = pdf.ImageByHolder(imgH, 20.0, 200, nil)
	if err != nil {
		t.Error(err)
		return
	}

	pdf.SetX(250)
	pdf.SetY(200)
	pdf.Cell(nil, "gopher and gopher")

	pdf.WritePdf("./test/out/image_test.pdf")
}

func TestRetrievingNumberOfPdfPage(t *testing.T) {
	pdf := GoPdf{}
	pdf.Start(Config{PageSize: Rect{W: 595.28, H: 841.89}}) //595.28, 841.89 = A4
	if pdf.GetNumberOfPages() != 0 {
		t.Error("Invalid starting number of pages, should be 0")
		return
	}

	pdf.AddPage()
	err := pdf.AddTTFFont("LiberationSerif-Regular", "./test/res/LiberationSerif-Regular.ttf")
	if err != nil {
		t.Error(err)
		return
	}

	err = pdf.SetFont("LiberationSerif-Regular", "", 14)
	if err != nil {
		log.Print(err.Error())
		return
	}

	bytesOfImg, err := ioutil.ReadFile("./test/res/gopher01.jpg")
	if err != nil {
		t.Error(err)
		return
	}

	imgH, err := ImageHolderByBytes(bytesOfImg)
	if err != nil {
		t.Error(err)
		return
	}

	err = pdf.ImageByHolder(imgH, 20.0, 20, nil)
	if err != nil {
		t.Error(err)
		return
	}

	if pdf.GetNumberOfPages() != 1 {
		t.Error(err)
		return
	}

	pdf.SetX(250)
	pdf.SetY(200)
	pdf.Cell(nil, "gopher and gopher")

	pdf.AddPage()

	pdf.SetX(250)
	pdf.SetY(200)
	pdf.Cell(nil, "gopher and gopher again")

	if pdf.GetNumberOfPages() != 2 {
		t.Error(err)
		return
	}

	pdf.WritePdf("./test/out/number_of_pages_test.pdf")
}

func TestImageCrop(t *testing.T) {
	pdf := GoPdf{}
	pdf.Start(Config{PageSize: Rect{W: 595.28, H: 841.89}}) //595.28, 841.89 = A4
	if pdf.GetNumberOfPages() != 0 {
		t.Error("Invalid starting number of pages, should be 0")
		return
	}

	pdf.AddPage()
	err := pdf.AddTTFFont("LiberationSerif-Regular", "./test/res/LiberationSerif-Regular.ttf")
	if err != nil {
		t.Error(err)
		return
	}

	err = pdf.SetFont("LiberationSerif-Regular", "", 14)
	if err != nil {
		log.Print(err.Error())
		return
	}

	bytesOfImg, err := ioutil.ReadFile("./test/res/gopher01.jpg")
	if err != nil {
		t.Error(err)
		return
	}

	imgH, err := ImageHolderByBytes(bytesOfImg)
	if err != nil {
		t.Error(err)
		return
	}

	//err = pdf.ImageByHolder(imgH, 20.0, 20, nil)
	err = pdf.ImageByHolderWithOptions(imgH, ImageOptions{
		//VerticalFlip: true,
		//HorizontalFlip: true,
		Rect: &Rect{
			W: 100,
			H: 100,
		},
		Crop: &CropOptions{
			X:      0,
			Y:      0,
			Width:  10,
			Height: 100,
		},
	})
	if err != nil {
		t.Error(err)
		return
	}

	if pdf.GetNumberOfPages() != 1 {
		t.Error(err)
		return
	}

	pdf.SetX(250)
	pdf.SetY(200)
	pdf.Cell(nil, "gopher and gopher")

	pdf.AddPage()

	pdf.SetX(250)
	pdf.SetY(200)
	pdf.Cell(nil, "gopher and gopher again")

	if pdf.GetNumberOfPages() != 2 {
		t.Error(err)
		return
	}

	pdf.WritePdf("./test/out/image_crop.pdf")
}

/*
func TestBuffer(t *testing.T) {
	b := bytes.NewReader([]byte("ssssssss"))

	b1, err := ioutil.ReadAll(b)
	if err != nil {
		t.Error(err)
		return
	}
	fmt.Printf("->%s\n", string(b1))
	b.Seek(0, 0)
	b2, err := ioutil.ReadAll(b)
	if err != nil {
		t.Error(err)
		return
	}

	fmt.Printf("+>%s\n", string(b2))
}*/

func BenchmarkAddTTFFontByReader(b *testing.B) {
	ttf, err := os.Open("test/res/LiberationSerif-Regular.ttf")
	if err != nil {
		b.Error(err)
		return
	}
	defer ttf.Close()

	fontData, err := ioutil.ReadAll(ttf)
	if err != nil {
		b.Error(err)
		return
	}

	for n := 0; n < b.N; n++ {
		pdf := &GoPdf{}
		pdf.Start(Config{PageSize: Rect{W: 595.28, H: 841.89}}) //595.28, 841.89 = A4
		if err := pdf.AddTTFFontByReader("LiberationSerif-Regular", bytes.NewReader(fontData)); err != nil {
			return
		}
	}
}

func BenchmarkAddTTFFontData(b *testing.B) {
	ttf, err := os.Open("test/res/LiberationSerif-Regular.ttf")
	if err != nil {
		b.Error(err)
		return
	}
	defer ttf.Close()

	fontData, err := ioutil.ReadAll(ttf)
	if err != nil {
		b.Error(err)
		return
	}

	for n := 0; n < b.N; n++ {
		pdf := &GoPdf{}
		pdf.Start(Config{PageSize: Rect{W: 595.28, H: 841.89}}) //595.28, 841.89 = A4
		if err := pdf.AddTTFFontData("LiberationSerif-Regular", fontData); err != nil {
			return
		}
	}
}

func TestReuseFontData(t *testing.T) {
	ttf, err := os.Open("test/res/LiberationSerif-Regular.ttf")
	if err != nil {
		t.Error(err)
		return
	}
	defer ttf.Close()

	fontData, err := ioutil.ReadAll(ttf)
	if err != nil {
		t.Error(err)
		return
	}

	pdf1 := &GoPdf{}
	rst1, err := generatePDFBytesByAddTTFFontData(pdf1, fontData)
	if err != nil {
		t.Error(err)
		return
	}

	// Reuse the parsed font data.
	pdf2 := &GoPdf{}
	rst2, err := generatePDFBytesByAddTTFFontData(pdf2, fontData)
	if err != nil {
		t.Error(err)
		return
	}

	if bytes.Compare(rst1, rst2) != 0 {
		t.Error(errors.New("The generated files must be exactly the same."))
		return
	}

	if err := os.WriteFile("./test/out/result1_by_parsed_ttf_font.pdf", rst1, 0644); err != nil {
		t.Error(err)
		return
	}
	if err := os.WriteFile("./test/out/result2_by_parsed_ttf_font.pdf", rst1, 0644); err != nil {
		t.Error(err)
		return
	}
}

func generatePDFBytesByAddTTFFontData(pdf *GoPdf, fontData []byte) ([]byte, error) {
	pdf.Start(Config{PageSize: Rect{W: 595.28, H: 841.89}}) //595.28, 841.89 = A4
	if pdf.GetNumberOfPages() != 0 {
		return nil, errors.New("Invalid starting number of pages, should be 0")
	}

	if err := pdf.AddTTFFontData("LiberationSerif-Regular", fontData); err != nil {
		return nil, err
	}

	if err := pdf.SetFont("LiberationSerif-Regular", "", 14); err != nil {
		return nil, err
	}

	pdf.AddPage()
	if err := pdf.Text("Test PDF content."); err != nil {
		return nil, err
	}

	return pdf.GetBytesPdfReturnErr()
}

func TestWhiteTransparent(t *testing.T) {
	err := initTesting()
	if err != nil {
		t.Error(err)
		return
	}
	// create pdf.
	pdf := GoPdf{}
	pdf.Start(Config{PageSize: *PageSizeA4})
	pdf.AddPage()

	var glyphNotFoundOfLiberationSerif []rune
	err = pdf.AddTTFFontWithOption("LiberationSerif-Regular", "test/res/LiberationSerif-Regular.ttf", TtfOption{
		OnGlyphNotFound: func(r rune) { //call when can not find glyph inside ttf file.
			glyphNotFoundOfLiberationSerif = append(glyphNotFoundOfLiberationSerif, r)
			//log.Printf("glyph not found %c", r)
		},
	})
	if err != nil {
		t.Error(err)
		return
	}
	err = pdf.SetFont("LiberationSerif-Regular", "", 14)
	if err != nil {
		t.Error(err)
		return
	}
	// write text.
	op := CellOption{Align: Left | Middle}
	rect := Rect{W: 20, H: 30}
	pdf.SetX(350)
	pdf.SetY(50)
	err = pdf.Cell(&rect, "あい")
	//err = pdf.CellWithOption(&rect, "あい", op)
	//err = pdf.CellWithOption(&rect, "あ", op)
	//err = pdf.CellWithOption(&rect, "a", op)
	if err != nil {
		t.Error(err)
		return
	}
	pdf.SetY(100)
	err = pdf.CellWithOption(&rect, "abcdef.", op)
	if err != nil {
		t.Error(err)
		return
	}

	//coz あ and い  not contain in "test/res/LiberationSerif-Regular.ttf"
	if len(glyphNotFoundOfLiberationSerif) != 2 {
		t.Error(err)
		return
	}

	//pdf.SetNoCompression()
	err = pdf.WritePdf("./test/out/white_transparent.pdf")
	if err != nil {
		t.Error(err)
		return
	}

}
<|endoftext|>


<commit_before>package goredirect

import (
	"fmt"
	"html/template"
	"net/http"
	"strings"
)

type Mapping struct {
	DstVCS                 string
	DstScheme              string
	DstHostname            string
	SrcToDstRepoPathMapper *StringMapper
}

func isGoGet(req *http.Request) bool {
	if req.URL.Query().Get("go-get") == "1" {
		return true
	}
	return false
}

func NewGoGetHandler(mappings []Mapping, defaultHandler http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		if isGoGet(req) {
			for _, mapping := range mappings {
				if mapping.tryServe(w, req) {
					return
				}
			}
			http.Error(w, "No mapping for go-get request", http.StatusNotFound)
		} else {
			if defaultHandler != nil {
				defaultHandler.ServeHTTP(w, req)
			} else {
				http.Error(w, "Not a go-get request and no default handler provided", http.StatusNotFound)
			}
		}
	})
}

func (m *Mapping) tryServe(w http.ResponseWriter, req *http.Request) bool {
	path := req.URL.Path
	srcHost := strings.Split(req.Host, ":")[0]

	dstRepoPath, srcRepoPath, _, err := m.SrcToDstRepoPathMapper.MapStringPrefix(path)
	if err != nil {
		return false
	}

	t, err := template.New("redirectTemplate").Parse(redirectTemplate)
	if err != nil {
		panic("error parsing template: " + err.Error())
	}

	err = t.Execute(w, templateParams{
		Root:         fmt.Sprintf("%s%s", srcHost, srcRepoPath),
		VCS:          m.DstVCS,
		RedirectRoot: fmt.Sprintf("%s://%s%s", m.DstScheme, m.DstHostname, dstRepoPath),
	})
	if err != nil {
		http.Error(w, "template execution error", http.StatusInternalServerError)
	}
	return true
}
<commit_msg>added comment<commit_after>package goredirect

import (
	"fmt"
	"html/template"
	"net/http"
	"strings"
)

type Mapping struct {
	DstVCS                 string
	DstScheme              string
	DstHostname            string
	SrcToDstRepoPathMapper *StringMapper
}

func isGoGet(req *http.Request) bool {
	if req.URL.Query().Get("go-get") == "1" {
		return true
	}
	return false
}

func NewGoGetHandler(mappings []Mapping, defaultHandler http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		if isGoGet(req) {
			for _, mapping := range mappings {
				if mapping.tryServe(w, req) {
					return
				}
			}
			http.Error(w, "No mapping for go-get request", http.StatusNotFound)
		} else {
			if defaultHandler != nil {
				defaultHandler.ServeHTTP(w, req)
			} else {
				http.Error(w, "Not a go-get request and no default handler provided", http.StatusNotFound)
			}
		}
	})
}

// Returns true if mapping input regex prefix-matches request URL
// (which indicates this mapping applies to this request), otherwise
// false.
func (m *Mapping) tryServe(w http.ResponseWriter, req *http.Request) bool {
	path := req.URL.Path
	srcHost := strings.Split(req.Host, ":")[0]

	dstRepoPath, srcRepoPath, _, err := m.SrcToDstRepoPathMapper.MapStringPrefix(path)
	if err != nil {
		return false
	}

	t, err := template.New("redirectTemplate").Parse(redirectTemplate)
	if err != nil {
		panic("error parsing template: " + err.Error())
	}

	err = t.Execute(w, templateParams{
		Root:         fmt.Sprintf("%s%s", srcHost, srcRepoPath),
		VCS:          m.DstVCS,
		RedirectRoot: fmt.Sprintf("%s://%s%s", m.DstScheme, m.DstHostname, dstRepoPath),
	})
	if err != nil {
		http.Error(w, "template execution error", http.StatusInternalServerError)
	}
	return true
}
<|endoftext|>


<commit_before>package zendesk

import (
	"fmt"
	"log"
	"time"

	gb "github.com/geckoboard/geckoboard-go"
	"github.com/geckoboard/zendesk_dataset/conf"
)

// TicketCount is the supported report template method name
const TicketCount = "ticket_counts"

var timeNow = time.Now()

// HandleReports takes a conf.Config and iterates over the Zendesk.Reports
// calling the method based on the Report.Name attribute if any errors
// occurs while processing a report it extracts the error and presents it
// to the user or prints that report was successfull and continues
// with the next report if any.
func HandleReports(c *conf.Config) {
	for _, r := range c.Zendesk.Reports {
		var rptError string

		switch r.Name {
		case TicketCount:
			if err := ticketCount(&r, c); err != nil {
				rptError = err.Error()
			}
		default:
			rptError = fmt.Sprintf("Report name %s was not found", r.Name)
		}

		if rptError == "" {
			log.Printf("INFO: Processing report '%s' completed successfully", r.DataSet)
		} else {
			log.Printf("ERRO: Processing report '%s' failed with: %s", r.DataSet, rptError)
		}
	}
}

func ticketCount(r *conf.Report, c *conf.Config) error {
	type GData struct {
		GroupedBy   string `json:"grouped_by"`
		TicketCount int    `json:"ticket_count"`
	}

	client := NewClient(&c.Zendesk.Auth, false)

	var gbData []GData

	if r.GroupBy.Key != "" {
		values := r.Filter.Values[r.GroupBy.Key]
		if len(values) == 0 {
			return fmt.Errorf("Group by values key '%s' returned no values to group by", r.GroupBy.Key)
		}

		delete(r.Filter.Values, r.GroupBy.Key)

		for _, v := range values {
			r.Filter.Values[r.GroupBy.Key] = []string{v}
			tp, err := client.SearchTickets(r.Filter.BuildQuery(&timeNow))

			if err != nil {
				return err
			}

			gbData = append(gbData, GData{GroupedBy: v, TicketCount: tp.Count})
		}
	} else {
		r.GroupBy.Name = "All"
		tp, err := client.SearchTickets(r.Filter.BuildQuery(&timeNow))

		if err != nil {
			return err
		}

		gbData = append(gbData, GData{GroupedBy: r.GroupBy.Name, TicketCount: tp.Count})
	}

	schema := gb.DataSet{
		ID: r.DataSet,
		Fields: gb.Fields{
			"grouped_by": gb.Field{
				Type: gb.StringFieldType,
				Name: r.GroupBy.DisplayName(),
			},
			"ticket_count": gb.Field{
				Type: gb.NumberFieldType,
				Name: "Ticket Count",
			},
		},
	}

	return pushToGeckoboard(&c.Geckoboard, &schema, gbData)
}

func pushToGeckoboard(c *conf.Geckoboard, schema *gb.DataSet, data interface{}) error {
	//Create the dataset schema
	gConf := gb.New(gb.Config{
		Key: c.APIKey,
		URL: c.URL,
	})

	err := schema.FindOrCreate(gConf)
	if err != nil {
		return err
	}

	err = schema.SendAll(gConf, data)
	if err != nil {
		return err
	}

	return nil
}
<commit_msg>Use error var and simplify if statements as per comments<commit_after>package zendesk

import (
	"fmt"
	"log"
	"time"

	gb "github.com/geckoboard/geckoboard-go"
	"github.com/geckoboard/zendesk_dataset/conf"
)

// TicketCount is the supported report template method name
const TicketCount = "ticket_counts"

var timeNow = time.Now()

// HandleReports takes a conf.Config and iterates over the Zendesk.Reports
// calling the method based on the Report.Name attribute if any errors
// occurs while processing a report it extracts the error and presents it
// to the user or prints that report was successfull and continues
// with the next report if any.
func HandleReports(c *conf.Config) {
	var err error

	for _, r := range c.Zendesk.Reports {

		switch r.Name {
		case TicketCount:
			err = ticketCount(&r, c)
		default:
			err = fmt.Errorf("Report name %s was not found", r.Name)
		}

		if err != nil {
			log.Printf("ERRO: Processing report '%s' failed with: %s", r.DataSet, err.Error())
			err = nil
		}

		log.Printf("INFO: Processing report '%s' completed successfully", r.DataSet)
	}
}

func ticketCount(r *conf.Report, c *conf.Config) error {
	type GData struct {
		GroupedBy   string `json:"grouped_by"`
		TicketCount int    `json:"ticket_count"`
	}

	client := NewClient(&c.Zendesk.Auth, false)

	var gbData []GData

	if r.GroupBy.Key != "" {
		values := r.Filter.Values[r.GroupBy.Key]
		if len(values) == 0 {
			return fmt.Errorf("Group by values key '%s' returned no values to group by", r.GroupBy.Key)
		}

		delete(r.Filter.Values, r.GroupBy.Key)

		for _, v := range values {
			r.Filter.Values[r.GroupBy.Key] = []string{v}
			tp, err := client.SearchTickets(r.Filter.BuildQuery(&timeNow))

			if err != nil {
				return err
			}

			gbData = append(gbData, GData{GroupedBy: v, TicketCount: tp.Count})
		}
	} else {
		r.GroupBy.Name = "All"
		tp, err := client.SearchTickets(r.Filter.BuildQuery(&timeNow))

		if err != nil {
			return err
		}

		gbData = append(gbData, GData{GroupedBy: r.GroupBy.Name, TicketCount: tp.Count})
	}

	schema := gb.DataSet{
		ID: r.DataSet,
		Fields: gb.Fields{
			"grouped_by": gb.Field{
				Type: gb.StringFieldType,
				Name: r.GroupBy.DisplayName(),
			},
			"ticket_count": gb.Field{
				Type: gb.NumberFieldType,
				Name: "Ticket Count",
			},
		},
	}

	return pushToGeckoboard(&c.Geckoboard, &schema, gbData)
}

func pushToGeckoboard(c *conf.Geckoboard, schema *gb.DataSet, data interface{}) error {
	//Create the dataset schema
	gConf := gb.New(gb.Config{
		Key: c.APIKey,
		URL: c.URL,
	})

	err := schema.FindOrCreate(gConf)
	if err != nil {
		return err
	}

	err = schema.SendAll(gConf, data)
	if err != nil {
		return err
	}

	return nil
}
<|endoftext|>