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

package cmd

import (
	"fmt"
	"os"

	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

var cfgFile string

// This represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
	Use:   "kafkactl",
	Short: "A brief description of your application",
	Long: `A longer description that spans multiple lines and likely contains
examples and usage of using your application. For example:

Cobra is a CLI library for Go that empowers applications.
This application is a tool to generate the needed files
to quickly create a Cobra application.`,
// Uncomment the following line if your bare application
// has an action associated with it:
//	Run: func(cmd *cobra.Command, args []string) { },
}

// Execute adds all child commands to the root command sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
	if err := RootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(-1)
	}
}

func init() {
	cobra.OnInitialize(initConfig)

	// Here you will define your flags and configuration settings.
	// Cobra supports Persistent Flags, which, if defined here,
	// will be global for your application.

	RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.kafkactl.yaml)")
	// Cobra also supports local flags, which will only run
	// when this action is called directly.
	RootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}

// initConfig reads in config file and ENV variables if set.
func initConfig() {
	if cfgFile != "" { // enable ability to specify config file via flag
		viper.SetConfigFile(cfgFile)
	}

	viper.SetConfigName(".kafkactl") // name of config file (without extension)
	viper.AddConfigPath("$HOME")  // adding home directory as first search path
	viper.AutomaticEnv()          // read in environment variables that match

	// If a config file is found, read it in.
	if err := viper.ReadInConfig(); err == nil {
		fmt.Println("Using config file:", viper.ConfigFileUsed())
	}
}
<commit_msg>root-cmd: Kafkactl description added<commit_after>// Copyright © 2016 NAME HERE <EMAIL ADDRESS>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cmd

import (
	"fmt"
	"os"

	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

var cfgFile string

// This represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
	Use:   "kafkactl",
	Short: "A simple REST client for the scheduler remote API",
	Long: `Kafkactl is a command line tool written in GO for controlling kafka scheduler
that runs on top of Apache Mesos.`,
}

// Execute adds all child commands to the root command sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
	if err := RootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(-1)
	}
}

func init() {
	cobra.OnInitialize(initConfig)

	// Here you will define your flags and configuration settings.
	// Cobra supports Persistent Flags, which, if defined here,
	// will be global for your application.

	RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.kafkactl.yaml)")
	// Cobra also supports local flags, which will only run
	// when this action is called directly.
	RootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}

// initConfig reads in config file and ENV variables if set.
func initConfig() {
	if cfgFile != "" { // enable ability to specify config file via flag
		viper.SetConfigFile(cfgFile)
	}

	viper.SetConfigName(".kafkactl") // name of config file (without extension)
	viper.AddConfigPath("$HOME")     // adding home directory as first search path
	viper.AutomaticEnv()             // read in environment variables that match

	// If a config file is found, read it in.
	if err := viper.ReadInConfig(); err == nil {
		fmt.Println("Using config file:", viper.ConfigFileUsed())
	}
}
<|endoftext|>


<commit_before>// The MIT License (MIT)
// Copyright (c) 2017 Matt Stratton
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

// Package cmd defines and implements command-line commands and flags
// used by probablyfine. Commands and flags are implemented using Cobra.
package cmd

import (
	"fmt"
	"os"
	"strings"

	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

// webdir is the path to the source files for the Hugo website
var webdir string = setWebdir()

// const webdir = "/Users/mattstratton/src/devopsdays-web"

var cfgFile string

// RootCmd represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
	Use:   "probablyfine",
	Short: "Run maintenance tasks for the devopsdays.org website",
	Long: `Command-line utilities for the devopsdays.org website
built with love by mattstratton in Go.

Complete documentation is available at https://github.com/mattstratton/probablyfine`,
	// Uncomment the following line if your bare application
	// has an action associated with it:
	//	Run: func(cmd *cobra.Command, args []string) { },
}

// Execute adds all child commands to the root command sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
	if err := RootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(-1)
	}
}

func init() {
	cobra.OnInitialize(initConfig)

	// Here you will define your flags and configuration settings.
	// Cobra supports Persistent Flags, which, if defined here,
	// will be global for your application.

	// RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.probablyfine.yaml)")
	// Cobra also supports local flags, which will only run
	// when this action is called directly.
	// RootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}

// initConfig reads in config file and ENV variables if set.
func initConfig() {
	if cfgFile != "" { // enable ability to specify config file via flag
		viper.SetConfigFile(cfgFile)
	}

	viper.SetConfigName(".probablyfine") // name of config file (without extension)
	viper.AddConfigPath("$HOME")         // adding home directory as first search path
	viper.AutomaticEnv()                 // read in environment variables that match

	// If a config file is found, read it in.
	if err := viper.ReadInConfig(); err == nil {
		fmt.Println("Using config file:", viper.ConfigFileUsed())
	}
}

func setWebdir() string {
	if os.Getenv("DODPATH") == "" {
		pwd, err := os.Getwd()
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
		return pwd
	} else {
		s := os.Getenv("DODPATH")
		s = strings.TrimSuffix(s, "/")
		s = strings.TrimSuffix(s, "\\")
		return s
	}
}
<commit_msg>add city and year flags<commit_after>// The MIT License (MIT)
// Copyright (c) 2017 Matt Stratton
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

// Package cmd defines and implements command-line commands and flags
// used by probablyfine. Commands and flags are implemented using Cobra.
package cmd

import (
	"fmt"
	"os"
	"strings"

	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

// webdir is the path to the source files for the Hugo website
var webdir string = setWebdir()

// const webdir = "/Users/mattstratton/src/devopsdays-web"

var cfgFile string
var cityFlag string
var yearFlag string

// RootCmd represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
	Use:   "probablyfine",
	Short: "Run maintenance tasks for the devopsdays.org website",
	Long: `Command-line utilities for the devopsdays.org website
built with love by mattstratton in Go.

Complete documentation is available at https://github.com/mattstratton/probablyfine`,
	// Uncomment the following line if your bare application
	// has an action associated with it:
	//	Run: func(cmd *cobra.Command, args []string) { },
}

// Execute adds all child commands to the root command sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
	if err := RootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(-1)
	}
}

func init() {
	cobra.OnInitialize(initConfig)
	RootCmd.PersistentFlags().StringVarP(&cityFlag, "city", "c", "", "city name")
	RootCmd.PersistentFlags().StringVarP(&yearFlag, "year", "y", "", "year")

	// Here you will define your flags and configuration settings.
	// Cobra supports Persistent Flags, which, if defined here,
	// will be global for your application.

	// RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.probablyfine.yaml)")
	// Cobra also supports local flags, which will only run
	// when this action is called directly.
	// RootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}

// initConfig reads in config file and ENV variables if set.
func initConfig() {
	if cfgFile != "" { // enable ability to specify config file via flag
		viper.SetConfigFile(cfgFile)
	}

	viper.SetConfigName(".probablyfine") // name of config file (without extension)
	viper.AddConfigPath("$HOME")         // adding home directory as first search path
	viper.AutomaticEnv()                 // read in environment variables that match

	// If a config file is found, read it in.
	if err := viper.ReadInConfig(); err == nil {
		fmt.Println("Using config file:", viper.ConfigFileUsed())
	}
}

func setWebdir() string {
	if os.Getenv("DODPATH") == "" {
		pwd, err := os.Getwd()
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
		return pwd
	} else {
		s := os.Getenv("DODPATH")
		s = strings.TrimSuffix(s, "/")
		s = strings.TrimSuffix(s, "\\")
		return s
	}
}
<|endoftext|>


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

package twodee

import (
	"encoding/json"
	"github.com/go-gl/mathgl/mgl32"
)

type SpritesheetFrame struct {
	Frame FrameConfig
}

type SpritesheetFrameConfig struct {
	sourceW float32
	sourceH float32
	textureX         float32
	textureY         float32
	textureW         float32
	textureH         float32
	textureOriginalW float32
	textureOriginalH float32
	pxPerUnit float32
}

func (c SpritesheetFrameConfig) ToSpritesheetFrame() *SpritesheetFrame {
	var (
		texX = c.textureX / c.textureOriginalW
		texY = c.textureY / c.textureOriginalH
		texW = c.textureW / c.textureOriginalW
		texH = c.textureH / c.textureOriginalH
	)
	var (
		texMove   = mgl32.Translate3D(texX, -texH-texY, 0.0)
		texScale  = mgl32.Scale3D(texW, texH, 1.0)
		texRotate = mgl32.HomogRotate3DZ(mgl32.DegToRad(0))
		texAdj    = texMove.Mul4(texScale).Mul4(texRotate).Transpose()
	)
	var (
		ptScale = mgl32.Scale3D(c.sourceW/c.pxPerUnit, c.sourceH/c.pxPerUnit, 1.0)
		ptAdj   = ptScale.Transpose()
	)
	return &SpritesheetFrame{
		Frame: FrameConfig{
			PointAdjustment:   ptAdj,
			TextureAdjustment: texAdj,
		},
	}
}

type Spritesheet struct {
	frames      map[string]*SpritesheetFrame
	TexturePath string
}

func NewSpritesheet(path string) *Spritesheet {
	return &Spritesheet{
		frames:      map[string]*SpritesheetFrame{},
		TexturePath: path,
	}
}

func (s *Spritesheet) GetFrame(name string) *SpritesheetFrame {
	var (
		present bool
	)
	if _, present = s.frames[name]; !present {
		return nil
	}
	return s.frames[name]
}

func (s *Spritesheet) AddFrame(name string, config SpritesheetFrameConfig) {
	s.frames[name] = config.ToSpritesheetFrame()
}

type texturePackerFloatCoords struct {
	X float32 `json:x,omitempty`
	Y float32 `json:y,omitempty`
}

type texturePackerIntCoords struct {
	X int `json:x,omitempty`
	Y int `json:y,omitempty`
	W int `json:w,omitempty`
	H int `json:h,omitempty`
}

type texturePackerFrame struct {
	Filename         string                   `json:filename`
	Frame            texturePackerIntCoords   `json:frame`
	Rotated          bool                     `json:rotated`
	Trimmed          bool                     `json:trimmed`
	SpriteSourceSize texturePackerIntCoords   `json:spriteSourceSize`
	SourceSize       texturePackerIntCoords   `json:sourceSize`
	Pivot            texturePackerFloatCoords `json:pivot`
}

type texturePackerMeta struct {
	Image  string                 `json:image`
	Format string                 `json:format`
	Size   texturePackerIntCoords `json:size`
	Scale  string                 `json:scale`
}

type texturePackerJSONArray struct {
	Frames []texturePackerFrame `json:frames`
	Meta   texturePackerMeta    `json:meta`
}

func ParseTexturePackerJSONArrayString(contents string, pxPerUnit float32) (s *Spritesheet, err error) {
	var (
		parsed texturePackerJSONArray
	)
	if err = json.Unmarshal([]byte(contents), &parsed); err != nil {
		return
	}
	s = NewSpritesheet(parsed.Meta.Image)
	for _, frame := range parsed.Frames {
		s.AddFrame(frame.Filename, SpritesheetFrameConfig{
			sourceW:          float32(frame.SpriteSourceSize.W),
			sourceH:          float32(frame.SpriteSourceSize.H),
			textureX:         float32(frame.Frame.X),
			textureY:         float32(frame.Frame.Y),
			textureW:         float32(frame.Frame.W),
			textureH:         float32(frame.Frame.H),
			textureOriginalW: float32(parsed.Meta.Size.W),
			textureOriginalH: float32(parsed.Meta.Size.H),
			pxPerUnit:        pxPerUnit,
		})
	}
	return
}
<commit_msg>Add width and height properties to frames<commit_after>// Copyright 2015 Arne Roomann-Kurrik
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package twodee

import (
	"encoding/json"
	"github.com/go-gl/mathgl/mgl32"
)

type SpritesheetFrame struct {
	Frame  FrameConfig
	Width  float32 // In units
	Height float32 // In units
}

type SpritesheetFrameConfig struct {
	sourceW          float32
	sourceH          float32
	textureX         float32
	textureY         float32
	textureW         float32
	textureH         float32
	textureOriginalW float32
	textureOriginalH float32
	pxPerUnit        float32
}

func (c SpritesheetFrameConfig) ToSpritesheetFrame() *SpritesheetFrame {
	var (
		texX = c.textureX / c.textureOriginalW
		texY = c.textureY / c.textureOriginalH
		texW = c.textureW / c.textureOriginalW
		texH = c.textureH / c.textureOriginalH
	)
	var (
		texMove   = mgl32.Translate3D(texX, -texH-texY, 0.0)
		texScale  = mgl32.Scale3D(texW, texH, 1.0)
		texRotate = mgl32.HomogRotate3DZ(mgl32.DegToRad(0))
		texAdj    = texMove.Mul4(texScale).Mul4(texRotate).Transpose()
	)
	var (
		ptScale = mgl32.Scale3D(c.sourceW/c.pxPerUnit, c.sourceH/c.pxPerUnit, 1.0)
		ptAdj   = ptScale.Transpose()
	)
	return &SpritesheetFrame{
		Frame: FrameConfig{
			PointAdjustment:   ptAdj,
			TextureAdjustment: texAdj,
		},
		Width:  c.sourceW / c.pxPerUnit,
		Height: c.sourceH / c.pxPerUnit,
	}
}

type Spritesheet struct {
	frames      map[string]*SpritesheetFrame
	TexturePath string
}

func NewSpritesheet(path string) *Spritesheet {
	return &Spritesheet{
		frames:      map[string]*SpritesheetFrame{},
		TexturePath: path,
	}
}

func (s *Spritesheet) GetFrame(name string) *SpritesheetFrame {
	var (
		present bool
	)
	if _, present = s.frames[name]; !present {
		return nil
	}
	return s.frames[name]
}

func (s *Spritesheet) AddFrame(name string, config SpritesheetFrameConfig) {
	s.frames[name] = config.ToSpritesheetFrame()
}

type texturePackerFloatCoords struct {
	X float32 `json:x,omitempty`
	Y float32 `json:y,omitempty`
}

type texturePackerIntCoords struct {
	X int `json:x,omitempty`
	Y int `json:y,omitempty`
	W int `json:w,omitempty`
	H int `json:h,omitempty`
}

type texturePackerFrame struct {
	Filename         string                   `json:filename`
	Frame            texturePackerIntCoords   `json:frame`
	Rotated          bool                     `json:rotated`
	Trimmed          bool                     `json:trimmed`
	SpriteSourceSize texturePackerIntCoords   `json:spriteSourceSize`
	SourceSize       texturePackerIntCoords   `json:sourceSize`
	Pivot            texturePackerFloatCoords `json:pivot`
}

type texturePackerMeta struct {
	Image  string                 `json:image`
	Format string                 `json:format`
	Size   texturePackerIntCoords `json:size`
	Scale  string                 `json:scale`
}

type texturePackerJSONArray struct {
	Frames []texturePackerFrame `json:frames`
	Meta   texturePackerMeta    `json:meta`
}

func ParseTexturePackerJSONArrayString(contents string, pxPerUnit float32) (s *Spritesheet, err error) {
	var (
		parsed texturePackerJSONArray
	)
	if err = json.Unmarshal([]byte(contents), &parsed); err != nil {
		return
	}
	s = NewSpritesheet(parsed.Meta.Image)
	for _, frame := range parsed.Frames {
		s.AddFrame(frame.Filename, SpritesheetFrameConfig{
			sourceW:          float32(frame.SpriteSourceSize.W),
			sourceH:          float32(frame.SpriteSourceSize.H),
			textureX:         float32(frame.Frame.X),
			textureY:         float32(frame.Frame.Y),
			textureW:         float32(frame.Frame.W),
			textureH:         float32(frame.Frame.H),
			textureOriginalW: float32(parsed.Meta.Size.W),
			textureOriginalH: float32(parsed.Meta.Size.H),
			pxPerUnit:        pxPerUnit,
		})
	}
	return
}
<|endoftext|>


<commit_before>package main

import (
	"net/http"
	"net/http/pprof"

	"github.com/nbari/violetear"
)

func hello(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("hello"))
}

