<commit_before>// Copyright 2016 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 graphics

import (
	"errors"
	"fmt"
	"image"
	"image/color"
	"image/draw"
	"math"
	"sync"

	"github.com/hajimehoshi/ebiten/internal/graphics/opengl"
)

func glMatrix(m *[4][4]float64) []float32 {
	return []float32{
		float32(m[0][0]), float32(m[1][0]), float32(m[2][0]), float32(m[3][0]),
		float32(m[0][1]), float32(m[1][1]), float32(m[2][1]), float32(m[3][1]),
		float32(m[0][2]), float32(m[1][2]), float32(m[2][2]), float32(m[3][2]),
		float32(m[0][3]), float32(m[1][3]), float32(m[2][3]), float32(m[3][3]),
	}
}

type Matrix interface {
	Element(i, j int) float64
}

type command interface {
	Exec(context *opengl.Context, indexOffsetInBytes int) error
}

type commandQueue struct {
	commands []command
	m        sync.Mutex
}

var theCommandQueue = &commandQueue{
	commands: []command{},
}

func (q *commandQueue) Enqueue(command command) {
	q.m.Lock()
	defer q.m.Unlock()
	q.commands = append(q.commands, command)
}

func mergeCommands(commands []command) []command {
	// TODO: This logic is relatively complicated. Add tests.
	cs := make([]command, 0, len(commands))
	var prev *drawImageCommand
	for _, c := range commands {
		switch c := c.(type) {
		case *drawImageCommand:
			if prev == nil {
				prev = c
				continue
			}
			if prev.isMergeable(c) {
				prev = prev.merge(c)
				continue
			}
			cs = append(cs, prev)
			prev = c
			continue
		}
		if prev != nil {
			cs = append(cs, prev)
			prev = nil
		}
		cs = append(cs, c)
	}
	if prev != nil {
		cs = append(cs, prev)
	}
	return cs
}

// commandGroups separates q.commands into some groups.
// The number of quads of drawImageCommand in one groups must be equal to or less than
// its limit (maxQuads).
func (q *commandQueue) commandGroups() [][]command {
	cs := mergeCommands(q.commands)
	gs := [][]command{}
	quads := 0
	for 0 < len(cs) {
		if len(gs) == 0 {
			gs = append(gs, []command{})
		}
		c := cs[0]
		switch c := c.(type) {
		case *drawImageCommand:
			if maxQuads >= quads+c.quadsNum() {
				quads += c.quadsNum()
				break
			}
			cc := c.split(maxQuads - quads)
			gs[len(gs)-1] = append(gs[len(gs)-1], cc[0])
			cs[0] = cc[1]
			quads = 0
			gs = append(gs, []command{})
			continue
		}
		gs[len(gs)-1] = append(gs[len(gs)-1], c)
		cs = cs[1:]
	}
	return gs
}

func (q *commandQueue) Flush(context *opengl.Context) error {
	q.m.Lock()
	defer q.m.Unlock()
	// glViewport must be called at least at every frame on iOS.
	context.ResetViewportSize()
	for _, g := range q.commandGroups() {
		vertices := []int16{}
		for _, c := range g {
			switch c := c.(type) {
			case *drawImageCommand:
				vertices = append(vertices, c.vertices...)
			}
		}
		if 0 < len(vertices) {
			context.BufferSubData(opengl.ArrayBuffer, vertices)
		}
		// NOTE: WebGL doesn't seem to have Check gl.MAX_ELEMENTS_VERTICES or gl.MAX_ELEMENTS_INDICES so far.
		// Let's use them to compare to len(quads) in the future.
		if maxQuads < len(vertices)/QuadVertexSizeInBytes() {
			return fmt.Errorf("len(quads) must be equal to or less than %d", maxQuads)
		}
		numc := len(g)
		indexOffsetInBytes := 0
		for _, c := range g {
			if err := c.Exec(context, indexOffsetInBytes); err != nil {
				return err
			}
			if c, ok := c.(*drawImageCommand); ok {
				n := len(c.vertices) * 2 / QuadVertexSizeInBytes()
				indexOffsetInBytes += 6 * n * 2
			}
		}
		if 0 < numc {
			// Call glFlush to prevent black flicking (especially on Android (#226) and iOS).
			context.Flush()
		}
	}
	q.commands = []command{}
	return nil
}

func FlushCommands(context *opengl.Context) error {
	return theCommandQueue.Flush(context)
}

type fillCommand struct {
	dst   *Image
	color color.RGBA
}

func (c *fillCommand) Exec(context *opengl.Context, indexOffsetInBytes int) error {
	if err := c.dst.framebuffer.setAsViewport(context); err != nil {
		return err
	}
	cr, cg, cb, ca := c.color.R, c.color.G, c.color.B, c.color.A
	const max = math.MaxUint8
	r := float64(cr) / max
	g := float64(cg) / max
	b := float64(cb) / max
	a := float64(ca) / max
	return context.FillFramebuffer(r, g, b, a)
}

type drawImageCommand struct {
	dst      *Image
	src      *Image
	vertices []int16
	color    Matrix
	mode     opengl.CompositeMode
}

func QuadVertexSizeInBytes() int {
	return 4 * theArrayBufferLayout.total()
}

func (c *drawImageCommand) Exec(context *opengl.Context, indexOffsetInBytes int) error {
	if err := c.dst.framebuffer.setAsViewport(context); err != nil {
		return err
	}
	context.BlendFunc(c.mode)

	n := c.quadsNum()
	if n == 0 {
		return nil
	}
	_, h := c.dst.Size()
	proj := glMatrix(c.dst.framebuffer.projectionMatrix(h))
	p := programContext{
		state:            &theOpenGLState,
		program:          theOpenGLState.programTexture,
		context:          context,
		projectionMatrix: proj,
		texture:          c.src.texture.native,
		colorM:           c.color,
	}
	if err := p.begin(); err != nil {
		return err
	}
	defer p.end()
	// TODO: We should call glBindBuffer here?
	// The buffer is already bound at begin() but it is counterintuitive.
	context.DrawElements(opengl.Triangles, 6*n, indexOffsetInBytes)
	return nil
}

func (c *drawImageCommand) split(quadsNum int) [2]*drawImageCommand {
	c1 := *c
	c2 := *c
	c1.vertices = c.vertices[:quadsNum*QuadVertexSizeInBytes()/2]
	c2.vertices = c.vertices[quadsNum*QuadVertexSizeInBytes()/2:]
	return [2]*drawImageCommand{&c1, &c2}
}

func (c *drawImageCommand) isMergeable(other *drawImageCommand) bool {
	if c.dst != other.dst {
		return false
	}
	if c.src != other.src {
		return false
	}
	for i := 0; i < 4; i++ {
		for j := 0; j < 5; j++ {
			if c.color.Element(i, j) != other.color.Element(i, j) {
				return false
			}
		}
	}
	if c.mode != other.mode {
		return false
	}
	return true
}

func (c *drawImageCommand) merge(other *drawImageCommand) *drawImageCommand {
	newC := *c
	newC.vertices = make([]int16, 0, len(c.vertices)+len(other.vertices))
	newC.vertices = append(newC.vertices, c.vertices...)
	newC.vertices = append(newC.vertices, other.vertices...)
	return &newC
}

func (c *drawImageCommand) quadsNum() int {
	return len(c.vertices) * 2 / QuadVertexSizeInBytes()
}

type replacePixelsCommand struct {
	dst    *Image
	pixels []uint8
}

func (c *replacePixelsCommand) Exec(context *opengl.Context, indexOffsetInBytes int) error {
	if err := c.dst.framebuffer.setAsViewport(context); err != nil {
		return err
	}
	// Filling with non black or white color is required here for glTexSubImage2D.
	// Very mysterious but this actually works (Issue #186).
	// This is needed even after fixing a shader bug at f537378f2a6a8ef56e1acf1c03034967b77c7b51.
	if err := context.FillFramebuffer(0, 0, 0.5, 1); err != nil {
		return err
	}
	// This is necessary on Android. We can't call glClear just before glTexSubImage2D without
	// glFlush. glTexSubImage2D didn't work without this hack at least on Nexus 5x (#211).
	// This also happens when a fillCommand precedes a replacePixelsCommand.
	// TODO: Can we have a better way like optimizing commands?
	context.Flush()
	if err := context.BindTexture(c.dst.texture.native); err != nil {
		return err
	}
	context.TexSubImage2D(c.pixels, c.dst.width, c.dst.height)
	return nil
}

type disposeCommand struct {
	target *Image
}

func (c *disposeCommand) Exec(context *opengl.Context, indexOffsetInBytes int) error {
	if c.target.framebuffer != nil {
		context.DeleteFramebuffer(c.target.framebuffer.native)
	}
	if c.target.texture != nil {
		context.DeleteTexture(c.target.texture.native)
	}
	return nil
}

type newImageFromImageCommand struct {
	result *Image
	img    *image.RGBA
	filter opengl.Filter
}

func adjustImageForTexture(img *image.RGBA) *image.RGBA {
	width, height := img.Bounds().Size().X, img.Bounds().Size().Y
	adjustedImageBounds := image.Rectangle{
		image.ZP,
		image.Point{
			NextPowerOf2Int(width),
			NextPowerOf2Int(height),
		},
	}
	if img.Bounds() == adjustedImageBounds {
		return img
	}

	adjustedImage := image.NewRGBA(adjustedImageBounds)
	dstBounds := image.Rectangle{
		image.ZP,
		img.Bounds().Size(),
	}
	draw.Draw(adjustedImage, dstBounds, img, img.Bounds().Min, draw.Src)
	return adjustedImage
}

func (c *newImageFromImageCommand) Exec(context *opengl.Context, indexOffsetInBytes int) error {
	origSize := c.img.Bounds().Size()
	if origSize.X < 1 {
		return errors.New("graphics: width must be equal or more than 1.")
	}
	if origSize.Y < 1 {
		return errors.New("graphics: height must be equal or more than 1.")
	}
	adjustedImage := adjustImageForTexture(c.img)
	size := adjustedImage.Bounds().Size()
	native, err := context.NewTexture(size.X, size.Y, adjustedImage.Pix, c.filter)
	if err != nil {
		return err
	}
	c.result.texture = &texture{
		native: native,
	}
	c.result.framebuffer, err = newFramebufferFromTexture(context, c.result.texture)
	if err != nil {
		return err
	}
	return nil
}

type newImageCommand struct {
	result *Image
	width  int
	height int
	filter opengl.Filter
}

func (c *newImageCommand) Exec(context *opengl.Context, indexOffsetInBytes int) error {
	w := NextPowerOf2Int(c.width)
	h := NextPowerOf2Int(c.height)
	if w < 1 {
		return errors.New("graphics: width must be equal or more than 1.")
	}
	if h < 1 {
		return errors.New("graphics: height must be equal or more than 1.")
	}
	native, err := context.NewTexture(w, h, nil, c.filter)
	if err != nil {
		return err
	}
	c.result.texture = &texture{
		native: native,
	}
	c.result.framebuffer, err = newFramebufferFromTexture(context, c.result.texture)
	if err != nil {
		return err
	}
	return nil
}

type newScreenFramebufferImageCommand struct {
	result *Image
	width  int
	height int
}

func (c *newScreenFramebufferImageCommand) Exec(context *opengl.Context, indexOffsetInBytes int) error {
	if c.width < 1 {
		return errors.New("graphics: width must be equal or more than 1.")
	}
	if c.height < 1 {
		return errors.New("graphics: height must be equal or more than 1.")
	}
	f := &framebuffer{
		native: context.ScreenFramebuffer(),
		flipY:  true,
	}
	c.result.framebuffer = f
	return nil
}
<commit_msg>graphics: Calc capacity of vertices<commit_after>// Copyright 2016 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 graphics

import (
	"errors"
	"fmt"
	"image"
	"image/color"
	"image/draw"
	"math"
	"sync"

	"github.com/hajimehoshi/ebiten/internal/graphics/opengl"
)

func glMatrix(m *[4][4]float64) []float32 {
	return []float32{
		float32(m[0][0]), float32(m[1][0]), float32(m[2][0]), float32(m[3][0]),
		float32(m[0][1]), float32(m[1][1]), float32(m[2][1]), float32(m[3][1]),
		float32(m[0][2]), float32(m[1][2]), float32(m[2][2]), float32(m[3][2]),
		float32(m[0][3]), float32(m[1][3]), float32(m[2][3]), float32(m[3][3]),
	}
}

type Matrix interface {
	Element(i, j int) float64
}

type command interface {
	Exec(context *opengl.Context, indexOffsetInBytes int) error
}

type commandQueue struct {
	commands []command
	m        sync.Mutex
}

var theCommandQueue = &commandQueue{
	commands: []command{},
}

func (q *commandQueue) Enqueue(command command) {
	q.m.Lock()
	defer q.m.Unlock()
	q.commands = append(q.commands, command)
}

func mergeCommands(commands []command) []command {
	// TODO: This logic is relatively complicated. Add tests.
	cs := make([]command, 0, len(commands))
	var prev *drawImageCommand
	for _, c := range commands {
		switch c := c.(type) {
		case *drawImageCommand:
			if prev == nil {
				prev = c
				continue
			}
			if prev.isMergeable(c) {
				prev = prev.merge(c)
				continue
			}
			cs = append(cs, prev)
			prev = c
			continue
		}
		if prev != nil {
			cs = append(cs, prev)
			prev = nil
		}
		cs = append(cs, c)
	}
	if prev != nil {
		cs = append(cs, prev)
	}
	return cs
}

