<commit_before>package docker

import (
	"bufio"
	"bytes"
	"context"
	"fmt"
	"github.com/ViBiOh/docker-deploy/jsonHttp"
	"github.com/docker/docker/api/types"
	"github.com/docker/docker/api/types/container"
	"github.com/docker/docker/api/types/filters"
	"github.com/docker/docker/api/types/network"
	"github.com/docker/docker/api/types/strslice"
	"github.com/docker/docker/client"
	"gopkg.in/yaml.v2"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"regexp"
	"strings"
)

const host = `DOCKER_HOST`
const version = `DOCKER_VERSION`
const configurationFile = `./users`
const admin = `admin`
const ownerLabel = `owner`
const appLabel = `app`
const minMemory = 67108864
const maxMemory = 536870912
const defaultTag = `latest`

var commaByte = []byte(`,`)
var splitLogs = regexp.MustCompile(`.{8}(.*?)\n`)

var networkConfig = network.NetworkingConfig{
	EndpointsConfig: map[string]*network.EndpointSettings{
		`traefik`: &network.EndpointSettings{},
	},
}

var imageTag = regexp.MustCompile(`^\S*?:\S+$`)

var containersRequest = regexp.MustCompile(`/containers/?$`)
var containerRequest = regexp.MustCompile(`/containers/([^/]+)/?$`)
var startRequest = regexp.MustCompile(`/containers/([^/]+)/start`)
var stopRequest = regexp.MustCompile(`/containers/([^/]+)/stop`)
var restartRequest = regexp.MustCompile(`/containers/([^/]+)/restart`)
var logRequest = regexp.MustCompile(`/containers/([^/]+)/logs`)

type results struct {
	Results interface{} `json:"results"`
}

type user struct {
	username string
	password string
	role     string
}

type dockerComposeService struct {
	Image       string
	Command     string
	Environment map[string]string
	Labels      map[string]string
	ReadOnly    bool  `yaml:"read_only"`
	CPUShares   int64 `yaml:"cpu_shares"`
	MemoryLimit int64 `yaml:"mem_limit"`
}

type dockerCompose struct {
	Version  string
	Services map[string]dockerComposeService
}

var docker *client.Client
var users map[string]*user

func errorHandler(w http.ResponseWriter, err error) {
	log.Print(err)
	http.Error(w, err.Error(), http.StatusInternalServerError)
}

func init() {
	users = readConfiguration(configurationFile)

	client, err := client.NewClient(os.Getenv(host), os.Getenv(version), nil, nil)
	if err != nil {
		log.Fatal(err)
	} else {
		docker = client
	}
}

func readConfiguration(path string) map[string]*user {
	configFile, err := os.Open(path)
	defer configFile.Close()

	if err != nil {
		log.Print(err)
		return nil
	}

	users := make(map[string]*user)

	scanner := bufio.NewScanner(configFile)
	for scanner.Scan() {
		parts := bytes.Split(scanner.Bytes(), commaByte)
		user := user{string(parts[0]), string(parts[1]), string(parts[2])}

		users[strings.ToLower(user.username)] = &user
	}

	return users
}

func isAllowed(loggedUser *user, containerID string) (bool, error) {
	if loggedUser.role != admin {
		container, err := inspectContainer(string(containerID))
		if err != nil {
			return false, err
		}

		owner, ok := container.Config.Labels[ownerLabel]
		if !ok || owner != loggedUser.username {
			return false, nil
		}
	}

	return true, nil
}

func listContainers(loggedUser *user, appName *string) ([]types.Container, error) {
	options := types.ContainerListOptions{All: true}

	options.Filters = filters.NewArgs()

	if loggedUser != nil && loggedUser.role != admin {
		if _, err := filters.ParseFlag(`label=`+ownerLabel+`=`+loggedUser.username, options.Filters); err != nil {
			return nil, err
		}
	} else if appName != nil && *appName != `` {
		if _, err := filters.ParseFlag(`label=`+appLabel+`=`+*appName, options.Filters); err != nil {
			return nil, err
		}
	}

	return docker.ContainerList(context.Background(), options)
}

func inspectContainer(containerID string) (types.ContainerJSON, error) {
	return docker.ContainerInspect(context.Background(), containerID)
}

func startContainer(containerID string) error {
	return docker.ContainerStart(context.Background(), string(containerID), types.ContainerStartOptions{})
}

func stopContainer(containerID string) error {
	return docker.ContainerStop(context.Background(), containerID, nil)
}

func restartContainer(containerID string) error {
	return docker.ContainerRestart(context.Background(), containerID, nil)
}

func rmContainer(containerID string) error {
	return docker.ContainerRemove(context.Background(), containerID, types.ContainerRemoveOptions{RemoveVolumes: true, Force: true})
}

func inspectContainerHandler(w http.ResponseWriter, containerID []byte) {
	if container, err := inspectContainer(string(containerID)); err != nil {
		errorHandler(w, err)
	} else {
		jsonHttp.ResponseJSON(w, container)
	}
}

func basicActionHandler(w http.ResponseWriter, loggedUser *user, containerID []byte, handle func(string) error) {
	id := string(containerID)

	allowed, err := isAllowed(loggedUser, id)
	if !allowed {
		forbidden(w)
	} else if err != nil {
		errorHandler(w, err)
	} else {
		if err = handle(id); err != nil {
			errorHandler(w, err)
		} else {
			w.Write(nil)
		}
	}
}

func logContainerHandler(w http.ResponseWriter, containerID []byte) {
	logs, err := docker.ContainerLogs(context.Background(), string(containerID), types.ContainerLogsOptions{ShowStdout: true, ShowStderr: true, Follow: false})
	if err != nil {
		errorHandler(w, err)
		return
	}

	defer logs.Close()

	if logLines, err := ioutil.ReadAll(logs); err != nil {
		errorHandler(w, err)
	} else {
		matches := splitLogs.FindAllSubmatch(logLines, -1)
		cleanLogs := make([]string, 0, len(matches))
		for _, match := range matches {
			cleanLogs = append(cleanLogs, string(match[1]))
		}

		jsonHttp.ResponseJSON(w, results{cleanLogs})
	}
}

func listContainersHandler(w http.ResponseWriter, loggerUser *user) {
	if containers, err := listContainers(loggerUser, nil); err != nil {
		errorHandler(w, err)
	} else {
		jsonHttp.ResponseJSON(w, results{containers})
	}
}

func readBody(body io.ReadCloser) ([]byte, error) {
	defer body.Close()
	return ioutil.ReadAll(body)
}

func getConfig(service *dockerComposeService, loggedUser *user, appName string) *container.Config {
	environments := make([]string, len(service.Environment))
	for key, value := range service.Environment {
		environments = append(environments, key+`=`+value)
	}

	if service.Labels == nil {
		service.Labels = make(map[string]string)
	}

	service.Labels[ownerLabel] = loggedUser.username
	service.Labels[appLabel] = appName

	config := container.Config{
		Image:  service.Image,
		Labels: service.Labels,
		Env:    environments,
	}

	if service.Command != `` {
		config.Cmd = strslice.StrSlice([]string{service.Command})
	}

	return &config
}

func getHostConfig(service *dockerComposeService) *container.HostConfig {
	hostConfig := container.HostConfig{
		LogConfig: container.LogConfig{Type: `json-file`, Config: map[string]string{
			`max-size`: `50m`,
		}},
		RestartPolicy: container.RestartPolicy{Name: `on-failure`, MaximumRetryCount: 5},
		Resources: container.Resources{
			CPUShares: 128,
			Memory:    minMemory,
		},
		SecurityOpt: []string{`no-new-privileges`},
	}

	if service.ReadOnly {
		hostConfig.ReadonlyRootfs = service.ReadOnly
	}

	if service.CPUShares != 0 {
		hostConfig.Resources.CPUShares = service.CPUShares
	}

	if service.MemoryLimit != 0 {
		if service.MemoryLimit < maxMemory {
			hostConfig.Resources.Memory = service.MemoryLimit
		} else {
			hostConfig.Resources.Memory = maxMemory
		}
	}

	return &hostConfig
}

func createAppHandler(w http.ResponseWriter, loggedUser *user, appName []byte, composeFile []byte) {
	if len(appName) == 0 || len(composeFile) == 0 {
		http.Error(w, `An application name and a compose file are required`, http.StatusBadRequest)
		return
	}

	compose := dockerCompose{}
	if err := yaml.Unmarshal(composeFile, &compose); err != nil {
		errorHandler(w, err)
		return
	}

	appNameStr := string(appName)
	log.Print(loggedUser.username + ` deploys ` + appNameStr)

	ownerContainers, err := listContainers(loggedUser, &appNameStr)
	if err != nil {
		errorHandler(w, err)
		return
	}
	for _, container := range ownerContainers {
		log.Print(loggedUser.username + ` stops ` + strings.Join(container.Names, `, `))
		stopContainer(container.ID)
		log.Print(loggedUser.username + ` rm ` + strings.Join(container.Names, `, `))
		rmContainer(container.ID)
	}

	ids := make([]string, len(compose.Services))
	for serviceName, service := range compose.Services {
		image := service.Image
		if !imageTag.Match(image) {
			image = image + defaultTag
		}

		log.Print(loggedUser.username + ` pulls ` + image)
		pull, err := docker.ImagePull(context.Background(), image, types.ImagePullOptions{})
		if err != nil {
			errorHandler(w, err)
			return
		}

		readBody(pull)
		log.Print(loggedUser.username + ` pulls ended for ` + image)

		log.Print(loggedUser.username + ` starts ` + serviceName)
		id, err := docker.ContainerCreate(context.Background(), getConfig(&service, loggedUser, appNameStr), getHostConfig(&service), &networkConfig, appNameStr+`_`+serviceName)
		if err != nil {
			errorHandler(w, err)
			return
		}

		startContainer(id.ID)
		ids = append(ids, id.ID)
	}

	jsonHttp.ResponseJSON(w, results{ids})
}

func isAuthenticated(r *http.Request) (*user, error) {
	username, password, ok := r.BasicAuth()

	if ok {
		user, ok := users[strings.ToLower(username)]

		if ok && user.password == password {
			return user, nil
		} else {
			return nil, fmt.Errorf(`Invalid credentials for ` + username)
		}
	}

	return nil, fmt.Errorf(`Unable to read basic authentication`)
}

func unauthorized(w http.ResponseWriter, err error) {
	http.Error(w, err.Error(), http.StatusUnauthorized)
}

func forbidden(w http.ResponseWriter) {
	http.Error(w, `Forbidden`, http.StatusForbidden)
}

// Handler for Hello request. Should be use with net/http
type Handler struct {
}