func helloWord(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("hello world"))
}

func catchAll(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("*"))
}

func main() {
	r := violetear.New()
	//	r.LogRequests = true
	r.AddRegex(":word", `^\w+$`)
	r.HandleFunc("/hello", hello, "GET,HEAD")
	r.HandleFunc("/hello/:word/", helloWord, "GET,HEAD")
	r.HandleFunc("/*", catchAll, "GET,HEAD")

	// Register pprof handlers
	r.HandleFunc("/debug/pprof/*", pprof.Index)
	r.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
	r.HandleFunc("/debug/pprof/profile", pprof.Profile)
	r.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
	r.HandleFunc("/debug/pprof/trace", pprof.Trace)

	http.ListenAndServe(":8080", r)
}
<commit_msg>sleep<commit_after>package main

import (
	"net/http"
	"net/http/pprof"
	"time"

	"github.com/nbari/violetear"
)

func hello(w http.ResponseWriter, r *http.Request) {
	time.Sleep(time.Millisecond)
	w.Write([]byte("hello"))
}

func helloWord(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("hello world"))
}

func catchAll(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("*"))
}

func main() {
	r := violetear.New()
	r.LogRequests = true
	r.AddRegex(":word", `^\w+$`)
	r.HandleFunc("/hello", hello, "GET,HEAD")
	r.HandleFunc("/hello/:word/", helloWord, "GET,HEAD")
	r.HandleFunc("/*", catchAll, "GET,HEAD")

	// Register pprof handlers
	r.HandleFunc("/debug/pprof/*", pprof.Index)
	r.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
	r.HandleFunc("/debug/pprof/profile", pprof.Profile)
	r.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
	r.HandleFunc("/debug/pprof/trace", pprof.Trace)

	http.ListenAndServe(":8080", r)
}
<|endoftext|>


<commit_before>// +build pkcs11,linux

package yubikey

var possiblePkcs11Libs = []string{
	"/usr/lib/libykcs11.so",
	"/usr/lib64/libykcs11.so",
	"/usr/lib/x86_64-linux-gnu/libykcs11.so",
	"/usr/local/lib/libykcs11.so",
}
<commit_msg>Add some filepaths on Fedora where libykcs11 may be found.<commit_after>// +build pkcs11,linux

package yubikey

var possiblePkcs11Libs = []string{
	"/usr/lib/libykcs11.so",
	"/usr/lib/libykcs11.so.1",    // yubico-piv-tool on Fedora installs here
	"/usr/lib64/libykcs11.so",
	"/usr/lib64/libykcs11.so.1",  // yubico-piv-tool on Fedora installs here
	"/usr/lib/x86_64-linux-gnu/libykcs11.so",
	"/usr/local/lib/libykcs11.so",
}
<|endoftext|>


<commit_before>package sftpd

import (
	"errors"
	"os"
	"path/filepath"
	"sort"
	"strings"
)

type PathMapper struct {
	tree     map[string][]string
	basePath string
}

func NewPathMapper(files []string, basePath string) *PathMapper {
	pathMapper := &PathMapper{
		basePath: basePath,
	}
	pathMapper.normalizeBasePath()
	pathMapper.buildTree(files)
	return pathMapper
}

func (mapper *PathMapper) normalizeBasePath() {
	mapper.basePath = mapper.normalizePath(mapper.basePath)
	if mapper.basePath == "" {
		mapper.basePath = "."
	}
}

func (mapper *PathMapper) normalizePath(basePath string) string {
	basePath = filepath.ToSlash(basePath)
	basePath = strings.TrimPrefix(basePath, "./")
	if basePath == "." {
		return ""
	}
	return strings.TrimRight(basePath, "/")
}

func (mapper *PathMapper) List(key string) ([]string, bool) {
	normalizedKey := mapper.slashify(key)
	value, ok := mapper.tree[normalizedKey]
	return value, ok
}

func (mapper *PathMapper) PathTo(reference string) (string, error) {
	normalizedKey := mapper.slashify(reference)
	_, ok := mapper.tree[normalizedKey]
	if ! ok {
		return "", errors.New("PathTo " + reference + " not found")
	}

	return filepath.FromSlash(mapper.normalizePath(mapper.basePath  + normalizedKey)), nil
}

func (mapper *PathMapper) Stat(reference string) (os.FileInfo, error) {
	path, err := mapper.PathTo(reference)
	if err != nil {
		return nil, err
	}
	return os.Stat(path)
}

func (mapper *PathMapper) slashify(path string) string {
	toSlash := filepath.ToSlash(path)
	trimmed := strings.TrimLeft(toSlash, "/")
	return "/" + trimmed
}

func (mapper *PathMapper) buildTree(matchingPaths []string) {
	mapper.tree = make(map[string][]string)

	sort.Strings(matchingPaths)

	for _, path := range matchingPaths {
		normalizedPath := mapper.normalizePath(path)
		key := mapper.slashify(strings.TrimPrefix(normalizedPath, mapper.basePath))
		for {

			mapper.tree[key] = []string{}
			idx := strings.LastIndex(key, "/")
			key = key[0:idx]
			if key == "" {
				break
			}
		}
		mapper.tree["/"] = []string{}
	}

	for key := range mapper.tree {
		if key == "/" {
			continue
		}
		idx := strings.LastIndex(key, "/")
		dir := key[0:idx]
		if dir == "" {
			dir = "/"
		}
		mapper.tree[dir] = append(mapper.tree[dir], key)
	}

	for key := range mapper.tree {
		sort.Strings(mapper.tree[key])
	}
}

func (mapper *PathMapper) normalizePathMapItem(path string) (string, string) {
	parentPath := mapper.normalizePath(filepath.Dir(path))
	parentWithoutBaseDir := strings.TrimPrefix(parentPath, mapper.basePath)
	key := mapper.slashify(parentWithoutBaseDir)
	return key, parentPath
}
<commit_msg>Fixed path handling in path_mapper<commit_after>package sftpd

import (
	"errors"
	"os"
	"path/filepath"
	"sort"
	"strings"
)

type PathMapper struct {
	tree     map[string][]string
	basePath string
}

func NewPathMapper(files []string, basePath string) *PathMapper {
	pathMapper := &PathMapper{
		basePath: basePath,
	}
	pathMapper.normalizeBasePath()
	pathMapper.buildTree(files)
	return pathMapper
}

func (mapper *PathMapper) normalizeBasePath() {
	mapper.basePath = mapper.normalizePath(mapper.basePath)
	if mapper.basePath == "" {
		mapper.basePath = "."
	}
}

func (mapper *PathMapper) normalizePath(basePath string) string {
	basePath = filepath.ToSlash(basePath)
	basePath = strings.TrimPrefix(basePath, "./")
	if basePath == "." {
		return ""
	}
	return strings.TrimRight(basePath, "/")
}

func (mapper *PathMapper) List(key string) ([]string, bool) {
	normalizedKey := mapper.slashify(key)
	value, ok := mapper.tree[normalizedKey]
	return value, ok
}

func (mapper *PathMapper) PathTo(reference string) (string, error) {
	normalizedKey := mapper.slashify(reference)
	_, ok := mapper.tree[normalizedKey]
	if ! ok {
		return "", errors.New("PathTo " + reference + " not found")
	}

	path := filepath.FromSlash(mapper.normalizePath(mapper.basePath  + normalizedKey))
	if path == "" {
		path = "."
	}
	return path, nil
}

func (mapper *PathMapper) Stat(reference string) (os.FileInfo, error) {
	path, err := mapper.PathTo(reference)
	if err != nil {
		return nil, err
	}

	return os.Stat(path)
}

func (mapper *PathMapper) slashify(path string) string {
	toSlash := filepath.ToSlash(path)
	trimmed := strings.TrimLeft(toSlash, "/")
	return "/" + trimmed
}