// commandGroups separates q.commands into some groups.
// The number of quads of drawImageCommand in one groups must be equal to or less than
// its limit (maxQuads).
func (q *commandQueue) commandGroups() [][]command {
	cs := mergeCommands(q.commands)
	gs := [][]command{}
	quads := 0
	for 0 < len(cs) {
		if len(gs) == 0 {
			gs = append(gs, []command{})
		}
		c := cs[0]
		switch c := c.(type) {
		case *drawImageCommand:
			if maxQuads >= quads+c.quadsNum() {
				quads += c.quadsNum()
				break
			}
			cc := c.split(maxQuads - quads)
			gs[len(gs)-1] = append(gs[len(gs)-1], cc[0])
			cs[0] = cc[1]
			quads = 0
			gs = append(gs, []command{})
			continue
		}
		gs[len(gs)-1] = append(gs[len(gs)-1], c)
		cs = cs[1:]
	}
	return gs
}

func (q *commandQueue) Flush(context *opengl.Context) error {
	q.m.Lock()
	defer q.m.Unlock()
	// glViewport must be called at least at every frame on iOS.
	context.ResetViewportSize()
	for _, g := range q.commandGroups() {
		n := 0
		for _, c := range g {
			switch c := c.(type) {
			case *drawImageCommand:
				n += len(c.vertices)
			}
		}
		vertices := make([]int16, 0, n)
		for _, c := range g {
			switch c := c.(type) {
			case *drawImageCommand:
				vertices = append(vertices, c.vertices...)
			}
		}
		if 0 < len(vertices) {
			context.BufferSubData(opengl.ArrayBuffer, vertices)
		}
		// NOTE: WebGL doesn't seem to have Check gl.MAX_ELEMENTS_VERTICES or gl.MAX_ELEMENTS_INDICES so far.
		// Let's use them to compare to len(quads) in the future.
		if maxQuads < len(vertices)/QuadVertexSizeInBytes() {
			return fmt.Errorf("len(quads) must be equal to or less than %d", maxQuads)
		}
		numc := len(g)
		indexOffsetInBytes := 0
		for _, c := range g {
			if err := c.Exec(context, indexOffsetInBytes); err != nil {
				return err
			}
			if c, ok := c.(*drawImageCommand); ok {
				n := len(c.vertices) * 2 / QuadVertexSizeInBytes()
				indexOffsetInBytes += 6 * n * 2
			}
		}
		if 0 < numc {
			// Call glFlush to prevent black flicking (especially on Android (#226) and iOS).
			context.Flush()
		}
	}
	q.commands = []command{}
	return nil
}

func FlushCommands(context *opengl.Context) error {
	return theCommandQueue.Flush(context)
}

type fillCommand struct {
	dst   *Image
	color color.RGBA
}

func (c *fillCommand) Exec(context *opengl.Context, indexOffsetInBytes int) error {
	if err := c.dst.framebuffer.setAsViewport(context); err != nil {
		return err
	}
	cr, cg, cb, ca := c.color.R, c.color.G, c.color.B, c.color.A
	const max = math.MaxUint8
	r := float64(cr) / max
	g := float64(cg) / max
	b := float64(cb) / max
	a := float64(ca) / max
	return context.FillFramebuffer(r, g, b, a)
}

type drawImageCommand struct {
	dst      *Image
	src      *Image
	vertices []int16
	color    Matrix
	mode     opengl.CompositeMode
}

func QuadVertexSizeInBytes() int {
	return 4 * theArrayBufferLayout.total()
}

func (c *drawImageCommand) Exec(context *opengl.Context, indexOffsetInBytes int) error {
	if err := c.dst.framebuffer.setAsViewport(context); err != nil {
		return err
	}
	context.BlendFunc(c.mode)

	n := c.quadsNum()
	if n == 0 {
		return nil
	}
	_, h := c.dst.Size()
	proj := glMatrix(c.dst.framebuffer.projectionMatrix(h))
	p := programContext{
		state:            &theOpenGLState,
		program:          theOpenGLState.programTexture,
		context:          context,
		projectionMatrix: proj,
		texture:          c.src.texture.native,
		colorM:           c.color,
	}
	if err := p.begin(); err != nil {
		return err
	}
	defer p.end()
	// TODO: We should call glBindBuffer here?
	// The buffer is already bound at begin() but it is counterintuitive.
	context.DrawElements(opengl.Triangles, 6*n, indexOffsetInBytes)
	return nil
}

func (c *drawImageCommand) split(quadsNum int) [2]*drawImageCommand {
	c1 := *c
	c2 := *c
	c1.vertices = c.vertices[:quadsNum*QuadVertexSizeInBytes()/2]
	c2.vertices = c.vertices[quadsNum*QuadVertexSizeInBytes()/2:]
	return [2]*drawImageCommand{&c1, &c2}
}

func (c *drawImageCommand) isMergeable(other *drawImageCommand) bool {
	if c.dst != other.dst {
		return false
	}
	if c.src != other.src {
		return false
	}
	for i := 0; i < 4; i++ {
		for j := 0; j < 5; j++ {
			if c.color.Element(i, j) != other.color.Element(i, j) {
				return false
			}
		}
	}
	if c.mode != other.mode {
		return false
	}
	return true
}

func (c *drawImageCommand) merge(other *drawImageCommand) *drawImageCommand {
	newC := *c
	newC.vertices = make([]int16, 0, len(c.vertices)+len(other.vertices))
	newC.vertices = append(newC.vertices, c.vertices...)
	newC.vertices = append(newC.vertices, other.vertices...)
	return &newC
}

func (c *drawImageCommand) quadsNum() int {
	return len(c.vertices) * 2 / QuadVertexSizeInBytes()
}

type replacePixelsCommand struct {
	dst    *Image
	pixels []uint8
}

func (c *replacePixelsCommand) Exec(context *opengl.Context, indexOffsetInBytes int) error {
	if err := c.dst.framebuffer.setAsViewport(context); err != nil {
		return err
	}
	// Filling with non black or white color is required here for glTexSubImage2D.
	// Very mysterious but this actually works (Issue #186).
	// This is needed even after fixing a shader bug at f537378f2a6a8ef56e1acf1c03034967b77c7b51.
	if err := context.FillFramebuffer(0, 0, 0.5, 1); err != nil {
		return err
	}
	// This is necessary on Android. We can't call glClear just before glTexSubImage2D without
	// glFlush. glTexSubImage2D didn't work without this hack at least on Nexus 5x (#211).
	// This also happens when a fillCommand precedes a replacePixelsCommand.
	// TODO: Can we have a better way like optimizing commands?
	context.Flush()
	if err := context.BindTexture(c.dst.texture.native); err != nil {
		return err
	}
	context.TexSubImage2D(c.pixels, c.dst.width, c.dst.height)
	return nil
}

type disposeCommand struct {
	target *Image
}

func (c *disposeCommand) Exec(context *opengl.Context, indexOffsetInBytes int) error {
	if c.target.framebuffer != nil {
		context.DeleteFramebuffer(c.target.framebuffer.native)
	}
	if c.target.texture != nil {
		context.DeleteTexture(c.target.texture.native)
	}
	return nil
}

type newImageFromImageCommand struct {
	result *Image
	img    *image.RGBA
	filter opengl.Filter
}

func adjustImageForTexture(img *image.RGBA) *image.RGBA {
	width, height := img.Bounds().Size().X, img.Bounds().Size().Y
	adjustedImageBounds := image.Rectangle{
		image.ZP,
		image.Point{
			NextPowerOf2Int(width),
			NextPowerOf2Int(height),
		},
	}
	if img.Bounds() == adjustedImageBounds {
		return img
	}

	adjustedImage := image.NewRGBA(adjustedImageBounds)
	dstBounds := image.Rectangle{
		image.ZP,
		img.Bounds().Size(),
	}
	draw.Draw(adjustedImage, dstBounds, img, img.Bounds().Min, draw.Src)
	return adjustedImage
}

func (c *newImageFromImageCommand) Exec(context *opengl.Context, indexOffsetInBytes int) error {
	origSize := c.img.Bounds().Size()
	if origSize.X < 1 {
		return errors.New("graphics: width must be equal or more than 1.")
	}
	if origSize.Y < 1 {
		return errors.New("graphics: height must be equal or more than 1.")
	}
	adjustedImage := adjustImageForTexture(c.img)
	size := adjustedImage.Bounds().Size()
	native, err := context.NewTexture(size.X, size.Y, adjustedImage.Pix, c.filter)
	if err != nil {
		return err
	}
	c.result.texture = &texture{
		native: native,
	}
	c.result.framebuffer, err = newFramebufferFromTexture(context, c.result.texture)
	if err != nil {
		return err
	}
	return nil
}

type newImageCommand struct {
	result *Image
	width  int
	height int
	filter opengl.Filter
}

func (c *newImageCommand) Exec(context *opengl.Context, indexOffsetInBytes int) error {
	w := NextPowerOf2Int(c.width)
	h := NextPowerOf2Int(c.height)
	if w < 1 {
		return errors.New("graphics: width must be equal or more than 1.")
	}
	if h < 1 {
		return errors.New("graphics: height must be equal or more than 1.")
	}
	native, err := context.NewTexture(w, h, nil, c.filter)
	if err != nil {
		return err
	}
	c.result.texture = &texture{
		native: native,
	}
	c.result.framebuffer, err = newFramebufferFromTexture(context, c.result.texture)
	if err != nil {
		return err
	}
	return nil
}

type newScreenFramebufferImageCommand struct {
	result *Image
	width  int
	height int
}