func (handler Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	w.Header().Add(`Access-Control-Allow-Origin`, `*`)
	w.Header().Add(`Access-Control-Allow-Headers`, `Content-Type, Authorization`)
	w.Header().Add(`Access-Control-Allow-Methods`, `GET, POST, DELETE`)
	w.Header().Add(`X-Content-Type-Options`, `nosniff`)

	if r.Method == http.MethodOptions {
		w.Write(nil)
		return
	}

	loggedUser, err := isAuthenticated(r)
	if err != nil {
		unauthorized(w, err)
		return
	}

	urlPath := []byte(r.URL.Path)

	if containersRequest.Match(urlPath) && r.Method == http.MethodGet {
		listContainersHandler(w, loggedUser)
	} else if containerRequest.Match(urlPath) && r.Method == http.MethodGet {
		inspectContainerHandler(w, containerRequest.FindSubmatch(urlPath)[1])
	} else if startRequest.Match(urlPath) && r.Method == http.MethodPost {
		basicActionHandler(w, loggedUser, startRequest.FindSubmatch(urlPath)[1], startContainer)
	} else if stopRequest.Match(urlPath) && r.Method == http.MethodPost {
		basicActionHandler(w, loggedUser, stopRequest.FindSubmatch(urlPath)[1], stopContainer)
	} else if restartRequest.Match(urlPath) && r.Method == http.MethodPost {
		basicActionHandler(w, loggedUser, restartRequest.FindSubmatch(urlPath)[1], restartContainer)
	} else if containerRequest.Match(urlPath) && r.Method == http.MethodDelete {
		basicActionHandler(w, loggedUser, containerRequest.FindSubmatch(urlPath)[1], rmContainer)
	} else if logRequest.Match(urlPath) && r.Method == http.MethodGet {
		logContainerHandler(w, logRequest.FindSubmatch(urlPath)[1])
	} else if containerRequest.Match(urlPath) && r.Method == http.MethodPost {
		if composeBody, err := readBody(r.Body); err != nil {
			errorHandler(w, err)
		} else {
			createAppHandler(w, loggedUser, containerRequest.FindSubmatch(urlPath)[1], composeBody)
		}
	}
}
<commit_msg>Update docker.go<commit_after>package docker

import (
	"bufio"
	"bytes"
	"context"
	"fmt"
	"github.com/ViBiOh/docker-deploy/jsonHttp"
	"github.com/docker/docker/api/types"
	"github.com/docker/docker/api/types/container"
	"github.com/docker/docker/api/types/filters"
	"github.com/docker/docker/api/types/network"
	"github.com/docker/docker/api/types/strslice"
	"github.com/docker/docker/client"
	"gopkg.in/yaml.v2"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"regexp"
	"strings"
)

const host = `DOCKER_HOST`
const version = `DOCKER_VERSION`
const configurationFile = `./users`
const admin = `admin`
const ownerLabel = `owner`
const appLabel = `app`
const minMemory = 67108864
const maxMemory = 536870912
const defaultTag = `latest`

var commaByte = []byte(`,`)
var splitLogs = regexp.MustCompile(`.{8}(.*?)\n`)

var networkConfig = network.NetworkingConfig{
	EndpointsConfig: map[string]*network.EndpointSettings{
		`traefik`: &network.EndpointSettings{},
	},
}

var imageTag = regexp.MustCompile(`^\S*?:\S+$`)

var containersRequest = regexp.MustCompile(`/containers/?$`)
var containerRequest = regexp.MustCompile(`/containers/([^/]+)/?$`)
var startRequest = regexp.MustCompile(`/containers/([^/]+)/start`)
var stopRequest = regexp.MustCompile(`/containers/([^/]+)/stop`)
var restartRequest = regexp.MustCompile(`/containers/([^/]+)/restart`)
var logRequest = regexp.MustCompile(`/containers/([^/]+)/logs`)

type results struct {
	Results interface{} `json:"results"`
}

type user struct {
	username string
	password string
	role     string
}

type dockerComposeService struct {
	Image       string
	Command     string
	Environment map[string]string
	Labels      map[string]string
	ReadOnly    bool  `yaml:"read_only"`
	CPUShares   int64 `yaml:"cpu_shares"`
	MemoryLimit int64 `yaml:"mem_limit"`
}

type dockerCompose struct {
	Version  string
	Services map[string]dockerComposeService
}

var docker *client.Client
var users map[string]*user

func errorHandler(w http.ResponseWriter, err error) {
	log.Print(err)
	http.Error(w, err.Error(), http.StatusInternalServerError)
}

func init() {
	users = readConfiguration(configurationFile)

	client, err := client.NewClient(os.Getenv(host), os.Getenv(version), nil, nil)
	if err != nil {
		log.Fatal(err)
	} else {
		docker = client
	}
}

func readConfiguration(path string) map[string]*user {
	configFile, err := os.Open(path)
	defer configFile.Close()

	if err != nil {
		log.Print(err)
		return nil
	}

	users := make(map[string]*user)

	scanner := bufio.NewScanner(configFile)
	for scanner.Scan() {
		parts := bytes.Split(scanner.Bytes(), commaByte)
		user := user{string(parts[0]), string(parts[1]), string(parts[2])}

		users[strings.ToLower(user.username)] = &user
	}

	return users
}

func isAllowed(loggedUser *user, containerID string) (bool, error) {
	if loggedUser.role != admin {
		container, err := inspectContainer(string(containerID))
		if err != nil {
			return false, err
		}

		owner, ok := container.Config.Labels[ownerLabel]
		if !ok || owner != loggedUser.username {
			return false, nil
		}
	}

	return true, nil
}

func listContainers(loggedUser *user, appName *string) ([]types.Container, error) {
	options := types.ContainerListOptions{All: true}

	options.Filters = filters.NewArgs()

	if loggedUser != nil && loggedUser.role != admin {
		if _, err := filters.ParseFlag(`label=`+ownerLabel+`=`+loggedUser.username, options.Filters); err != nil {
			return nil, err
		}
	} else if appName != nil && *appName != `` {
		if _, err := filters.ParseFlag(`label=`+appLabel+`=`+*appName, options.Filters); err != nil {
			return nil, err
		}
	}

	return docker.ContainerList(context.Background(), options)
}

func inspectContainer(containerID string) (types.ContainerJSON, error) {
	return docker.ContainerInspect(context.Background(), containerID)
}

func startContainer(containerID string) error {
	return docker.ContainerStart(context.Background(), string(containerID), types.ContainerStartOptions{})
}

func stopContainer(containerID string) error {
	return docker.ContainerStop(context.Background(), containerID, nil)
}

func restartContainer(containerID string) error {
	return docker.ContainerRestart(context.Background(), containerID, nil)
}

func rmContainer(containerID string) error {
	return docker.ContainerRemove(context.Background(), containerID, types.ContainerRemoveOptions{RemoveVolumes: true, Force: true})
}

func inspectContainerHandler(w http.ResponseWriter, containerID []byte) {
	if container, err := inspectContainer(string(containerID)); err != nil {
		errorHandler(w, err)
	} else {
		jsonHttp.ResponseJSON(w, container)
	}
}

func basicActionHandler(w http.ResponseWriter, loggedUser *user, containerID []byte, handle func(string) error) {
	id := string(containerID)

	allowed, err := isAllowed(loggedUser, id)
	if !allowed {
		forbidden(w)
	} else if err != nil {
		errorHandler(w, err)
	} else {
		if err = handle(id); err != nil {
			errorHandler(w, err)
		} else {
			w.Write(nil)
		}
	}
}

func logContainerHandler(w http.ResponseWriter, containerID []byte) {
	logs, err := docker.ContainerLogs(context.Background(), string(containerID), types.ContainerLogsOptions{ShowStdout: true, ShowStderr: true, Follow: false})
	if err != nil {
		errorHandler(w, err)
		return
	}

	defer logs.Close()

	if logLines, err := ioutil.ReadAll(logs); err != nil {
		errorHandler(w, err)
	} else {
		matches := splitLogs.FindAllSubmatch(logLines, -1)
		cleanLogs := make([]string, 0, len(matches))
		for _, match := range matches {
			cleanLogs = append(cleanLogs, string(match[1]))
		}

		jsonHttp.ResponseJSON(w, results{cleanLogs})
	}
}

func listContainersHandler(w http.ResponseWriter, loggerUser *user) {
	if containers, err := listContainers(loggerUser, nil); err != nil {
		errorHandler(w, err)
	} else {
		jsonHttp.ResponseJSON(w, results{containers})
	}
}

func readBody(body io.ReadCloser) ([]byte, error) {
	defer body.Close()
	return ioutil.ReadAll(body)
}

func getConfig(service *dockerComposeService, loggedUser *user, appName string) *container.Config {
	environments := make([]string, len(service.Environment))
	for key, value := range service.Environment {
		environments = append(environments, key+`=`+value)
	}

	if service.Labels == nil {
		service.Labels = make(map[string]string)
	}

	service.Labels[ownerLabel] = loggedUser.username
	service.Labels[appLabel] = appName

	config := container.Config{
		Image:  service.Image,
		Labels: service.Labels,
		Env:    environments,
	}

	if service.Command != `` {
		config.Cmd = strslice.StrSlice([]string{service.Command})
	}

	return &config
}

func getHostConfig(service *dockerComposeService) *container.HostConfig {
	hostConfig := container.HostConfig{
		LogConfig: container.LogConfig{Type: `json-file`, Config: map[string]string{
			`max-size`: `50m`,
		}},
		RestartPolicy: container.RestartPolicy{Name: `on-failure`, MaximumRetryCount: 5},
		Resources: container.Resources{
			CPUShares: 128,
			Memory:    minMemory,
		},
		SecurityOpt: []string{`no-new-privileges`},
	}

	if service.ReadOnly {
		hostConfig.ReadonlyRootfs = service.ReadOnly
	}

	if service.CPUShares != 0 {
		hostConfig.Resources.CPUShares = service.CPUShares
	}

	if service.MemoryLimit != 0 {
		if service.MemoryLimit < maxMemory {
			hostConfig.Resources.Memory = service.MemoryLimit
		} else {
			hostConfig.Resources.Memory = maxMemory
		}
	}

	return &hostConfig
}

func createAppHandler(w http.ResponseWriter, loggedUser *user, appName []byte, composeFile []byte) {
	if len(appName) == 0 || len(composeFile) == 0 {
		http.Error(w, `An application name and a compose file are required`, http.StatusBadRequest)
		return
	}

	compose := dockerCompose{}
	if err := yaml.Unmarshal(composeFile, &compose); err != nil {
		errorHandler(w, err)
		return
	}

	appNameStr := string(appName)
	log.Print(loggedUser.username + ` deploys ` + appNameStr)

	ownerContainers, err := listContainers(loggedUser, &appNameStr)
	if err != nil {
		errorHandler(w, err)
		return
	}
	for _, container := range ownerContainers {
		log.Print(loggedUser.username + ` stops ` + strings.Join(container.Names, `, `))
		stopContainer(container.ID)
		log.Print(loggedUser.username + ` rm ` + strings.Join(container.Names, `, `))
		rmContainer(container.ID)
	}

	ids := make([]string, len(compose.Services))
	for serviceName, service := range compose.Services {
		image := service.Image
		if !imageTag.MatchString(image) {
			image = image + defaultTag
		}

		log.Print(loggedUser.username + ` pulls ` + image)
		pull, err := docker.ImagePull(context.Background(), image, types.ImagePullOptions{})
		if err != nil {
			errorHandler(w, err)
			return
		}

		readBody(pull)
		log.Print(loggedUser.username + ` pulls ended for ` + image)

		log.Print(loggedUser.username + ` starts ` + serviceName)
		id, err := docker.ContainerCreate(context.Background(), getConfig(&service, loggedUser, appNameStr), getHostConfig(&service), &networkConfig, appNameStr+`_`+serviceName)
		if err != nil {
			errorHandler(w, err)
			return
		}

		startContainer(id.ID)
		ids = append(ids, id.ID)
	}

	jsonHttp.ResponseJSON(w, results{ids})
}

func isAuthenticated(r *http.Request) (*user, error) {
	username, password, ok := r.BasicAuth()

	if ok {
		user, ok := users[strings.ToLower(username)]

		if ok && user.password == password {
			return user, nil
		} else {
			return nil, fmt.Errorf(`Invalid credentials for ` + username)
		}
	}

	return nil, fmt.Errorf(`Unable to read basic authentication`)
}

func unauthorized(w http.ResponseWriter, err error) {
	http.Error(w, err.Error(), http.StatusUnauthorized)
}

func forbidden(w http.ResponseWriter) {
	http.Error(w, `Forbidden`, http.StatusForbidden)
}