func (mapper *PathMapper) buildTree(matchingPaths []string) {
	mapper.tree = make(map[string][]string)

	sort.Strings(matchingPaths)

	for _, path := range matchingPaths {
		normalizedPath := mapper.normalizePath(path)
		key := mapper.slashify(strings.TrimPrefix(normalizedPath, mapper.basePath))
		for {

			mapper.tree[key] = []string{}
			idx := strings.LastIndex(key, "/")
			key = key[0:idx]
			if key == "" {
				break
			}
		}
		mapper.tree["/"] = []string{}
	}

	for key := range mapper.tree {
		if key == "/" {
			continue
		}
		idx := strings.LastIndex(key, "/")
		dir := key[0:idx]
		if dir == "" {
			dir = "/"
		}
		mapper.tree[dir] = append(mapper.tree[dir], key)
	}

	for key := range mapper.tree {
		sort.Strings(mapper.tree[key])
	}
}

func (mapper *PathMapper) normalizePathMapItem(path string) (string, string) {
	parentPath := mapper.normalizePath(filepath.Dir(path))
	parentWithoutBaseDir := strings.TrimPrefix(parentPath, mapper.basePath)
	key := mapper.slashify(parentWithoutBaseDir)
	return key, parentPath
}
<|endoftext|>


<commit_before>package sqlego

import (
	s "strings"
	"testing"
)

func TestSelectStatement(t *testing.T) {
	node := Select("Users", []string{"id", "name", "email"})
	sql := node.Compile()
	if sql != "SELECT id,name,email FROM Users;" {
		t.Fatal(sql)
	}
}

func TestInsertStatement(t *testing.T) {
	node := Insert("Users", map[string]string{"name": "Bruce"})
	sql := node.Compile()
	if sql != "INSERT INTO Users (name) VALUES (Bruce);" {
		t.Fatal(sql)
	}
}

func TestUpdateStatement(t *testing.T) {
	node := Update("Users", map[string]string{"id": "2", "name": "Bruce", "email": "bruce@example.com"})
	sql := node.Compile()
	if !s.Contains(sql, "UPDATE Users SET") && !s.Contains(sql, "id=2") && !s.Contains(sql, "name=Bruce") && !s.Contains(sql, "email=bruce@example.com") {
		t.Fatal(sql)
	}
}

func TestDeleteStatement(t *testing.T) {
	node := Delete("Users")
	sql := node.Compile()
	if sql != "DELETE FROM Users;" {
		t.Fatal(sql)
	}
}
<commit_msg>Add basic SELECT statement with WHERE testing<commit_after>package sqlego

import (
	s "strings"
	"testing"
)

func TestSelectStatement(t *testing.T) {
	node := Select("Users", []string{"id", "name", "email"})
	sql := node.Compile()
	if sql != "SELECT id,name,email FROM Users;" {
		t.Fatal(sql)
	}
}

func TestSelectStatementWithWhere(t *testing.T) {
	node := Select("Users", []string{"id", "name", "email"})
	node.Where(Gte("id", "10"))
	sql := node.Compile()
	if sql != "SELECT id,name,email FROM Users WHERE id>=10;" {
		t.Fatalf("Single condition:\n%s", sql)
	}
}

func TestInsertStatement(t *testing.T) {
	node := Insert("Users", map[string]string{"name": "Bruce"})
	sql := node.Compile()
	if sql != "INSERT INTO Users (name) VALUES (Bruce);" {
		t.Fatal(sql)
	}
}

func TestUpdateStatement(t *testing.T) {
	node := Update("Users", map[string]string{"id": "2", "name": "Bruce", "email": "bruce@example.com"})
	sql := node.Compile()
	if !s.Contains(sql, "UPDATE Users SET") && !s.Contains(sql, "id=2") && !s.Contains(sql, "name=Bruce") && !s.Contains(sql, "email=bruce@example.com") {
		t.Fatal(sql)
	}
}

func TestDeleteStatement(t *testing.T) {
	node := Delete("Users")
	sql := node.Compile()
	if sql != "DELETE FROM Users;" {
		t.Fatal(sql)
	}
}
<|endoftext|>


<commit_before>// Package verifalia provides an API client for Verifalia API. For more details, see http://verifalia.com/developers
package verifalia

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"log"
	"net/http"
	"net/url"
	"time"
)

const (
	libraryVersion = "0.1"
	defaultBaseUrl = "https://api.verifalia.com/v1.2/"
	userAgent      = "go-verifalia/" + libraryVersion
	contentType    = "application/json"
)

// A Client manages communication with the Verifalia REST API.
type Client struct {
	// Authentication to the API occurs via HTTP Basic Auth
	// using the sub-account SID as the username and the auth token as password
	AccountSID string
	AuthToken  string

	// Base URL for communicating with the API..
	BaseURL *url.URL

	// User agent used when communicating with the API.
	UserAgent string
}

// Returns a new Verifalia API client.
// It requires account SID and auth token which are used for basic http authentication
func NewClient(accountSID, authToken string) *Client {
	if accountSID == "" || authToken == "" {
		return nil
	}

	baseUrl, _ := url.Parse(defaultBaseUrl)

	c := &Client{
		AccountSID: accountSID,
		AuthToken:  authToken,
		UserAgent:  userAgent,
		BaseURL:    baseUrl,
	}
	return c
}

// NewRequest creates an API request.
// method is the HTTP VERB
// path is the relative URL resolved relative to the BaseURL of the Client (eg. "email-validations").
// Relative URLs should always be specified without a preceding slash.
// It can also be an absolute URL.
// If specified, the value pointed to by body is JSON encoded and included as the request body.
func (c *Client) NewRequest(method, path string, body interface{}) (*http.Request, error) {
	rel, err := url.Parse(path)
	if err != nil {
		log.Fatalln(err)
		return nil, err
	}
	url := c.BaseURL.ResolveReference(rel)

	var buf io.ReadWriter
	if body != nil {
		buf = new(bytes.Buffer)
		err = json.NewEncoder(buf).Encode(body)
		if err != nil {
			log.Fatalln(err)
			return nil, err
		}
	}

	req, err := http.NewRequest(method, url.String(), buf)
	if err != nil {
		log.Fatalln(err)
		return nil, err
	}

	// Verifalia uses basic auth
	req.SetBasicAuth(c.AccountSID, c.AuthToken)
	req.Header.Add("Content-Type", contentType)
	if c.UserAgent != "" {
		req.Header.Add("User-Agent", c.UserAgent)
	}
	return req, nil
}

// Query the Email Validations API with an array of emails to validate.
// Response returned by this API is available in "Data" struct.
// POST: https://api.verifalia.com/v1.1/email-validations
// Emails to validate are passed as a slice of string.
func (c *Client) Validate(emails []string) (*Response, error) {
	if len(emails) <= 0 {
		err := errors.New("emails must not be empty")
		log.Fatalln(err)
		return nil, err
	}
	// create a request object to send in http request body
	params := Request{}
	for _, email := range emails {
		inp := inputEmail{email}
		params.Entries = append(params.Entries, inp)
	}
	// build request object for "email-validations" API
	req, err := c.NewRequest("POST", "email-validations", params)
	if err != nil {
		log.Fatalln(err)
		return nil, err
	}
	log.Println(req.URL)
	// send request to "email-validations" API with request params
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		log.Fatalln(err)
		return nil, err
	}
	// close request body after "Validate" method executes
	defer resp.Body.Close()
	return buildResponse(resp)
}

// Query the Email Validations API for specific validation job's result.
// In order to use this API, you need to pass a unique job ID as a string argument.
// The email validation job must already be queued or completed on the server
// or else use 'Validate' to queue a new job.
// Response returned by this API is available in "Data" struct.
// Response is same as 'Validate' API.
// GET: https://api.verifalia.com/v1.1/email-validations/{uniqueID}
func (c *Client) Query(uniqueID string) (*Response, error) {
	if uniqueID == "" {
		err := errors.New("unique job ID should not be an empty string")
		log.Fatalln(err)
		return nil, err
	}
	// create the request URL using uniqueID
	url := fmt.Sprintf("email-validations/%v", uniqueID)
	// build request object for email validation job status API
	req, err := c.NewRequest("GET", url, nil)
	if err != nil {
		log.Fatalln(err)
		return nil, err
	}
	log.Println(req.URL)
	// send request to the API
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		log.Fatalln(err)
		return nil, err
	}
	// close request body after "Query" method executes
	defer resp.Body.Close()
	return buildResponse(resp)
}

// Query the Verifalia API to delete a specific validation job.
// In order to use this API, you need to pass a unique job ID as a string argument.
// The email validation job must be completed on the server or else server will return 406
// DELETE: https://api.verifalia.com/v1.1/email-validations/{uniqueID}
func (c *Client) Delete(uniqueID string) (*Response, error) {
	if uniqueID == "" {
		err := errors.New("unique job ID should not be an empty string")
		log.Fatalln(err)
		return nil, err
	}
	// create the request URL using uniqueID
	url := fmt.Sprintf("email-validations/%v", uniqueID)
	// build request object for email validation job status API
	req, err := c.NewRequest("DELETE", url, nil)
	if err != nil {
		log.Fatalln(err)
		return nil, err
	}
	log.Println(req.URL)
	// send request to the API
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		log.Fatalln(err)
		return nil, err
	}
	// close request body after "Query" method executes
	defer resp.Body.Close()
	r := Response{
		StatusCode: resp.StatusCode,
		Status:     http.StatusText(resp.StatusCode),
	}
	return &r, nil
}

// Since server response is same for 'Validate' and 'Query',
// extract it out in a separate method which will be used by both methods.
// This is a private method not exported by the package.
func buildResponse(resp *http.Response) (*Response, error) {
	// build a "Response" object from API response body
	r := Response{}
	err := json.NewDecoder(resp.Body).Decode(&r.Data)
	if err != nil {
		log.Fatalln(err)
		return nil, err
	}
	r.StatusCode = resp.StatusCode
	r.Status = http.StatusText(r.StatusCode)
	// next "Location" if any is returned in the "Location" header
	r.Location, _ = resp.Location()
	if r.Data != nil {
		r.UniqueID = r.Data.UniqueID
	}
	return &r, nil
}

// Email address is sent to email validations API as "inputData"
// [{inputData: "test@test.com"}]
type inputEmail struct {
	InputData string `json:"inputData"`
}

// Request body for email validations API is represented by "Request" struct
type Request struct {
	Entries []inputEmail `json:"entries"`
}

// All information about an email in a validation job is represented by an "Entry" struct
type Entry struct {
	InputData                   string     `json:"inputData"`
	Status                      string     `json:"status"`
	CompletedOn                 *time.Time `json:"completedOn"`
	EmailAddress                string     `json:"emailAddress"`
	AsciiEmailAddressDomainPart string     `json:"asciiEmailAddressDomainPart"`
	EmailAddressLocalPart       string     `json:"emailAddressLocalPart"`
	EmailAddressDomainPart      string     `json:"emailAddressDomainPart"`
	HasInternationalDomainName  bool       `json:"hasInternationalDomainName"`
	HasInternationalMailboxName bool       `json:"hasInternationalMailboxName"`
	IsDisposableEmailAddress    bool       `json:"isDisposableEmailAddress"`
	IsRoleAccount               bool       `json:"isRoleAccount"`
	SyntaxFailureIndex          int        `json:"syntaxFailureIndex"`
	IsCatchAllFailure           bool       `json:"isCatchAllFailure"`
	IsSuccess                   bool       `json:"isSuccess"`
	IsSyntaxFailure             bool       `json:"isSyntaxFailure"`
	IsDnsFailure                bool       `json:"isDnsFailure"`
	IsSmtpFailure               bool       `json:"isSmtpFailure"`
	IsMailboxFailure            bool       `json:"isMailboxFailure"`
	IsTimeoutFailure            bool       `json:"isTimeoutFailure"`
	IsNetworkFailure            bool       `json:"isNetworkFailure"`
}