func (c *newScreenFramebufferImageCommand) Exec(context *opengl.Context, indexOffsetInBytes int) error {
	if c.width < 1 {
		return errors.New("graphics: width must be equal or more than 1.")
	}
	if c.height < 1 {
		return errors.New("graphics: height must be equal or more than 1.")
	}
	f := &framebuffer{
		native: context.ScreenFramebuffer(),
		flipY:  true,
	}
	c.result.framebuffer = f
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package postgres

import (
	"context"
	"database/sql"
	"fmt"
	"strings"

	"github.com/Masterminds/squirrel"
	"golang.org/x/pkgsite/internal"
	"golang.org/x/pkgsite/internal/derrors"
	"golang.org/x/pkgsite/internal/version"
)

// GetVersionsForPath returns a list of tagged versions sorted in
// descending semver order if any exist. If none, it returns the 10 most
// recent from a list of pseudo-versions sorted in descending semver order.
func (db *DB) GetVersionsForPath(ctx context.Context, path string) (_ []*internal.ModuleInfo, err error) {
	defer derrors.Wrap(&err, "GetVersionsForPath(ctx, %q)", path)

	versions, err := getPathVersions(ctx, db, path, version.TypeRelease, version.TypePrerelease)
	if err != nil {
		return nil, err
	}
	if len(versions) != 0 {
		return versions, nil
	}
	versions, err = getPathVersions(ctx, db, path, version.TypePseudo)
	if err != nil {
		return nil, err
	}
	return versions, nil
}

// getPathVersions returns a list of versions sorted in descending semver
// order. The version types included in the list are specified by a list of
// VersionTypes.
func getPathVersions(ctx context.Context, db *DB, path string, versionTypes ...version.Type) (_ []*internal.ModuleInfo, err error) {
	defer derrors.Wrap(&err, "getPathVersions(ctx, db, %q, %v)", path, versionTypes)

	baseQuery := `
	SELECT
		m.module_path,
		m.version,
		m.commit_time,
		m.redistributable,
		m.has_go_mod,
		m.source_info
	FROM modules m
	INNER JOIN units u
		ON u.module_id = m.id
	LEFT JOIN documentation d
		ON d.unit_id = u.id
	WHERE
		u.v1_path = (
			SELECT u2.v1_path
			FROM units as u2
			WHERE u2.path = $1
			LIMIT 1
		)
		AND version_type in (%s)
		-- Packages must have documentation source
		AND (u.name = '' OR d.source IS NOT NULL)
	ORDER BY
		m.incompatible,
		m.module_path DESC,
		m.sort_version DESC %s`

	queryEnd := `;`
	if len(versionTypes) == 0 {
		return nil, fmt.Errorf("error: must specify at least one version type")
	} else if len(versionTypes) == 1 && versionTypes[0] == version.TypePseudo {
		queryEnd = `LIMIT 10;`
	}
	query := fmt.Sprintf(baseQuery, versionTypeExpr(versionTypes), queryEnd)
	var versions []*internal.ModuleInfo
	collect := func(rows *sql.Rows) error {
		mi, err := scanModuleInfo(rows.Scan)
		if err != nil {
			return fmt.Errorf("row.Scan(): %v", err)
		}
		versions = append(versions, mi)
		return nil
	}
	if err := db.db.RunQuery(ctx, query, collect, path); err != nil {
		return nil, err
	}
	return versions, nil
}

// versionTypeExpr returns a comma-separated list of version types,
// for use in a clause like "WHERE version_type IN (%s)"
func versionTypeExpr(vts []version.Type) string {
	var vs []string
	for _, vt := range vts {
		vs = append(vs, fmt.Sprintf("'%s'", vt.String()))
	}
	return strings.Join(vs, ", ")
}

// GetLatestMajorVersion returns the latest module path and the full package path
// of the latest version found, given the fullPath and the modulePath.
// For example, in the module path "github.com/casbin/casbin", there
// is another module path with a greater major version "github.com/casbin/casbin/v3".
// This function will return "github.com/casbin/casbin/v3" or the input module path
// if no later module path was found. It also returns the full package path at the
// latest module version if it exists. If not, it returns the module path.
func (db *DB) GetLatestMajorVersion(ctx context.Context, fullPath, modulePath string) (_ string, _ string, err error) {
	defer derrors.Wrap(&err, "DB.GetLatestMajorVersion(ctx, %q, %q)", fullPath, modulePath)

	seriesPath := internal.SeriesPathForModule(modulePath)
	v1Path := internal.V1Path(fullPath, modulePath)
	q, args, err := orderByLatest(squirrel.Select("m.module_path, u.path").
		From("modules m").
		LeftJoin("units u ON u.module_id = m.id").
		Where(squirrel.Eq{"m.series_path": seriesPath})).
		OrderByClause(`CASE
			WHEN u.v1_path = ? THEN 1
			ELSE 2
		END`, v1Path).
		Limit(1).
		ToSql()
	if err != nil {
		return "", "", err
	}
	var latestModulePath, latestPackagePath string
	row := db.db.QueryRow(ctx, q, args...)
	if err := row.Scan(&latestModulePath, &latestPackagePath); err != nil {
		return "", "", err
	}
	return latestModulePath, latestPackagePath, nil
}
<commit_msg>internal/postgres: GetLatestMajorVersion returns module path if package is missing<commit_after>// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package postgres

import (
	"context"
	"database/sql"
	"fmt"
	"strings"

	"github.com/Masterminds/squirrel"
	"golang.org/x/pkgsite/internal"
	"golang.org/x/pkgsite/internal/derrors"
	"golang.org/x/pkgsite/internal/version"
)

// GetVersionsForPath returns a list of tagged versions sorted in
// descending semver order if any exist. If none, it returns the 10 most
// recent from a list of pseudo-versions sorted in descending semver order.
func (db *DB) GetVersionsForPath(ctx context.Context, path string) (_ []*internal.ModuleInfo, err error) {
	defer derrors.Wrap(&err, "GetVersionsForPath(ctx, %q)", path)

	versions, err := getPathVersions(ctx, db, path, version.TypeRelease, version.TypePrerelease)
	if err != nil {
		return nil, err
	}
	if len(versions) != 0 {
		return versions, nil
	}
	versions, err = getPathVersions(ctx, db, path, version.TypePseudo)
	if err != nil {
		return nil, err
	}
	return versions, nil
}

// getPathVersions returns a list of versions sorted in descending semver
// order. The version types included in the list are specified by a list of
// VersionTypes.
func getPathVersions(ctx context.Context, db *DB, path string, versionTypes ...version.Type) (_ []*internal.ModuleInfo, err error) {
	defer derrors.Wrap(&err, "getPathVersions(ctx, db, %q, %v)", path, versionTypes)

	baseQuery := `
	SELECT
		m.module_path,
		m.version,
		m.commit_time,
		m.redistributable,
		m.has_go_mod,
		m.source_info
	FROM modules m
	INNER JOIN units u
		ON u.module_id = m.id
	LEFT JOIN documentation d
		ON d.unit_id = u.id
	WHERE
		u.v1_path = (
			SELECT u2.v1_path
			FROM units as u2
			WHERE u2.path = $1
			LIMIT 1
		)
		AND version_type in (%s)
		-- Packages must have documentation source
		AND (u.name = '' OR d.source IS NOT NULL)
	ORDER BY
		m.incompatible,
		m.module_path DESC,
		m.sort_version DESC %s`

	queryEnd := `;`
	if len(versionTypes) == 0 {
		return nil, fmt.Errorf("error: must specify at least one version type")
	} else if len(versionTypes) == 1 && versionTypes[0] == version.TypePseudo {
		queryEnd = `LIMIT 10;`
	}
	query := fmt.Sprintf(baseQuery, versionTypeExpr(versionTypes), queryEnd)
	var versions []*internal.ModuleInfo
	collect := func(rows *sql.Rows) error {
		mi, err := scanModuleInfo(rows.Scan)
		if err != nil {
			return fmt.Errorf("row.Scan(): %v", err)
		}
		versions = append(versions, mi)
		return nil
	}
	if err := db.db.RunQuery(ctx, query, collect, path); err != nil {
		return nil, err
	}
	return versions, nil
}

// versionTypeExpr returns a comma-separated list of version types,
// for use in a clause like "WHERE version_type IN (%s)"
func versionTypeExpr(vts []version.Type) string {
	var vs []string
	for _, vt := range vts {
		vs = append(vs, fmt.Sprintf("'%s'", vt.String()))
	}
	return strings.Join(vs, ", ")
}

// GetLatestMajorVersion returns the latest module path and the full package path
// of the latest version found, given the fullPath and the modulePath.
// For example, in the module path "github.com/casbin/casbin", there
// is another module path with a greater major version "github.com/casbin/casbin/v3".
// This function will return "github.com/casbin/casbin/v3" or the input module path
// if no later module path was found. It also returns the full package path at the
// latest module version if it exists. If not, it returns the module path.
func (db *DB) GetLatestMajorVersion(ctx context.Context, fullPath, modulePath string) (_ string, _ string, err error) {
	defer derrors.Wrap(&err, "DB.GetLatestMajorVersion(ctx, %q, %q)", fullPath, modulePath)

	seriesPath := internal.SeriesPathForModule(modulePath)
	v1Path := internal.V1Path(fullPath, modulePath)
	q, args, err := orderByLatest(squirrel.Select("m.module_path, u.path").
		From("modules m").
		LeftJoin("units u ON u.module_id = m.id").
		Where(squirrel.Eq{"m.series_path": seriesPath})).
		OrderByClause(`CASE
			WHEN u.v1_path = ? THEN 1
			ELSE 2
		END`, v1Path).
		Limit(1).
		ToSql()
	if err != nil {
		return "", "", err
	}
	var latestModulePath, latestPackagePath string
	if err := db.db.QueryRow(ctx, q, args...).Scan(&latestModulePath, &latestPackagePath); err != nil {
		return "", "", err
	}
	// If the package path is not the one we're expecting, then it doesn't exist
	// in the latest module version (or it would have been sorted first by the
	// OrderByClause above).
	if internal.V1Path(latestPackagePath, latestModulePath) != v1Path {
		return latestModulePath, latestModulePath, nil
	}
	return latestModulePath, latestPackagePath, nil
}
<|endoftext|>


<commit_before>package immortal

import (
	"fmt"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"time"

	"github.com/immortal/xtime"
)

// ScanDir struct
type ScanDir struct {
	scandir  string
	services map[string]string
}

// NewScanDir returns ScanDir struct
func NewScanDir(path string) (*ScanDir, error) {
	if info, err := os.Stat(path); os.IsNotExist(err) {
		return nil, fmt.Errorf("%q no such file or directory.", path)
	} else if !info.IsDir() {
		return nil, fmt.Errorf("%q is not a directory.", path)
	}

	dir, err := filepath.EvalSymlinks(path)
	if err != nil {
		return nil, err
	}

	dir, err = filepath.Abs(filepath.Clean(dir))
	if err != nil {
		return nil, err
	}

	d, err := os.Open(dir)
	if err != nil {
		if os.IsPermission(err) {
			return nil, os.ErrPermission
		}
		return nil, err
	}
	defer d.Close()

	return &ScanDir{
		scandir:  dir,
		services: map[string]string{},
	}, nil
}

// Start scans directory every 5 seconds
func (s *ScanDir) Start() {
	log.Printf("immortal scandir: %s", s.scandir)
	s.Scaner()
	ticker := time.NewTicker(5 * time.Second)
	for {
		select {
		case <-ticker.C:
			s.Scaner()
		}
	}
}

// Scaner searchs for run.yml and based on the perms start/stops the process
// if file changes it will reload(exit-start)
func (s *ScanDir) Scaner() {
	find := func(path string, f os.FileInfo, err error) error {
		var (
			hash string
			md5  string
			name string
			exit bool
		)
		if err != nil {
			return err
		}
		if strings.HasSuffix(f.Name(), ".yml") {
			name = strings.TrimSuffix(f.Name(), filepath.Ext(f.Name()))
			md5, err = md5sum(path)
			if err != nil {
				return err
			}
			// add service and reload if any changes
			if hash, ok := s.services[name]; !ok {
				s.services[name] = md5
			} else if hash != md5 {
				exit = true
			}
			refresh := (time.Now().Unix() - xtime.Get(f).Ctime().Unix()) <= 5
			if refresh {
				// if file is executable start
				if m := f.Mode(); m&0111 != 0 {
					if exit {
						SendSignal(socket, "exit")
					}
					println("turn on ", name)
					// try to start before via socket
					cmd := exec.Command("immortal", "-c", path, "-ctl", name)
					cmd.Env = os.Environ()
					fmt.Printf("cmd.Path = %+v\n", cmd.Path)
					stdoutStderr, err := cmd.CombinedOutput()
					if err != nil {
						return err
					}
					log.Printf("%s\n", stdoutStderr)
				} else {
					// socket put down
					SendSignal(socket, "exit")
				}
			}
		}
		return nil
	}
	err := filepath.Walk(s.scandir, find)
	if err != nil {
		log.Println(err)
	}
	return
}
<commit_msg>send signals<commit_after>package immortal

import (
	"fmt"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"time"

	"github.com/immortal/xtime"
)

// ScanDir struct
type ScanDir struct {
	scandir  string
	sdir     string
	services map[string]string
}

// NewScanDir returns ScanDir struct
func NewScanDir(path string) (*ScanDir, error) {
	if info, err := os.Stat(path); os.IsNotExist(err) {
		return nil, fmt.Errorf("%q no such file or directory.", path)
	} else if !info.IsDir() {
		return nil, fmt.Errorf("%q is not a directory.", path)
	}

	dir, err := filepath.EvalSymlinks(path)
	if err != nil {
		return nil, err
	}

	dir, err = filepath.Abs(filepath.Clean(dir))
	if err != nil {
		return nil, err
	}

	d, err := os.Open(dir)
	if err != nil {
		if os.IsPermission(err) {
			return nil, os.ErrPermission
		}
		return nil, err
	}
	defer d.Close()

	// if IMMORTAL_SDIR env is set, use it as default sdir
	sdir := os.Getenv("IMMORTAL_SDIR")
	if sdir == "" {
		sdir = "/var/run/immortal"
	}

	return &ScanDir{
		scandir:  dir,
		sdir:     sdir,
		services: map[string]string{},
	}, nil
}

// Start scans directory every 5 seconds
func (s *ScanDir) Start() {
	log.Printf("immortal scandir: %s", s.scandir)
	s.Scaner()
	ticker := time.NewTicker(5 * time.Second)
	for {
		select {
		case <-ticker.C:
			s.Scaner()
		}
	}
}

// Scaner searchs for run.yml and based on the perms start/stops the process
// if file changes it will reload(exit-start)
func (s *ScanDir) Scaner() {
	find := func(path string, f os.FileInfo, err error) error {
		var (
			md5  string
			name string
			exit bool
		)
		if err != nil {
			return err
		}
		if strings.HasSuffix(f.Name(), ".yml") {
			name = strings.TrimSuffix(f.Name(), filepath.Ext(f.Name()))
			md5, err = md5sum(path)
			if err != nil {
				return err
			}
			// add service to services map or reload if file has been changed
			if hash, ok := s.services[name]; !ok {
				s.services[name] = md5
			} else if hash != md5 {
				exit = true
			}
			// check if file hasn't been changed since last tick (5 seconds)
			refresh := (time.Now().Unix() - xtime.Get(f).Ctime().Unix()) <= 5
			if refresh {
				// if file is executable start
				if m := f.Mode(); m&0111 != 0 {
					if exit {
						log.Printf("Restarting %q\n", name)
						SendSignal(filepath.Join(s.sdir, name, "immortal.sock"), "exit")
					}
					// try to start before via socket
					if _, err := SendSignal(filepath.Join(s.sdir, name, "immortal.sock"), "start"); err != nil {
						log.Printf("Starting %q\n", name)
						cmd := exec.Command("immortal", "-c", path, "-ctl", name)
						cmd.Env = os.Environ()
						fmt.Printf("cmd.Path = %+v\n", cmd.Path)
						stdoutStderr, err := cmd.CombinedOutput()
						if err != nil {
							return err
						}
						log.Printf("%s\n", stdoutStderr)
					} else {
						log.Printf("%q restarted\n", name)
					}
				} else {
					_, err := SendSignal(filepath.Join(s.sdir, name, "immortal.sock"), "down")
					if err != nil {
						log.Printf("%q not running\n", name)
					}
				}
			}
		}
		return nil
	}
	err := filepath.Walk(s.scandir, find)
	if err != nil {
		log.Println(err)
	}
	return
}
<|endoftext|>


<commit_before>package models

const (
	version = "0.10.5"

	OpenTrace   = "open_trace"
	WebVersion  = "web_version"
	Unsubscribe = "unsubscribe"

	StatusUnavaibleRecentTime = "Unavaible recent time"
	StatusUnsubscribe         = "Unsubscribe"
	StatusSending             = "Sending"
)
<commit_msg>bump version<commit_after>package models

const (
	version = "0.10.6"

	OpenTrace   = "open_trace"
	WebVersion  = "web_version"
	Unsubscribe = "unsubscribe"

	StatusUnavaibleRecentTime = "Unavaible recent time"
	StatusUnsubscribe         = "Unsubscribe"
	StatusSending             = "Sending"
)
<|endoftext|>


<commit_before>package builder

import (
	"crypto/sha256"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/user"
	"path"
	"path/filepath"
	"strings"
	"sync"
	"time"

	"github.com/docker/engine-api/client"
	"github.com/docker/engine-api/types"
	"github.com/docker/engine-api/types/container"
	"github.com/docker/engine-api/types/filters"
	"github.com/pkg/errors"
	"golang.org/x/net/context"
)

var DefaultCmdTimeout = 600 * time.Second

type Builder struct {
	docker  *client.Client
	id      string
	workdir string
	//path:volume_name
	volumes map[string]string

	spec    *BuildSpec
	profile *ProfileSpec

	image            string
	environmentImage string
	stepCount        int

	ui UI
}

func NewBuilder(workdir string, build *BuildSpec, profile *ProfileSpec) (*Builder, error) {
	var err error

	builder := &Builder{
		id:      randStringBytesMask(8),
		workdir: workdir,
		spec:    build,
		profile: profile,
		ui:      &ConsolUI{},
	}

	if os.Getenv("DOCKER_HOST") != "" {
		builder.docker, err = client.NewEnvClient()
	} else {
		builder.docker, err = client.NewClient("unix:///var/run/docker.sock", "v1.22", nil, nil)
	}
	if err != nil {
		return nil, errors.Wrap(err, "failed to create docker client")
	}

	return builder, nil
}

func (b *Builder) ExecInEnvironment(cmd string) error {
	_, err := b.runCmdInImage(b.environmentImage, "environment-exec", cmd, []string{}, DefaultCmdTimeout)
	return err
}

func (b *Builder) ExecuteEnivronmentStage(useCache bool, cacheImage string) (string, error) {
	/*err := b.createVolumes()
	if err != nil {
		return b.image, errors.Wrap(err, "failed to create volumes for cache directories")
	}*/

	if useCache && cacheImage != "" {
		_, _, err := b.docker.ImageInspectWithRaw(context.TODO(), cacheImage, false)
		if err != nil {
			b.ui.Printf("recieved err for cached environment, proceeding without cache: %s", err)
			goto EXECUTE_ENVIRONMENT_STAGE_NOCACHE
		}
		b.image = cacheImage
		b.environmentImage = b.image
		return b.image, nil
	}

EXECUTE_ENVIRONMENT_STAGE_NOCACHE:
	b.ui.Printf("--> Stage(environment-before): Pulling image(%s):\n\n", b.image)
	reader, err := b.docker.ImagePull(context.TODO(), b.profile.Image, types.ImagePullOptions{})
	if err != nil {
		return "", errors.Wrap(err, "failed to pull image")
	}
	//TODO: display pull status
	if _, err = ioutil.ReadAll(reader); err != nil {
		return "", err
	}

	b.image = b.profile.Image

	for _, step := range b.spec.Environment.After.Steps {
		err := b.runStep("environment-after", step)
		if err != nil {
			return b.image, errors.Wrapf(err, "failed to run cmd(%s)", step.Cmd)
		}
	}
	b.environmentImage = b.image

	return b.image, nil
}

func (b *Builder) ExecuteDependenciesStage(useCache bool, cacheImage string) (string, error) {
	if useCache && cacheImage != "" {
		_, _, err := b.docker.ImageInspectWithRaw(context.TODO(), cacheImage, false)
		if err != nil {
			b.ui.Printf("recieved err for cached dependencies, proceeding without cache: %s", err)
			goto EXECUTE_DEPENDENCIES_STAGE_NOCACHE
		}
		b.image = cacheImage
		return b.image, nil
	}

EXECUTE_DEPENDENCIES_STAGE_NOCACHE:
	var err error
	for _, step := range b.spec.Dependencies.Before.Steps {
		err = b.runStep("dependancies-before", step)
		if err != nil {
			return b.image, errors.Wrapf(err, "failed to run cmd(%s)", step.Cmd)
		}
	}

	if len(b.spec.Dependencies.Override.Steps) > 0 {
		for _, step := range b.spec.Dependencies.Override.Steps {
			err = b.runStep("dependancies-override", step)
			if err != nil {
				return b.image, errors.Wrapf(err, "failed to run cmd(%s)", step.Cmd)
			}
		}
	} else {
		for _, step := range b.profile.Dependencies {
			err = b.runStep("dependancies-default", step)
			if err != nil {
				return b.image, errors.Wrapf(err, "failed to run cmd(%s)", step.Cmd)
			}
		}
	}

	for _, step := range b.spec.Dependencies.After.Steps {
		err = b.runStep("dependancies-after", step)
		if err != nil {
			return b.image, errors.Wrapf(err, "failed to run cmd(%s)", step.Cmd)
		}
	}

	return b.image, nil
}

func (b *Builder) ExecuteTestStage() error {
	var err error
	for _, step := range b.spec.Test.Before.Steps {
		err = b.runStep("test-before", step)
		if err != nil {
			return errors.Wrapf(err, "failed to run cmd(%s)", step.Cmd)
		}
	}

	if len(b.spec.Test.Override.Steps) > 0 {
		for _, step := range b.spec.Test.Override.Steps {
			err = b.runStep("test-override", step)
			if err != nil {
				return errors.Wrapf(err, "failed to run cmd(%s)", step.Cmd)
			}
		}
	} else {
		for _, step := range b.profile.Test {
			err = b.runStep("test-default", step)
			if err != nil {
				return errors.Wrapf(err, "failed to run cmd(%s)", step.Cmd)
			}
		}
	}

	for _, step := range b.spec.Test.After.Steps {
		err = b.runStep("test-after", step)
		if err != nil {
			return errors.Wrapf(err, "failed to run cmd(%s)", step.Cmd)
		}
	}

	return nil
}

func (b *Builder) createVolumes() error {
	b.volumes = map[string]string{}
	for idx := range b.profile.CacheDirectories {
		ops := types.VolumeCreateRequest{
			Driver: "local",
			Labels: map[string]string{
				"containme_id":  b.id,
				"containme_dir": b.profile.CacheDirectories[idx],
			},
		}
		vol, err := b.docker.VolumeCreate(context.TODO(), ops)
		if err != nil {
			return errors.Wrap(err, "failed to create volume")
		}
		b.volumes[b.profile.CacheDirectories[idx]] = vol.Name
	}
	return nil
}

func (b *Builder) destroyVolumes() error {
	for idx := range b.profile.CacheDirectories {
		err := b.docker.VolumeRemove(context.TODO(), b.volumes[b.profile.CacheDirectories[idx]])
		if err != nil {
			return errors.Wrap(err, "failed to create volume")
		}
		delete(b.volumes, b.profile.CacheDirectories[idx])
	}
	return nil
}

func (b *Builder) runStep(stage string, step Step) error {
	timeout := DefaultCmdTimeout
	if step.Timeout > 0 {
		timeout = time.Duration(step.Timeout) * time.Second
	}
	return b.runCmd(stage, step.Cmd, step.Env, timeout)
}

func (b *Builder) runCmd(stage, cmd string, env []string, timeout time.Duration) error {
	nextImage, err := b.runCmdInImage(b.image, stage, cmd, env, timeout)
	if err != nil {
		return err
	}

	b.image = nextImage
	b.stepCount++
	return nil
}

func (b *Builder) runCmdInImage(image, stage, cmd string, env []string, timeout time.Duration) (string, error) {
	config, hostConfig := b.containerConfig()
	config.Cmd = b.profile.MakeCmd(cmd)
	config.Env = processEnv(env)

	b.ui.Printf("--> Stage(%s): Running command (%s) for build-step-%d in image(%s):\n\n", stage, cmd, b.stepCount, b.image)

	resp, err := b.docker.ContainerCreate(context.TODO(), config, hostConfig, nil, fmt.Sprintf("cme_builder_%s-%d", b.id, b.stepCount))
	if err != nil {
		return "", errors.Wrapf(err, "failed to create build-step-%d container", b.stepCount)
	}
	defer b.docker.ContainerRemove(context.Background(), resp.ID, types.ContainerRemoveOptions{
		Force: true,
	})

	err = b.docker.ContainerStart(context.TODO(), resp.ID, types.ContainerStartOptions{})
	if err != nil {
		return "", errors.Wrapf(err, "failed to start build-step-%d container", b.stepCount)
	}

	wg := sync.WaitGroup{}

	go func() {
		wg.Add(1)
		defer wg.Done()
		var hyjack types.HijackedResponse
		hyjack, err = b.docker.ContainerAttach(context.TODO(), resp.ID, types.ContainerAttachOptions{
			Stream: true,
			Stderr: true,
			Stdout: true,
		})
		if err != nil {
			b.ui.Printf("failed to attached to build-step-%d output", b.stepCount)
			return
		}
		defer hyjack.Close()
		io.Copy(b.ui, hyjack.Reader)
	}()

	ctx, cancel := context.WithTimeout(context.Background(), timeout)
	defer cancel()

	containerWait := make(chan struct{})
	go func() {
		b.docker.ContainerWait(ctx, resp.ID)
		containerWait <- struct{}{}
	}()

	select {
	case <-ctx.Done():
		b.docker.ContainerKill(context.TODO(), resp.ID, "")
		return b.image, errors.Wrap(ctx.Err(), "timeout exceeded running cmd")
	case <-containerWait:
	}

	wg.Wait()

	job, _ := b.docker.ContainerInspect(context.TODO(), resp.ID)
	if job.State.ExitCode != 0 {
		return b.image, errors.Errorf("command failed with exit code %d", job.State.ExitCode)
	}

	commit, err := b.docker.ContainerCommit(context.TODO(), resp.ID, types.ContainerCommitOptions{})
	if err != nil {
		return "", errors.Wrapf(err, "failed to commit build-step-%d", b.stepCount)
	}

	return commit.ID, nil
}

func (b *Builder) containerConfig() (*container.Config, *container.HostConfig) {
	config := &container.Config{
		Image:      b.image,
		WorkingDir: b.profile.Workspace,
		Labels: map[string]string{
			"containme_id": b.id,
		},
		Tty:       true,
		StdinOnce: true,
	}

	if b.spec.Environment.Workspace != "" {
		if filepath.IsAbs(b.spec.Environment.Workspace) {
			config.WorkingDir = b.spec.Environment.Workspace
		} else {
			config.WorkingDir = path.Join(config.WorkingDir, b.spec.Environment.Workspace)
		}
	}

	hostConfig := &container.HostConfig{
		Binds: []string{fmt.Sprintf("%s:%s", b.workdir, config.WorkingDir)},
	}
	for _, mount := range b.spec.Environment.Mounts {
		if mount[:2] == "~/" {
			usr, _ := user.Current()
			mount = strings.Replace(mount, "~", usr.HomeDir, 1)
		}
		hostConfig.Binds = append(hostConfig.Binds, mount)
	}
	//hostConfig.Binds = append(hostConfig.Binds, b.spec.Environment.Mounts...)
	for path, vol := range b.volumes {
		hostConfig.Binds = append(hostConfig.Binds, fmt.Sprintf("%s:%s", vol, path))
	}

	return config, hostConfig
}

func (b *Builder) cmdHash(stage, cmd string) string {
	return fmt.Sprintf("%x", (sha256.Sum256([]byte(fmt.Sprintf("%s.%s.%s", b.spec.Environment.Profile, stage, cmd)))))
}

func (b *Builder) getCachedImage(hash string) (string, error) {
	args := filters.NewArgs()
	args.Add("containme_hash", hash)
	ops := types.ImageListOptions{

		Filters: args,
	}
	resp, err := b.docker.ImageList(context.TODO(), ops)
	if err != nil {
		return "", errors.Wrap(err, "failed to list images")
	}

	switch len(resp) {
	case 0:
		return "", nil
	case 1:
		return resp[0].ID, nil
	default:
		return "", errors.Errorf("multiple images for hash(%s)", hash)
	}
}
<commit_msg>Update builder.go<commit_after>package builder

import (
	"crypto/sha256"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/user"
	"path"
	"path/filepath"
	"strings"
	"sync"
	"time"

	"github.com/docker/engine-api/client"
	"github.com/docker/engine-api/types"
	"github.com/docker/engine-api/types/container"
	"github.com/docker/engine-api/types/filters"
	"github.com/pkg/errors"
	"golang.org/x/net/context"
)

var DefaultCmdTimeout = 600 * time.Second

type Builder struct {
	docker  *client.Client
	id      string
	workdir string
	//path:volume_name
	volumes map[string]string

	spec    *BuildSpec
	profile *ProfileSpec

	image            string
	environmentImage string
	stepCount        int

	ui UI
}

func NewBuilder(workdir string, build *BuildSpec, profile *ProfileSpec) (*Builder, error) {
	var err error

	builder := &Builder{
		id:      randStringBytesMask(8),
		workdir: workdir,
		spec:    build,
		profile: profile,
		ui:      &ConsolUI{},
	}

	if os.Getenv("DOCKER_HOST") != "" {
		builder.docker, err = client.NewEnvClient()
	} else {
		builder.docker, err = client.NewClient("unix:///var/run/docker.sock", "v1.22", nil, nil)
	}
	if err != nil {
		return nil, errors.Wrap(err, "failed to create docker client")
	}

	return builder, nil
}

func (b *Builder) ExecInEnvironment(cmd string) error {
	_, err := b.runCmdInImage(b.environmentImage, "environment-exec", cmd, []string{}, DefaultCmdTimeout)
	return err
}

func (b *Builder) ExecuteEnivronmentStage(useCache bool, cacheImage string) (string, error) {
	/*err := b.createVolumes()
	if err != nil {
		return b.image, errors.Wrap(err, "failed to create volumes for cache directories")
	}*/

	if useCache && cacheImage != "" {
		_, _, err := b.docker.ImageInspectWithRaw(context.TODO(), cacheImage, false)
		if err != nil {
			b.ui.Printf("recieved err for cached environment, proceeding without cache: %s", err)
			goto EXECUTE_ENVIRONMENT_STAGE_NOCACHE
		}
		b.image = cacheImage
		b.environmentImage = b.image
		return b.image, nil
	}

EXECUTE_ENVIRONMENT_STAGE_NOCACHE:
	b.ui.Printf("--> Stage(environment-before): Pulling image(%s):\n\n", b.image)
	reader, err := b.docker.ImagePull(context.TODO(), b.profile.Image, types.ImagePullOptions{})
	if err != nil {
		return "", errors.Wrap(err, "failed to pull image")
	}
	//TODO: display pull status
	if _, err = ioutil.ReadAll(reader); err != nil {
		return "", err
	}

	b.image = b.profile.Image

	for _, step := range b.spec.Environment.After.Steps {
		err := b.runStep("environment-after", step)
		if err != nil {
			return b.image, errors.Wrapf(err, "failed to run cmd(%s)", step.Cmd)
		}
	}
	b.environmentImage = b.image

	return b.image, nil
}

func (b *Builder) ExecuteDependenciesStage(useCache bool, cacheImage string) (string, error) {
	if useCache && cacheImage != "" {
		_, _, err := b.docker.ImageInspectWithRaw(context.TODO(), cacheImage, false)
		if err != nil {
			b.ui.Printf("recieved err for cached dependencies, proceeding without cache: %s", err)
			goto EXECUTE_DEPENDENCIES_STAGE_NOCACHE
		}
		b.image = cacheImage
		return b.image, nil
	}

EXECUTE_DEPENDENCIES_STAGE_NOCACHE:
	var err error
	for _, step := range b.spec.Dependencies.Before.Steps {
		err = b.runStep("dependancies-before", step)
		if err != nil {
			return b.image, errors.Wrapf(err, "failed to run cmd(%s)", step.Cmd)
		}
	}

	if len(b.spec.Dependencies.Override.Steps) > 0 {
		for _, step := range b.spec.Dependencies.Override.Steps {
			err = b.runStep("dependancies-override", step)
			if err != nil {
				return b.image, errors.Wrapf(err, "failed to run cmd(%s)", step.Cmd)
			}
		}
	} else {
		for _, step := range b.profile.Dependencies {
			err = b.runStep("dependancies-default", step)
			if err != nil {
				return b.image, errors.Wrapf(err, "failed to run cmd(%s)", step.Cmd)
			}
		}
	}

	for _, step := range b.spec.Dependencies.After.Steps {
		err = b.runStep("dependancies-after", step)
		if err != nil {
			return b.image, errors.Wrapf(err, "failed to run cmd(%s)", step.Cmd)
		}
	}

	return b.image, nil
}

func (b *Builder) ExecuteTestStage() error {
	var err error
	for _, step := range b.spec.Test.Before.Steps {
		err = b.runStep("test-before", step)
		if err != nil {
			return errors.Wrapf(err, "failed to run cmd(%s)", step.Cmd)
		}
	}

	if len(b.spec.Test.Override.Steps) > 0 {
		for _, step := range b.spec.Test.Override.Steps {
			err = b.runStep("test-override", step)
			if err != nil {
				return errors.Wrapf(err, "failed to run cmd(%s)", step.Cmd)
			}
		}
	} else {
		for _, step := range b.profile.Test {
			err = b.runStep("test-default", step)
			if err != nil {
				return errors.Wrapf(err, "failed to run cmd(%s)", step.Cmd)
			}
		}
	}

	for _, step := range b.spec.Test.After.Steps {
		err = b.runStep("test-after", step)
		if err != nil {
			return errors.Wrapf(err, "failed to run cmd(%s)", step.Cmd)
		}
	}

	return nil
}

func (b *Builder) createVolumes() error {
	b.volumes = map[string]string{}
	for idx := range b.profile.CacheDirectories {
		ops := types.VolumeCreateRequest{
			Driver: "local",
			Labels: map[string]string{
				"containme_id":  b.id,
				"containme_dir": b.profile.CacheDirectories[idx],
			},
		}
		vol, err := b.docker.VolumeCreate(context.TODO(), ops)
		if err != nil {
			return errors.Wrap(err, "failed to create volume")
		}
		b.volumes[b.profile.CacheDirectories[idx]] = vol.Name
	}
	return nil
}

func (b *Builder) destroyVolumes() error {
	for idx := range b.profile.CacheDirectories {
		err := b.docker.VolumeRemove(context.TODO(), b.volumes[b.profile.CacheDirectories[idx]], false)
		if err != nil {
			return errors.Wrap(err, "failed to create volume")
		}
		delete(b.volumes, b.profile.CacheDirectories[idx])
	}
	return nil
}

func (b *Builder) runStep(stage string, step Step) error {
	timeout := DefaultCmdTimeout
	if step.Timeout > 0 {
		timeout = time.Duration(step.Timeout) * time.Second
	}
	return b.runCmd(stage, step.Cmd, step.Env, timeout)
}

func (b *Builder) runCmd(stage, cmd string, env []string, timeout time.Duration) error {
	nextImage, err := b.runCmdInImage(b.image, stage, cmd, env, timeout)
	if err != nil {
		return err
	}

	b.image = nextImage
	b.stepCount++
	return nil
}

func (b *Builder) runCmdInImage(image, stage, cmd string, env []string, timeout time.Duration) (string, error) {
	config, hostConfig := b.containerConfig()
	config.Cmd = b.profile.MakeCmd(cmd)
	config.Env = processEnv(env)

	b.ui.Printf("--> Stage(%s): Running command (%s) for build-step-%d in image(%s):\n\n", stage, cmd, b.stepCount, b.image)

	resp, err := b.docker.ContainerCreate(context.TODO(), config, hostConfig, nil, fmt.Sprintf("cme_builder_%s-%d", b.id, b.stepCount))
	if err != nil {
		return "", errors.Wrapf(err, "failed to create build-step-%d container", b.stepCount)
	}
	defer b.docker.ContainerRemove(context.Background(), resp.ID, types.ContainerRemoveOptions{
		Force: true,
	})

	err = b.docker.ContainerStart(context.TODO(), resp.ID, types.ContainerStartOptions{})
	if err != nil {
		return "", errors.Wrapf(err, "failed to start build-step-%d container", b.stepCount)
	}

	wg := sync.WaitGroup{}

	go func() {
		wg.Add(1)
		defer wg.Done()
		var hyjack types.HijackedResponse
		hyjack, err = b.docker.ContainerAttach(context.TODO(), resp.ID, types.ContainerAttachOptions{
			Stream: true,
			Stderr: true,
			Stdout: true,
		})
		if err != nil {
			b.ui.Printf("failed to attached to build-step-%d output", b.stepCount)
			return
		}
		defer hyjack.Close()
		io.Copy(b.ui, hyjack.Reader)
	}()

	ctx, cancel := context.WithTimeout(context.Background(), timeout)
	defer cancel()

	containerWait := make(chan struct{})
	go func() {
		b.docker.ContainerWait(ctx, resp.ID)
		containerWait <- struct{}{}
	}()

	select {
	case <-ctx.Done():
		b.docker.ContainerKill(context.TODO(), resp.ID, "")
		return b.image, errors.Wrap(ctx.Err(), "timeout exceeded running cmd")
	case <-containerWait:
	}

	wg.Wait()

	job, _ := b.docker.ContainerInspect(context.TODO(), resp.ID)
	if job.State.ExitCode != 0 {
		return b.image, errors.Errorf("command failed with exit code %d", job.State.ExitCode)
	}

	commit, err := b.docker.ContainerCommit(context.TODO(), resp.ID, types.ContainerCommitOptions{})
	if err != nil {
		return "", errors.Wrapf(err, "failed to commit build-step-%d", b.stepCount)
	}

	return commit.ID, nil
}

func (b *Builder) containerConfig() (*container.Config, *container.HostConfig) {
	config := &container.Config{
		Image:      b.image,
		WorkingDir: b.profile.Workspace,
		Labels: map[string]string{
			"containme_id": b.id,
		},
		Tty:       true,
		StdinOnce: true,
	}

	if b.spec.Environment.Workspace != "" {
		if filepath.IsAbs(b.spec.Environment.Workspace) {
			config.WorkingDir = b.spec.Environment.Workspace
		} else {
			config.WorkingDir = path.Join(config.WorkingDir, b.spec.Environment.Workspace)
		}
	}

	hostConfig := &container.HostConfig{
		Binds: []string{fmt.Sprintf("%s:%s", b.workdir, config.WorkingDir)},
	}
	for _, mount := range b.spec.Environment.Mounts {
		if mount[:2] == "~/" {
			usr, _ := user.Current()
			mount = strings.Replace(mount, "~", usr.HomeDir, 1)
		}
		hostConfig.Binds = append(hostConfig.Binds, mount)
	}
	//hostConfig.Binds = append(hostConfig.Binds, b.spec.Environment.Mounts...)
	for path, vol := range b.volumes {
		hostConfig.Binds = append(hostConfig.Binds, fmt.Sprintf("%s:%s", vol, path))
	}

	return config, hostConfig
}

func (b *Builder) cmdHash(stage, cmd string) string {
	return fmt.Sprintf("%x", (sha256.Sum256([]byte(fmt.Sprintf("%s.%s.%s", b.spec.Environment.Profile, stage, cmd)))))
}

func (b *Builder) getCachedImage(hash string) (string, error) {
	args := filters.NewArgs()
	args.Add("containme_hash", hash)
	ops := types.ImageListOptions{

		Filters: args,
	}
	resp, err := b.docker.ImageList(context.TODO(), ops)
	if err != nil {
		return "", errors.Wrap(err, "failed to list images")
	}

	switch len(resp) {
	case 0:
		return "", nil
	case 1:
		return resp[0].ID, nil
	default:
		return "", errors.Errorf("multiple images for hash(%s)", hash)
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2015 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package registry

import (
	"github.com/golang/glog"

	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apiserver/pkg/registry/generic"
	"k8s.io/apiserver/pkg/storage"
	etcdstorage "k8s.io/apiserver/pkg/storage/etcd"
	"k8s.io/apiserver/pkg/storage/storagebackend"
	"k8s.io/apiserver/pkg/storage/storagebackend/factory"
)

// Creates a cacher based given storageConfig.
func StorageWithCacher(capacity int) generic.StorageDecorator {
	return func(
		storageConfig *storagebackend.Config,
		objectType runtime.Object,
		resourcePrefix string,
		keyFunc func(obj runtime.Object) (string, error),
		newListFunc func() runtime.Object,
		getAttrsFunc storage.AttrFunc,
		triggerFunc storage.TriggerPublisherFunc) (storage.Interface, factory.DestroyFunc) {

		s, d := generic.NewRawStorage(storageConfig)
		if capacity == 0 {
			glog.V(5).Infof("Storage caching is disabled for %T", objectType)
			return s, d
		}
		glog.V(5).Infof("Storage caching is enabled for %T with capacity %v", objectType, capacity)

		// TODO: we would change this later to make storage always have cacher and hide low level KV layer inside.
		// Currently it has two layers of same storage interface -- cacher and low level kv.
		cacherConfig := storage.CacherConfig{
			CacheCapacity:        capacity,
			Storage:              s,
			Versioner:            etcdstorage.APIObjectVersioner{},
			Type:                 objectType,
			ResourcePrefix:       resourcePrefix,
			KeyFunc:              keyFunc,
			NewListFunc:          newListFunc,
			GetAttrsFunc:         getAttrsFunc,
			TriggerPublisherFunc: triggerFunc,
			Codec:                storageConfig.Codec,
		}
		cacher := storage.NewCacherFromConfig(cacherConfig)
		destroyFunc := func() {
			cacher.Stop()
			d()
		}

		// TODO : Remove RegisterStorageCleanup below when PR
		// https://github.com/kubernetes/kubernetes/pull/50690
		// merges as that shuts down storage properly
		RegisterStorageCleanup(destroyFunc)

		return cacher, destroyFunc
	}
}

// TODO : Remove all the code below when PR
// https://github.com/kubernetes/kubernetes/pull/50690
// merges as that shuts down storage properly
// HACK ALERT : Track the destroy methods to call them
// from the test harness. TrackStorageCleanup will be called
// only from the test harness, so Register/Cleanup will be
// no-op at runtime.

var cleanup []func() = nil

func TrackStorageCleanup() {
	cleanup = make([]func(), 0)
}

func RegisterStorageCleanup(fn func()) {
	if cleanup == nil {
		return
	}
	cleanup = append(cleanup, fn)
}

func CleanupStorage() {
	if cleanup == nil {
		return
	}
	for _, d := range cleanup {
		d()
	}
	cleanup = nil
}
<commit_msg>apiserver: protect registry cleanup against concurrent access<commit_after>/*
Copyright 2015 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package registry

import (
	"sync"

	"github.com/golang/glog"

	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apiserver/pkg/registry/generic"
	"k8s.io/apiserver/pkg/storage"
	etcdstorage "k8s.io/apiserver/pkg/storage/etcd"
	"k8s.io/apiserver/pkg/storage/storagebackend"
	"k8s.io/apiserver/pkg/storage/storagebackend/factory"
)

// Creates a cacher based given storageConfig.
func StorageWithCacher(capacity int) generic.StorageDecorator {
	return func(
		storageConfig *storagebackend.Config,
		objectType runtime.Object,
		resourcePrefix string,
		keyFunc func(obj runtime.Object) (string, error),
		newListFunc func() runtime.Object,
		getAttrsFunc storage.AttrFunc,
		triggerFunc storage.TriggerPublisherFunc) (storage.Interface, factory.DestroyFunc) {

		s, d := generic.NewRawStorage(storageConfig)
		if capacity == 0 {
			glog.V(5).Infof("Storage caching is disabled for %T", objectType)
			return s, d
		}
		glog.V(5).Infof("Storage caching is enabled for %T with capacity %v", objectType, capacity)

		// TODO: we would change this later to make storage always have cacher and hide low level KV layer inside.
		// Currently it has two layers of same storage interface -- cacher and low level kv.
		cacherConfig := storage.CacherConfig{
			CacheCapacity:        capacity,
			Storage:              s,
			Versioner:            etcdstorage.APIObjectVersioner{},
			Type:                 objectType,
			ResourcePrefix:       resourcePrefix,
			KeyFunc:              keyFunc,
			NewListFunc:          newListFunc,
			GetAttrsFunc:         getAttrsFunc,
			TriggerPublisherFunc: triggerFunc,
			Codec:                storageConfig.Codec,
		}
		cacher := storage.NewCacherFromConfig(cacherConfig)
		destroyFunc := func() {
			cacher.Stop()
			d()
		}

		// TODO : Remove RegisterStorageCleanup below when PR
		// https://github.com/kubernetes/kubernetes/pull/50690
		// merges as that shuts down storage properly
		RegisterStorageCleanup(destroyFunc)

		return cacher, destroyFunc
	}
}

// TODO : Remove all the code below when PR
// https://github.com/kubernetes/kubernetes/pull/50690
// merges as that shuts down storage properly
// HACK ALERT : Track the destroy methods to call them
// from the test harness. TrackStorageCleanup will be called
// only from the test harness, so Register/Cleanup will be
// no-op at runtime.

var cleanupLock sync.Mutex
var cleanup []func() = nil

func TrackStorageCleanup() {
	cleanupLock.Lock()
	defer cleanupLock.Unlock()

	if cleanup != nil {
		panic("Conflicting storage tracking")
	}
	cleanup = make([]func(), 0)
}

func RegisterStorageCleanup(fn func()) {
	cleanupLock.Lock()
	defer cleanupLock.Unlock()

	if cleanup == nil {
		return
	}
	cleanup = append(cleanup, fn)
}

func CleanupStorage() {
	cleanupLock.Lock()
	old := cleanup
	cleanup = nil
	cleanupLock.Unlock()

	for _, d := range old {
		d()
	}
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"os"

	"github.com/containers/buildah"
	cp "github.com/containers/image/v5/copy"
	"github.com/containers/image/v5/signature"
	imageStorage "github.com/containers/image/v5/storage"
	"github.com/containers/image/v5/transports/alltransports"
	"github.com/containers/image/v5/types"
	"github.com/containers/storage"
	"github.com/containers/storage/pkg/unshare"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
	"github.com/spf13/cobra"
)

func main() {
	var storeOptions storage.StoreOptions
	var systemContext types.SystemContext
	var logLevel string
	var maxParallelDownloads uint

	if buildah.InitReexec() {
		return
	}

	unshare.MaybeReexecUsingUserNamespace(false)

	rootCmd := &cobra.Command{
		Use:  "copy [flags] source destination",
		Long: "copies an image",
		RunE: func(cmd *cobra.Command, args []string) error {
			if err := cobra.ExactArgs(2)(cmd, args); err != nil {
				return err
			}

			level, err := logrus.ParseLevel(logLevel)
			if err != nil {
				return err
			}
			logrus.SetLevel(level)

			store, err := storage.GetStore(storeOptions)
			if err != nil {
				return err
			}
			imageStorage.Transport.SetStore(store)

			if len(args) < 1 {
				return errors.Wrapf(err, "no source name provided")
			}
			src, err := alltransports.ParseImageName(args[0])
			if err != nil {
				return errors.Wrapf(err, "error parsing source name")
			}
			if len(args) < 1 {
				return errors.Wrapf(err, "no destination name provided")
			}
			dest, err := alltransports.ParseImageName(args[1])
			if err != nil {
				return errors.Wrapf(err, "error parsing destination name")
			}

			policy, err := signature.DefaultPolicy(&systemContext)
			if err != nil {
				return errors.Wrapf(err, "error reading signature policy")
			}
			policyContext, err := signature.NewPolicyContext(policy)
			if err != nil {
				return errors.Wrapf(err, "error creating new signature policy context")
			}
			defer func() {
				if err := policyContext.Destroy(); err != nil {
					logrus.Error(errors.Wrapf(err, "error destroying signature policy context"))
				}
			}()

			options := cp.Options{
				ReportWriter:         os.Stdout,
				SourceCtx:            &systemContext,
				DestinationCtx:       &systemContext,
				MaxParallelDownloads: maxParallelDownloads,
			}
			if _, err = cp.Image(context.TODO(), policyContext, dest, src, &options); err != nil {
				return err
			}

			defer func() {
				_, err := store.Shutdown(false)
				if err != nil {
					logrus.Error(err)
				}
			}()
			return nil
		},
	}

	rootCmd.PersistentFlags().StringVar(&storeOptions.GraphRoot, "root", "", "storage root")
	rootCmd.PersistentFlags().StringVar(&storeOptions.RunRoot, "runroot", "", "runtime root")
	rootCmd.PersistentFlags().StringVar(&storeOptions.GraphDriverName, "storage-driver", "", "storage driver")
	rootCmd.PersistentFlags().StringSliceVar(&storeOptions.GraphDriverOptions, "storage-opt", nil, "storage option")
	rootCmd.PersistentFlags().StringVar(&systemContext.SystemRegistriesConfPath, "registries-conf", "", "location of registries.conf")
	rootCmd.PersistentFlags().StringVar(&systemContext.SystemRegistriesConfDirPath, "registries-conf-dir", "", "location of registries.d")
	rootCmd.PersistentFlags().StringVar(&systemContext.SignaturePolicyPath, "signature-policy", "", "`pathname` of signature policy file")
	rootCmd.PersistentFlags().StringVar(&systemContext.UserShortNameAliasConfPath, "short-name-alias-conf", "", "`pathname` of short name alias cache file (not usually used)")
	rootCmd.PersistentFlags().StringVar(&logLevel, "log-level", "warn", "logging level")
	rootCmd.PersistentFlags().UintVar(&maxParallelDownloads, "max-parallel-downloads", 0, "maximum `number` of blobs to copy at once")
	if err := rootCmd.Execute(); err != nil {
		os.Exit(1)
	}
}
<commit_msg>tests/copy/copy: wire up compression options<commit_after>package main

import (
	"context"
	"os"
	"strings"

	"github.com/containers/buildah"
	cp "github.com/containers/image/v5/copy"
	"github.com/containers/image/v5/manifest"
	"github.com/containers/image/v5/pkg/compression"
	"github.com/containers/image/v5/signature"
	imageStorage "github.com/containers/image/v5/storage"
	"github.com/containers/image/v5/transports/alltransports"
	"github.com/containers/image/v5/types"
	"github.com/containers/storage"
	"github.com/containers/storage/pkg/unshare"
	v1 "github.com/opencontainers/image-spec/specs-go/v1"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
	"github.com/spf13/cobra"
)

func main() {
	var storeOptions storage.StoreOptions
	var systemContext types.SystemContext
	var logLevel string
	var maxParallelDownloads uint
	var compressionFormat string
	var manifestFormat string
	compressionLevel := -1

	if buildah.InitReexec() {
		return
	}

	unshare.MaybeReexecUsingUserNamespace(false)

	rootCmd := &cobra.Command{
		Use:  "copy [flags] source destination",
		Long: "copies an image",
		RunE: func(cmd *cobra.Command, args []string) error {
			if err := cobra.ExactArgs(2)(cmd, args); err != nil {
				return err
			}
			if compressionLevel != -1 {
				systemContext.CompressionLevel = &compressionLevel
			}
			if compressionFormat != "" {
				alg, err := compression.AlgorithmByName(compressionFormat)
				if err != nil {
					return err
				}
				systemContext.CompressionFormat = &alg
			}
			switch strings.ToLower(manifestFormat) {
			case "oci":
				manifestFormat = v1.MediaTypeImageManifest
			case "docker", "dockerv2s2":
				manifestFormat = manifest.DockerV2Schema2MediaType
			}

			level, err := logrus.ParseLevel(logLevel)
			if err != nil {
				return err
			}
			logrus.SetLevel(level)

			store, err := storage.GetStore(storeOptions)
			if err != nil {
				return err
			}
			imageStorage.Transport.SetStore(store)

			if len(args) < 1 {
				return errors.Wrapf(err, "no source name provided")
			}
			src, err := alltransports.ParseImageName(args[0])
			if err != nil {
				return errors.Wrapf(err, "error parsing source name")
			}
			if len(args) < 1 {
				return errors.Wrapf(err, "no destination name provided")
			}
			dest, err := alltransports.ParseImageName(args[1])
			if err != nil {
				return errors.Wrapf(err, "error parsing destination name")
			}

			policy, err := signature.DefaultPolicy(&systemContext)
			if err != nil {
				return errors.Wrapf(err, "error reading signature policy")
			}
			policyContext, err := signature.NewPolicyContext(policy)
			if err != nil {
				return errors.Wrapf(err, "error creating new signature policy context")
			}
			defer func() {
				if err := policyContext.Destroy(); err != nil {
					logrus.Error(errors.Wrapf(err, "error destroying signature policy context"))
				}
			}()

			options := cp.Options{
				ReportWriter:          os.Stdout,
				SourceCtx:             &systemContext,
				DestinationCtx:        &systemContext,
				MaxParallelDownloads:  maxParallelDownloads,
				ForceManifestMIMEType: manifestFormat,
			}
			if _, err = cp.Image(context.TODO(), policyContext, dest, src, &options); err != nil {
				return err
			}

			defer func() {
				_, err := store.Shutdown(false)
				if err != nil {
					logrus.Error(err)
				}
			}()
			return nil
		},
	}

	rootCmd.PersistentFlags().StringVar(&storeOptions.GraphRoot, "root", "", "storage root")
	rootCmd.PersistentFlags().StringVar(&storeOptions.RunRoot, "runroot", "", "runtime root")
	rootCmd.PersistentFlags().StringVar(&storeOptions.GraphDriverName, "storage-driver", "", "storage driver")
	rootCmd.PersistentFlags().StringSliceVar(&storeOptions.GraphDriverOptions, "storage-opt", nil, "storage option")
	rootCmd.PersistentFlags().StringVar(&systemContext.SystemRegistriesConfPath, "registries-conf", "", "location of registries.conf")
	rootCmd.PersistentFlags().StringVar(&systemContext.SystemRegistriesConfDirPath, "registries-conf-dir", "", "location of registries.d")
	rootCmd.PersistentFlags().StringVar(&systemContext.SignaturePolicyPath, "signature-policy", "", "`pathname` of signature policy file")
	rootCmd.PersistentFlags().StringVar(&systemContext.UserShortNameAliasConfPath, "short-name-alias-conf", "", "`pathname` of short name alias cache file (not usually used)")
	rootCmd.PersistentFlags().StringVar(&logLevel, "log-level", "warn", "logging level")
	rootCmd.PersistentFlags().UintVar(&maxParallelDownloads, "max-parallel-downloads", 0, "maximum `number` of blobs to copy at once")
	rootCmd.PersistentFlags().StringVar(&manifestFormat, "format", "", "image manifest type")
	rootCmd.PersistentFlags().BoolVar(&systemContext.DirForceCompress, "dest-compress", false, "force compression of layers for dir: destinations")
	rootCmd.PersistentFlags().BoolVar(&systemContext.DirForceDecompress, "dest-decompress", false, "force decompression of layers for dir: destinations")
	rootCmd.PersistentFlags().StringVar(&compressionFormat, "dest-compress-format", "", "compression type")
	rootCmd.PersistentFlags().IntVar(&compressionLevel, "dest-compress-level", 0, "compression level")
	if err := rootCmd.Execute(); err != nil {
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package gorm

import (
	"fmt"
	"strings"
)

func AssignUpdateAttributes(scope *Scope) {
	if attrs, ok := scope.InstanceGet("gorm:update_interface"); ok {
		if maps := convertInterfaceToMap(attrs); len(maps) > 0 {
			protected, ok := scope.Get("gorm:ignore_protected_attrs")
			_, updateColumn := scope.Get("gorm:update_column")
			updateAttrs, hasUpdate := scope.updatedAttrsWithValues(maps, ok && protected.(bool))

			if updateColumn {
				scope.InstanceSet("gorm:update_attrs", maps)
			} else if len(updateAttrs) > 0 {
				scope.InstanceSet("gorm:update_attrs", updateAttrs)
			} else if !hasUpdate {
				scope.SkipLeft()
				return
			}
		}
	}
}

func BeforeUpdate(scope *Scope) {
	if _, ok := scope.Get("gorm:update_column"); !ok {
		scope.CallMethodWithErrorCheck("BeforeSave")
		scope.CallMethodWithErrorCheck("BeforeUpdate")
	}
}

func UpdateTimeStampWhenUpdate(scope *Scope) {
	if _, ok := scope.Get("gorm:update_column"); !ok {
		scope.SetColumn("UpdatedAt", NowFunc())
	}
}

func Update(scope *Scope) {
	if !scope.HasError() {
		var sqls []string

		if updateAttrs, ok := scope.InstanceGet("gorm:update_attrs"); ok {
			for key, value := range updateAttrs.(map[string]interface{}) {
				if scope.changeableDBColumn(key) {
					sqls = append(sqls, fmt.Sprintf("%v = %v", scope.Quote(key), scope.AddToVars(value)))
				}
			}
		} else {
			fields := scope.Fields()
			for _, field := range fields {
				if scope.changeableField(field) && !field.IsPrimaryKey && field.IsNormal {
					sqls = append(sqls, fmt.Sprintf("%v = %v", scope.Quote(field.DBName), scope.AddToVars(field.Field.Interface())))
				} else if relationship := field.Relationship; relationship != nil && relationship.Kind == "belongs_to" {
					for _, dbName := range relationship.ForeignDBNames {
						if relationField := fields[dbName]; !scope.changeableField(relationField) && !relationField.IsBlank {
							sql := fmt.Sprintf("%v = %v", scope.Quote(relationField.DBName), scope.AddToVars(relationField.Field.Interface()))
							sqls = append(sqls, sql)
						}
					}
				}
			}
		}

		if len(sqls) > 0 {
			scope.Raw(fmt.Sprintf(
				"UPDATE %v SET %v %v",
				scope.QuotedTableName(),
				strings.Join(sqls, ", "),
				scope.CombinedConditionSql(),
			))
			scope.Exec()
		}
	}
}

func AfterUpdate(scope *Scope) {
	if _, ok := scope.Get("gorm:update_column"); !ok {
		scope.CallMethodWithErrorCheck("AfterUpdate")
		scope.CallMethodWithErrorCheck("AfterSave")
	}
}

func init() {
	DefaultCallback.Update().Register("gorm:assign_update_attributes", AssignUpdateAttributes)
	DefaultCallback.Update().Register("gorm:begin_transaction", BeginTransaction)
	DefaultCallback.Update().Register("gorm:before_update", BeforeUpdate)
	DefaultCallback.Update().Register("gorm:save_before_associations", SaveBeforeAssociations)
	DefaultCallback.Update().Register("gorm:update_time_stamp_when_update", UpdateTimeStampWhenUpdate)
	DefaultCallback.Update().Register("gorm:update", Update)
	DefaultCallback.Update().Register("gorm:save_after_associations", SaveAfterAssociations)
	DefaultCallback.Update().Register("gorm:after_update", AfterUpdate)
	DefaultCallback.Update().Register("gorm:commit_or_rollback_transaction", CommitOrRollbackTransaction)
}
<commit_msg>[Hack] No more ignoring updated_at field when updating through UpdateColumn.<commit_after>package gorm

import (
	"fmt"
	"strings"
)

func AssignUpdateAttributes(scope *Scope) {
	if attrs, ok := scope.InstanceGet("gorm:update_interface"); ok {
		if maps := convertInterfaceToMap(attrs); len(maps) > 0 {
			protected, ok := scope.Get("gorm:ignore_protected_attrs")
			_, updateColumn := scope.Get("gorm:update_column")
			updateAttrs, hasUpdate := scope.updatedAttrsWithValues(maps, ok && protected.(bool))

			if updateColumn {
				scope.InstanceSet("gorm:update_attrs", maps)
			} else if len(updateAttrs) > 0 {
				scope.InstanceSet("gorm:update_attrs", updateAttrs)
			} else if !hasUpdate {
				scope.SkipLeft()
				return
			}
		}
	}
}

func BeforeUpdate(scope *Scope) {
	if _, ok := scope.Get("gorm:update_column"); !ok {
		scope.CallMethodWithErrorCheck("BeforeSave")
		scope.CallMethodWithErrorCheck("BeforeUpdate")
	}
}

func UpdateTimeStampWhenUpdate(scope *Scope) {
	if _, ok := scope.Get("gorm:update_column"); !ok {
		scope.SetColumn("UpdatedAt", NowFunc())
	}
}

func Update(scope *Scope) {
	if !scope.HasError() {
		var sqls []string

		if updateAttrs, ok := scope.InstanceGet("gorm:update_attrs"); ok {
			aMap := updateAttrs.(map[string]interface{})
			if _, exist := aMap["updated_at"]; exist == false {
				aMap["updated_at"] = NowFunc()
			}
			for key, value := range aMap {
				if scope.changeableDBColumn(key) {
					sqls = append(sqls, fmt.Sprintf("%v = %v", scope.Quote(key), scope.AddToVars(value)))
				}
			}
		} else {
			fields := scope.Fields()
			for _, field := range fields {
				if scope.changeableField(field) && !field.IsPrimaryKey && field.IsNormal {
					sqls = append(sqls, fmt.Sprintf("%v = %v", scope.Quote(field.DBName), scope.AddToVars(field.Field.Interface())))
				} else if relationship := field.Relationship; relationship != nil && relationship.Kind == "belongs_to" {
					for _, dbName := range relationship.ForeignDBNames {
						if relationField := fields[dbName]; !scope.changeableField(relationField) && !relationField.IsBlank {
							sql := fmt.Sprintf("%v = %v", scope.Quote(relationField.DBName), scope.AddToVars(relationField.Field.Interface()))
							sqls = append(sqls, sql)
						}
					}
				}
			}
		}

		if len(sqls) > 0 {
			scope.Raw(fmt.Sprintf(
				"UPDATE %v SET %v %v",
				scope.QuotedTableName(),
				strings.Join(sqls, ", "),
				scope.CombinedConditionSql(),
			))
			scope.Exec()
		}
	}
}

func AfterUpdate(scope *Scope) {
	if _, ok := scope.Get("gorm:update_column"); !ok {
		scope.CallMethodWithErrorCheck("AfterUpdate")
		scope.CallMethodWithErrorCheck("AfterSave")
	}
}

func init() {
	DefaultCallback.Update().Register("gorm:assign_update_attributes", AssignUpdateAttributes)
	DefaultCallback.Update().Register("gorm:begin_transaction", BeginTransaction)
	DefaultCallback.Update().Register("gorm:before_update", BeforeUpdate)
	DefaultCallback.Update().Register("gorm:save_before_associations", SaveBeforeAssociations)
	DefaultCallback.Update().Register("gorm:update_time_stamp_when_update", UpdateTimeStampWhenUpdate)
	DefaultCallback.Update().Register("gorm:update", Update)
	DefaultCallback.Update().Register("gorm:save_after_associations", SaveAfterAssociations)
	DefaultCallback.Update().Register("gorm:after_update", AfterUpdate)
	DefaultCallback.Update().Register("gorm:commit_or_rollback_transaction", CommitOrRollbackTransaction)
}
<|endoftext|>


<commit_before>// Package version returns the version of the application(s)
package version

const (
	version = "0.7.3"
)

// Version returns the current application version
func Version() string {
	return version
}
<commit_msg>v0.7.4<commit_after>// Package version returns the version of the application(s)
package version

const (
	version = "0.7.4"
)

// Version returns the current application version
func Version() string {
	return version
}
<|endoftext|>


<commit_before>// The version package provides a location to set the release versions for all
// packages to consume, without creating import cycles.
//
// This package should not import any other terraform packages.
package version

import (
	"fmt"

	version "github.com/hashicorp/go-version"
)

// The main version number that is being run at the moment.
var Version = "1.1.0"

// A pre-release marker for the version. If this is "" (empty string)
// then it means that it is a final release. Otherwise, this is a pre-release
// such as "dev" (in development), "beta", "rc1", etc.
var Prerelease = "alpha20210908"

// SemVer is an instance of version.Version. This has the secondary
// benefit of verifying during tests and init time that our version is a
// proper semantic version, which should always be the case.
var SemVer *version.Version

func init() {
	SemVer = version.Must(version.NewVersion(Version))
}

// Header is the header name used to send the current terraform version
// in http requests.
const Header = "Terraform-Version"

// String returns the complete version string, including prerelease
func String() string {
	if Prerelease != "" {
		return fmt.Sprintf("%s-%s", Version, Prerelease)
	}
	return Version
}
<commit_msg>Cleanup after v1.1.0-alpha20210908 release<commit_after>// The version package provides a location to set the release versions for all
// packages to consume, without creating import cycles.
//
// This package should not import any other terraform packages.
package version

import (
	"fmt"

	version "github.com/hashicorp/go-version"
)

// The main version number that is being run at the moment.
var Version = "1.1.0"

// A pre-release marker for the version. If this is "" (empty string)
// then it means that it is a final release. Otherwise, this is a pre-release
// such as "dev" (in development), "beta", "rc1", etc.
var Prerelease = "dev"

// SemVer is an instance of version.Version. This has the secondary
// benefit of verifying during tests and init time that our version is a
// proper semantic version, which should always be the case.
var SemVer *version.Version

func init() {
	SemVer = version.Must(version.NewVersion(Version))
}

// Header is the header name used to send the current terraform version
// in http requests.
const Header = "Terraform-Version"

// String returns the complete version string, including prerelease
func String() string {
	if Prerelease != "" {
		return fmt.Sprintf("%s-%s", Version, Prerelease)
	}
	return Version
}
<|endoftext|>


<commit_before>package version

const Version = "0.2.0+dev"

var GITCOMMIT string
<commit_msg>Bump version to v0.2.0<commit_after>package version

const Version = "0.2.0"

var GITCOMMIT string
<|endoftext|>


<commit_before>// The version package provides a location to set the release versions for all
// packages to consume, without creating import cycles.
//
// This package should not import any other terraform packages.
package version

import (
	"fmt"

	version "github.com/hashicorp/go-version"
)

// The main version number that is being run at the moment.
var Version = "1.1.0"

// A pre-release marker for the version. If this is "" (empty string)
// then it means that it is a final release. Otherwise, this is a pre-release
// such as "dev" (in development), "beta", "rc1", etc.
var Prerelease = "dev"

// SemVer is an instance of version.Version. This has the secondary
// benefit of verifying during tests and init time that our version is a
// proper semantic version, which should always be the case.
var SemVer *version.Version

func init() {
	SemVer = version.Must(version.NewVersion(Version))
}

// Header is the header name used to send the current terraform version
// in http requests.
const Header = "Terraform-Version"

// String returns the complete version string, including prerelease
func String() string {
	if Prerelease != "" {
		return fmt.Sprintf("%s-%s", Version, Prerelease)
	}
	return Version
}
<commit_msg>Release v1.1.0-alpha20210811<commit_after>// The version package provides a location to set the release versions for all
// packages to consume, without creating import cycles.
//
// This package should not import any other terraform packages.
package version

import (
	"fmt"

	version "github.com/hashicorp/go-version"
)

// The main version number that is being run at the moment.
var Version = "1.1.0"

// A pre-release marker for the version. If this is "" (empty string)
// then it means that it is a final release. Otherwise, this is a pre-release
// such as "dev" (in development), "beta", "rc1", etc.
var Prerelease = "alpha20210811"

// SemVer is an instance of version.Version. This has the secondary
// benefit of verifying during tests and init time that our version is a
// proper semantic version, which should always be the case.
var SemVer *version.Version

func init() {
	SemVer = version.Must(version.NewVersion(Version))
}

// Header is the header name used to send the current terraform version
// in http requests.
const Header = "Terraform-Version"

// String returns the complete version string, including prerelease
func String() string {
	if Prerelease != "" {
		return fmt.Sprintf("%s-%s", Version, Prerelease)
	}
	return Version
}
<|endoftext|>


<commit_before>package version

// VERSION ...
const VERSION = "1.1.53"
<commit_msg>v1.1.54 [skip ci]<commit_after>package version

// VERSION ...
const VERSION = "1.1.54"
<|endoftext|>


<commit_before>// Copyright 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

// The version package implements version parsing.
// It also acts as guardian of the current client Juju version number.
package version

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"
	"runtime"
	"strconv"
	"strings"

	"labix.org/v2/mgo/bson"
)

// The presence and format of this constant is very important.
// The debian/rules build recipe uses this value for the version
// number of the release package.
const version = "1.11.4"

// CurrentNumber returns the version number.
func CurrentNumber() Number {
	return MustParse(version)
}

// CurrentSeries returns the current Ubuntu release name.
func CurrentSeries() string {
	return readSeries("/etc/lsb-release")
}

// CurrentArch returns the architecture of the machine.
func CurrentArch() string {
	return ubuntuArch(runtime.GOARCH)
}

// Current gives the current version of the system.  If the file
// "FORCE-VERSION" is present in the same directory as the running
// binary, it will override this.
var Current = Binary{
	Number: CurrentNumber(),
	Series: CurrentSeries(),
	Arch:   CurrentArch(),
}

func init() {
	toolsDir := filepath.Dir(os.Args[0])
	v, err := ioutil.ReadFile(filepath.Join(toolsDir, "FORCE-VERSION"))
	if err != nil {
		if os.IsNotExist(err) {
			return
		}
		panic(fmt.Errorf("version: cannot read forced version: %v", err))
	}
	Current.Number = MustParse(strings.TrimSpace(string(v)))
}

// Number represents a juju version.  When bugs are fixed the patch
// number is incremented; when new features are added the minor number
// is incremented and patch is reset; and when compatibility is broken
// the major version is incremented and minor and patch are reset.  The
// build number is automatically assigned and has no well defined
// sequence.  If the build number is greater than zero or the minor
// version is odd, it indicates that the release is still in
// development.
type Number struct {
	Major int
	Minor int
	Patch int
	Build int
}

// Zero is occasionally convenient and readable.
// Please don't change its value.
var Zero = Number{}

// Binary specifies a binary version of juju.
type Binary struct {
	Number
	Series string
	Arch   string
}

func (v Binary) String() string {
	return fmt.Sprintf("%v-%s-%s", v.Number, v.Series, v.Arch)
}

// GetBSON turns v into a bson.Getter so it can be saved directly
// on a MongoDB database with mgo.
func (v Binary) GetBSON() (interface{}, error) {
	return v.String(), nil
}

// SetBSON turns v into a bson.Setter so it can be loaded directly
// from a MongoDB database with mgo.
func (vp *Binary) SetBSON(raw bson.Raw) error {
	var s string
	err := raw.Unmarshal(&s)
	if err != nil {
		return err
	}
	v, err := ParseBinary(s)
	if err != nil {
		return err
	}
	*vp = v
	return nil
}

var (
	binaryPat = regexp.MustCompile(`^(\d{1,9})\.(\d{1,9})\.(\d{1,9})(\.\d{1,9})?-([^-]+)-([^-]+)$`)
	numberPat = regexp.MustCompile(`^(\d{1,9})\.(\d{1,9})\.(\d{1,9})(\.\d{1,9})?$`)
)

// MustParse parses a version and panics if it does
// not parse correctly.
func MustParse(s string) Number {
	v, err := Parse(s)
	if err != nil {
		panic(err)
	}
	return v
}

// MustParseBinary parses a binary version and panics if it does
// not parse correctly.
func MustParseBinary(s string) Binary {
	v, err := ParseBinary(s)
	if err != nil {
		panic(err)
	}
	return v
}

// ParseBinary parses a binary version of the form "1.2.3-series-arch".
func ParseBinary(s string) (Binary, error) {
	m := binaryPat.FindStringSubmatch(s)
	if m == nil {
		return Binary{}, fmt.Errorf("invalid binary version %q", s)
	}
	var v Binary
	v.Major = atoi(m[1])
	v.Minor = atoi(m[2])
	v.Patch = atoi(m[3])
	if m[4] != "" {
		v.Build = atoi(m[4][1:])
	}
	v.Series = m[5]
	v.Arch = m[6]
	return v, nil
}

// Parse parses the version, which is of the form 1.2.3
// giving the major, minor and release versions
// respectively.
func Parse(s string) (Number, error) {
	m := numberPat.FindStringSubmatch(s)
	if m == nil {
		return Number{}, fmt.Errorf("invalid version %q", s)
	}
	var v Number
	v.Major = atoi(m[1])
	v.Minor = atoi(m[2])
	v.Patch = atoi(m[3])
	if m[4] != "" {
		v.Build = atoi(m[4][1:])
	}
	return v, nil
}

// atoi is the same as strconv.Atoi but assumes that
// the string has been verified to be a valid integer.
func atoi(s string) int {
	n, err := strconv.Atoi(s)
	if err != nil {
		panic(err)
	}
	return n
}

func (v Number) String() string {
	s := fmt.Sprintf("%d.%d.%d", v.Major, v.Minor, v.Patch)
	if v.Build > 0 {
		s += fmt.Sprintf(".%d", v.Build)
	}
	return s
}

// Less returns whether v is semantically earlier in the
// version sequence than w.
func (v Number) Less(w Number) bool {
	switch {
	case v.Major != w.Major:
		return v.Major < w.Major
	case v.Minor != w.Minor:
		return v.Minor < w.Minor
	case v.Patch != w.Patch:
		return v.Patch < w.Patch
	case v.Build != w.Build:
		return v.Build < w.Build
	}
	return false
}

// GetBSON turns v into a bson.Getter so it can be saved directly
// on a MongoDB database with mgo.
func (v Number) GetBSON() (interface{}, error) {
	return v.String(), nil
}

// SetBSON turns v into a bson.Setter so it can be loaded directly
// from a MongoDB database with mgo.
func (vp *Number) SetBSON(raw bson.Raw) error {
	var s string
	err := raw.Unmarshal(&s)
	if err != nil {
		return err
	}
	v, err := Parse(s)
	if err != nil {
		return err
	}
	*vp = v
	return nil
}

func isOdd(x int) bool {
	return x%2 != 0
}

// IsDev returns whether the version represents a development
// version. A version with an odd-numbered minor component or
// a nonzero build component is considered to be a development
// version.
func (v Number) IsDev() bool {
	return isOdd(v.Minor) || v.Build > 0
}

func readSeries(releaseFile string) string {
	data, err := ioutil.ReadFile(releaseFile)
	if err != nil {
		return "unknown"
	}
	for _, line := range strings.Split(string(data), "\n") {
		const p = "DISTRIB_CODENAME="
		if strings.HasPrefix(line, p) {
			return strings.Trim(line[len(p):], "\t '\"")
		}
	}
	return "unknown"
}

func ubuntuArch(arch string) string {
	if arch == "386" {
		arch = "i386"
	}
	return arch
}
<commit_msg>set development version to 1.11.5<commit_after>// Copyright 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

// The version package implements version parsing.
// It also acts as guardian of the current client Juju version number.
package version

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"
	"runtime"
	"strconv"
	"strings"

	"labix.org/v2/mgo/bson"
)

// The presence and format of this constant is very important.
// The debian/rules build recipe uses this value for the version
// number of the release package.
const version = "1.11.5"

// CurrentNumber returns the version number.
func CurrentNumber() Number {
	return MustParse(version)
}

// CurrentSeries returns the current Ubuntu release name.
func CurrentSeries() string {
	return readSeries("/etc/lsb-release")
}

// CurrentArch returns the architecture of the machine.
func CurrentArch() string {
	return ubuntuArch(runtime.GOARCH)
}

// Current gives the current version of the system.  If the file
// "FORCE-VERSION" is present in the same directory as the running
// binary, it will override this.
var Current = Binary{
	Number: CurrentNumber(),
	Series: CurrentSeries(),
	Arch:   CurrentArch(),
}

func init() {
	toolsDir := filepath.Dir(os.Args[0])
	v, err := ioutil.ReadFile(filepath.Join(toolsDir, "FORCE-VERSION"))
	if err != nil {
		if os.IsNotExist(err) {
			return
		}
		panic(fmt.Errorf("version: cannot read forced version: %v", err))
	}
	Current.Number = MustParse(strings.TrimSpace(string(v)))
}

// Number represents a juju version.  When bugs are fixed the patch
// number is incremented; when new features are added the minor number
// is incremented and patch is reset; and when compatibility is broken
// the major version is incremented and minor and patch are reset.  The
// build number is automatically assigned and has no well defined
// sequence.  If the build number is greater than zero or the minor
// version is odd, it indicates that the release is still in
// development.
type Number struct {
	Major int
	Minor int
	Patch int
	Build int
}

// Zero is occasionally convenient and readable.
// Please don't change its value.
var Zero = Number{}

// Binary specifies a binary version of juju.
type Binary struct {
	Number
	Series string
	Arch   string
}

func (v Binary) String() string {
	return fmt.Sprintf("%v-%s-%s", v.Number, v.Series, v.Arch)
}

// GetBSON turns v into a bson.Getter so it can be saved directly
// on a MongoDB database with mgo.
func (v Binary) GetBSON() (interface{}, error) {
	return v.String(), nil
}

// SetBSON turns v into a bson.Setter so it can be loaded directly
// from a MongoDB database with mgo.
func (vp *Binary) SetBSON(raw bson.Raw) error {
	var s string
	err := raw.Unmarshal(&s)
	if err != nil {
		return err
	}
	v, err := ParseBinary(s)
	if err != nil {
		return err
	}
	*vp = v
	return nil
}

var (
	binaryPat = regexp.MustCompile(`^(\d{1,9})\.(\d{1,9})\.(\d{1,9})(\.\d{1,9})?-([^-]+)-([^-]+)$`)
	numberPat = regexp.MustCompile(`^(\d{1,9})\.(\d{1,9})\.(\d{1,9})(\.\d{1,9})?$`)
)

// MustParse parses a version and panics if it does
// not parse correctly.
func MustParse(s string) Number {
	v, err := Parse(s)
	if err != nil {
		panic(err)
	}
	return v
}

// MustParseBinary parses a binary version and panics if it does
// not parse correctly.
func MustParseBinary(s string) Binary {
	v, err := ParseBinary(s)
	if err != nil {
		panic(err)
	}
	return v
}

// ParseBinary parses a binary version of the form "1.2.3-series-arch".
func ParseBinary(s string) (Binary, error) {
	m := binaryPat.FindStringSubmatch(s)
	if m == nil {
		return Binary{}, fmt.Errorf("invalid binary version %q", s)
	}
	var v Binary
	v.Major = atoi(m[1])
	v.Minor = atoi(m[2])
	v.Patch = atoi(m[3])
	if m[4] != "" {
		v.Build = atoi(m[4][1:])
	}
	v.Series = m[5]
	v.Arch = m[6]
	return v, nil
}

// Parse parses the version, which is of the form 1.2.3
// giving the major, minor and release versions
// respectively.
func Parse(s string) (Number, error) {
	m := numberPat.FindStringSubmatch(s)
	if m == nil {
		return Number{}, fmt.Errorf("invalid version %q", s)
	}
	var v Number
	v.Major = atoi(m[1])
	v.Minor = atoi(m[2])
	v.Patch = atoi(m[3])
	if m[4] != "" {
		v.Build = atoi(m[4][1:])
	}
	return v, nil
}

// atoi is the same as strconv.Atoi but assumes that
// the string has been verified to be a valid integer.
func atoi(s string) int {
	n, err := strconv.Atoi(s)
	if err != nil {
		panic(err)
	}
	return n
}

func (v Number) String() string {
	s := fmt.Sprintf("%d.%d.%d", v.Major, v.Minor, v.Patch)
	if v.Build > 0 {
		s += fmt.Sprintf(".%d", v.Build)
	}
	return s
}

// Less returns whether v is semantically earlier in the
// version sequence than w.
func (v Number) Less(w Number) bool {
	switch {
	case v.Major != w.Major:
		return v.Major < w.Major
	case v.Minor != w.Minor:
		return v.Minor < w.Minor
	case v.Patch != w.Patch:
		return v.Patch < w.Patch
	case v.Build != w.Build:
		return v.Build < w.Build
	}
	return false
}

// GetBSON turns v into a bson.Getter so it can be saved directly
// on a MongoDB database with mgo.
func (v Number) GetBSON() (interface{}, error) {
	return v.String(), nil
}

// SetBSON turns v into a bson.Setter so it can be loaded directly
// from a MongoDB database with mgo.
func (vp *Number) SetBSON(raw bson.Raw) error {
	var s string
	err := raw.Unmarshal(&s)
	if err != nil {
		return err
	}
	v, err := Parse(s)
	if err != nil {
		return err
	}
	*vp = v
	return nil
}

func isOdd(x int) bool {
	return x%2 != 0
}

// IsDev returns whether the version represents a development
// version. A version with an odd-numbered minor component or
// a nonzero build component is considered to be a development
// version.
func (v Number) IsDev() bool {
	return isOdd(v.Minor) || v.Build > 0
}

func readSeries(releaseFile string) string {
	data, err := ioutil.ReadFile(releaseFile)
	if err != nil {
		return "unknown"
	}
	for _, line := range strings.Split(string(data), "\n") {
		const p = "DISTRIB_CODENAME="
		if strings.HasPrefix(line, p) {
			return strings.Trim(line[len(p):], "\t '\"")
		}
	}
	return "unknown"
}

func ubuntuArch(arch string) string {
	if arch == "386" {
		arch = "i386"
	}
	return arch
}
<|endoftext|>