// Handler for Hello request. Should be use with net/http
type Handler struct {
}

func (handler Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	w.Header().Add(`Access-Control-Allow-Origin`, `*`)
	w.Header().Add(`Access-Control-Allow-Headers`, `Content-Type, Authorization`)
	w.Header().Add(`Access-Control-Allow-Methods`, `GET, POST, DELETE`)
	w.Header().Add(`X-Content-Type-Options`, `nosniff`)

	if r.Method == http.MethodOptions {
		w.Write(nil)
		return
	}

	loggedUser, err := isAuthenticated(r)
	if err != nil {
		unauthorized(w, err)
		return
	}

	urlPath := []byte(r.URL.Path)

	if containersRequest.Match(urlPath) && r.Method == http.MethodGet {
		listContainersHandler(w, loggedUser)
	} else if containerRequest.Match(urlPath) && r.Method == http.MethodGet {
		inspectContainerHandler(w, containerRequest.FindSubmatch(urlPath)[1])
	} else if startRequest.Match(urlPath) && r.Method == http.MethodPost {
		basicActionHandler(w, loggedUser, startRequest.FindSubmatch(urlPath)[1], startContainer)
	} else if stopRequest.Match(urlPath) && r.Method == http.MethodPost {
		basicActionHandler(w, loggedUser, stopRequest.FindSubmatch(urlPath)[1], stopContainer)
	} else if restartRequest.Match(urlPath) && r.Method == http.MethodPost {
		basicActionHandler(w, loggedUser, restartRequest.FindSubmatch(urlPath)[1], restartContainer)
	} else if containerRequest.Match(urlPath) && r.Method == http.MethodDelete {
		basicActionHandler(w, loggedUser, containerRequest.FindSubmatch(urlPath)[1], rmContainer)
	} else if logRequest.Match(urlPath) && r.Method == http.MethodGet {
		logContainerHandler(w, logRequest.FindSubmatch(urlPath)[1])
	} else if containerRequest.Match(urlPath) && r.Method == http.MethodPost {
		if composeBody, err := readBody(r.Body); err != nil {
			errorHandler(w, err)
		} else {
			createAppHandler(w, loggedUser, containerRequest.FindSubmatch(urlPath)[1], composeBody)
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2014 Hajime Hoshi
//
// 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 affine

import (
	"image/color"
	"math"
)

// ColorMDim is a dimension of a ColorM.
const ColorMDim = 5

var (
	colorMIdentityBody = []float32{
		1, 0, 0, 0,
		0, 1, 0, 0,
		0, 0, 1, 0,
		0, 0, 0, 1,
	}
	colorMIdentityTranslate = []float32{
		0, 0, 0, 0,
	}
)

// A ColorM represents a matrix to transform coloring when rendering an image.
//
// A ColorM is applied to the source alpha color
// while an Image's pixels' format is alpha premultiplied.
// Before applying a matrix, a color is un-multiplied, and after applying the matrix,
// the color is multiplied again.
//
// The nil and initial value is identity.
type ColorM struct {
	// When elements is nil, this matrix is identity.
	// elements are immutable and a new array must be created when updating.
	body      []float32
	translate []float32
}

func clamp(x float32) float32 {
	if x > 1 {
		return 1
	}
	if x < 0 {
		return 0
	}
	return x
}

func (c *ColorM) isInited() bool {
	return c != nil && c.body != nil
}

func (c *ColorM) Apply(clr color.Color) color.Color {
	if !c.isInited() {
		return clr
	}
	r, g, b, a := clr.RGBA()
	rf, gf, bf, af := float32(0.0), float32(0.0), float32(0.0), float32(0.0)
	// Unmultiply alpha
	if a > 0 {
		rf = float32(r) / float32(a)
		gf = float32(g) / float32(a)
		bf = float32(b) / float32(a)
		af = float32(a) / 0xffff
	}
	eb := c.body
	et := c.translate
	rf2 := eb[0]*rf + eb[4]*gf + eb[8]*bf + eb[12]*af + et[0]
	gf2 := eb[1]*rf + eb[5]*gf + eb[9]*bf + eb[13]*af + et[1]
	bf2 := eb[2]*rf + eb[6]*gf + eb[10]*bf + eb[14]*af + et[2]
	af2 := eb[3]*rf + eb[7]*gf + eb[11]*bf + eb[15]*af + et[3]
	rf2 = clamp(rf2)
	gf2 = clamp(gf2)
	bf2 = clamp(bf2)
	af2 = clamp(af2)
	return color.NRGBA64{
		R: uint16(rf2 * 0xffff),
		G: uint16(gf2 * 0xffff),
		B: uint16(bf2 * 0xffff),
		A: uint16(af2 * 0xffff),
	}
}

func (c *ColorM) UnsafeElements() ([]float32, []float32) {
	if !c.isInited() {
		return colorMIdentityBody, colorMIdentityTranslate
	}
	return c.body, c.translate
}

// SetElement sets an element at (i, j).
func (c *ColorM) SetElement(i, j int, element float32) *ColorM {
	newC := &ColorM{
		body:      make([]float32, 16),
		translate: make([]float32, 4),
	}
	if !c.isInited() {
		copy(newC.body, colorMIdentityBody)
		copy(newC.translate, colorMIdentityTranslate)
	} else {
		copy(newC.body, c.body)
		copy(newC.translate, c.translate)
	}
	if j < (ColorMDim - 1) {
		newC.body[i+j*(ColorMDim-1)] = element
	} else {
		newC.translate[i] = element
	}
	return newC
}

func (c *ColorM) Equals(other *ColorM) bool {
	if !c.isInited() && !other.isInited() {
		return true
	}

	lhsb := colorMIdentityBody
	lhst := colorMIdentityTranslate
	rhsb := colorMIdentityBody
	rhst := colorMIdentityTranslate
	if other.isInited() {
		lhsb = other.body
		lhst = other.translate
	}
	if c.isInited() {
		rhsb = c.body
		rhst = c.translate
	}

	for i := range lhsb {
		if lhsb[i] != rhsb[i] {
			return false
		}
	}
	for i := range lhst {
		if lhst[i] != rhst[i] {
			return false
		}
	}
	return true
}

// Concat multiplies a color matrix with the other color matrix.
// This is same as muptiplying the matrix other and the matrix c in this order.
func (c *ColorM) Concat(other *ColorM) *ColorM {
	if !c.isInited() {
		return other
	}
	if !other.isInited() {
		return c
	}

	lhsb := colorMIdentityBody
	lhst := colorMIdentityTranslate
	rhsb := colorMIdentityBody
	rhst := colorMIdentityTranslate
	if other.isInited() {
		lhsb = other.body
		lhst = other.translate
	}
	if c.isInited() {
		rhsb = c.body
		rhst = c.translate
	}

	return &ColorM{
		// TODO: This is a temporary hack to calculate multiply of transposed matrices.
		// Fix mulSquare implmentation and swap the arguments.
		body: mulSquare(rhsb, lhsb, ColorMDim-1),
		translate: []float32{
			lhsb[0]*rhst[0] + lhsb[4]*rhst[1] + lhsb[8]*rhst[2] + lhsb[12]*rhst[3] + lhst[0],
			lhsb[1]*rhst[0] + lhsb[5]*rhst[1] + lhsb[9]*rhst[2] + lhsb[13]*rhst[3] + lhst[1],
			lhsb[2]*rhst[0] + lhsb[6]*rhst[1] + lhsb[10]*rhst[2] + lhsb[14]*rhst[3] + lhst[2],
			lhsb[3]*rhst[0] + lhsb[7]*rhst[1] + lhsb[11]*rhst[2] + lhsb[15]*rhst[3] + lhst[3],
		},
	}
}

// Add is deprecated.
func (c *ColorM) Add(other *ColorM) *ColorM {
	lhsb := colorMIdentityBody
	lhst := colorMIdentityTranslate
	rhsb := colorMIdentityBody
	rhst := colorMIdentityTranslate
	if other.isInited() {
		lhsb = other.body
		lhst = other.translate
	}
	if c.isInited() {
		rhsb = c.body
		rhst = c.translate
	}

	newC := &ColorM{
		body:      make([]float32, 16),
		translate: make([]float32, 4),
	}
	for i := range lhsb {
		newC.body[i] = lhsb[i] + rhsb[i]
	}
	for i := range lhst {
		newC.translate[i] = lhst[i] + rhst[i]
	}

	return newC
}

// Scale scales the matrix by (r, g, b, a).
func (c *ColorM) Scale(r, g, b, a float32) *ColorM {
	if !c.isInited() {
		return &ColorM{
			body: []float32{
				r, 0, 0, 0,
				0, g, 0, 0,
				0, 0, b, 0,
				0, 0, 0, a,
			},
			translate: colorMIdentityTranslate,
		}
	}
	es := make([]float32, len(c.body))
	copy(es, c.body)
	for i := 0; i < ColorMDim-1; i++ {
		es[i*(ColorMDim-1)] *= r
		es[i*(ColorMDim-1)+1] *= g
		es[i*(ColorMDim-1)+2] *= b
		es[i*(ColorMDim-1)+3] *= a
	}

	return &ColorM{
		body: es,
		translate: []float32{
			c.translate[0] * r,
			c.translate[1] * g,
			c.translate[2] * b,
			c.translate[3] * a,
		},
	}
}

// Translate translates the matrix by (r, g, b, a).
func (c *ColorM) Translate(r, g, b, a float32) *ColorM {
	if !c.isInited() {
		return &ColorM{
			body:      colorMIdentityBody,
			translate: []float32{r, g, b, a},
		}
	}
	es := make([]float32, len(c.translate))
	copy(es, c.translate)
	es[0] += r
	es[1] += g
	es[2] += b
	es[3] += a
	return &ColorM{
		body:      c.body,
		translate: es,
	}
}

var (
	// The YCbCr value ranges are:
	//   Y:  [ 0   - 1  ]
	//   Cb: [-0.5 - 0.5]
	//   Cr: [-0.5 - 0.5]

	rgbToYCbCr = &ColorM{
		body: []float32{
			0.2990, -0.1687, 0.5000, 0,
			0.5870, -0.3313, -0.4187, 0,
			0.1140, 0.5000, -0.0813, 0,
			0, 0, 0, 1,
		},
		translate: []float32{0, 0, 0, 0},
	}
	yCbCrToRgb = &ColorM{
		body: []float32{
			1, 1, 1, 0,
			0, -0.34414, 1.77200, 0,
			1.40200, -0.71414, 0, 0,
			0, 0, 0, 1,
		},
		translate: []float32{0, 0, 0, 0},
	}
)

// ChangeHSV changes HSV (Hue-Saturation-Value) elements.
// hueTheta is a radian value to ratate hue.
// saturationScale is a value to scale saturation.
// valueScale is a value to scale value (a.k.a. brightness).
//
// This conversion uses RGB to/from YCrCb conversion.
func (c *ColorM) ChangeHSV(hueTheta float64, saturationScale float32, valueScale float32) *ColorM {
	sin, cos := math.Sincos(hueTheta)
	s32, c32 := float32(sin), float32(cos)
	c = c.Concat(rgbToYCbCr)
	c = c.Concat(&ColorM{
		body: []float32{
			1, 0, 0, 0,
			0, c32, s32, 0,
			0, -s32, c32, 0,
			0, 0, 0, 1,
		},
		translate: []float32{0, 0, 0, 0},
	})
	s := saturationScale
	v := valueScale
	c = c.Scale(v, s*v, s*v, 1)
	c = c.Concat(yCbCrToRgb)
	return c
}
<commit_msg>affine: Optimization Equals<commit_after>// Copyright 2014 Hajime Hoshi
//
// 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 affine

import (
	"image/color"
	"math"
)

// ColorMDim is a dimension of a ColorM.
const ColorMDim = 5

var (
	colorMIdentityBody = []float32{
		1, 0, 0, 0,
		0, 1, 0, 0,
		0, 0, 1, 0,
		0, 0, 0, 1,
	}
	colorMIdentityTranslate = []float32{
		0, 0, 0, 0,
	}
)

// A ColorM represents a matrix to transform coloring when rendering an image.
//
// A ColorM is applied to the source alpha color
// while an Image's pixels' format is alpha premultiplied.
// Before applying a matrix, a color is un-multiplied, and after applying the matrix,
// the color is multiplied again.
//
// The nil and initial value is identity.
type ColorM struct {
	// When elements is nil, this matrix is identity.
	// elements are immutable and a new array must be created when updating.
	body      []float32
	translate []float32
}

func clamp(x float32) float32 {
	if x > 1 {
		return 1
	}
	if x < 0 {
		return 0
	}
	return x
}

func (c *ColorM) isInited() bool {
	return c != nil && c.body != nil
}

func (c *ColorM) Apply(clr color.Color) color.Color {
	if !c.isInited() {
		return clr
	}
	r, g, b, a := clr.RGBA()
	rf, gf, bf, af := float32(0.0), float32(0.0), float32(0.0), float32(0.0)
	// Unmultiply alpha
	if a > 0 {
		rf = float32(r) / float32(a)
		gf = float32(g) / float32(a)
		bf = float32(b) / float32(a)
		af = float32(a) / 0xffff
	}
	eb := c.body
	et := c.translate
	rf2 := eb[0]*rf + eb[4]*gf + eb[8]*bf + eb[12]*af + et[0]
	gf2 := eb[1]*rf + eb[5]*gf + eb[9]*bf + eb[13]*af + et[1]
	bf2 := eb[2]*rf + eb[6]*gf + eb[10]*bf + eb[14]*af + et[2]
	af2 := eb[3]*rf + eb[7]*gf + eb[11]*bf + eb[15]*af + et[3]
	rf2 = clamp(rf2)
	gf2 = clamp(gf2)
	bf2 = clamp(bf2)
	af2 = clamp(af2)
	return color.NRGBA64{
		R: uint16(rf2 * 0xffff),
		G: uint16(gf2 * 0xffff),
		B: uint16(bf2 * 0xffff),
		A: uint16(af2 * 0xffff),
	}
}

func (c *ColorM) UnsafeElements() ([]float32, []float32) {
	if !c.isInited() {
		return colorMIdentityBody, colorMIdentityTranslate
	}
	return c.body, c.translate
}

// SetElement sets an element at (i, j).
func (c *ColorM) SetElement(i, j int, element float32) *ColorM {
	newC := &ColorM{
		body:      make([]float32, 16),
		translate: make([]float32, 4),
	}
	if !c.isInited() {
		copy(newC.body, colorMIdentityBody)
		copy(newC.translate, colorMIdentityTranslate)
	} else {
		copy(newC.body, c.body)
		copy(newC.translate, c.translate)
	}
	if j < (ColorMDim - 1) {
		newC.body[i+j*(ColorMDim-1)] = element
	} else {
		newC.translate[i] = element
	}
	return newC
}

func (c *ColorM) Equals(other *ColorM) bool {
	if !c.isInited() && !other.isInited() {
		return true
	}

	lhsb := colorMIdentityBody
	lhst := colorMIdentityTranslate
	rhsb := colorMIdentityBody
	rhst := colorMIdentityTranslate
	if other.isInited() {
		lhsb = other.body
		lhst = other.translate
	}
	if c.isInited() {
		rhsb = c.body
		rhst = c.translate
	}
	if &lhsb == &rhsb && &lhst == &rhst {
		return true
	}

	for i := range lhsb {
		if lhsb[i] != rhsb[i] {
			return false
		}
	}
	for i := range lhst {
		if lhst[i] != rhst[i] {
			return false
		}
	}
	return true
}

// Concat multiplies a color matrix with the other color matrix.
// This is same as muptiplying the matrix other and the matrix c in this order.
func (c *ColorM) Concat(other *ColorM) *ColorM {
	if !c.isInited() {
		return other
	}
	if !other.isInited() {
		return c
	}

	lhsb := colorMIdentityBody
	lhst := colorMIdentityTranslate
	rhsb := colorMIdentityBody
	rhst := colorMIdentityTranslate
	if other.isInited() {
		lhsb = other.body
		lhst = other.translate
	}
	if c.isInited() {
		rhsb = c.body
		rhst = c.translate
	}

	return &ColorM{
		// TODO: This is a temporary hack to calculate multiply of transposed matrices.
		// Fix mulSquare implmentation and swap the arguments.
		body: mulSquare(rhsb, lhsb, ColorMDim-1),
		translate: []float32{
			lhsb[0]*rhst[0] + lhsb[4]*rhst[1] + lhsb[8]*rhst[2] + lhsb[12]*rhst[3] + lhst[0],
			lhsb[1]*rhst[0] + lhsb[5]*rhst[1] + lhsb[9]*rhst[2] + lhsb[13]*rhst[3] + lhst[1],
			lhsb[2]*rhst[0] + lhsb[6]*rhst[1] + lhsb[10]*rhst[2] + lhsb[14]*rhst[3] + lhst[2],
			lhsb[3]*rhst[0] + lhsb[7]*rhst[1] + lhsb[11]*rhst[2] + lhsb[15]*rhst[3] + lhst[3],
		},
	}
}

// Add is deprecated.
func (c *ColorM) Add(other *ColorM) *ColorM {
	lhsb := colorMIdentityBody
	lhst := colorMIdentityTranslate
	rhsb := colorMIdentityBody
	rhst := colorMIdentityTranslate
	if other.isInited() {
		lhsb = other.body
		lhst = other.translate
	}
	if c.isInited() {
		rhsb = c.body
		rhst = c.translate
	}

	newC := &ColorM{
		body:      make([]float32, 16),
		translate: make([]float32, 4),
	}
	for i := range lhsb {
		newC.body[i] = lhsb[i] + rhsb[i]
	}
	for i := range lhst {
		newC.translate[i] = lhst[i] + rhst[i]
	}

	return newC
}

// Scale scales the matrix by (r, g, b, a).
func (c *ColorM) Scale(r, g, b, a float32) *ColorM {
	if !c.isInited() {
		return &ColorM{
			body: []float32{
				r, 0, 0, 0,
				0, g, 0, 0,
				0, 0, b, 0,
				0, 0, 0, a,
			},
			translate: colorMIdentityTranslate,
		}
	}
	es := make([]float32, len(c.body))
	copy(es, c.body)
	for i := 0; i < ColorMDim-1; i++ {
		es[i*(ColorMDim-1)] *= r
		es[i*(ColorMDim-1)+1] *= g
		es[i*(ColorMDim-1)+2] *= b
		es[i*(ColorMDim-1)+3] *= a
	}

	return &ColorM{
		body: es,
		translate: []float32{
			c.translate[0] * r,
			c.translate[1] * g,
			c.translate[2] * b,
			c.translate[3] * a,
		},
	}
}

// Translate translates the matrix by (r, g, b, a).
func (c *ColorM) Translate(r, g, b, a float32) *ColorM {
	if !c.isInited() {
		return &ColorM{
			body:      colorMIdentityBody,
			translate: []float32{r, g, b, a},
		}
	}
	es := make([]float32, len(c.translate))
	copy(es, c.translate)
	es[0] += r
	es[1] += g
	es[2] += b
	es[3] += a
	return &ColorM{
		body:      c.body,
		translate: es,
	}
}

var (
	// The YCbCr value ranges are:
	//   Y:  [ 0   - 1  ]
	//   Cb: [-0.5 - 0.5]
	//   Cr: [-0.5 - 0.5]

	rgbToYCbCr = &ColorM{
		body: []float32{
			0.2990, -0.1687, 0.5000, 0,
			0.5870, -0.3313, -0.4187, 0,
			0.1140, 0.5000, -0.0813, 0,
			0, 0, 0, 1,
		},
		translate: []float32{0, 0, 0, 0},
	}
	yCbCrToRgb = &ColorM{
		body: []float32{
			1, 1, 1, 0,
			0, -0.34414, 1.77200, 0,
			1.40200, -0.71414, 0, 0,
			0, 0, 0, 1,
		},
		translate: []float32{0, 0, 0, 0},
	}
)

// ChangeHSV changes HSV (Hue-Saturation-Value) elements.
// hueTheta is a radian value to ratate hue.
// saturationScale is a value to scale saturation.
// valueScale is a value to scale value (a.k.a. brightness).
//
// This conversion uses RGB to/from YCrCb conversion.
func (c *ColorM) ChangeHSV(hueTheta float64, saturationScale float32, valueScale float32) *ColorM {
	sin, cos := math.Sincos(hueTheta)
	s32, c32 := float32(sin), float32(cos)
	c = c.Concat(rgbToYCbCr)
	c = c.Concat(&ColorM{
		body: []float32{
			1, 0, 0, 0,
			0, c32, s32, 0,
			0, -s32, c32, 0,
			0, 0, 0, 1,
		},
		translate: []float32{0, 0, 0, 0},
	})
	s := saturationScale
	v := valueScale
	c = c.Scale(v, s*v, s*v, 1)
	c = c.Concat(yCbCrToRgb)
	return c
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"

	"github.com/azure/azure-sdk-for-go/arm/examples"
)

func help() {
	fmt.Println(`Select an example to run:
		Client  -- Basic storage account example
		Storage -- Create / Delete storage account example
		`)
}

func main() {
	if len(os.Args) < 2 {
		help()
		return
	}
	args := os.Args[2:]

	e := os.Args[1]
	switch e {
	case "Client":
		examples.Client(args)
	case "Storage":
		examples.Storage(args)
	default:
		fmt.Printf("%s is not a know example\n", e)
		help()
	}
}
<commit_msg>Removed runner<commit_after><|endoftext|>


<commit_before>package storage

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"net/url"
)

func init() {
	log.SetFlags(log.Lshortfile)
}

type Metadata map[string]string

type ParsedURLNameQuery struct {
	Name  string
	Query url.Values
}

func ParseURLNameQuery(name string) (parsedURL ParsedURLNameQuery, err error) {
	uri, err := url.Parse(name)
	if err != nil {
		return
	}
	parsedURL.Query = uri.Query()
	uri.RawQuery = ""
	parsedURL.Name = uri.String()
	return
}

type BlobStorageStruct struct {
	AccountName string
	AccountKey  []byte
	UseHTTPS    bool
	BaseURL     string
	ApiVersion  string
}

func BlobStorageClientToJson(c BlobStorageClient) string {
	c2 := BlobStorageStruct{
		AccountName: c.client.accountName,
		AccountKey:  c.client.accountKey,
		UseHTTPS:    c.client.useHTTPS,
		BaseURL:     c.client.baseURL,
		ApiVersion:  c.client.apiVersion,
	}
	txt, _ := json.MarshalIndent(c2, "", "  ")
	return string(txt)
}

type SnapshotResponse struct {
	StatusCode int
	Headers    http.Header
}

func renderRequest(name string, container string, verb string, uri string, headers map[string]string) string {
	s := struct {
		Name      string
		Container string
		Verb      string
		URI       string
		Headers   map[string]string
	}{name, container, verb, uri, headers}
	jbytes, err := json.MarshalIndent(s, "", "  ")
	if err != nil {
		return "unable to render request"
	}
	return string(jbytes)
}

func (b BlobStorageClient) Snapshot(container, name string, metaSnap Metadata) (res SnapshotResponse, err error) {
	debug := false

	if debug == true {
		jbytes, _ := json.MarshalIndent(metaSnap, "", "  ")
		log.Printf("metaSnap headers to add = ...\n%s", string(jbytes))
	}

	verb := "PUT"
	path := fmt.Sprintf("%s/%s", container, name)
	urlValues := url.Values{"comp": {"snapshot"}}

	uri := b.client.getEndpoint(blobServiceName, path, urlValues)
	headers := b.client.getStandardHeaders()
	headers["Content-Length"] = fmt.Sprintf("%v", 0)

	if debug == true {
		log.Printf("base request = %s", renderRequest(name, container, verb, uri, headers))
		//
	}

	// Add snapshot tags
	for key, value := range metaSnap {
		hv := fmt.Sprintf("x-ms-meta-%s", key)
		//log.Printf("metasnap headers[%s] = %s", hv, value)
		headers[hv] = value
	}

	if debug == true {
		log.Printf("snapshot request = %s", renderRequest(name, container, verb, uri, headers))
		//
	}

	resp, err := b.client.exec(verb, uri, headers, nil)
	if err != nil {
		return res, err
	}
	defer resp.body.Close()

	res = SnapshotResponse{
		StatusCode: resp.statusCode,
		Headers:    resp.headers,
	}

	if debug == true {
		metaBlob, err := b.client.GetBlobService().GetBlobMetadata(container, name)
		if err != nil {
			return res, err
		}
		jbytes, _ := json.MarshalIndent(metaBlob, "", "  ")
		log.Printf("after snapshot: basename metadata = ...\n%s", string(jbytes))

		snapname := name + "?snapshot=" + res.Headers.Get("X-Ms-Snapshot")
		log.Printf("snapname = %s", snapname)
		metaBlob, err = b.client.GetBlobService().GetBlobMetadata(container, snapname)
		if err != nil {
			return res, err
		}
		jbytes, _ = json.MarshalIndent(metaBlob, "", "  ")
		log.Printf("after snapshot: snapshot metadata = ...\n%s", string(jbytes))
	}

	return
}
<commit_msg>update exec call<commit_after>package storage

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"net/url"
)

func init() {
	log.SetFlags(log.Lshortfile)
}

type Metadata map[string]string

type ParsedURLNameQuery struct {
	Name  string
	Query url.Values
}

func ParseURLNameQuery(name string) (parsedURL ParsedURLNameQuery, err error) {
	uri, err := url.Parse(name)
	if err != nil {
		return
	}
	parsedURL.Query = uri.Query()
	uri.RawQuery = ""
	parsedURL.Name = uri.String()
	return
}

type BlobStorageStruct struct {
	AccountName string
	AccountKey  []byte
	UseHTTPS    bool
	BaseURL     string
	ApiVersion  string
}

func BlobStorageClientToJson(c BlobStorageClient) string {
	c2 := BlobStorageStruct{
		AccountName: c.client.accountName,
		AccountKey:  c.client.accountKey,
		UseHTTPS:    c.client.useHTTPS,
		BaseURL:     c.client.baseURL,
		ApiVersion:  c.client.apiVersion,
	}
	txt, _ := json.MarshalIndent(c2, "", "  ")
	return string(txt)
}

type SnapshotResponse struct {
	StatusCode int
	Headers    http.Header
}

func renderRequest(name string, container string, verb string, uri string, headers map[string]string) string {
	s := struct {
		Name      string
		Container string
		Verb      string
		URI       string
		Headers   map[string]string
	}{name, container, verb, uri, headers}
	jbytes, err := json.MarshalIndent(s, "", "  ")
	if err != nil {
		return "unable to render request"
	}
	return string(jbytes)
}

func (b BlobStorageClient) Snapshot(container, name string, metaSnap Metadata) (res SnapshotResponse, err error) {
	debug := false

	if debug == true {
		jbytes, _ := json.MarshalIndent(metaSnap, "", "  ")
		log.Printf("metaSnap headers to add = ...\n%s", string(jbytes))
	}

	verb := "PUT"
	path := fmt.Sprintf("%s/%s", container, name)
	urlValues := url.Values{"comp": {"snapshot"}}

	uri := b.client.getEndpoint(blobServiceName, path, urlValues)
	headers := b.client.getStandardHeaders()
	headers["Content-Length"] = fmt.Sprintf("%v", 0)

	if debug == true {
		log.Printf("base request = %s", renderRequest(name, container, verb, uri, headers))
		//
	}

	// Add snapshot tags
	for key, value := range metaSnap {
		hv := fmt.Sprintf("x-ms-meta-%s", key)
		//log.Printf("metasnap headers[%s] = %s", hv, value)
		headers[hv] = value
	}

	if debug == true {
		log.Printf("snapshot request = %s", renderRequest(name, container, verb, uri, headers))
		//
	}

	resp, err := b.client.exec(verb, uri, headers, nil, b.auth)
	if err != nil {
		return res, err
	}
	defer resp.body.Close()

	res = SnapshotResponse{
		StatusCode: resp.statusCode,
		Headers:    resp.headers,
	}

	if debug == true {
		metaBlob, err := b.client.GetBlobService().GetBlobMetadata(container, name)
		if err != nil {
			return res, err
		}
		jbytes, _ := json.MarshalIndent(metaBlob, "", "  ")
		log.Printf("after snapshot: basename metadata = ...\n%s", string(jbytes))

		snapname := name + "?snapshot=" + res.Headers.Get("X-Ms-Snapshot")
		log.Printf("snapname = %s", snapname)
		metaBlob, err = b.client.GetBlobService().GetBlobMetadata(container, snapname)
		if err != nil {
			return res, err
		}
		jbytes, _ = json.MarshalIndent(metaBlob, "", "  ")
		log.Printf("after snapshot: snapshot metadata = ...\n%s", string(jbytes))
	}

	return
}
<|endoftext|>


<commit_before>//go:build boringcrypto
// +build boringcrypto

package boring

import (
	"crypto/boring"

	"gitlab.com/gitlab-org/labkit/log"
)

// CheckBoring checks whether FIPS crypto has been enabled. For the FIPS Go
// compiler in https://github.com/golang-fips/go, this requires that:
//
// 1. The kernel has FIPS enabled (e.g. `/proc/sys/crypto/fips_enabled` is 1).
// 2. A system OpenSSL can be dynamically loaded via ldopen().
func CheckBoring() {
	if boring.Enabled() {
		log.Info("FIPS mode is enabled. Using an external SSL library.")
		return
	}
	log.Info("Gitaly was compiled with FIPS mode, but an external SSL library was not enabled.")
}
<commit_msg>Fix typo in FIPS mode message<commit_after>//go:build boringcrypto
// +build boringcrypto

package boring

import (
	"crypto/boring"

	"gitlab.com/gitlab-org/labkit/log"
)

// CheckBoring checks whether FIPS crypto has been enabled. For the FIPS Go
// compiler in https://github.com/golang-fips/go, this requires that:
//
// 1. The kernel has FIPS enabled (e.g. `/proc/sys/crypto/fips_enabled` is 1).
// 2. A system OpenSSL can be dynamically loaded via ldopen().
func CheckBoring() {
	if boring.Enabled() {
		log.Info("FIPS mode is enabled. Using an external SSL library.")
		return
	}
	log.Info("gitlab-shell was compiled with FIPS mode, but an external SSL library was not enabled.")
}
<|endoftext|>


<commit_before>package asciiimg

import (
	"image"
	_ "image/gif"
	_ "image/jpeg"
	_ "image/png"
	"io"
	"math"

	"github.com/mnhkahn/asciiimg/gray"
)

type AsciiImg struct {
	name string
	img  image.Image
}

func NewAsciiImg(r io.Reader) (*AsciiImg, error) {
	ai := new(AsciiImg)
	var err error
	ai.img, ai.name, err = image.Decode(r)
	return ai, err
}

// func (this *AsciiImg) DoBlackWhite(cols int) (image.Image, error) {
// 	if this.img == nil {
// 		return ascii
// 	}
// 	img_test := image.NewNRGBA(this.img.Bounds())
// 	for y := 0; y < this.img.Bounds().Dy(); y++ {
// 		for x := 0; x < this.img.Bounds().Dx(); x++ {
// 			Red, Green, Blue, Alpha := this.img.At(x, y).RGBA()
// 			Grey := Red*3/10 + Green*59/100 + Blue*11/100
// 			img_test.Set(x, y, color.NRGBA{uint8(Grey), uint8(Grey), uint8(Grey), uint8(Alpha)})
// 		}
// 	}

// 	png.Decode(r)
// }

func (this *AsciiImg) DoByCol(cols int) string {
	ascii := ""

	if this.img == nil {
		return ascii
	}

	// img_test := image.NewNRGBA(this.img.Bounds())
	// for y := 0; y < this.img.Bounds().Dy(); y++ {
	// 	for x := 0; x < this.img.Bounds().Dx(); x++ {
	// 		Red, Green, Blue, Alpha := this.img.At(x, y).RGBA()
	// 		Grey := Red*3/10 + Green*59/100 + Blue*11/100
	// 		img_test.Set(x, y, color.NRGBA{uint8(Grey), uint8(Grey), uint8(Grey), uint8(Alpha)})
	// 	}
	// }

	w := this.img.Bounds().Dx() / cols
	h := w * 2
	rows := this.img.Bounds().Dy() / h

	for r := 0; r < rows; r++ {
		for c := 0; c < cols; c++ {
			x, y := c*w, r*h

			avg := this.getBlockInfo(x, y, w, h)
			ascii += string(gray.Get("default", avg))
		}
		ascii += "\r\n"
	}

	return ascii
}

func (this *AsciiImg) Do(w, h int) string {
	ascii := ""

	if this.img == nil {
		return ascii
	}

	// img_test := image.NewNRGBA(this.img.Bounds())
	// for y := 0; y < this.img.Bounds().Dy(); y++ {
	// 	for x := 0; x < this.img.Bounds().Dx(); x++ {
	// 		Red, Green, Blue, Alpha := this.img.At(x, y).RGBA()
	// 		Grey := Red*3/10 + Green*59/100 + Blue*11/100
	// 		img_test.Set(x, y, color.NRGBA{uint8(Grey), uint8(Grey), uint8(Grey), uint8(Alpha)})
	// 	}
	// }

	rows := int(math.Ceil(float64(this.img.Bounds().Dy()) / float64(h)))
	cols := int(math.Ceil(float64(this.img.Bounds().Dx()) / float64(w)))

	for r := 0; r < rows; r++ {
		for c := 0; c < cols; c++ {
			x, y := c*w, r*h

			avg := this.getBlockInfo(x, y, w, h)
			ascii += string(gray.Get("default", avg))
		}
		ascii += "\r\n"
	}

	return ascii
}

func (this *AsciiImg) getSize(x, y, w, h int) (int, int) {
	if x+w > this.img.Bounds().Dx() {
		w = this.img.Bounds().Dx() - x
	}
	if y+h > this.img.Bounds().Dy() {
		h = this.img.Bounds().Dy() - y
	}
	return w, h
}

func (this *AsciiImg) getBlockInfo(x, y, w, h int) uint32 {
	w, h = this.getSize(x, y, w, h)
	var sumGray uint32
	for i := 0; i < h; i++ {
		for j := 0; j < w; j++ {
			Red, Green, Blue, _ := this.img.At(x+j, y+i).RGBA()
			Gray := Red*3/10 + Green*59/100 + Blue*11/100
			sumGray += Gray
		}
	}
	return sumGray / uint32(w*h)
}
<commit_msg>rm useless code<commit_after>package asciiimg

import (
	"image"
	_ "image/gif"
	_ "image/jpeg"
	_ "image/png"
	"io"
	"math"

	"github.com/mnhkahn/asciiimg/gray"
)

type AsciiImg struct {
	name string
	img  image.Image
}

func NewAsciiImg(r io.Reader) (*AsciiImg, error) {
	ai := new(AsciiImg)
	var err error
	ai.img, ai.name, err = image.Decode(r)
	return ai, err
}

func (this *AsciiImg) DoByCol(cols int) string {
	ascii := ""

	if this.img == nil {
		return ascii
	}

	w := this.img.Bounds().Dx() / cols
	h := w * 2
	rows := this.img.Bounds().Dy() / h

	for r := 0; r < rows; r++ {
		for c := 0; c < cols; c++ {
			x, y := c*w, r*h

			avg := this.getBlockInfo(x, y, w, h)
			ascii += string(gray.Get("default", avg))
		}
		ascii += "\r\n"
	}

	return ascii
}

func (this *AsciiImg) Do(w, h int) string {
	ascii := ""

	if this.img == nil {
		return ascii
	}

	rows := int(math.Ceil(float64(this.img.Bounds().Dy()) / float64(h)))
	cols := int(math.Ceil(float64(this.img.Bounds().Dx()) / float64(w)))

	for r := 0; r < rows; r++ {
		for c := 0; c < cols; c++ {
			x, y := c*w, r*h

			avg := this.getBlockInfo(x, y, w, h)
			ascii += string(gray.Get("default", avg))
		}
		ascii += "\r\n"
	}

	return ascii
}

func (this *AsciiImg) getSize(x, y, w, h int) (int, int) {
	if x+w > this.img.Bounds().Dx() {
		w = this.img.Bounds().Dx() - x
	}
	if y+h > this.img.Bounds().Dy() {
		h = this.img.Bounds().Dy() - y
	}
	return w, h
}

func (this *AsciiImg) getBlockInfo(x, y, w, h int) uint32 {
	w, h = this.getSize(x, y, w, h)
	var sumGray uint32
	for i := 0; i < h; i++ {
		for j := 0; j < w; j++ {
			Red, Green, Blue, _ := this.img.At(x+j, y+i).RGBA()
			Gray := Red*3/10 + Green*59/100 + Blue*11/100
			sumGray += Gray
		}
	}
	return sumGray / uint32(w*h)
}
<|endoftext|>


<commit_before>package storage

import (
	"calf/config"
	cdb "calf/db"
	"calf/image"
	"database/sql"
	_ "database/sql/driver"
	_ "github.com/lib/pq"
	"log"
	// "strings"
)

type MetaWrapper interface {
	Browse(limit int, offset int) (*sql.Rows, error)
	Store(entry *Entry) error
	Get(id EntryId) (*Entry, error)
	Delete(id EntryId) error
}

type MetaWrap struct {
	dsn string
	// section string
	// prefix  string

	table string
}

func newMetaWrap(section string) *MetaWrap {
	if section == "" {
		section = "common"
	}
	dsn := config.GetValue(section, "meta_dsn")
	table := config.GetValue(section, "meta_table")
	mw := &MetaWrap{dsn: dsn, table: table}

	return mw
}

func NewMetaWrapper(section string) (mw MetaWrapper) {
	mw = newMetaWrap(section)
	return mw
}

func (mw *MetaWrap) Browse(limit int, offset int) (rows *sql.Rows, err error) {
	if limit < 1 {
		limit = 1
	}
	if offset < 0 {
		offset = 0
	}

	db := mw.getDb()

	table := mw.table

	rows, err = db.Query("SELECT * FROM "+table+" LIMIT $1 OFFSET $2", limit, offset)

	log.Print(rows)
	return rows, err
}

func (mw *MetaWrap) Get(id EntryId) (*Entry, error) {
	db := mw.getDb()
	defer db.Close()

	table := mw.table
	sql := "SELECT name, path, size, mime, meta, ids, hashes FROM " + table + " WHERE id = $1 LIMIT 1"
	entry := Entry{Id: &id}
	row := db.QueryRow(sql, id.String())

	var meta cdb.Hstore
	err := row.Scan(&entry.Name, &entry.Path, &entry.Size, &entry.Mime, &meta, &entry.Hashes, &entry.Ids)

	if err != nil {
		log.Println(err)
		return &entry, err
	}
	// entry.Meta = image.
	log.Println("meta:", meta)
	var ia image.ImageAttr
	err = meta.ToStruct(&ia)
	if err != nil {
		log.Println(err)
		return &entry, err
	}
	log.Println(ia.Width)

	log.Printf("name: %s, path: %s, size: %d, mime: %s\n", entry.Name, entry.Path, entry.Size, entry.Mime)

	return &entry, nil
}

func (mw *MetaWrap) Store(entry *Entry) error {
	db := mw.getDb()
	defer db.Close()

	table := mw.table
	log.Println("table:", table)
	log.Printf("hashes: %s\n", entry.Hashes.String())
	log.Printf("ids: %s\n", entry.Ids.String())
	// hashes := "{" + strings.Join(entry.Hashes, ",") + "}"
	// ids := "{" + strings.Join(entry.Ids, ",") + "}"
	meta := entry.Meta.Hstore()
	log.Println(meta)
	tx, err := db.Begin()
	if err != nil {
		log.Println(err)
		// tx.Rollback()
		return err
	}

	sql := "INSERT INTO " + table + "(id, name, hashes, ids, meta, path, size, mime) VALUES($1, $2, $3, $4, $5, $6, $7, $8)"
	result, err := tx.Exec(sql, entry.Id.String(), entry.Name, entry.Hashes.String(), entry.Ids.String(), meta, entry.Path, entry.Size, entry.Mime)

	if err != nil {
		log.Fatal(err)
	}

	var ra int64
	ra, err = result.RowsAffected()

	if err != nil {
		log.Fatal(err)
	}

	log.Println("RowsAffected ", ra)

	tx.Commit()

	return nil
}

func (mw *MetaWrap) Delete(id EntryId) error {
	return nil
}

func (mw *MetaWrap) getDb() *sql.DB {
	dsn := mw.dsn
	db, err := sql.Open("postgres", dsn)

	if err != nil {
		log.Fatal(err)
	}
	return db
}
<commit_msg>fix MetaWrap.Get()<commit_after>package storage

import (
	"calf/config"
	cdb "calf/db"
	"calf/image"
	"database/sql"
	_ "database/sql/driver"
	_ "github.com/lib/pq"
	"log"
	// "strings"
)

type MetaWrapper interface {
	Browse(limit int, offset int) (*sql.Rows, error)
	Store(entry *Entry) error
	Get(id EntryId) (*Entry, error)
	Delete(id EntryId) error
}

type MetaWrap struct {
	dsn string
	// section string
	// prefix  string

	table string
}

func newMetaWrap(section string) *MetaWrap {
	if section == "" {
		section = "common"
	}
	dsn := config.GetValue(section, "meta_dsn")
	table := config.GetValue(section, "meta_table")
	mw := &MetaWrap{dsn: dsn, table: table}

	return mw
}

func NewMetaWrapper(section string) (mw MetaWrapper) {
	mw = newMetaWrap(section)
	return mw
}

func (mw *MetaWrap) Browse(limit int, offset int) (rows *sql.Rows, err error) {
	if limit < 1 {
		limit = 1
	}
	if offset < 0 {
		offset = 0
	}

	db := mw.getDb()

	table := mw.table

	rows, err = db.Query("SELECT * FROM "+table+" LIMIT $1 OFFSET $2", limit, offset)

	log.Print(rows)
	return rows, err
}

func (mw *MetaWrap) Get(id EntryId) (*Entry, error) {
	db := mw.getDb()
	defer db.Close()

	table := mw.table
	sql := "SELECT name, path, size, mime, meta, ids, hashes FROM " + table + " WHERE id = $1 LIMIT 1"
	entry := Entry{Id: &id}
	row := db.QueryRow(sql, id.String())

	var meta cdb.Hstore
	err := row.Scan(&entry.Name, &entry.Path, &entry.Size, &entry.Mime, &meta, &entry.Hashes, &entry.Ids)

	if err != nil {
		log.Println(err)
		return &entry, err
	}
	// entry.Meta = image.
	log.Println("meta:", meta)
	var ia image.ImageAttr
	err = meta.ToStruct(&ia)
	if err != nil {
		log.Println(err)
		return &entry, err
	}
	log.Println(ia.Width)

	entry.Meta = &ia

	log.Printf("name: %s, path: %s, size: %d, mime: %s\n", entry.Name, entry.Path, entry.Size, entry.Mime)

	return &entry, nil
}

func (mw *MetaWrap) Store(entry *Entry) error {
	db := mw.getDb()
	defer db.Close()

	table := mw.table
	log.Println("table:", table)
	log.Printf("hashes: %s\n", entry.Hashes.String())
	log.Printf("ids: %s\n", entry.Ids.String())
	// hashes := "{" + strings.Join(entry.Hashes, ",") + "}"
	// ids := "{" + strings.Join(entry.Ids, ",") + "}"
	meta := entry.Meta.Hstore()
	log.Println(meta)
	tx, err := db.Begin()
	if err != nil {
		log.Println(err)
		// tx.Rollback()
		return err
	}

	sql := "INSERT INTO " + table + "(id, name, hashes, ids, meta, path, size, mime) VALUES($1, $2, $3, $4, $5, $6, $7, $8)"
	result, err := tx.Exec(sql, entry.Id.String(), entry.Name, entry.Hashes.String(), entry.Ids.String(), meta, entry.Path, entry.Size, entry.Mime)

	if err != nil {
		log.Fatal(err)
	}

	var ra int64
	ra, err = result.RowsAffected()

	if err != nil {
		log.Fatal(err)
	}

	log.Println("RowsAffected ", ra)

	tx.Commit()

	return nil
}

func (mw *MetaWrap) Delete(id EntryId) error {
	return nil
}

func (mw *MetaWrap) getDb() *sql.DB {
	dsn := mw.dsn
	db, err := sql.Open("postgres", dsn)

	if err != nil {
		log.Fatal(err)
	}
	return db
}
<|endoftext|>


<commit_before>// inomap translates (Dev, Flags, Ino) tuples to unique uint64
// inode numbers.
//
// Format of the returned inode numbers:
//
//   [spill bit = 0][15 bit namespace id][48 bit passthru inode number]
//   [spill bit = 1][63 bit spill inode number                        ]
//
// Each (Dev, Flags) tuple gets a namespace id assigned. The original inode
// number is then passed through in the lower 48 bits.
//
// If namespace ids are exhaused, or the original id is larger than 48 bits,
// the whole (Dev, Flags, Ino) tuple gets mapped in the spill map, and the
// spill bit is set to 1.
package inomap

import (
	"log"
	"sync"
	"syscall"
)

const (
	// max value of 15 bit namespace id
	maxNamespaceId = 1<<15 - 1
	// max value of 48 bit passthru inode number
	maxPassthruIno = 1<<48 - 1
	// max value of 63 bit spill inode number
	maxSpillIno = 1<<63 - 1
	// bit 63 is used as the spill bit
	spillBit = 1 << 63
)

// InoMap stores the maps using for inode number translation.
// See package comment for details.
type InoMap struct {
	sync.Mutex
	// namespaces keeps the mapping of (Dev,Flags) tuples to
	// 15-bit identifiers (stored in an uint16 with the high bit always zero)
	namespaceMap map[namespaceData]uint16
	// spillNext is the next free namespace number in the namespaces map
	namespaceNext uint16
	// spill is used once the namespaces map is full
	spillMap map[QIno]uint64
	// spillNext is the next free inode number in the spill map
	spillNext uint64
}

// New returns a new InoMap.
func New() *InoMap {
	return &InoMap{
		namespaceMap:  make(map[namespaceData]uint16),
		namespaceNext: 0,
		spillMap:      make(map[QIno]uint64),
		spillNext:     0,
	}
}

func (m *InoMap) spill(in QIno) (out uint64) {
	out, found := m.spillMap[in]
	if found {
		return out | spillBit
	}
	if m.spillNext >= maxSpillIno {
		log.Panicf("spillMap overflow: spillNext = 0x%x", m.spillNext)
	}
	out = m.spillNext
	m.spillNext++
	m.spillMap[in] = out
	return out | spillBit
}

// Translate maps the passed-in (device, inode) pair to a unique inode number.
func (m *InoMap) Translate(in QIno) (out uint64) {
	m.Lock()
	defer m.Unlock()

	if in.Ino > maxPassthruIno {
		out = m.spill(in)
		return out
	}
	ns, found := m.namespaceMap[in.namespaceData]
	// Use existing namespace
	if found {
		out = uint64(ns)<<48 | in.Ino
		return out
	}
	// No free namespace slots?
	if m.namespaceNext >= maxNamespaceId {
		out = m.spill(in)
		return out
	}
	ns = m.namespaceNext
	m.namespaceNext++
	m.namespaceMap[in.namespaceData] = ns
	out = uint64(ns)<<48 | in.Ino
	return out
}

// TranslateStat translates the inode number contained in "st" if necessary.
// Convience wrapper around Translate().
func (m *InoMap) TranslateStat(st *syscall.Stat_t) {
	in := QInoFromStat(st)
	st.Ino = m.Translate(in)
}
<commit_msg>inomap: clarify TranslateStat function comment<commit_after>// inomap translates (Dev, Flags, Ino) tuples to unique uint64
// inode numbers.
//
// Format of the returned inode numbers:
//
//   [spill bit = 0][15 bit namespace id][48 bit passthru inode number]
//   [spill bit = 1][63 bit spill inode number                        ]
//
// Each (Dev, Flags) tuple gets a namespace id assigned. The original inode
// number is then passed through in the lower 48 bits.
//
// If namespace ids are exhaused, or the original id is larger than 48 bits,
// the whole (Dev, Flags, Ino) tuple gets mapped in the spill map, and the
// spill bit is set to 1.
package inomap

import (
	"log"
	"sync"
	"syscall"
)

const (
	// max value of 15 bit namespace id
	maxNamespaceId = 1<<15 - 1
	// max value of 48 bit passthru inode number
	maxPassthruIno = 1<<48 - 1
	// max value of 63 bit spill inode number
	maxSpillIno = 1<<63 - 1
	// bit 63 is used as the spill bit
	spillBit = 1 << 63
)

// InoMap stores the maps using for inode number translation.
// See package comment for details.
type InoMap struct {
	sync.Mutex
	// namespaceMap keeps the mapping of (Dev,Flags) tuples to
	// 15-bit identifiers (stored in an uint16 with the high bit always zero)
	namespaceMap map[namespaceData]uint16
	// spillNext is the next free namespace number in the namespaces map
	namespaceNext uint16
	// spill is used once the namespaces map is full
	spillMap map[QIno]uint64
	// spillNext is the next free inode number in the spill map
	spillNext uint64
}

// New returns a new InoMap.
func New() *InoMap {
	return &InoMap{
		namespaceMap:  make(map[namespaceData]uint16),
		namespaceNext: 0,
		spillMap:      make(map[QIno]uint64),
		spillNext:     0,
	}
}

func (m *InoMap) spill(in QIno) (out uint64) {
	out, found := m.spillMap[in]
	if found {
		return out | spillBit
	}
	if m.spillNext >= maxSpillIno {
		log.Panicf("spillMap overflow: spillNext = 0x%x", m.spillNext)
	}
	out = m.spillNext
	m.spillNext++
	m.spillMap[in] = out
	return out | spillBit
}

// Translate maps the passed-in (device, inode) pair to a unique inode number.
func (m *InoMap) Translate(in QIno) (out uint64) {
	m.Lock()
	defer m.Unlock()

	if in.Ino > maxPassthruIno {
		out = m.spill(in)
		return out
	}
	ns, found := m.namespaceMap[in.namespaceData]
	// Use existing namespace
	if found {
		out = uint64(ns)<<48 | in.Ino
		return out
	}
	// No free namespace slots?
	if m.namespaceNext >= maxNamespaceId {
		out = m.spill(in)
		return out
	}
	ns = m.namespaceNext
	m.namespaceNext++
	m.namespaceMap[in.namespaceData] = ns
	out = uint64(ns)<<48 | in.Ino
	return out
}

// TranslateStat translates (device, ino) pair contained in "st" into a unique
// inode number and overwrites the ino in "st" with it.
// Convience wrapper around Translate().
func (m *InoMap) TranslateStat(st *syscall.Stat_t) {
	in := QInoFromStat(st)
	st.Ino = m.Translate(in)
}
<|endoftext|>


<commit_before>package loader

import (
	"encoding/binary"
	"fmt"
	"math"

	"github.com/tsavola/wag/internal/reader"
)

// L provides panicking alternatives for reader.Reader methods, and then some.
type L struct {
	reader.Reader
}

func (load L) Into(buf []byte) {
	if len(buf) == 0 {
		return
	}
	if _, err := load.Read(buf); err != nil {
		panic(err)
	}
}

func (load L) Bytes(n uint32) (data []byte) {
	data = make([]byte, n)
	load.Into(data)
	return
}

func (load L) Byte() byte {
	x, err := load.ReadByte()
	if err != nil {
		panic(err)
	}
	return x
}

func (load L) Uint32() (x uint32) {
	if err := binary.Read(load, binary.LittleEndian, &x); err != nil {
		panic(err)
	}
	return
}

func (load L) Uint64() (x uint64) {
	if err := binary.Read(load, binary.LittleEndian, &x); err != nil {
		panic(err)
	}
	return
}

func (load L) Varint7() int8 {
	return int8(load.Varint64())
}

func (load L) Varint32() int32 {
	return int32(load.Varint64())
}

func (load L) Varint64() (x int64) {
	var shift uint
	for {
		b := load.Byte()
		x |= (int64(b) & 0x7f) << shift
		shift += 7
		if (b & 0x80) == 0 {
			if shift < 64 && (b&0x40) != 0 {
				x |= -1 << shift
			}
			return
		}
	}
}

func (load L) Varuint1() bool {
	x, err := load.ReadByte()
	if err != nil {
		panic(err)
	}
	if x > 1 {
		panic(fmt.Errorf("varuint1 is too large: 0x%x", x))
	}
	return x == 1
}

func (load L) Varuint32() uint32 {
	x, err := binary.ReadUvarint(load)
	if err != nil {
		panic(err)
	}
	if x > math.MaxUint32 {
		panic(fmt.Errorf("varuint32 is too large: 0x%x", x))
	}
	return uint32(x)
}

func (load L) Varuint64() (x uint64) {
	x, err := binary.ReadUvarint(load)
	if err != nil {
		panic(err)
	}
	return
}

// Count reads a varuint32 for iteration.
func (load L) Count() []struct{} {
	count := load.Varuint32()
	if count > math.MaxInt32 {
		panic(fmt.Errorf("count is too large: 0x%x", count))
	}
	return make([]struct{}, int(count))
}
<commit_msg>module loading bug fixed<commit_after>package loader

import (
	"encoding/binary"
	"fmt"
	"io"
	"math"

	"github.com/tsavola/wag/internal/reader"
)

// L provides panicking alternatives for reader.Reader methods, and then some.
type L struct {
	reader.Reader
}

func (load L) Into(buf []byte) {
	if _, err := io.ReadFull(load, buf); err != nil {
		panic(err)
	}
}

func (load L) Bytes(n uint32) (data []byte) {
	data = make([]byte, n)
	load.Into(data)
	return
}

func (load L) Byte() byte {
	x, err := load.ReadByte()
	if err != nil {
		panic(err)
	}
	return x
}

func (load L) Uint32() (x uint32) {
	if err := binary.Read(load, binary.LittleEndian, &x); err != nil {
		panic(err)
	}
	return
}

func (load L) Uint64() (x uint64) {
	if err := binary.Read(load, binary.LittleEndian, &x); err != nil {
		panic(err)
	}
	return
}

func (load L) Varint7() int8 {
	return int8(load.Varint64())
}

func (load L) Varint32() int32 {
	return int32(load.Varint64())
}

func (load L) Varint64() (x int64) {
	var shift uint
	for {
		b := load.Byte()
		x |= (int64(b) & 0x7f) << shift
		shift += 7
		if (b & 0x80) == 0 {
			if shift < 64 && (b&0x40) != 0 {
				x |= -1 << shift
			}
			return
		}
	}
}

func (load L) Varuint1() bool {
	x, err := load.ReadByte()
	if err != nil {
		panic(err)
	}
	if x > 1 {
		panic(fmt.Errorf("varuint1 is too large: 0x%x", x))
	}
	return x == 1
}

func (load L) Varuint32() uint32 {
	x, err := binary.ReadUvarint(load)
	if err != nil {
		panic(err)
	}
	if x > math.MaxUint32 {
		panic(fmt.Errorf("varuint32 is too large: 0x%x", x))
	}
	return uint32(x)
}

func (load L) Varuint64() (x uint64) {
	x, err := binary.ReadUvarint(load)
	if err != nil {
		panic(err)
	}
	return
}

// Count reads a varuint32 for iteration.
func (load L) Count() []struct{} {
	count := load.Varuint32()
	if count > math.MaxInt32 {
		panic(fmt.Errorf("count is too large: 0x%x", count))
	}
	return make([]struct{}, int(count))
}
<|endoftext|>


<commit_before>// Copyright 2019 Google Inc. All Rights Reserved.
// This file is available under the Apache license.
// +build integration

package mtail

import (
	"bytes"
	"encoding/json"
	"expvar"
	"fmt"
	"net"
	"net/http"
	"os"
	"runtime"
	"testing"
	"time"

	"github.com/golang/glog"
	"github.com/google/mtail/internal/metrics"
	"github.com/google/mtail/internal/testutil"
	"github.com/google/mtail/internal/watcher"
)

const timeoutMultiplier = 3

type TestServer struct {
	*Server

	tb testing.TB
}

// TestMakeServer makes a new TestServer for use in tests, but does not start
// the server.  If an error occurs during creation, a testing.Fatal is issued.
func TestMakeServer(tb testing.TB, pollInterval time.Duration, enableFsNotify bool, options ...func(*Server) error) *TestServer {
	tb.Helper()
	w, err := watcher.NewLogWatcher(pollInterval, enableFsNotify)
	if err != nil {
		tb.Fatal(err)
	}

	expvar.Get("lines_total").(*expvar.Int).Set(0)
	expvar.Get("log_count").(*expvar.Int).Set(0)
	expvar.Get("log_rotations_total").(*expvar.Map).Init()
	expvar.Get("prog_loads_total").(*expvar.Map).Init()

	m, err := New(metrics.NewStore(), w, options...)
	if err != nil {
		tb.Fatal(err)
	}
	return &TestServer{Server: m, tb: tb}
}

// TestStartServer creates a new TestServer and starts it running.  It
// returns the server, and a cleanup function.
func TestStartServer(tb testing.TB, pollInterval time.Duration, enableFsNotify bool, options ...func(*Server) error) (*TestServer, func()) {
	tb.Helper()
	options = append(options, BindAddress("", "0"))

	m := TestMakeServer(tb, pollInterval, enableFsNotify, options...)
	return m, m.Start()
}

// Start starts the TestServer and returns a cleanup function.
func (m *TestServer) Start() func() {
	m.tb.Helper()
	errc := make(chan error, 1)
	go func() {
		err := m.Run()
		errc <- err
	}()

	glog.Infof("check that server is listening")
	count := 0
	for _, err := net.DialTimeout("tcp", m.Addr(), 10*time.Millisecond*timeoutMultiplier); err != nil && count < 10; count++ {
		glog.Infof("err: %s, retrying to dial %s", err, m.Addr())
		time.Sleep(100 * time.Millisecond * timeoutMultiplier)
	}
	if count >= 10 {
		m.tb.Fatal("server wasn't listening after 10 attempts")
	}

	return func() {
		err := m.Close(true)
		if err != nil {
			m.tb.Fatal(err)
		}
		select {
		case err = <-errc:
		case <-time.After(5 * time.Second):
			buf := make([]byte, 1<<16)
			n := runtime.Stack(buf, true)
			fmt.Fprintf(os.Stderr, "%s", buf[0:n])
			m.tb.Fatal("timeout waiting for shutdown")
		}

		if err != nil {
			m.tb.Fatal(err)
		}
	}
}

// TestGetMetric fetches the expvar metrics from the Server at addr, and
// returns the value of one named name.  Callers are responsible for type
// assertions on the returned value.
func TestGetMetric(tb testing.TB, addr, name string) interface{} {
	uri := fmt.Sprintf("http://%s/debug/vars", addr)
	client := &http.Client{
		Timeout: 5 * time.Second,
	}
	resp, err := client.Get(uri)
	if err != nil {
		tb.Fatal(err)
	}
	buf := new(bytes.Buffer)
	n, err := buf.ReadFrom(resp.Body)
	resp.Body.Close()
	testutil.FatalIfErr(tb, err)
	glog.V(2).Infof("TestGetMetric: http client read %d bytes from debug/vars", n)
	var r map[string]interface{}
	if err := json.Unmarshal(buf.Bytes(), &r); err != nil {
		tb.Fatalf("%s: body was %s", err, buf.String())
	}
	glog.Infof("TestGetMetric: returned value for %s: %v", name, r[name])
	return r[name]
}

// TestMetricDelta checks to see if the difference between a and b is want;
// it assumes both values are float64s that came from a TestGetMetric.
func TestMetricDelta(a, b interface{}) float64 {
	if a == nil {
		a = 0.
	}
	if b == nil {
		b = 0.
	}
	return a.(float64) - b.(float64)
}

// ExpectMetricDelta checks to see if the difference between a and b is want;
// it assumes both values are float64s that came from a TestGetMetric.
func ExpectMetricDelta(tb testing.TB, a, b interface{}, want float64) {
	tb.Helper()
	delta := TestMetricDelta(a, b)
	if delta != want {
		tb.Errorf("Unexpected delta: got %v - %v = %g, want %g", a, b, delta, want)
	}
}

// ExpectMetricDeltaWithDeadline returns a deferrable function which tests if the metric with name has changed by delta within the given deadline, once the function begins.  Before returning, it fetches the original value for comparison.
func ExpectMetricDeltaWithDeadline(tb testing.TB, address, name string, want float64, deadline time.Duration) func() {
	tb.Helper()
	start := TestGetMetric(tb, address, name)
	check := func() (bool, error) {
		now := TestGetMetric(tb, address, name)
		return TestMetricDelta(now, start) == want, nil
	}
	return func() {
		ok, err := testutil.DoOrTimeout(check, deadline, 10*time.Millisecond)
		if err != nil {
			tb.Fatal(err)
		}
		if !ok {
			now := TestGetMetric(tb, address, name)
			delta := TestMetricDelta(now, start)
			tb.Errorf("Did not see delta by deadline: got %v - %v = %g, want %g", now, start, delta, want)
		}
	}
}

// ExpectMapMetricDeltaWithDeadline returns a deferrable function which tests if the map metric with name and key has changed by delta within the given deadline, once the function begins.  Before returning, it fetches the original value for comparison.
func ExpectMapMetricDeltaWithDeadline(tb testing.TB, address, name, key string, want float64, deadline time.Duration) func() {
	tb.Helper()
	start := TestGetMetric(tb, address, name).(map[string]interface{})
	check := func() (bool, error) {
		now := TestGetMetric(tb, address, name).(map[string]interface{})
		return TestMetricDelta(now[key], start[key]) == want, nil
	}
	return func() {
		ok, err := testutil.DoOrTimeout(check, deadline, 10*time.Millisecond)
		if err != nil {
			tb.Fatal(err)
		}
		if !ok {
			now := TestGetMetric(tb, address, name).(map[string]interface{})
			delta := TestMetricDelta(now[key], start[key])
			tb.Errorf("Did not see delta by deadline: got %v - %v = %g, want %g", now[key], start[key], delta, want)
		}
	}
}
<commit_msg>Mark test helpers as such to get better error messages.<commit_after>// Copyright 2019 Google Inc. All Rights Reserved.
// This file is available under the Apache license.
// +build integration

package mtail

import (
	"bytes"
	"encoding/json"
	"expvar"
	"fmt"
	"net"
	"net/http"
	"os"
	"runtime"
	"testing"
	"time"

	"github.com/golang/glog"
	"github.com/google/mtail/internal/metrics"
	"github.com/google/mtail/internal/testutil"
	"github.com/google/mtail/internal/watcher"
)

const timeoutMultiplier = 3

type TestServer struct {
	*Server

	tb testing.TB
}

// TestMakeServer makes a new TestServer for use in tests, but does not start
// the server.  If an error occurs during creation, a testing.Fatal is issued.
func TestMakeServer(tb testing.TB, pollInterval time.Duration, enableFsNotify bool, options ...func(*Server) error) *TestServer {
	tb.Helper()
	w, err := watcher.NewLogWatcher(pollInterval, enableFsNotify)
	if err != nil {
		tb.Fatal(err)
	}

	expvar.Get("lines_total").(*expvar.Int).Set(0)
	expvar.Get("log_count").(*expvar.Int).Set(0)
	expvar.Get("log_rotations_total").(*expvar.Map).Init()
	expvar.Get("prog_loads_total").(*expvar.Map).Init()

	m, err := New(metrics.NewStore(), w, options...)
	if err != nil {
		tb.Fatal(err)
	}
	return &TestServer{Server: m, tb: tb}
}

// TestStartServer creates a new TestServer and starts it running.  It
// returns the server, and a cleanup function.
func TestStartServer(tb testing.TB, pollInterval time.Duration, enableFsNotify bool, options ...func(*Server) error) (*TestServer, func()) {
	tb.Helper()
	options = append(options, BindAddress("", "0"))

	m := TestMakeServer(tb, pollInterval, enableFsNotify, options...)
	return m, m.Start()
}

// Start starts the TestServer and returns a cleanup function.
func (m *TestServer) Start() func() {
	m.tb.Helper()
	errc := make(chan error, 1)
	go func() {
		err := m.Run()
		errc <- err
	}()

	glog.Infof("check that server is listening")
	count := 0
	for _, err := net.DialTimeout("tcp", m.Addr(), 10*time.Millisecond*timeoutMultiplier); err != nil && count < 10; count++ {
		glog.Infof("err: %s, retrying to dial %s", err, m.Addr())
		time.Sleep(100 * time.Millisecond * timeoutMultiplier)
	}
	if count >= 10 {
		m.tb.Fatal("server wasn't listening after 10 attempts")
	}

	return func() {
		err := m.Close(true)
		if err != nil {
			m.tb.Fatal(err)
		}

		select {
		case err = <-errc:
		case <-time.After(5 * time.Second):
			buf := make([]byte, 1<<16)
			n := runtime.Stack(buf, true)
			fmt.Fprintf(os.Stderr, "%s", buf[0:n])
			m.tb.Fatal("timeout waiting for shutdown")
		}
		if err != nil {
			m.tb.Fatal(err)
		}
	}
}

// TestGetMetric fetches the expvar metrics from the Server at addr, and
// returns the value of one named name.  Callers are responsible for type
// assertions on the returned value.
func TestGetMetric(tb testing.TB, addr, name string) interface{} {
	tb.Helper()
	uri := fmt.Sprintf("http://%s/debug/vars", addr)
	client := &http.Client{
		Timeout: 5 * time.Second,
	}
	resp, err := client.Get(uri)
	if err != nil {
		tb.Fatal(err)
	}
	buf := new(bytes.Buffer)
	n, err := buf.ReadFrom(resp.Body)
	resp.Body.Close()
	testutil.FatalIfErr(tb, err)
	glog.V(2).Infof("TestGetMetric: http client read %d bytes from debug/vars", n)
	var r map[string]interface{}
	if err := json.Unmarshal(buf.Bytes(), &r); err != nil {
		tb.Fatalf("%s: body was %s", err, buf.String())
	}
	glog.Infof("TestGetMetric: returned value for %s: %v", name, r[name])
	return r[name]
}

// TestMetricDelta checks to see if the difference between a and b is want;
// it assumes both values are float64s that came from a TestGetMetric.
func TestMetricDelta(a, b interface{}) float64 {
	if a == nil {
		a = 0.
	}
	if b == nil {
		b = 0.
	}
	return a.(float64) - b.(float64)
}

// ExpectMetricDelta checks to see if the difference between a and b is want;
// it assumes both values are float64s that came from a TestGetMetric.
func ExpectMetricDelta(tb testing.TB, a, b interface{}, want float64) {
	tb.Helper()
	delta := TestMetricDelta(a, b)
	if delta != want {
		tb.Errorf("Unexpected delta: got %v - %v = %g, want %g", a, b, delta, want)
	}
}

// ExpectMetricDeltaWithDeadline returns a deferrable function which tests if the metric with name has changed by delta within the given deadline, once the function begins.  Before returning, it fetches the original value for comparison.
func ExpectMetricDeltaWithDeadline(tb testing.TB, address, name string, want float64, deadline time.Duration) func() {
	tb.Helper()
	start := TestGetMetric(tb, address, name)
	check := func() (bool, error) {
		now := TestGetMetric(tb, address, name)
		return TestMetricDelta(now, start) == want, nil
	}
	return func() {
		tb.Helper()
		ok, err := testutil.DoOrTimeout(check, deadline, 10*time.Millisecond)
		if err != nil {
			tb.Fatal(err)
		}
		if !ok {
			now := TestGetMetric(tb, address, name)
			delta := TestMetricDelta(now, start)
			tb.Errorf("Did not see delta by deadline: got %v - %v = %g, want %g", now, start, delta, want)
		}
	}
}

// ExpectMapMetricDeltaWithDeadline returns a deferrable function which tests if the map metric with name and key has changed by delta within the given deadline, once the function begins.  Before returning, it fetches the original value for comparison.
func ExpectMapMetricDeltaWithDeadline(tb testing.TB, address, name, key string, want float64, deadline time.Duration) func() {
	tb.Helper()
	start := TestGetMetric(tb, address, name).(map[string]interface{})
	check := func() (bool, error) {
		now := TestGetMetric(tb, address, name).(map[string]interface{})
		return TestMetricDelta(now[key], start[key]) == want, nil
	}
	return func() {
		ok, err := testutil.DoOrTimeout(check, deadline, 10*time.Millisecond)
		if err != nil {
			tb.Fatal(err)
		}
		if !ok {
			now := TestGetMetric(tb, address, name).(map[string]interface{})
			delta := TestMetricDelta(now[key], start[key])
			tb.Errorf("Did not see delta by deadline: got %v - %v = %g, want %g", now[key], start[key], delta, want)
		}
	}
}
<|endoftext|>