// Data returned by Verifalia for an email validation job is represented by "Data" struct
type Data struct {
	UniqueID      string     `json:"uniqueID"`
	EngineVersion string     `json:"engineVersion"`
	SubmittedOn   *time.Time `json:"submittedOn"`
	CompletedOn   *time.Time `json:"completedOn"`
	Entries       []Entry    `json:"entries"`
	Progress      struct {
		NoOfTotalEntries     int `json:"noOfTotalEntries"`
		NoOfCompletedEntries int `json:"noOfCompletedEntries"`
	} `json:"progress"`
}

// All API response will be represented by general purpose "Response" struct
// Response returned after an email validation job is represented by "Data" struct
// Data is pointer so we can ignore it for DELETE job as it will be nil
// Status code represents if job was queued, executed or rejected by Verifalia
// Location stores the next API location after current request.
type Response struct {
	StatusCode int
	Status     string
	Location   *url.URL
	UniqueID   string
	*Data
}
<commit_msg>Changes recommended by Go Lint<commit_after>// Package verifalia provides an API client for Verifalia API. For more details, see http://verifalia.com/developers
package verifalia

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"log"
	"net/http"
	"net/url"
	"time"
)

const (
	libraryVersion = "0.1"
	defaultBaseURL = "https://api.verifalia.com/v1.2/"
	userAgent      = "go-verifalia/" + libraryVersion
	contentType    = "application/json"
)

// A Client manages communication with the Verifalia REST API.
type Client struct {
	// Authentication to the API occurs via HTTP Basic Auth
	// using the sub-account SID as the username and the auth token as password
	AccountSID string
	AuthToken  string

	// Base URL for communicating with the API..
	BaseURL *url.URL

	// User agent used when communicating with the API.
	UserAgent string
}

// NewClient returns a new Verifalia API client.
// It requires account SID and auth token which are used for basic http authentication
func NewClient(accountSID, authToken string) *Client {
	if accountSID == "" || authToken == "" {
		return nil
	}

	baseURL, _ := url.Parse(defaultBaseURL)

	c := &Client{
		AccountSID: accountSID,
		AuthToken:  authToken,
		UserAgent:  userAgent,
		BaseURL:    baseURL,
	}
	return c
}

// NewRequest creates an API request.
// method is the HTTP VERB
// path is the relative URL resolved relative to the BaseURL of the Client (eg. "email-validations").
// Relative URLs should always be specified without a preceding slash.
// It can also be an absolute URL.
// If specified, the value pointed to by body is JSON encoded and included as the request body.
func (c *Client) NewRequest(method, path string, body interface{}) (*http.Request, error) {
	rel, err := url.Parse(path)
	if err != nil {
		log.Fatalln(err)
		return nil, err
	}
	url := c.BaseURL.ResolveReference(rel)

	var buf io.ReadWriter
	if body != nil {
		buf = new(bytes.Buffer)
		err = json.NewEncoder(buf).Encode(body)
		if err != nil {
			log.Fatalln(err)
			return nil, err
		}
	}

	req, err := http.NewRequest(method, url.String(), buf)
	if err != nil {
		log.Fatalln(err)
		return nil, err
	}

	// Verifalia uses basic auth
	req.SetBasicAuth(c.AccountSID, c.AuthToken)
	req.Header.Add("Content-Type", contentType)
	if c.UserAgent != "" {
		req.Header.Add("User-Agent", c.UserAgent)
	}
	return req, nil
}

// Validate calls the Email Validations API with an array of emails to validate.
// Response returned by this API is available in "Data" struct.
// POST: https://api.verifalia.com/v1.1/email-validations
// Emails to validate are passed as a slice of string.
func (c *Client) Validate(emails []string) (*Response, error) {
	if len(emails) <= 0 {
		err := errors.New("emails must not be empty")
		log.Fatalln(err)
		return nil, err
	}
	// create a request object to send in http request body
	params := Request{}
	for _, email := range emails {
		inp := inputEmail{email}
		params.Entries = append(params.Entries, inp)
	}
	// build request object for "email-validations" API
	req, err := c.NewRequest("POST", "email-validations", params)
	if err != nil {
		log.Fatalln(err)
		return nil, err
	}
	log.Println(req.URL)
	// send request to "email-validations" API with request params
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		log.Fatalln(err)
		return nil, err
	}
	// close request body after "Validate" method executes
	defer resp.Body.Close()
	return buildResponse(resp)
}

// Query calls the Email Validations API for specific validation job's result with a unique job Id
// The job must already be queued or completed on the server or else use 'Validate' to queue a new job.
// Response returned by this API is available in "Data" struct and is same as 'Validate' API.
// GET: https://api.verifalia.com/v1.1/email-validations/{uniqueID}
func (c *Client) Query(uniqueID string) (*Response, error) {
	if uniqueID == "" {
		err := errors.New("unique job ID should not be an empty string")
		log.Fatalln(err)
		return nil, err
	}
	// create the request URL using a uniqueID
	url := fmt.Sprintf("email-validations/%v", uniqueID)
	// build request object for email validation job status API
	req, err := c.NewRequest("GET", url, nil)
	if err != nil {
		log.Fatalln(err)
		return nil, err
	}
	log.Println(req.URL)
	// send request to the API
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		log.Fatalln(err)
		return nil, err
	}
	// close request body after "Query" method executes
	defer resp.Body.Close()
	return buildResponse(resp)
}

// Delete calls the Verifalia API to delete a specific validation job with a unique job ID.
// The email validation job must be completed on the server or else server will return 406
// DELETE: https://api.verifalia.com/v1.1/email-validations/{uniqueID}
func (c *Client) Delete(uniqueID string) (*Response, error) {
	if uniqueID == "" {
		err := errors.New("unique job ID should not be an empty string")
		log.Fatalln(err)
		return nil, err
	}
	// create the request URL using uniqueID
	url := fmt.Sprintf("email-validations/%v", uniqueID)
	// build request object for email validation job status API
	req, err := c.NewRequest("DELETE", url, nil)
	if err != nil {
		log.Fatalln(err)
		return nil, err
	}
	log.Println(req.URL)
	// send request to the API
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		log.Fatalln(err)
		return nil, err
	}
	// close request body after "Query" method executes
	defer resp.Body.Close()
	r := Response{
		StatusCode: resp.StatusCode,
		Status:     http.StatusText(resp.StatusCode),
	}
	return &r, nil
}

// Since server response is same for 'Validate' and 'Query',
// extract it out in a separate method which will be used by both methods.
// This is a private method not exported by the package.
func buildResponse(resp *http.Response) (*Response, error) {
	// build a "Response" object from API response body
	r := Response{}
	err := json.NewDecoder(resp.Body).Decode(&r.Data)
	if err != nil {
		log.Fatalln(err)
		return nil, err
	}
	r.StatusCode = resp.StatusCode
	r.Status = http.StatusText(r.StatusCode)
	// next "Location" if any is returned in the "Location" header
	r.Location, _ = resp.Location()
	if r.Data != nil {
		r.UniqueID = r.Data.UniqueID
	}
	return &r, nil
}

// Email address is sent to email validations API as "inputData"
// [{inputData: "test@test.com"}]
type inputEmail struct {
	InputData string `json:"inputData"`
}

// Request body for email validations API is represented by "Request" struct
type Request struct {
	Entries []inputEmail `json:"entries"`
}

// Entry represents all information about an email in a validation job.
type Entry struct {
	InputData                   string     `json:"inputData"`
	Status                      string     `json:"status"`
	CompletedOn                 *time.Time `json:"completedOn"`
	EmailAddress                string     `json:"emailAddress"`
	ASCIIEmailAddressDomainPart string     `json:"asciiEmailAddressDomainPart"`
	EmailAddressLocalPart       string     `json:"emailAddressLocalPart"`
	EmailAddressDomainPart      string     `json:"emailAddressDomainPart"`
	HasInternationalDomainName  bool       `json:"hasInternationalDomainName"`
	HasInternationalMailboxName bool       `json:"hasInternationalMailboxName"`
	IsDisposableEmailAddress    bool       `json:"isDisposableEmailAddress"`
	IsRoleAccount               bool       `json:"isRoleAccount"`
	SyntaxFailureIndex          int        `json:"syntaxFailureIndex"`
	IsCatchAllFailure           bool       `json:"isCatchAllFailure"`
	IsSuccess                   bool       `json:"isSuccess"`
	IsSyntaxFailure             bool       `json:"isSyntaxFailure"`
	IsDNSFailure                bool       `json:"isDnsFailure"`
	IsSMTPFailure               bool       `json:"isSmtpFailure"`
	IsMailboxFailure            bool       `json:"isMailboxFailure"`
	IsTimeoutFailure            bool       `json:"isTimeoutFailure"`
	IsNetworkFailure            bool       `json:"isNetworkFailure"`
}

// Data represents all the data returned by Verifalia for an email validation job.
type Data struct {
	UniqueID      string     `json:"uniqueID"`
	EngineVersion string     `json:"engineVersion"`
	SubmittedOn   *time.Time `json:"submittedOn"`
	CompletedOn   *time.Time `json:"completedOn"`
	Entries       []Entry    `json:"entries"`
	Progress      struct {
		NoOfTotalEntries     int `json:"noOfTotalEntries"`
		NoOfCompletedEntries int `json:"noOfCompletedEntries"`
	} `json:"progress"`
}

// Response is a general purpose struct to represent API response.
// API response returned after an email validation job is represented by "Data" struct
// Data is pointer so we can ignore it for DELETE job as it will be nil
// Status code represents if job was queued, executed or rejected by Verifalia
// Location stores the next API location after current request.
type Response struct {
	StatusCode int
	Status     string
	Location   *url.URL
	UniqueID   string
	*Data
}
<|endoftext|>


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

package verify_test

import (
	"errors"
	"fmt"
	"testing"

	"golang.org/x/net/context"

	"github.com/jacobsa/comeback/blob"
	"github.com/jacobsa/comeback/blob/mock"
	"github.com/jacobsa/comeback/fs"
	"github.com/jacobsa/comeback/graph"
	"github.com/jacobsa/comeback/repr"
	"github.com/jacobsa/comeback/verify"
	. "github.com/jacobsa/oglematchers"
	. "github.com/jacobsa/oglemock"
	. "github.com/jacobsa/ogletest"
)

func TestVisitor(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Boilerplate
////////////////////////////////////////////////////////////////////////

const namePrefix = "blobs/"

type superTest struct {
	ctx       context.Context
	blobStore mock_blob.MockStore
	visitor   graph.Visitor
}

func (t *superTest) setUp(
	ti *TestInfo,
	readFiles bool,
	allScores []blob.Score) {
	t.ctx = ti.Ctx
	t.blobStore = mock_blob.NewMockStore(ti.MockController, "blobStore")
	t.visitor = verify.NewVisitor(readFiles, allScores, t.blobStore)
}

////////////////////////////////////////////////////////////////////////
// Common
////////////////////////////////////////////////////////////////////////

type CommonTest struct {
	superTest
}

var _ SetUpInterface = &CommonTest{}

func init() { RegisterTestSuite(&CommonTest{}) }

func (t *CommonTest) SetUp(ti *TestInfo) {
	t.superTest.setUp(ti, false, nil)
}

func (t *CommonTest) InvalidNodeName() {
	_, err := t.visitor.Visit(t.ctx, "taco")

	ExpectThat(err, Error(HasSubstr("ParseNodeName")))
	ExpectThat(err, Error(HasSubstr("taco")))
}

////////////////////////////////////////////////////////////////////////
// Directories
////////////////////////////////////////////////////////////////////////

type DirsTest struct {
	superTest

	listing  []*fs.DirectoryEntry
	contents []byte
	score    blob.Score
	node     string
}

var _ SetUpInterface = &DirsTest{}

func init() { RegisterTestSuite(&DirsTest{}) }

func (t *DirsTest) SetUp(ti *TestInfo) {
	t.superTest.setUp(ti, false, nil)

	// Set up canned data for a valid listing.
	t.listing = []*fs.DirectoryEntry{
		&fs.DirectoryEntry{
			Type: fs.TypeFile,
			Name: "foo",
			Scores: []blob.Score{
				blob.ComputeScore([]byte("0")),
				blob.ComputeScore([]byte("1")),
			},
		},

		&fs.DirectoryEntry{
			Type: fs.TypeDirectory,
			Name: "bar",
			Scores: []blob.Score{
				blob.ComputeScore([]byte("2")),
			},
		},
	}

	var err error
	t.contents, err = repr.MarshalDir(t.listing)
	AssertEq(nil, err)

	t.score = blob.ComputeScore(t.contents)
	t.node = verify.FormatNodeName(true, t.score)
}

func (t *DirsTest) CallsBlobStore() {
	// Load
	ExpectCall(t.blobStore, "Load")(t.score).
		WillOnce(Return(nil, errors.New("")))

	// Call
	t.visitor.Visit(t.ctx, t.node)
}

func (t *DirsTest) BlobStoreReturnsError() {
	// Load
	ExpectCall(t.blobStore, "Load")(Any()).
		WillOnce(Return(nil, errors.New("taco")))

	// Call
	_, err := t.visitor.Visit(t.ctx, t.node)

	ExpectThat(err, Error(HasSubstr("Load")))
	ExpectThat(err, Error(HasSubstr("taco")))
}

func (t *DirsTest) BlobIsJunk() {
	// Set up junk contents.
	t.contents = append(t.contents, 'a')
	t.score = blob.ComputeScore(t.contents)
	t.node = verify.FormatNodeName(true, t.score)

	// Load
	ExpectCall(t.blobStore, "Load")(Any()).
		WillOnce(Return(t.contents, nil))

	// Call
	_, err := t.visitor.Visit(t.ctx, t.node)

	ExpectThat(err, Error(HasSubstr(t.score.Hex())))
	ExpectThat(err, Error(HasSubstr("UnmarshalDir")))
}

func (t *DirsTest) UnknownEntryType() {
	// Set up a listing with a junk entry type.
	t.listing = []*fs.DirectoryEntry{
		&fs.DirectoryEntry{
			Type: fs.TypeSymlink,
			Name: "foo",
			Scores: []blob.Score{
				blob.ComputeScore([]byte("0")),
			},
		},
	}

	var err error
	t.contents, err = repr.MarshalDir(t.listing)
	AssertEq(nil, err)

	t.score = blob.ComputeScore(t.contents)
	t.node = verify.FormatNodeName(true, t.score)

	// Load
	ExpectCall(t.blobStore, "Load")(Any()).
		WillOnce(Return(t.contents, nil))

	// Call
	_, err = t.visitor.Visit(t.ctx, t.node)

	ExpectThat(err, Error(HasSubstr("entry type")))
	ExpectThat(err, Error(HasSubstr(fmt.Sprintf("%d", fs.TypeSymlink))))
}

func (t *DirsTest) ReturnsAppropriateAdjacentNodes() {
	// Load
	ExpectCall(t.blobStore, "Load")(Any()).
		WillOnce(Return(t.contents, nil))

	// Call
	adjacent, err := t.visitor.Visit(t.ctx, t.node)
	AssertEq(nil, err)

	var expected []interface{}
	for _, entry := range t.listing {
		dir := entry.Type == fs.TypeDirectory
		for _, score := range entry.Scores {
			expected = append(expected, verify.FormatNodeName(dir, score))
		}
	}

	ExpectThat(adjacent, ElementsAre(expected...))
}

////////////////////////////////////////////////////////////////////////
// Files, no read
////////////////////////////////////////////////////////////////////////

type FilesLiteTest struct {
	superTest

	contents []byte

	knownScore blob.Score
	knownNode  string

	unknownScore blob.Score
	unknownNode  string
}

var _ SetUpInterface = &FilesLiteTest{}

func init() { RegisterTestSuite(&FilesLiteTest{}) }

func (t *FilesLiteTest) setUp(ti *TestInfo, readFiles bool) {
	t.contents = []byte("foobarbaz")

	t.knownScore = blob.ComputeScore(t.contents)
	t.knownNode = verify.FormatNodeName(false, t.knownScore)

	t.unknownScore = blob.ComputeScore(append(t.contents, 'a'))
	t.unknownNode = verify.FormatNodeName(false, t.unknownScore)

	t.superTest.setUp(ti, readFiles, []blob.Score{t.knownScore})
}

func (t *FilesLiteTest) SetUp(ti *TestInfo) {
	t.setUp(ti, false)
}

func (t *FilesLiteTest) ScoreNotInList() {
	// Call
	_, err := t.visitor.Visit(t.ctx, t.unknownNode)

	ExpectThat(err, Error(HasSubstr("Unknown score")))
	ExpectThat(err, Error(HasSubstr(t.unknownScore.Hex())))
}

func (t *FilesLiteTest) ScoreIsInList() {
	AssertFalse(true, "TODO")
}

////////////////////////////////////////////////////////////////////////
// Files, read
////////////////////////////////////////////////////////////////////////

type FilesFullTest struct {
	FilesLiteTest
}

var _ SetUpInterface = &FilesFullTest{}

func init() { RegisterTestSuite(&FilesFullTest{}) }

func (t *FilesFullTest) SetUp(ti *TestInfo) {
	t.FilesLiteTest.setUp(ti, true)
}

func (t *FilesFullTest) CallsBlobStore() {
	AssertFalse(true, "TODO")
}

func (t *FilesFullTest) BlobStoreReturnsError() {
	AssertFalse(true, "TODO")
}

func (t *FilesFullTest) BlobStoreSucceeds() {
	AssertFalse(true, "TODO")
}
<commit_msg>FilesLiteTest.ScoreIsInList<commit_after>// Copyright 2015 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package verify_test

import (
	"errors"
	"fmt"
	"testing"

	"golang.org/x/net/context"

	"github.com/jacobsa/comeback/blob"
	"github.com/jacobsa/comeback/blob/mock"
	"github.com/jacobsa/comeback/fs"
	"github.com/jacobsa/comeback/graph"
	"github.com/jacobsa/comeback/repr"
	"github.com/jacobsa/comeback/verify"
	. "github.com/jacobsa/oglematchers"
	. "github.com/jacobsa/oglemock"
	. "github.com/jacobsa/ogletest"
)

func TestVisitor(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Boilerplate
////////////////////////////////////////////////////////////////////////

const namePrefix = "blobs/"

type superTest struct {
	ctx       context.Context
	blobStore mock_blob.MockStore
	visitor   graph.Visitor
}

func (t *superTest) setUp(
	ti *TestInfo,
	readFiles bool,
	allScores []blob.Score) {
	t.ctx = ti.Ctx
	t.blobStore = mock_blob.NewMockStore(ti.MockController, "blobStore")
	t.visitor = verify.NewVisitor(readFiles, allScores, t.blobStore)
}

////////////////////////////////////////////////////////////////////////
// Common
////////////////////////////////////////////////////////////////////////

type CommonTest struct {
	superTest
}

var _ SetUpInterface = &CommonTest{}

func init() { RegisterTestSuite(&CommonTest{}) }

func (t *CommonTest) SetUp(ti *TestInfo) {
	t.superTest.setUp(ti, false, nil)
}

func (t *CommonTest) InvalidNodeName() {
	_, err := t.visitor.Visit(t.ctx, "taco")

	ExpectThat(err, Error(HasSubstr("ParseNodeName")))
	ExpectThat(err, Error(HasSubstr("taco")))
}

////////////////////////////////////////////////////////////////////////
// Directories
////////////////////////////////////////////////////////////////////////

type DirsTest struct {
	superTest

	listing  []*fs.DirectoryEntry
	contents []byte
	score    blob.Score
	node     string
}

var _ SetUpInterface = &DirsTest{}

func init() { RegisterTestSuite(&DirsTest{}) }

func (t *DirsTest) SetUp(ti *TestInfo) {
	t.superTest.setUp(ti, false, nil)

	// Set up canned data for a valid listing.
	t.listing = []*fs.DirectoryEntry{
		&fs.DirectoryEntry{
			Type: fs.TypeFile,
			Name: "foo",
			Scores: []blob.Score{
				blob.ComputeScore([]byte("0")),
				blob.ComputeScore([]byte("1")),
			},
		},

		&fs.DirectoryEntry{
			Type: fs.TypeDirectory,
			Name: "bar",
			Scores: []blob.Score{
				blob.ComputeScore([]byte("2")),
			},
		},
	}

	var err error
	t.contents, err = repr.MarshalDir(t.listing)
	AssertEq(nil, err)

	t.score = blob.ComputeScore(t.contents)
	t.node = verify.FormatNodeName(true, t.score)
}

func (t *DirsTest) CallsBlobStore() {
	// Load
	ExpectCall(t.blobStore, "Load")(t.score).
		WillOnce(Return(nil, errors.New("")))

	// Call
	t.visitor.Visit(t.ctx, t.node)
}

func (t *DirsTest) BlobStoreReturnsError() {
	// Load
	ExpectCall(t.blobStore, "Load")(Any()).
		WillOnce(Return(nil, errors.New("taco")))

	// Call
	_, err := t.visitor.Visit(t.ctx, t.node)

	ExpectThat(err, Error(HasSubstr("Load")))
	ExpectThat(err, Error(HasSubstr("taco")))
}

func (t *DirsTest) BlobIsJunk() {
	// Set up junk contents.
	t.contents = append(t.contents, 'a')
	t.score = blob.ComputeScore(t.contents)
	t.node = verify.FormatNodeName(true, t.score)

	// Load
	ExpectCall(t.blobStore, "Load")(Any()).
		WillOnce(Return(t.contents, nil))

	// Call
	_, err := t.visitor.Visit(t.ctx, t.node)

	ExpectThat(err, Error(HasSubstr(t.score.Hex())))
	ExpectThat(err, Error(HasSubstr("UnmarshalDir")))
}

func (t *DirsTest) UnknownEntryType() {
	// Set up a listing with a junk entry type.
	t.listing = []*fs.DirectoryEntry{
		&fs.DirectoryEntry{
			Type: fs.TypeSymlink,
			Name: "foo",
			Scores: []blob.Score{
				blob.ComputeScore([]byte("0")),
			},
		},
	}

	var err error
	t.contents, err = repr.MarshalDir(t.listing)
	AssertEq(nil, err)

	t.score = blob.ComputeScore(t.contents)
	t.node = verify.FormatNodeName(true, t.score)

	// Load
	ExpectCall(t.blobStore, "Load")(Any()).
		WillOnce(Return(t.contents, nil))

	// Call
	_, err = t.visitor.Visit(t.ctx, t.node)

	ExpectThat(err, Error(HasSubstr("entry type")))
	ExpectThat(err, Error(HasSubstr(fmt.Sprintf("%d", fs.TypeSymlink))))
}

func (t *DirsTest) ReturnsAppropriateAdjacentNodes() {
	// Load
	ExpectCall(t.blobStore, "Load")(Any()).
		WillOnce(Return(t.contents, nil))

	// Call
	adjacent, err := t.visitor.Visit(t.ctx, t.node)
	AssertEq(nil, err)

	var expected []interface{}
	for _, entry := range t.listing {
		dir := entry.Type == fs.TypeDirectory
		for _, score := range entry.Scores {
			expected = append(expected, verify.FormatNodeName(dir, score))
		}
	}

	ExpectThat(adjacent, ElementsAre(expected...))
}

////////////////////////////////////////////////////////////////////////
// Files, no read
////////////////////////////////////////////////////////////////////////

type FilesLiteTest struct {
	superTest

	contents []byte

	knownScore blob.Score
	knownNode  string

	unknownScore blob.Score
	unknownNode  string
}

var _ SetUpInterface = &FilesLiteTest{}

func init() { RegisterTestSuite(&FilesLiteTest{}) }

func (t *FilesLiteTest) setUp(ti *TestInfo, readFiles bool) {
	t.contents = []byte("foobarbaz")

	t.knownScore = blob.ComputeScore(t.contents)
	t.knownNode = verify.FormatNodeName(false, t.knownScore)

	t.unknownScore = blob.ComputeScore(append(t.contents, 'a'))
	t.unknownNode = verify.FormatNodeName(false, t.unknownScore)

	t.superTest.setUp(ti, readFiles, []blob.Score{t.knownScore})
}

func (t *FilesLiteTest) SetUp(ti *TestInfo) {
	t.setUp(ti, false)
}

func (t *FilesLiteTest) ScoreNotInList() {
	// Call
	_, err := t.visitor.Visit(t.ctx, t.unknownNode)

	ExpectThat(err, Error(HasSubstr("Unknown score")))
	ExpectThat(err, Error(HasSubstr(t.unknownScore.Hex())))
}

func (t *FilesLiteTest) ScoreIsInList() {
	// Call
	adjacent, err := t.visitor.Visit(t.ctx, t.knownNode)

	AssertEq(nil, err)
	ExpectThat(adjacent, ElementsAre())
}

////////////////////////////////////////////////////////////////////////
// Files, read
////////////////////////////////////////////////////////////////////////

type FilesFullTest struct {
	FilesLiteTest
}

var _ SetUpInterface = &FilesFullTest{}

func init() { RegisterTestSuite(&FilesFullTest{}) }

func (t *FilesFullTest) SetUp(ti *TestInfo) {
	t.FilesLiteTest.setUp(ti, true)
}

func (t *FilesFullTest) CallsBlobStore() {
	AssertFalse(true, "TODO")
}

func (t *FilesFullTest) BlobStoreReturnsError() {
	AssertFalse(true, "TODO")
}

func (t *FilesFullTest) BlobStoreSucceeds() {
	AssertFalse(true, "TODO")
}
<|endoftext|>


<commit_before>/*
	Copyright (C) 2016-2017 vLife Systems Ltd <http://vlifesystems.com>
	This file is part of rhkit.

	rhkit is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	rhkit is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with rhkit; see the file COPYING.  If not, see
	<http://www.gnu.org/licenses/>.
*/

// Package to handle functions to be used by dexpr
package dexprfuncs

import (
	"errors"
	"fmt"
	"github.com/lawrencewoodman/dexpr"
	"github.com/lawrencewoodman/dlit"
	"math"
	"strings"
)

var CallFuncs = map[string]dexpr.CallFun{}

func init() {
	CallFuncs["in"] = in
	CallFuncs["ni"] = ni
	CallFuncs["min"] = min
	CallFuncs["max"] = max
	CallFuncs["pow"] = pow
	CallFuncs["roundto"] = roundTo
	CallFuncs["sqrt"] = sqrt
	CallFuncs["true"] = alwaysTrue
}

var trueLiteral = dlit.MustNew(true)
var falseLiteral = dlit.MustNew(false)

type WrongNumOfArgsError struct {
	Got  int
	Want int
}

var ErrTooFewArguments = errors.New("too few arguments")
var ErrIncompatibleTypes = errors.New("incompatible types")

func (e WrongNumOfArgsError) Error() string {
	return fmt.Sprintf("wrong number of arguments got: %d, expected: %d",
		e.Got, e.Want)
}

type CantConvertToTypeError struct {
	Kind  string
	Value *dlit.Literal
}

func (e CantConvertToTypeError) Error() string {
	return fmt.Sprintf("can't convert to %s: %s", e.Kind, e.Value)
}

// sqrt returns the square root of a number
func sqrt(args []*dlit.Literal) (*dlit.Literal, error) {
	if len(args) != 1 {
		err := WrongNumOfArgsError{Got: len(args), Want: 1}
		r := dlit.MustNew(err)
		return r, err
	}
	x, isFloat := args[0].Float()
	if !isFloat {
		if err := args[0].Err(); err != nil {
			return args[0], err
		}
		err := CantConvertToTypeError{Kind: "float", Value: args[0]}
		r := dlit.MustNew(err)
		return r, err
	}
	return dlit.New(math.Sqrt(x))
}

// pow returns the base raised to the power of the exponent
func pow(args []*dlit.Literal) (*dlit.Literal, error) {
	if len(args) != 2 {
		err := WrongNumOfArgsError{Got: len(args), Want: 2}
		r := dlit.MustNew(err)
		return r, err
	}
	x, isFloat := args[0].Float()
	if !isFloat {
		if err := args[0].Err(); err != nil {
			return args[0], err
		}
		err := CantConvertToTypeError{Kind: "float", Value: args[0]}
		return dlit.MustNew(err), err
	}
	y, isFloat := args[1].Float()
	if !isFloat {
		if err := args[1].Err(); err != nil {
			return args[1], err
		}
		err := CantConvertToTypeError{Kind: "float", Value: args[1]}
		return dlit.MustNew(err), err
	}
	return dlit.New(math.Pow(x, y))
}

// roundto returns a number rounded to a number of decimal places.
// This uses round half-up to tie-break
func roundTo(args []*dlit.Literal) (*dlit.Literal, error) {
	if len(args) != 2 {
		err := WrongNumOfArgsError{Got: len(args), Want: 2}
		r := dlit.MustNew(err)
		return r, err
	}

	if _, isInt := args[0].Int(); isInt {
		return args[0], nil
	}

	x, isFloat := args[0].Float()
	if !isFloat {
		if err := args[0].Err(); err != nil {
			return args[0], err
		}
		err := CantConvertToTypeError{Kind: "float", Value: args[0]}
		r := dlit.MustNew(err)
		return r, err
	}
	dp, isInt := args[1].Int()
	if !isInt {
		if err := args[1].Err(); err != nil {
			return args[1], err
		}
		err := CantConvertToTypeError{Kind: "int", Value: args[0]}
		r := dlit.MustNew(err)
		return r, err
	}

	// Prevent rounding errors where too high dp is used
	xNumDP := numDecPlaces(args[0].String())
	if dp > int64(xNumDP) {
		dp = int64(xNumDP)
	}
	shift := math.Pow(10, float64(dp))
	return dlit.New(math.Floor(.5+x*shift) / shift)
}

// in returns whether a string is in a slice strings
func in(args []*dlit.Literal) (*dlit.Literal, error) {
	if len(args) < 2 {
		r := dlit.MustNew(ErrTooFewArguments)
		return r, ErrTooFewArguments
	}
	needle := args[0]
	haystack := args[1:]
	for _, v := range haystack {
		if needle.String() == v.String() {
			return trueLiteral, nil
		}
	}
	return falseLiteral, nil
}

// ni returns whether a string is not in a slice strings
func ni(args []*dlit.Literal) (*dlit.Literal, error) {
	if len(args) < 2 {
		r := dlit.MustNew(ErrTooFewArguments)
		return r, ErrTooFewArguments
	}
	needle := args[0]
	haystack := args[1:]
	for _, v := range haystack {
		if needle.String() == v.String() {
			return falseLiteral, nil
		}
	}
	return trueLiteral, nil
}

// min returns the smallest number of those supplied
func min(args []*dlit.Literal) (*dlit.Literal, error) {
	if len(args) < 2 {
		r := dlit.MustNew(ErrTooFewArguments)
		return r, ErrTooFewArguments
	}

	min := args[0]
	for _, v := range args[1:] {
		vars := map[string]*dlit.Literal{"min": min, "v": v}
		isSmaller, err := dexpr.EvalBool("v < min", CallFuncs, vars)
		if err != nil {
			if x, ok := err.(dexpr.InvalidExprError); ok {
				if x.Err == dexpr.ErrIncompatibleTypes {
					return dlit.MustNew(ErrIncompatibleTypes), ErrIncompatibleTypes
				}
				return dlit.MustNew(x.Err), x.Err
			}
			return dlit.MustNew(err), err
		}
		if isSmaller {
			min = v
		}
	}
	return min, nil
}

// max returns the smallest number of those supplied
func max(args []*dlit.Literal) (*dlit.Literal, error) {
	if len(args) < 2 {
		r := dlit.MustNew(ErrTooFewArguments)
		return r, ErrTooFewArguments
	}

	max := args[0]
	for _, v := range args[1:] {
		vars := map[string]*dlit.Literal{"max": max, "v": v}
		isBigger, err := dexpr.EvalBool("v > max", CallFuncs, vars)
		if err != nil {
			if x, ok := err.(dexpr.InvalidExprError); ok {
				if x.Err == dexpr.ErrIncompatibleTypes {
					return dlit.MustNew(ErrIncompatibleTypes), ErrIncompatibleTypes
				}
				return dlit.MustNew(x.Err), x.Err
			}
			return dlit.MustNew(err), err
		}
		if isBigger {
			max = v
		}
	}
	return max, nil
}

// alwaysTrue returns true
func alwaysTrue(args []*dlit.Literal) (*dlit.Literal, error) {
	return trueLiteral, nil
}

func numDecPlaces(s string) int {
	i := strings.IndexByte(s, '.')
	if i > -1 {
		s = strings.TrimRight(s, "0")
		return len(s) - i - 1
	}
	return 0
}
<commit_msg>Move expression creation out of Min/Max<commit_after>/*
	Copyright (C) 2016-2017 vLife Systems Ltd <http://vlifesystems.com>
	This file is part of rhkit.

	rhkit is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	rhkit is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with rhkit; see the file COPYING.  If not, see
	<http://www.gnu.org/licenses/>.
*/

// Package to handle functions to be used by dexpr
package dexprfuncs

import (
	"errors"
	"fmt"
	"github.com/lawrencewoodman/dexpr"
	"github.com/lawrencewoodman/dlit"
	"math"
	"strings"
)

var CallFuncs = map[string]dexpr.CallFun{}

func init() {
	CallFuncs["in"] = in
	CallFuncs["ni"] = ni
	CallFuncs["min"] = min
	CallFuncs["max"] = max
	CallFuncs["pow"] = pow
	CallFuncs["roundto"] = roundTo
	CallFuncs["sqrt"] = sqrt
	CallFuncs["true"] = alwaysTrue
}

var trueLiteral = dlit.MustNew(true)
var falseLiteral = dlit.MustNew(false)

type WrongNumOfArgsError struct {
	Got  int
	Want int
}

var ErrTooFewArguments = errors.New("too few arguments")
var ErrIncompatibleTypes = errors.New("incompatible types")

func (e WrongNumOfArgsError) Error() string {
	return fmt.Sprintf("wrong number of arguments got: %d, expected: %d",
		e.Got, e.Want)
}

type CantConvertToTypeError struct {
	Kind  string
	Value *dlit.Literal
}

func (e CantConvertToTypeError) Error() string {
	return fmt.Sprintf("can't convert to %s: %s", e.Kind, e.Value)
}

// sqrt returns the square root of a number
func sqrt(args []*dlit.Literal) (*dlit.Literal, error) {
	if len(args) != 1 {
		err := WrongNumOfArgsError{Got: len(args), Want: 1}
		r := dlit.MustNew(err)
		return r, err
	}
	x, isFloat := args[0].Float()
	if !isFloat {
		if err := args[0].Err(); err != nil {
			return args[0], err
		}
		err := CantConvertToTypeError{Kind: "float", Value: args[0]}
		r := dlit.MustNew(err)
		return r, err
	}
	return dlit.New(math.Sqrt(x))
}

// pow returns the base raised to the power of the exponent
func pow(args []*dlit.Literal) (*dlit.Literal, error) {
	if len(args) != 2 {
		err := WrongNumOfArgsError{Got: len(args), Want: 2}
		r := dlit.MustNew(err)
		return r, err
	}
	x, isFloat := args[0].Float()
	if !isFloat {
		if err := args[0].Err(); err != nil {
			return args[0], err
		}
		err := CantConvertToTypeError{Kind: "float", Value: args[0]}
		return dlit.MustNew(err), err
	}
	y, isFloat := args[1].Float()
	if !isFloat {
		if err := args[1].Err(); err != nil {
			return args[1], err
		}
		err := CantConvertToTypeError{Kind: "float", Value: args[1]}
		return dlit.MustNew(err), err
	}
	return dlit.New(math.Pow(x, y))
}

// roundto returns a number rounded to a number of decimal places.
// This uses round half-up to tie-break
func roundTo(args []*dlit.Literal) (*dlit.Literal, error) {
	if len(args) != 2 {
		err := WrongNumOfArgsError{Got: len(args), Want: 2}
		r := dlit.MustNew(err)
		return r, err
	}

	if _, isInt := args[0].Int(); isInt {
		return args[0], nil
	}

	x, isFloat := args[0].Float()
	if !isFloat {
		if err := args[0].Err(); err != nil {
			return args[0], err
		}
		err := CantConvertToTypeError{Kind: "float", Value: args[0]}
		r := dlit.MustNew(err)
		return r, err
	}
	dp, isInt := args[1].Int()
	if !isInt {
		if err := args[1].Err(); err != nil {
			return args[1], err
		}
		err := CantConvertToTypeError{Kind: "int", Value: args[0]}
		r := dlit.MustNew(err)
		return r, err
	}

	// Prevent rounding errors where too high dp is used
	xNumDP := numDecPlaces(args[0].String())
	if dp > int64(xNumDP) {
		dp = int64(xNumDP)
	}
	shift := math.Pow(10, float64(dp))
	return dlit.New(math.Floor(.5+x*shift) / shift)
}

// in returns whether a string is in a slice strings
func in(args []*dlit.Literal) (*dlit.Literal, error) {
	if len(args) < 2 {
		r := dlit.MustNew(ErrTooFewArguments)
		return r, ErrTooFewArguments
	}
	needle := args[0]
	haystack := args[1:]
	for _, v := range haystack {
		if needle.String() == v.String() {
			return trueLiteral, nil
		}
	}
	return falseLiteral, nil
}

// ni returns whether a string is not in a slice strings
func ni(args []*dlit.Literal) (*dlit.Literal, error) {
	if len(args) < 2 {
		r := dlit.MustNew(ErrTooFewArguments)
		return r, ErrTooFewArguments
	}
	needle := args[0]
	haystack := args[1:]
	for _, v := range haystack {
		if needle.String() == v.String() {
			return falseLiteral, nil
		}
	}
	return trueLiteral, nil
}

var isSmallerExpr = dexpr.MustNew("v < min", CallFuncs)

// min returns the smallest number of those supplied
func min(args []*dlit.Literal) (*dlit.Literal, error) {
	if len(args) < 2 {
		r := dlit.MustNew(ErrTooFewArguments)
		return r, ErrTooFewArguments
	}

	min := args[0]
	for _, v := range args[1:] {
		vars := map[string]*dlit.Literal{"min": min, "v": v}
		isSmaller, err := isSmallerExpr.EvalBool(vars)
		if err != nil {
			if x, ok := err.(dexpr.InvalidExprError); ok {
				if x.Err == dexpr.ErrIncompatibleTypes {
					return dlit.MustNew(ErrIncompatibleTypes), ErrIncompatibleTypes
				}
				return dlit.MustNew(x.Err), x.Err
			}
			return dlit.MustNew(err), err
		}
		if isSmaller {
			min = v
		}
	}
	return min, nil
}

var isBiggerExpr = dexpr.MustNew("v > max", CallFuncs)

// max returns the smallest number of those supplied
func max(args []*dlit.Literal) (*dlit.Literal, error) {
	if len(args) < 2 {
		r := dlit.MustNew(ErrTooFewArguments)
		return r, ErrTooFewArguments
	}

	max := args[0]
	for _, v := range args[1:] {
		vars := map[string]*dlit.Literal{"max": max, "v": v}
		isBigger, err := isBiggerExpr.EvalBool(vars)
		if err != nil {
			if x, ok := err.(dexpr.InvalidExprError); ok {
				if x.Err == dexpr.ErrIncompatibleTypes {
					return dlit.MustNew(ErrIncompatibleTypes), ErrIncompatibleTypes
				}
				return dlit.MustNew(x.Err), x.Err
			}
			return dlit.MustNew(err), err
		}
		if isBigger {
			max = v
		}
	}
	return max, nil
}

// alwaysTrue returns true
func alwaysTrue(args []*dlit.Literal) (*dlit.Literal, error) {
	return trueLiteral, nil
}

func numDecPlaces(s string) int {
	i := strings.IndexByte(s, '.')
	if i > -1 {
		s = strings.TrimRight(s, "0")
		return len(s) - i - 1
	}
	return 0
}
<|endoftext|>


<commit_before>package fusefrontend

import (
	"fmt"
	"log"
	"sync"
	"syscall"
	"time"

	"github.com/rfjakob/gocryptfs/internal/nametransform"
	"github.com/rfjakob/gocryptfs/internal/tlog"
)

const (
	// Number of entries in the dirCache. Three entries work well for two
	// (probably also three) parallel tar extracts (hit rate around 92%).
	dirCacheSize = 3
	// Enable Lookup/Store/Clear debug messages
	enableDebugMessages = false
	// Enable hit rate statistics printing
	enableStats = false
)

type dirCacheEntryStruct struct {
	// relative plaintext path to the directory
	dirRelPath string
	// fd to the directory (opened with O_PATH!)
	fd int
	// content of gocryptfs.diriv in this directory
	iv []byte
}

func (e *dirCacheEntryStruct) Clear() {
	// An earlier clear may have already closed the fd, or the cache
	// has never been filled (fd is 0 in that case).
	if e.fd > 0 {
		err := syscall.Close(e.fd)
		if err != nil {
			tlog.Warn.Printf("dirCache.Clear: Close failed: %v", err)
		}
	}
	e.fd = -1
	e.dirRelPath = ""
	e.iv = nil
}

type dirCacheStruct struct {
	sync.Mutex
	// Cache entries
	entries [dirCacheSize]dirCacheEntryStruct
	// Where to store the next entry (index into entries)
	nextIndex int
	// On the first Lookup(), the expire thread is stared, and this flag is set
	// to true.
	expireThreadRunning bool
	// Hit rate stats. Evaluated and reset by the expire thread.
	lookups uint64
	hits    uint64
}

// Clear clears the cache contents.
func (d *dirCacheStruct) Clear() {
	d.Lock()
	defer d.Unlock()
	for i := range d.entries {
		d.entries[i].Clear()
	}
}

// Store the entry in the cache. The passed "fd" will be Dup()ed, and the caller
// can close their copy at will.
func (d *dirCacheStruct) Store(dirRelPath string, fd int, iv []byte) {
	if fd <= 0 || len(iv) != nametransform.DirIVLen {
		log.Panicf("Store sanity check failed: fd=%d len=%d", fd, len(iv))
	}
	d.Lock()
	defer d.Unlock()
	e := &d.entries[d.nextIndex]
	// Round-robin works well enough
	d.nextIndex = (d.nextIndex + 1) % dirCacheSize
	// Close the old fd
	e.Clear()
	fd2, err := syscall.Dup(fd)
	if err != nil {
		tlog.Warn.Printf("dirCache.Store: Dup failed: %v", err)
		return
	}
	d.dbg("Store: %q %d %x\n", dirRelPath, fd2, iv)
	e.fd = fd2
	e.dirRelPath = dirRelPath
	e.iv = iv
	// expireThread is started on the first Lookup()
	if !d.expireThreadRunning {
		d.expireThreadRunning = true
		go d.expireThread()
	}
}

// Lookup checks if relPath is in the cache, and returns an (fd, iv) pair.
// It returns (-1, nil) if not found. The fd is internally Dup()ed and the
// caller must close it when done.
func (d *dirCacheStruct) Lookup(dirRelPath string) (fd int, iv []byte) {
	d.Lock()
	defer d.Unlock()
	if enableStats {
		d.lookups++
	}
	for i := range d.entries {
		e := &d.entries[i]
		if e.fd <= 0 {
			// Cache slot is empty
			continue
		}
		if dirRelPath != e.dirRelPath {
			// Not the right path
			continue
		}
		var err error
		fd, err = syscall.Dup(e.fd)
		if err != nil {
			tlog.Warn.Printf("dirCache.Lookup: Dup failed: %v", err)
			return -1, nil
		}
		iv = e.iv
	}
	if fd == 0 {
		d.dbg("Lookup %q: miss\n", dirRelPath)
		return -1, nil
	}
	if enableStats {
		d.hits++
	}
	if fd <= 0 || len(iv) != nametransform.DirIVLen {
		log.Panicf("Lookup sanity check failed: fd=%d len=%d", fd, len(iv))
	}
	d.dbg("Lookup %q: hit %d %x\n", dirRelPath, fd, iv)
	return fd, iv
}

// expireThread is started on the first Lookup()
func (d *dirCacheStruct) expireThread() {
	for {
		time.Sleep(1 * time.Second)
		d.Clear()
		if enableStats {
			d.Lock()
			lookups := d.lookups
			hits := d.hits
			d.lookups = 0
			d.hits = 0
			d.Unlock()
			if lookups > 0 {
				fmt.Printf("dirCache: hits=%3d lookups=%3d, rate=%3d%%\n", hits, lookups, (hits*100)/lookups)
			}
		}
	}
}

// dbg prints a debug message. Usually disabled.
func (d *dirCacheStruct) dbg(format string, a ...interface{}) {
	if enableDebugMessages {
		fmt.Printf(format, a...)
	}
}
<commit_msg>fusefrontend: fix fd leak in dirCache<commit_after>package fusefrontend

import (
	"fmt"
	"log"
	"sync"
	"syscall"
	"time"

	"github.com/rfjakob/gocryptfs/internal/nametransform"
	"github.com/rfjakob/gocryptfs/internal/tlog"
)

const (
	// Number of entries in the dirCache. Three entries work well for two
	// (probably also three) parallel tar extracts (hit rate around 92%).
	dirCacheSize = 3
	// Enable Lookup/Store/Clear debug messages
	enableDebugMessages = false
	// Enable hit rate statistics printing
	enableStats = false
)

type dirCacheEntryStruct struct {
	// relative plaintext path to the directory
	dirRelPath string
	// fd to the directory (opened with O_PATH!)
	fd int
	// content of gocryptfs.diriv in this directory
	iv []byte
}

func (e *dirCacheEntryStruct) Clear() {
	// An earlier clear may have already closed the fd, or the cache
	// has never been filled (fd is 0 in that case).
	if e.fd > 0 {
		err := syscall.Close(e.fd)
		if err != nil {
			tlog.Warn.Printf("dirCache.Clear: Close failed: %v", err)
		}
	}
	e.fd = -1
	e.dirRelPath = ""
	e.iv = nil
}

type dirCacheStruct struct {
	sync.Mutex
	// Cache entries
	entries [dirCacheSize]dirCacheEntryStruct
	// Where to store the next entry (index into entries)
	nextIndex int
	// On the first Lookup(), the expire thread is stared, and this flag is set
	// to true.
	expireThreadRunning bool
	// Hit rate stats. Evaluated and reset by the expire thread.
	lookups uint64
	hits    uint64
}

// Clear clears the cache contents.
func (d *dirCacheStruct) Clear() {
	d.Lock()
	defer d.Unlock()
	for i := range d.entries {
		d.entries[i].Clear()
	}
}

// Store the entry in the cache. The passed "fd" will be Dup()ed, and the caller
// can close their copy at will.
func (d *dirCacheStruct) Store(dirRelPath string, fd int, iv []byte) {
	if fd <= 0 || len(iv) != nametransform.DirIVLen {
		log.Panicf("Store sanity check failed: fd=%d len=%d", fd, len(iv))
	}
	d.Lock()
	defer d.Unlock()
	e := &d.entries[d.nextIndex]
	// Round-robin works well enough
	d.nextIndex = (d.nextIndex + 1) % dirCacheSize
	// Close the old fd
	e.Clear()
	fd2, err := syscall.Dup(fd)
	if err != nil {
		tlog.Warn.Printf("dirCache.Store: Dup failed: %v", err)
		return
	}
	d.dbg("Store: %q %d %x\n", dirRelPath, fd2, iv)
	e.fd = fd2
	e.dirRelPath = dirRelPath
	e.iv = iv
	// expireThread is started on the first Lookup()
	if !d.expireThreadRunning {
		d.expireThreadRunning = true
		go d.expireThread()
	}
}

// Lookup checks if relPath is in the cache, and returns an (fd, iv) pair.
// It returns (-1, nil) if not found. The fd is internally Dup()ed and the
// caller must close it when done.
func (d *dirCacheStruct) Lookup(dirRelPath string) (fd int, iv []byte) {
	d.Lock()
	defer d.Unlock()
	if enableStats {
		d.lookups++
	}
	for i := range d.entries {
		e := &d.entries[i]
		if e.fd <= 0 {
			// Cache slot is empty
			continue
		}
		if dirRelPath != e.dirRelPath {
			// Not the right path
			continue
		}
		var err error
		fd, err = syscall.Dup(e.fd)
		if err != nil {
			tlog.Warn.Printf("dirCache.Lookup: Dup failed: %v", err)
			return -1, nil
		}
		iv = e.iv
		break
	}
	if fd == 0 {
		d.dbg("Lookup %q: miss\n", dirRelPath)
		return -1, nil
	}
	if enableStats {
		d.hits++
	}
	if fd <= 0 || len(iv) != nametransform.DirIVLen {
		log.Panicf("Lookup sanity check failed: fd=%d len=%d", fd, len(iv))
	}
	d.dbg("Lookup %q: hit %d %x\n", dirRelPath, fd, iv)
	return fd, iv
}

// expireThread is started on the first Lookup()
func (d *dirCacheStruct) expireThread() {
	for {
		time.Sleep(1 * time.Second)
		d.Clear()
		if enableStats {
			d.Lock()
			lookups := d.lookups
			hits := d.hits
			d.lookups = 0
			d.hits = 0
			d.Unlock()
			if lookups > 0 {
				fmt.Printf("dirCache: hits=%3d lookups=%3d, rate=%3d%%\n", hits, lookups, (hits*100)/lookups)
			}
		}
	}
}

// dbg prints a debug message. Usually disabled.
func (d *dirCacheStruct) dbg(format string, a ...interface{}) {
	if enableDebugMessages {
		fmt.Printf(format, a...)
	}
}
<|endoftext|>


<commit_before>// +build windows

package hcsoci

// Contains functions relating to a WCOW container, as opposed to a utility VM

import (
	"fmt"
	"os"
	"path/filepath"
	"strings"

	"github.com/Microsoft/hcsshim/internal/guestrequest"
	"github.com/Microsoft/hcsshim/internal/schema2"
	"github.com/Microsoft/hcsshim/internal/schemaversion"
	"github.com/Microsoft/hcsshim/internal/wclayer"
	specs "github.com/opencontainers/runtime-spec/specs-go"
	"github.com/sirupsen/logrus"
)

func allocateWindowsResources(coi *createOptionsInternal, resources *Resources) error {
	scratchFolder := coi.Spec.Windows.LayerFolders[len(coi.Spec.Windows.LayerFolders)-1]
	logrus.Debugf("hcsshim::allocateWindowsResources scratch folder: %s", scratchFolder)

	// TODO: Remove this code for auto-creation. Make the caller responsible.
	// Create the directory for the RW scratch layer if it doesn't exist
	if _, err := os.Stat(scratchFolder); os.IsNotExist(err) {
		logrus.Debugf("hcsshim::allocateWindowsResources container scratch folder does not exist so creating: %s ", scratchFolder)
		if err := os.MkdirAll(scratchFolder, 0777); err != nil {
			return fmt.Errorf("failed to auto-create container scratch folder %s: %s", scratchFolder, err)
		}
	}

	// Create sandbox.vhdx if it doesn't exist in the scratch folder. It's called sandbox.vhdx
	// rather than scratch.vhdx as in the v1 schema, it's hard-coded in HCS.
	if _, err := os.Stat(filepath.Join(scratchFolder, "sandbox.vhdx")); os.IsNotExist(err) {
		logrus.Debugf("hcsshim::allocateWindowsResources container sandbox.vhdx does not exist so creating in %s ", scratchFolder)
		if err := wclayer.CreateScratchLayer(scratchFolder, coi.Spec.Windows.LayerFolders[:len(coi.Spec.Windows.LayerFolders)-1]); err != nil {
			return fmt.Errorf("failed to CreateSandboxLayer %s", err)
		}
	}

	if coi.Spec.Root == nil {
		coi.Spec.Root = &specs.Root{}
	}

	if coi.Spec.Root.Path == "" && (coi.HostingSystem != nil || coi.Spec.Windows.HyperV == nil) {
		logrus.Debugln("hcsshim::allocateWindowsResources mounting storage")
		mcl, err := MountContainerLayers(coi.Spec.Windows.LayerFolders, resources.containerRootInUVM, coi.HostingSystem)
		if err != nil {
			return fmt.Errorf("failed to mount container storage: %s", err)
		}
		if coi.HostingSystem == nil {
			coi.Spec.Root.Path = mcl.(string) // Argon v1 or v2
		} else {
			coi.Spec.Root.Path = mcl.(guestrequest.CombinedLayers).ContainerRootPath // v2 Xenon WCOW
		}
		resources.layers = coi.Spec.Windows.LayerFolders
	}

	// Validate each of the mounts. If this is a V2 Xenon, we have to add them as
	// VSMB shares to the utility VM. For V1 Xenon and Argons, there's nothing for
	// us to do as it's done by HCS.
	for _, mount := range coi.Spec.Mounts {
		if mount.Destination == "" || mount.Source == "" {
			return fmt.Errorf("invalid OCI spec - a mount must have both source and a destination: %+v", mount)
		}
		if mount.Type != "" {
			return fmt.Errorf("invalid OCI spec - Type '%s' must not be set", mount.Type)
		}

		if coi.HostingSystem != nil && schemaversion.IsV21(coi.actualSchemaVersion) {
			logrus.Debugf("hcsshim::allocateWindowsResources Hot-adding VSMB share for OCI mount %+v", mount)
			options := &hcsschema.VirtualSmbShareOptions{}
			for _, o := range mount.Options {
				if strings.ToLower(o) == "ro" {
					options.ReadOnly = true
					options.CacheIo = true
					options.ShareRead = true
					options.ForceLevelIIOplocks = true
					break
				}
			}

			err := coi.HostingSystem.AddVSMB(mount.Source, "", options)
			if err != nil {
				return fmt.Errorf("failed to add VSMB share to utility VM for mount %+v: %s", mount, err)
			}
			resources.vsmbMounts = append(resources.vsmbMounts, mount.Source)
		}
	}

	return nil
}
<commit_msg>Nil check in allocateWindowsResources<commit_after>// +build windows

package hcsoci

// Contains functions relating to a WCOW container, as opposed to a utility VM

import (
	"fmt"
	"os"
	"path/filepath"
	"strings"

	"github.com/Microsoft/hcsshim/internal/guestrequest"
	"github.com/Microsoft/hcsshim/internal/schema2"
	"github.com/Microsoft/hcsshim/internal/schemaversion"
	"github.com/Microsoft/hcsshim/internal/wclayer"
	specs "github.com/opencontainers/runtime-spec/specs-go"
	"github.com/sirupsen/logrus"
)

func allocateWindowsResources(coi *createOptionsInternal, resources *Resources) error {
	if coi.Spec == nil || coi.Spec.Windows == nil || coi.Spec.Windows.LayerFolders == nil {
		return fmt.Errorf("field 'Spec.Windows.Layerfolders' is not populated")
	}

	scratchFolder := coi.Spec.Windows.LayerFolders[len(coi.Spec.Windows.LayerFolders)-1]
	logrus.Debugf("hcsshim::allocateWindowsResources scratch folder: %s", scratchFolder)

	// TODO: Remove this code for auto-creation. Make the caller responsible.
	// Create the directory for the RW scratch layer if it doesn't exist
	if _, err := os.Stat(scratchFolder); os.IsNotExist(err) {
		logrus.Debugf("hcsshim::allocateWindowsResources container scratch folder does not exist so creating: %s ", scratchFolder)
		if err := os.MkdirAll(scratchFolder, 0777); err != nil {
			return fmt.Errorf("failed to auto-create container scratch folder %s: %s", scratchFolder, err)
		}
	}

	// Create sandbox.vhdx if it doesn't exist in the scratch folder. It's called sandbox.vhdx
	// rather than scratch.vhdx as in the v1 schema, it's hard-coded in HCS.
	if _, err := os.Stat(filepath.Join(scratchFolder, "sandbox.vhdx")); os.IsNotExist(err) {
		logrus.Debugf("hcsshim::allocateWindowsResources container sandbox.vhdx does not exist so creating in %s ", scratchFolder)
		if err := wclayer.CreateScratchLayer(scratchFolder, coi.Spec.Windows.LayerFolders[:len(coi.Spec.Windows.LayerFolders)-1]); err != nil {
			return fmt.Errorf("failed to CreateSandboxLayer %s", err)
		}
	}

	if coi.Spec.Root == nil {
		coi.Spec.Root = &specs.Root{}
	}

	if coi.Spec.Root.Path == "" && (coi.HostingSystem != nil || coi.Spec.Windows.HyperV == nil) {
		logrus.Debugln("hcsshim::allocateWindowsResources mounting storage")
		mcl, err := MountContainerLayers(coi.Spec.Windows.LayerFolders, resources.containerRootInUVM, coi.HostingSystem)
		if err != nil {
			return fmt.Errorf("failed to mount container storage: %s", err)
		}
		if coi.HostingSystem == nil {
			coi.Spec.Root.Path = mcl.(string) // Argon v1 or v2
		} else {
			coi.Spec.Root.Path = mcl.(guestrequest.CombinedLayers).ContainerRootPath // v2 Xenon WCOW
		}
		resources.layers = coi.Spec.Windows.LayerFolders
	}

	// Validate each of the mounts. If this is a V2 Xenon, we have to add them as
	// VSMB shares to the utility VM. For V1 Xenon and Argons, there's nothing for
	// us to do as it's done by HCS.
	for _, mount := range coi.Spec.Mounts {
		if mount.Destination == "" || mount.Source == "" {
			return fmt.Errorf("invalid OCI spec - a mount must have both source and a destination: %+v", mount)
		}
		if mount.Type != "" {
			return fmt.Errorf("invalid OCI spec - Type '%s' must not be set", mount.Type)
		}

		if coi.HostingSystem != nil && schemaversion.IsV21(coi.actualSchemaVersion) {
			logrus.Debugf("hcsshim::allocateWindowsResources Hot-adding VSMB share for OCI mount %+v", mount)
			options := &hcsschema.VirtualSmbShareOptions{}
			for _, o := range mount.Options {
				if strings.ToLower(o) == "ro" {
					options.ReadOnly = true
					options.CacheIo = true
					options.ShareRead = true
					options.ForceLevelIIOplocks = true
					break
				}
			}

			err := coi.HostingSystem.AddVSMB(mount.Source, "", options)
			if err != nil {
				return fmt.Errorf("failed to add VSMB share to utility VM for mount %+v: %s", mount, err)
			}
			resources.vsmbMounts = append(resources.vsmbMounts, mount.Source)
		}
	}

	return nil
}
<|endoftext|>