<commit_before>/*
Copyright (c) 2015 VMware, Inc. All Rights Reserved.

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 session

import (
	"context"
	"io/ioutil"
	"net/url"
	"os"
	"strings"

	"github.com/vmware/govmomi/property"
	"github.com/vmware/govmomi/vim25"
	"github.com/vmware/govmomi/vim25/methods"
	"github.com/vmware/govmomi/vim25/mo"
	"github.com/vmware/govmomi/vim25/types"
)

// Locale defaults to "en_US" and can be overridden via this var or the GOVMOMI_LOCALE env var.
// A value of "_" uses the server locale setting.
var Locale = os.Getenv("GOVMOMI_LOCALE")

func init() {
	if Locale == "_" {
		Locale = ""
	} else if Locale == "" {
		Locale = "en_US"
	}
}

// Secret returns the contents if a file path value is given, otherwise returns value itself.
func Secret(value string) (string, error) {
	if len(value) == 0 {
		return value, nil
	}
	contents, err := ioutil.ReadFile(value)
	if err != nil {
		if os.IsPermission(err) {
			return "", err
		}
		return value, nil
	}
	return strings.TrimSpace(string(contents)), nil
}

type Manager struct {
	client      *vim25.Client
	userSession *types.UserSession
}

func NewManager(client *vim25.Client) *Manager {
	m := Manager{
		client: client,
	}

	return &m
}

func (sm Manager) Reference() types.ManagedObjectReference {
	return *sm.client.ServiceContent.SessionManager
}

func (sm *Manager) SetLocale(ctx context.Context, locale string) error {
	req := types.SetLocale{
		This:   sm.Reference(),
		Locale: locale,
	}

	_, err := methods.SetLocale(ctx, sm.client, &req)
	return err
}

func (sm *Manager) Login(ctx context.Context, u *url.Userinfo) error {
	req := types.Login{
		This:   sm.Reference(),
		Locale: Locale,
	}

	if u != nil {
		req.UserName = u.Username()
		if pw, ok := u.Password(); ok {
			req.Password = pw
		}
	}

	login, err := methods.Login(ctx, sm.client, &req)
	if err != nil {
		return err
	}

	sm.userSession = &login.Returnval
	return nil
}

// LoginExtensionByCertificate uses the vCenter SDK tunnel to login using a client certificate.
// The client certificate can be set using the soap.Client.SetCertificate method.
// See: https://kb.vmware.com/s/article/2004305
func (sm *Manager) LoginExtensionByCertificate(ctx context.Context, key string) error {
	c := sm.client
	u := c.URL()
	if u.Hostname() != "sdkTunnel" {
		sc := c.Tunnel()
		c = &vim25.Client{
			Client:         sc,
			RoundTripper:   sc,
			ServiceContent: c.ServiceContent,
		}
		// When http.Transport.Proxy is used, our thumbprint checker is bypassed, resulting in:
		// "Post https://sdkTunnel:8089/sdk: x509: certificate is valid for $vcenter_hostname, not sdkTunnel"
		// The only easy way around this is to disable verification for the call to LoginExtensionByCertificate().
		// TODO: find a way to avoid disabling InsecureSkipVerify.
		c.DefaultTransport().TLSClientConfig.InsecureSkipVerify = true
	}

	req := types.LoginExtensionByCertificate{
		This:         sm.Reference(),
		ExtensionKey: key,
		Locale:       Locale,
	}

	login, err := methods.LoginExtensionByCertificate(ctx, c, &req)
	if err != nil {
		return err
	}

	// Copy the session cookie
	sm.client.Jar.SetCookies(u, c.Jar.Cookies(c.URL()))

	sm.userSession = &login.Returnval
	return nil
}

func (sm *Manager) LoginByToken(ctx context.Context) error {
	req := types.LoginByToken{
		This:   sm.Reference(),
		Locale: Locale,
	}

	login, err := methods.LoginByToken(ctx, sm.client, &req)
	if err != nil {
		return err
	}

	sm.userSession = &login.Returnval
	return nil
}

func (sm *Manager) Logout(ctx context.Context) error {
	req := types.Logout{
		This: sm.Reference(),
	}

	_, err := methods.Logout(ctx, sm.client, &req)
	if err != nil {
		return err
	}

	sm.userSession = nil
	return nil
}

// UserSession retrieves and returns the SessionManager's CurrentSession field.
// Nil is returned if the session is not authenticated.
func (sm *Manager) UserSession(ctx context.Context) (*types.UserSession, error) {
	var mgr mo.SessionManager

	pc := property.DefaultCollector(sm.client)
	err := pc.RetrieveOne(ctx, sm.Reference(), []string{"currentSession"}, &mgr)
	if err != nil {
		// It's OK if we can't retrieve properties because we're not authenticated
		if f, ok := err.(types.HasFault); ok {
			switch f.Fault().(type) {
			case *types.NotAuthenticated:
				return nil, nil
			}
		}

		return nil, err
	}

	return mgr.CurrentSession, nil
}

func (sm *Manager) TerminateSession(ctx context.Context, sessionId []string) error {
	req := types.TerminateSession{
		This:      sm.Reference(),
		SessionId: sessionId,
	}

	_, err := methods.TerminateSession(ctx, sm.client, &req)
	return err
}

// SessionIsActive checks whether the session that was created at login is
// still valid. This function only works against vCenter.
func (sm *Manager) SessionIsActive(ctx context.Context) (bool, error) {
	if sm.userSession == nil {
		return false, nil
	}

	req := types.SessionIsActive{
		This:      sm.Reference(),
		SessionID: sm.userSession.Key,
		UserName:  sm.userSession.UserName,
	}

	active, err := methods.SessionIsActive(ctx, sm.client, &req)
	if err != nil {
		return false, err
	}

	return active.Returnval, err
}

func (sm *Manager) AcquireGenericServiceTicket(ctx context.Context, spec types.BaseSessionManagerServiceRequestSpec) (*types.SessionManagerGenericServiceTicket, error) {
	req := types.AcquireGenericServiceTicket{
		This: sm.Reference(),
		Spec: spec,
	}

	res, err := methods.AcquireGenericServiceTicket(ctx, sm.client, &req)
	if err != nil {
		return nil, err
	}

	return &res.Returnval, nil
}

func (sm *Manager) AcquireLocalTicket(ctx context.Context, userName string) (*types.SessionManagerLocalTicket, error) {
	req := types.AcquireLocalTicket{
		This:     sm.Reference(),
		UserName: userName,
	}

	res, err := methods.AcquireLocalTicket(ctx, sm.client, &req)
	if err != nil {
		return nil, err
	}

	return &res.Returnval, nil
}

func (sm *Manager) AcquireCloneTicket(ctx context.Context) (string, error) {
	req := types.AcquireCloneTicket{
		This: sm.Reference(),
	}

	res, err := methods.AcquireCloneTicket(ctx, sm.client, &req)
	if err != nil {
		return "", err
	}

	return res.Returnval, nil
}

func (sm *Manager) CloneSession(ctx context.Context, ticket string) error {
	req := types.CloneSession{
		This:        sm.Reference(),
		CloneTicket: ticket,
	}

	res, err := methods.CloneSession(ctx, sm.client, &req)
	if err != nil {
		return err
	}

	sm.userSession = &res.Returnval
	return nil
}
<commit_msg>Added UpdateServiceMessage to Session Manager<commit_after>/*
Copyright (c) 2015 VMware, Inc. All Rights Reserved.

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 session

import (
	"context"
	"io/ioutil"
	"net/url"
	"os"
	"strings"

	"github.com/vmware/govmomi/property"
	"github.com/vmware/govmomi/vim25"
	"github.com/vmware/govmomi/vim25/methods"
	"github.com/vmware/govmomi/vim25/mo"
	"github.com/vmware/govmomi/vim25/types"
)

// Locale defaults to "en_US" and can be overridden via this var or the GOVMOMI_LOCALE env var.
// A value of "_" uses the server locale setting.
var Locale = os.Getenv("GOVMOMI_LOCALE")

func init() {
	if Locale == "_" {
		Locale = ""
	} else if Locale == "" {
		Locale = "en_US"
	}
}

// Secret returns the contents if a file path value is given, otherwise returns value itself.
func Secret(value string) (string, error) {
	if len(value) == 0 {
		return value, nil
	}
	contents, err := ioutil.ReadFile(value)
	if err != nil {
		if os.IsPermission(err) {
			return "", err
		}
		return value, nil
	}
	return strings.TrimSpace(string(contents)), nil
}

type Manager struct {
	client      *vim25.Client
	userSession *types.UserSession
}

func NewManager(client *vim25.Client) *Manager {
	m := Manager{
		client: client,
	}

	return &m
}

func (sm Manager) Reference() types.ManagedObjectReference {
	return *sm.client.ServiceContent.SessionManager
}

func (sm *Manager) SetLocale(ctx context.Context, locale string) error {
	req := types.SetLocale{
		This:   sm.Reference(),
		Locale: locale,
	}

	_, err := methods.SetLocale(ctx, sm.client, &req)
	return err
}

func (sm *Manager) Login(ctx context.Context, u *url.Userinfo) error {
	req := types.Login{
		This:   sm.Reference(),
		Locale: Locale,
	}

	if u != nil {
		req.UserName = u.Username()
		if pw, ok := u.Password(); ok {
			req.Password = pw
		}
	}

	login, err := methods.Login(ctx, sm.client, &req)
	if err != nil {
		return err
	}

	sm.userSession = &login.Returnval
	return nil
}

// LoginExtensionByCertificate uses the vCenter SDK tunnel to login using a client certificate.
// The client certificate can be set using the soap.Client.SetCertificate method.
// See: https://kb.vmware.com/s/article/2004305
func (sm *Manager) LoginExtensionByCertificate(ctx context.Context, key string) error {
	c := sm.client
	u := c.URL()
	if u.Hostname() != "sdkTunnel" {
		sc := c.Tunnel()
		c = &vim25.Client{
			Client:         sc,
			RoundTripper:   sc,
			ServiceContent: c.ServiceContent,
		}
		// When http.Transport.Proxy is used, our thumbprint checker is bypassed, resulting in:
		// "Post https://sdkTunnel:8089/sdk: x509: certificate is valid for $vcenter_hostname, not sdkTunnel"
		// The only easy way around this is to disable verification for the call to LoginExtensionByCertificate().
		// TODO: find a way to avoid disabling InsecureSkipVerify.
		c.DefaultTransport().TLSClientConfig.InsecureSkipVerify = true
	}

	req := types.LoginExtensionByCertificate{
		This:         sm.Reference(),
		ExtensionKey: key,
		Locale:       Locale,
	}

	login, err := methods.LoginExtensionByCertificate(ctx, c, &req)
	if err != nil {
		return err
	}

	// Copy the session cookie
	sm.client.Jar.SetCookies(u, c.Jar.Cookies(c.URL()))

	sm.userSession = &login.Returnval
	return nil
}

func (sm *Manager) LoginByToken(ctx context.Context) error {
	req := types.LoginByToken{
		This:   sm.Reference(),
		Locale: Locale,
	}

	login, err := methods.LoginByToken(ctx, sm.client, &req)
	if err != nil {
		return err
	}

	sm.userSession = &login.Returnval
	return nil
}

func (sm *Manager) Logout(ctx context.Context) error {
	req := types.Logout{
		This: sm.Reference(),
	}

	_, err := methods.Logout(ctx, sm.client, &req)
	if err != nil {
		return err
	}

	sm.userSession = nil
	return nil
}

// UserSession retrieves and returns the SessionManager's CurrentSession field.
// Nil is returned if the session is not authenticated.
func (sm *Manager) UserSession(ctx context.Context) (*types.UserSession, error) {
	var mgr mo.SessionManager

	pc := property.DefaultCollector(sm.client)
	err := pc.RetrieveOne(ctx, sm.Reference(), []string{"currentSession"}, &mgr)
	if err != nil {
		// It's OK if we can't retrieve properties because we're not authenticated
		if f, ok := err.(types.HasFault); ok {
			switch f.Fault().(type) {
			case *types.NotAuthenticated:
				return nil, nil
			}
		}

		return nil, err
	}

	return mgr.CurrentSession, nil
}

func (sm *Manager) TerminateSession(ctx context.Context, sessionId []string) error {
	req := types.TerminateSession{
		This:      sm.Reference(),
		SessionId: sessionId,
	}

	_, err := methods.TerminateSession(ctx, sm.client, &req)
	return err
}

// SessionIsActive checks whether the session that was created at login is
// still valid. This function only works against vCenter.
func (sm *Manager) SessionIsActive(ctx context.Context) (bool, error) {
	if sm.userSession == nil {
		return false, nil
	}

	req := types.SessionIsActive{
		This:      sm.Reference(),
		SessionID: sm.userSession.Key,
		UserName:  sm.userSession.UserName,
	}

	active, err := methods.SessionIsActive(ctx, sm.client, &req)
	if err != nil {
		return false, err
	}

	return active.Returnval, err
}

func (sm *Manager) AcquireGenericServiceTicket(ctx context.Context, spec types.BaseSessionManagerServiceRequestSpec) (*types.SessionManagerGenericServiceTicket, error) {
	req := types.AcquireGenericServiceTicket{
		This: sm.Reference(),
		Spec: spec,
	}

	res, err := methods.AcquireGenericServiceTicket(ctx, sm.client, &req)
	if err != nil {
		return nil, err
	}

	return &res.Returnval, nil
}

func (sm *Manager) AcquireLocalTicket(ctx context.Context, userName string) (*types.SessionManagerLocalTicket, error) {
	req := types.AcquireLocalTicket{
		This:     sm.Reference(),
		UserName: userName,
	}

	res, err := methods.AcquireLocalTicket(ctx, sm.client, &req)
	if err != nil {
		return nil, err
	}

	return &res.Returnval, nil
}

func (sm *Manager) AcquireCloneTicket(ctx context.Context) (string, error) {
	req := types.AcquireCloneTicket{
		This: sm.Reference(),
	}

	res, err := methods.AcquireCloneTicket(ctx, sm.client, &req)
	if err != nil {
		return "", err
	}

	return res.Returnval, nil
}

func (sm *Manager) CloneSession(ctx context.Context, ticket string) error {
	req := types.CloneSession{
		This:        sm.Reference(),
		CloneTicket: ticket,
	}

	res, err := methods.CloneSession(ctx, sm.client, &req)
	if err != nil {
		return err
	}

	sm.userSession = &res.Returnval
	return nil
}

func (sm *Manager) UpdateServiceMessage(ctx context.Context, message string) error {
	req := types.UpdateServiceMessage{
		This:    sm.Reference(),
		Message: message,
	}

	_, err := methods.UpdateServiceMessage(ctx, sm.client, &req)

	return err
}
<|endoftext|>


<commit_before>package main

import (
    "fmt"
    "os"
    "github.com/codegangsta/cli"
)

func main() {
    app := cli.NewApp()
    app.Name = "substenv"
    app.Usage = "substitute environment variables into template"
    app.Action = func(c *cli.Context) {
        fmt.Printf("Hello, World!\n")
    }

    app.Run(os.Args)
}
<commit_msg>Change cli to kingpin<commit_after>package main

import (
    "fmt"
    "gopkg.in/alecthomas/kingpin.v1"
)

var (
    app = kingpin.New("substenv", "Substitute environment variables into templates")
    input = kingpin.Arg("input", "Input file or stdin if not given").File()
)

func main() {
    kingpin.Version("0.0.1")
    kingpin.Parse()
    fmt.Printf("Hello, World!\n")
}
<|endoftext|>


<commit_before>package draw

import (
	"encoding/hex"
	"fmt"
	"image/color"
	"log"
	"math"
	"math/rand"
	"strconv"
)

// RandomColorFromArray returns a random color from the given array.
func RandomColorFromArray(colors []color.RGBA) color.RGBA {
	r := rand.Intn(len(colors))
	return colors[r]
}

// RandomIndexFromArray returns an index from the given array.
func RandomIndexFromArray(colors []color.RGBA) int {
	r := rand.Intn(len(colors))
	return r
}

// ColorByPercentage returns a color based on the given percentage and the
// number of colors present in the 'colors' array in a gradient way.
func ColorByPercentage(colors []color.RGBA, percentage int) color.RGBA {
	r := rand.Intn(100)
	colorChange := 100 / len(colors)
	frontier := 0
	frontier = int(math.Ceil(float64(r) / float64(colorChange)))

	if r < percentage {
		if frontier == 0 {
			frontier++
		}
		return RandomColorFromArray(colors[:frontier])
	}
	if frontier == len(colors) {
		frontier--
	}
	return RandomColorFromArray(colors[frontier:])
}

// FillFromRGBA return a "fill" SVG style from a color.RGBA
func FillFromRGBA(c color.RGBA) string {
	return fmt.Sprintf("fill:rgb(%d,%d,%d)", c.R, c.G, c.B)
}

// PickColor returns a color given a key string, an array of colors and an index.
// key: should be a md5 hash string.
// index: is an index from the key string. Should be in interval [0, 16]
// Algorithm: PickColor converts the key[index] value to a decimal value.
// We pick the ith colors that respects the equality value%numberOfColors == i.
func PickColor(key string, colors []color.RGBA, index int) color.RGBA {
	n := len(colors)
	s := hex.EncodeToString([]byte{key[index]})
	if r, err := strconv.ParseInt(s, 16, 0); err == nil {
		for i := 0; i < n; i++ {
			if int(r)%n == i {
				return colors[i]
			}
		}
	} else {
		log.Println("Error calling ParseInt(%v, 16, 0)", s, err)
	}
	return colors[0]
}

func PickIndex(key string, n int, index int) int {
	s := hex.EncodeToString([]byte{key[index]})
	if r, err := strconv.ParseInt(s, 16, 0); err == nil {
		for i := 0; i < n; i++ {
			if int(r)%n == i {
				return i
			}
		}
	}
	return 0
}

// RGBToHex converts an RGB triple to an Hex string.
func RGBToHex(r, g, b uint8) string {
	return fmt.Sprintf("#%02X%02X%02X", r, g, b)
}
<commit_msg>add functions to tools pkg. + RandomIndexFromArrayWithFreq + RandomColorFromArrayWithFreq<commit_after>package draw

import (
	"encoding/hex"
	"fmt"
	"image/color"
	"log"
	"math"
	"math/rand"
	"strconv"
)

func RandomColorFromArrayWithFreq(colors []color.RGBA, prob float64) color.RGBA {
	if rf := rand.Float64(); rf < prob {
		return colors[0]
	}
	return RandomColorFromArray(colors[1:])
}

// RandomColorFromArray returns a random color from the given array.
func RandomColorFromArray(colors []color.RGBA) color.RGBA {
	r := rand.Intn(len(colors))
	return colors[r]
}

func RandomIndexFromArrayWithFreq(colors []color.RGBA, prob float64) int {
	if rf := rand.Float64(); rf < prob {
		return 0
	}
	return RandomIndexFromArray(colors[1:]) + 1
}

// RandomIndexFromArray returns an index from the given array.
func RandomIndexFromArray(colors []color.RGBA) int {
	r := rand.Intn(len(colors))
	return r
}

// ColorByPercentage returns a color based on the given percentage and the
// number of colors present in the 'colors' array in a gradient way.
func ColorByPercentage(colors []color.RGBA, percentage int) color.RGBA {
	r := rand.Intn(100)
	colorChange := 100 / len(colors)
	frontier := 0
	frontier = int(math.Ceil(float64(r) / float64(colorChange)))

	if r < percentage {
		if frontier == 0 {
			frontier++
		}
		return RandomColorFromArray(colors[:frontier])
	}
	if frontier == len(colors) {
		frontier--
	}
	return RandomColorFromArray(colors[frontier:])
}

// FillFromRGBA return a "fill" SVG style from a color.RGBA
func FillFromRGBA(c color.RGBA) string {
	return fmt.Sprintf("fill:rgb(%d,%d,%d)", c.R, c.G, c.B)
}

// PickColor returns a color given a key string, an array of colors and an index.
// key: should be a md5 hash string.
// index: is an index from the key string. Should be in interval [0, 16]
// Algorithm: PickColor converts the key[index] value to a decimal value.
// We pick the ith colors that respects the equality value%numberOfColors == i.
func PickColor(key string, colors []color.RGBA, index int) color.RGBA {
	n := len(colors)
	s := hex.EncodeToString([]byte{key[index]})
	if r, err := strconv.ParseInt(s, 16, 0); err == nil {
		for i := 0; i < n; i++ {
			if int(r)%n == i {
				return colors[i]
			}
		}
	} else {
		log.Println("Error calling ParseInt(%v, 16, 0)", s, err)
	}
	return colors[0]
}

func PickIndex(key string, n int, index int) int {
	s := hex.EncodeToString([]byte{key[index]})
	if r, err := strconv.ParseInt(s, 16, 0); err == nil {
		for i := 0; i < n; i++ {
			if int(r)%n == i {
				return i
			}
		}
	}
	return 0
}

// RGBToHex converts an RGB triple to an Hex string.
func RGBToHex(r, g, b uint8) string {
	return fmt.Sprintf("#%02X%02X%02X", r, g, b)
}
<|endoftext|>


<commit_before>package driver

import (
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"

	"github.com/blang/semver"
	"github.com/concourse/semver-resource/version"
)

var gitRepoDir string
var privateKeyPath string

var ErrEncryptedKey = errors.New("private keys with passphrases are not supported")

func init() {
	gitRepoDir = filepath.Join(os.TempDir(), "semver-git-repo")
	privateKeyPath = filepath.Join(os.TempDir(), "private-key")
}

type GitDriver struct {
	InitialVersion semver.Version

	URI        string
	Branch     string
	PrivateKey string
	File       string
}

func (driver *GitDriver) Bump(bump version.Bump) (semver.Version, error) {
	err := driver.setUpKey()
	if err != nil {
		return semver.Version{}, err
	}

	var newVersion semver.Version

	for {
		err = driver.setUpRepo()
		if err != nil {
			return semver.Version{}, err
		}

		currentVersion, exists, err := driver.readVersion()
		if err != nil {
			return semver.Version{}, err
		}

		if !exists {
			currentVersion = driver.InitialVersion
		}

		newVersion = bump.Apply(currentVersion)

		wrote, err := driver.writeVersion(newVersion)
		if wrote {
			break
		}
	}

	return newVersion, nil
}

func (driver *GitDriver) Set(newVersion semver.Version) error {
	err := driver.setUpKey()
	if err != nil {
		return err
	}

	for {
		err = driver.setUpRepo()
		if err != nil {
			return err
		}

		wrote, err := driver.writeVersion(newVersion)
		if err != nil {
			return err
		}

		if wrote {
			break
		}
	}

	return nil
}

func (driver *GitDriver) Check(cursor *semver.Version) ([]semver.Version, error) {
	err := driver.setUpKey()
	if err != nil {
		return nil, err
	}

	err = driver.setUpRepo()
	if err != nil {
		return nil, err
	}

	currentVersion, exists, err := driver.readVersion()
	if err != nil {
		return nil, err
	}

	if !exists {
		return []semver.Version{driver.InitialVersion}, nil
	}

	if cursor == nil || currentVersion.GT(*cursor) {
		return []semver.Version{currentVersion}, nil
	}

	return []semver.Version{}, nil
}

func (driver *GitDriver) setUpRepo() error {
	_, err := os.Stat(gitRepoDir)
	if err != nil {
		gitClone := exec.Command("git", "clone", driver.URI, "--branch", driver.Branch, gitRepoDir)
		gitClone.Stdout = os.Stderr
		gitClone.Stderr = os.Stderr
		if err := gitClone.Run(); err != nil {
			return err
		}
	} else {
		gitFetch := exec.Command("git", "fetch", "origin", driver.Branch)
		gitFetch.Dir = gitRepoDir
		gitFetch.Stdout = os.Stderr
		gitFetch.Stderr = os.Stderr
		if err := gitFetch.Run(); err != nil {
			return err
		}
	}

	gitCheckout := exec.Command("git", "reset", "--hard", "origin/"+driver.Branch)
	gitCheckout.Dir = gitRepoDir
	gitCheckout.Stdout = os.Stderr
	gitCheckout.Stderr = os.Stderr
	if err := gitCheckout.Run(); err != nil {
		return err
	}

	return nil
}

func (driver *GitDriver) setUpKey() error {
	if strings.Contains(driver.PrivateKey, "ENCRYPTED") {
		return ErrEncryptedKey
	}

	_, err := os.Stat(privateKeyPath)
	if err != nil {
		if os.IsNotExist(err) {
			err := ioutil.WriteFile(privateKeyPath, []byte(driver.PrivateKey), 0600)
			if err != nil {
				return err
			}
		} else {
			return err
		}
	}

	return os.Setenv("GIT_SSH_COMMAND", "ssh -i "+privateKeyPath)
}

func (driver *GitDriver) readVersion() (semver.Version, bool, error) {
	var currentVersionStr string
	versionFile, err := os.Open(filepath.Join(gitRepoDir, driver.File))
	if err != nil {
		if os.IsNotExist(err) {
			return semver.Version{}, false, nil
		}

		return semver.Version{}, false, err
	}

	defer versionFile.Close()

	_, err = fmt.Fscanf(versionFile, "%s", &currentVersionStr)
	if err != nil {
		return semver.Version{}, false, err
	}

	currentVersion, err := semver.Parse(currentVersionStr)
	if err != nil {
		return semver.Version{}, false, err
	}

	return currentVersion, true, nil
}

const nothingToCommitString = "nothing to commit"
const falsePushString = "Everything up-to-date"
const pushRejectedString = "[rejected]"
const pushRemoteRejectedString = "[remote rejected]"

func (driver *GitDriver) writeVersion(newVersion semver.Version) (bool, error) {
	err := ioutil.WriteFile(filepath.Join(gitRepoDir, driver.File), []byte(newVersion.String()+"\n"), 0644)
	if err != nil {
		return false, err
	}

	gitAdd := exec.Command("git", "add", driver.File)
	gitAdd.Dir = gitRepoDir
	gitAdd.Stdout = os.Stderr
	gitAdd.Stderr = os.Stderr
	if err := gitAdd.Run(); err != nil {
		return false, err
	}

	gitCommit := exec.Command("git", "commit", "-m", "bump to "+newVersion.String())
	gitCommit.Dir = gitRepoDir

	commitOutput, err := gitCommit.CombinedOutput()

	if strings.Contains(string(commitOutput), nothingToCommitString) {
		return true, nil
	}

	if err != nil {
		os.Stderr.Write(commitOutput)
		return false, err
	}

	gitPush := exec.Command("git", "push", "origin", "HEAD:"+driver.Branch)
	gitPush.Dir = gitRepoDir

	pushOutput, err := gitPush.CombinedOutput()

	if strings.Contains(string(pushOutput), falsePushString) {
		return false, nil
	}

	if strings.Contains(string(pushOutput), pushRejectedString) {
		return false, nil
	}

	if strings.Contains(string(pushOutput), pushRemoteRejectedString) {
		return false, nil
	}

	if err != nil {
		os.Stderr.Write(pushOutput)
		return false, err
	}

	return true, nil
}
<commit_msg>Host key verification failed.<commit_after>package driver

import (
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"

	"github.com/blang/semver"
	"github.com/concourse/semver-resource/version"
)

var gitRepoDir string
var privateKeyPath string

var ErrEncryptedKey = errors.New("private keys with passphrases are not supported")

func init() {
	gitRepoDir = filepath.Join(os.TempDir(), "semver-git-repo")
	privateKeyPath = filepath.Join(os.TempDir(), "private-key")
}

type GitDriver struct {
	InitialVersion semver.Version

	URI        string
	Branch     string
	PrivateKey string
	File       string
}

func (driver *GitDriver) Bump(bump version.Bump) (semver.Version, error) {
	err := driver.setUpKey()
	if err != nil {
		return semver.Version{}, err
	}

	var newVersion semver.Version

	for {
		err = driver.setUpRepo()
		if err != nil {
			return semver.Version{}, err
		}

		currentVersion, exists, err := driver.readVersion()
		if err != nil {
			return semver.Version{}, err
		}

		if !exists {
			currentVersion = driver.InitialVersion
		}

		newVersion = bump.Apply(currentVersion)

		wrote, err := driver.writeVersion(newVersion)
		if wrote {
			break
		}
	}

	return newVersion, nil
}

func (driver *GitDriver) Set(newVersion semver.Version) error {
	err := driver.setUpKey()
	if err != nil {
		return err
	}

	for {
		err = driver.setUpRepo()
		if err != nil {
			return err
		}

		wrote, err := driver.writeVersion(newVersion)
		if err != nil {
			return err
		}

		if wrote {
			break
		}
	}

	return nil
}

func (driver *GitDriver) Check(cursor *semver.Version) ([]semver.Version, error) {
	err := driver.setUpKey()
	if err != nil {
		return nil, err
	}

	err = driver.setUpRepo()
	if err != nil {
		return nil, err
	}

	currentVersion, exists, err := driver.readVersion()
	if err != nil {
		return nil, err
	}

	if !exists {
		return []semver.Version{driver.InitialVersion}, nil
	}

	if cursor == nil || currentVersion.GT(*cursor) {
		return []semver.Version{currentVersion}, nil
	}

	return []semver.Version{}, nil
}

func (driver *GitDriver) setUpRepo() error {
	_, err := os.Stat(gitRepoDir)
	if err != nil {
		gitClone := exec.Command("git", "clone", driver.URI, "--branch", driver.Branch, gitRepoDir)
		gitClone.Stdout = os.Stderr
		gitClone.Stderr = os.Stderr
		if err := gitClone.Run(); err != nil {
			return err
		}
	} else {
		gitFetch := exec.Command("git", "fetch", "origin", driver.Branch)
		gitFetch.Dir = gitRepoDir
		gitFetch.Stdout = os.Stderr
		gitFetch.Stderr = os.Stderr
		if err := gitFetch.Run(); err != nil {
			return err
		}
	}

	gitCheckout := exec.Command("git", "reset", "--hard", "origin/"+driver.Branch)
	gitCheckout.Dir = gitRepoDir
	gitCheckout.Stdout = os.Stderr
	gitCheckout.Stderr = os.Stderr
	if err := gitCheckout.Run(); err != nil {
		return err
	}

	return nil
}

func (driver *GitDriver) setUpKey() error {
	if strings.Contains(driver.PrivateKey, "ENCRYPTED") {
		return ErrEncryptedKey
	}

	_, err := os.Stat(privateKeyPath)
	if err != nil {
		if os.IsNotExist(err) {
			err := ioutil.WriteFile(privateKeyPath, []byte(driver.PrivateKey), 0600)
			if err != nil {
				return err
			}
		} else {
			return err
		}
	}

	return os.Setenv("GIT_SSH_COMMAND", "ssh -o StrictHostKeyChecking=no -i "+privateKeyPath)
}

func (driver *GitDriver) readVersion() (semver.Version, bool, error) {
	var currentVersionStr string
	versionFile, err := os.Open(filepath.Join(gitRepoDir, driver.File))
	if err != nil {
		if os.IsNotExist(err) {
			return semver.Version{}, false, nil
		}

		return semver.Version{}, false, err
	}

	defer versionFile.Close()

	_, err = fmt.Fscanf(versionFile, "%s", &currentVersionStr)
	if err != nil {
		return semver.Version{}, false, err
	}

	currentVersion, err := semver.Parse(currentVersionStr)
	if err != nil {
		return semver.Version{}, false, err
	}

	return currentVersion, true, nil
}

const nothingToCommitString = "nothing to commit"
const falsePushString = "Everything up-to-date"
const pushRejectedString = "[rejected]"
const pushRemoteRejectedString = "[remote rejected]"

func (driver *GitDriver) writeVersion(newVersion semver.Version) (bool, error) {
	err := ioutil.WriteFile(filepath.Join(gitRepoDir, driver.File), []byte(newVersion.String()+"\n"), 0644)
	if err != nil {
		return false, err
	}

	gitAdd := exec.Command("git", "add", driver.File)
	gitAdd.Dir = gitRepoDir
	gitAdd.Stdout = os.Stderr
	gitAdd.Stderr = os.Stderr
	if err := gitAdd.Run(); err != nil {
		return false, err
	}

	gitCommit := exec.Command("git", "commit", "-m", "bump to "+newVersion.String())
	gitCommit.Dir = gitRepoDir

	commitOutput, err := gitCommit.CombinedOutput()

	if strings.Contains(string(commitOutput), nothingToCommitString) {
		return true, nil
	}

	if err != nil {
		os.Stderr.Write(commitOutput)
		return false, err
	}

	gitPush := exec.Command("git", "push", "origin", "HEAD:"+driver.Branch)
	gitPush.Dir = gitRepoDir

	pushOutput, err := gitPush.CombinedOutput()

	if strings.Contains(string(pushOutput), falsePushString) {
		return false, nil
	}

	if strings.Contains(string(pushOutput), pushRejectedString) {
		return false, nil
	}

	if strings.Contains(string(pushOutput), pushRemoteRejectedString) {
		return false, nil
	}

	if err != nil {
		os.Stderr.Write(pushOutput)
		return false, err
	}

	return true, nil
}
<|endoftext|>


<commit_before>package main

import (
        "bufio"
        "crypt/md5"
        "encoding/json"
        "encoding/hex"
        "errors"
        "fmt"
        "io"
        "log"
        "os"
        "os/exec"
        "regexp"
        "sync"
        "time"
)

/* ========================= */
/* The follow code is forked */
/* from github.com/nf/goto   */
/* ========================= */
const (
        saveTimeout     = 10e9
        saveQueueLength = 1000
)

type Store inteface {
        Put(path, key *string) error
        Get(key, path *string) error
}

type PathStore struct {
        mu sync.RWMutex
        paths map[string]string
        count int
        save chan record
}

type record struct {
        key, path string
}

// Use md5 hash sums for the filepaths
func md5hash(text string, DriveSyncDirectory string) string {
        r := strings.NewReplacer(DriveSyncDirectory, "")
        relative-path := r.Replace(text)
        hasher := md5.New()
        hasher.Write([]byte(relative-path))
        return hex.EncodeToString(hasher.Sum(nil))
}

// Create a hashtable of paths and keys
func NewPathStore(filename string) *PathStore {
        s := &PathStore{paths: make(map[string]string)}
        if filename != "" {
                s.save = make(chan record, saveQueueLength)
                if err := s.load(filename); err != nil {
                        log.Println("[ERROR] Error storing paths: ", err)
                }
                go s.saveLoop(filename)
        }
        return s
}

// Check for a path in the hashtable
func (s *PathStore) Get(key, path *string) bool {
        s.mu.RLock()
        defer s.mu.RUnlock()
        if p, okay := s.paths[*key]; ok {
                *path = u
                return nil
        }
        return errors.New("Key not found")
}

// Write a new path to the hashtable for an known key
func (s *PathStore) Set(key, path *string) bool {
        s.mu.Lock()
        defer s.mu.Unlock()
        if _, present := s.paths[*key]; present {
                return errors.New("Key already exists")
        }
        // Otherwise add the new path
        s.paths[*key] = *path
        return nil
}

// Write a new path to the hashtable without a known key
func (s *PathStore) Put(path, DriveSyncDirectory, key *string) error {
        for {
                *key = md5hash(path, DriveSyncDirectory)
                s.count++
                if err := s.Set(key, path); err = nil {
                        break
                }
        }
        if s.save != nil {
                s.save <- record{*key, *path}
        }
        return nil
}

// Load the hashtable from a file
func (s *PathStore) load(filename string) error {
        f, err := os.Open(filename)
        if err != nil {
                return err
        }
        defer f.Close()
        b := bufio.NewReader(f)
        d := json.NewDecoder(b)
        for {
                var r record
                if err := d.Decode(&r); err == io.EOF {
                        break
                } else if err != nil {
                        return err
                }
                if err = s.Set(&r.key, &r.path); err != nil {
                        return err
                }
        }
        return nil
}

// Save the hashtable to a file
func (s *PathStore) saveLoop(filename string) {
        f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
        if err != nil {
                log.Println("PathStore: ", err)
                return
        }
        b := bufio.NewWriter(f)
        e := json.NewEncoder(b)
        t := time.NewTicker(saveTimeout)
        defer f.Close()
        defer b.Flush()
        for {
                var err error
                select {
                case r:= <-s.save:
                        err = e.Encode(r)
                case <-t.C:
                        err = b.Flush()
                }
                if err != nil {
                        log.Println("PathStore: ", err)
                }
        }
}
/* ============================= */
/* End of modified /nf/goto code */
/* ============================= */

// The configuration file struct
type Configuration struct {
        DriveSyncDirectory string
        GoogleDriveRemoteDirectory string
        HugoPostDirectory string
}

// Read the configuration JSON file in order to get some settings and directories
func read_cfg(filename string, wg *sync.WaitGroup, conf_message chan string) {
        file, _ := os.Open(filename)
        decoder := json.NewDecoder(file)
        configuration := Configuration{}
        err := decoder.Decode(&configuration)
        if err != nil {
                fmt.Println("[ERROR] Error reading the JSON confguration: ", err)
                return
        }
        drive_sync_dir := fmt.Sprintf(configuration.DriveSyncDirectory)
        conf_message <- drive_sync_dir
        drive_remote_dir := fmt.Sprintf(configuration.GoogleDriveRemoteDirectory)
        conf_message <- drive_remote_dir
        hugo_post_dir := fmt.Sprintf(configuration.HugoPostDirectory)
        conf_message <- hugo_post_dir
        wg.Done()
}

// Sync google drive remote folder to the configured local directory.
// Then send the output from drive CLI to a function to intepret the output
// by stripping the full output down to an array of string paths to docx files.
func sync_google_drive(sync_dir string, drive_remote_dir string, wg *sync.WaitGroup) {
        sync_gd := new(sync.WaitGroup)
        output := make(chan string)
        sync := exec.Command("drive pull -no-prompt -desktop-links=false -export docx", drive_remote_dir)
        sync.Dir = sync_dir
        fmt.Println("Syncing Google Drive...")
        out, err := sync.Output()
        if err != nil {
                fmt.Println("[ERROR] Error syncing Google Drive: ", err)
                return
        }
        fmt.Println("Done syncing!")
        sync_gd.Add(1)
        go intepret_drive_output(sync_gd, output)
        output <- string(out)
        sync_gd.Wait()
        wg.Done()
}

// Find all Exported file paths via a regex expression and then add them to an array
func interpret_drive_output(sync_gd *sync.WaitGroup, output chan string) {
        results := <-output
        re := regexp.MustCompile(`to '(.*?)'`)
        matches := re.FindAllString(results, -1)
        sync_gd.Done()
}

// Convert from docx to markdown with pandoc
func convert_to_markdown_with_pandoc(docx_file_path string, md_file_path string, wg *sync.WaitGroup) {
        convert := exec.Command("pandoc --atx-headers --smart --normalize --email-obfuscation=references --mathjax -t markdown_strict -o", md_file_path, docx_file_path)
        out, err := convert.Output()
        if err != nil {
                fmt.Println("[ERROR] Error converting files to markdown with pandoc: ", err)
        }
        wg.Done()
}

func add_hugo_headers(md_file_path string, wg *sync.WaitGroup) {
	f, err := os.Open(md_file_path)
	if err != nil {
		fmt.Println("[ERROR] Error opening markdown file: ", err)
	}
	// TODO: implement something like https://gist.github.com/toruuetani/f6aa4751a66ef65646c1a4934471396b
	// in order to prepend hugo headers to the markdown files
}

// Use hugo to compile the markdown files into html and then serve with hugo or with nginx
func compile_and_serve_hugo_site(hugo_dir string, prod_dir string, use_hugo bool, wg *sync.WaitGroup) {
}

/* func main() {
        conf_message := make(chan string)
        wg := new(sync.WaitGroup)
        wg.Add(2)
        go exe_cmd("echo", "ping", wg)
        go read_cfg("conf.json", wg, conf_message)
        drive_sync_dir := <-conf_message
        fmt.Println(drive_sync_dir)
        drive_remote_dir := <-conf_message
        fmt.Println(drive_remote_dir)
        hugo_post_dir := <-conf_message
        fmt.Println(hugo_post_dir)
        wg.Wait()
} */<commit_msg>Added the prepend to file code<commit_after>package main

import (
        "bufio"
        "crypt/md5"
        "encoding/json"
        "encoding/hex"
        "errors"
        "fmt"
        "io"
        "log"
        "os"
        "os/exec"
        "regexp"
        "sync"
        "time"
)

/* ========================= */
/* The follow code is forked */
/* from github.com/nf/goto   */
/* ========================= */
const (
        saveTimeout     = 10e9
        saveQueueLength = 1000
)

type Store inteface {
        Put(path, key *string) error
        Get(key, path *string) error
}

type PathStore struct {
        mu sync.RWMutex
        paths map[string]string
        count int
        save chan record
}

type record struct {
        key, path string
}

// Use md5 hash sums for the filepaths
func md5hash(text string, DriveSyncDirectory string) string {
        r := strings.NewReplacer(DriveSyncDirectory, "")
        relative-path := r.Replace(text)
        hasher := md5.New()
        hasher.Write([]byte(relative-path))
        return hex.EncodeToString(hasher.Sum(nil))
}

// Create a hashtable of paths and keys
func NewPathStore(filename string) *PathStore {
        s := &PathStore{paths: make(map[string]string)}
        if filename != "" {
                s.save = make(chan record, saveQueueLength)
                if err := s.load(filename); err != nil {
                        log.Println("[ERROR] Error storing paths: ", err)
                }
                go s.saveLoop(filename)
        }
        return s
}

// Check for a path in the hashtable
func (s *PathStore) Get(key, path *string) bool {
        s.mu.RLock()
        defer s.mu.RUnlock()
        if p, okay := s.paths[*key]; ok {
                *path = u
                return nil
        }
        return errors.New("Key not found")
}

// Write a new path to the hashtable for an known key
func (s *PathStore) Set(key, path *string) bool {
        s.mu.Lock()
        defer s.mu.Unlock()
        if _, present := s.paths[*key]; present {
                return errors.New("Key already exists")
        }
        // Otherwise add the new path
        s.paths[*key] = *path
        return nil
}

// Write a new path to the hashtable without a known key
func (s *PathStore) Put(path, DriveSyncDirectory, key *string) error {
        for {
                *key = md5hash(path, DriveSyncDirectory)
                s.count++
                if err := s.Set(key, path); err = nil {
                        break
                }
        }
        if s.save != nil {
                s.save <- record{*key, *path}
        }
        return nil
}

// Load the hashtable from a file
func (s *PathStore) load(filename string) error {
        f, err := os.Open(filename)
        if err != nil {
                return err
        }
        defer f.Close()
        b := bufio.NewReader(f)
        d := json.NewDecoder(b)
        for {
                var r record
                if err := d.Decode(&r); err == io.EOF {
                        break
                } else if err != nil {
                        return err
                }
                if err = s.Set(&r.key, &r.path); err != nil {
                        return err
                }
        }
        return nil
}

// Save the hashtable to a file
func (s *PathStore) saveLoop(filename string) {
        f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
        if err != nil {
                log.Println("PathStore: ", err)
                return
        }
        b := bufio.NewWriter(f)
        e := json.NewEncoder(b)
        t := time.NewTicker(saveTimeout)
        defer f.Close()
        defer b.Flush()
        for {
                var err error
                select {
                case r:= <-s.save:
                        err = e.Encode(r)
                case <-t.C:
                        err = b.Flush()
                }
                if err != nil {
                        log.Println("PathStore: ", err)
                }
        }
}
/* ============================= */
/* End of modified /nf/goto code */
/* ============================= */

// The configuration file struct
type Configuration struct {
        DriveSyncDirectory string
        GoogleDriveRemoteDirectory string
        HugoPostDirectory string
}

// Read the configuration JSON file in order to get some settings and directories
func read_cfg(filename string, wg *sync.WaitGroup, conf_message chan string) {
        file, _ := os.Open(filename)
        decoder := json.NewDecoder(file)
        configuration := Configuration{}
        err := decoder.Decode(&configuration)
        if err != nil {
                fmt.Println("[ERROR] Error reading the JSON confguration: ", err)
                return
        }
        drive_sync_dir := fmt.Sprintf(configuration.DriveSyncDirectory)
        conf_message <- drive_sync_dir
        drive_remote_dir := fmt.Sprintf(configuration.GoogleDriveRemoteDirectory)
        conf_message <- drive_remote_dir
        hugo_post_dir := fmt.Sprintf(configuration.HugoPostDirectory)
        conf_message <- hugo_post_dir
        wg.Done()
}

// Sync google drive remote folder to the configured local directory.
// Then send the output from drive CLI to a function to intepret the output
// by stripping the full output down to an array of string paths to docx files.
func sync_google_drive(sync_dir string, drive_remote_dir string, wg *sync.WaitGroup) {
        sync_gd := new(sync.WaitGroup)
        output := make(chan string)
        sync := exec.Command("drive pull -no-prompt -desktop-links=false -export docx", drive_remote_dir)
        sync.Dir = sync_dir
        fmt.Println("Syncing Google Drive...")
        out, err := sync.Output()
        if err != nil {
                fmt.Println("[ERROR] Error syncing Google Drive: ", err)
                return
        }
        fmt.Println("Done syncing!")
        sync_gd.Add(1)
        go intepret_drive_output(sync_gd, output)
        output <- string(out)
        sync_gd.Wait()
        wg.Done()
}

// Find all Exported file paths via a regex expression and then add them to an array
func interpret_drive_output(sync_gd *sync.WaitGroup, output chan string) {
        results := <-output
        re := regexp.MustCompile(`to '(.*?)'`)
        matches := re.FindAllString(results, -1)
        sync_gd.Done()
}

// Convert from docx to markdown with pandoc
func convert_to_markdown_with_pandoc(docx_file_path string, md_file_path string, wg *sync.WaitGroup) {
        convert := exec.Command("pandoc --atx-headers --smart --normalize --email-obfuscation=references --mathjax -t markdown_strict -o", md_file_path, docx_file_path)
        out, err := convert.Output()
        if err != nil {
                fmt.Println("[ERROR] Error converting files to markdown with pandoc: ", err)
        }
        wg.Done()
}

/* =================================================================== */
/* The following code forked from:                                     */
/* https://gist.github.com/toruuetani/f6aa4751a66ef65646c1a4934471396b */
/* =================================================================== */
type MarkdownFileRecord struct {
        Filename string
        Contents []string
}

func NewMarkdownFile(filename string) *MarkdownFileRecord {
        return &MarkdownFileRecord {
                Filename: filename
                Contents make([]string, 0)
        }
}

func (m *MarkdownFileRecord) readMarkdownLines() error {
        if _, err := os.Stat(m.Filename); err != nil {
                return nil
        }
        f, err := os.OpenFile(m.Filename, os.O_RDONLY, 0600)
        if err != nil {
                return err
        }
        defer f.Close()

        scanner := bufio.NewScanner(f)
        for scanner.Scan() {
                if tmp := scanner.Text(); len(tmp) != 0 {
                        m.Contents = append(m.Contents, tmp)
                }
        }
}

func (m *MarkdownFileRecord) Prepend(content string) error {
        err := m.readLines()
        if err != nil {
                return err
        }

        f, err := os.OpenFile(m.Filename, os.O_CREATE|os.O_WRONLY, 0600)
        if err != nil {
                return err
        }
        defer f.Close()

        writer := bufio.NewWriter(f)
        writer.WriteString(fmt.Sprintf("%s\n", content))
        for _, line := range m.Contents {
                _, err := writer.WriteString(fmt.Sprintf("%s\n", line))
                if err != nil {
                        return err
                }
        }

        if err := writer.Flush(); err != nil {
                return err
        }

        return nil
}
/* ============================== */
/* End of modified record.go code */
/* ============================== */

// Add the hugo headers to the markdown file
func add_hugo_headers(md_file_path string, wg *sync.WaitGroup) {
}

// Use hugo to compile the markdown files into html and then serve with hugo or with nginx
func compile_and_serve_hugo_site(hugo_dir string, prod_dir string, use_hugo bool, wg *sync.WaitGroup) {
}
<|endoftext|>


<commit_before>package shells

import (
	"path"
	"path/filepath"
	"strconv"
	"strings"

	"gitlab.com/gitlab-org/gitlab-ci-multi-runner/common"
)

type AbstractShell struct {
}

func (b *AbstractShell) GetFeatures(features *common.FeaturesInfo) {
	features.Artifacts = true
	features.Cache = true
}

func (b *AbstractShell) GetSupportedOptions() []string {
	return []string{"artifacts", "cache", "dependencies"}
}

func (b *AbstractShell) writeCdBuildDir(w ShellWriter, info common.ShellScriptInfo) {
	w.Cd(info.Build.FullProjectDir())
}

func (b *AbstractShell) writeExports(w ShellWriter, info common.ShellScriptInfo) {
	for _, variable := range info.Build.GetAllVariables() {
		w.Variable(variable)
	}
}

func (b *AbstractShell) writeTLSCAInfo(w ShellWriter, build *common.Build, key string) {
	if build.TLSCAChain != "" {
		w.Variable(common.BuildVariable{
			Key:      key,
			Value:    build.TLSCAChain,
			Public:   true,
			Internal: true,
			File:     true,
		})
	}
}

func (b *AbstractShell) writeCloneCmd(w ShellWriter, build *common.Build, projectDir string) {
	w.Notice("Cloning repository...")
	w.RmDir(projectDir)
	w.Command("git", "clone", build.RepoURL, projectDir)
	w.Cd(projectDir)
}

func (b *AbstractShell) writeFetchCmd(w ShellWriter, build *common.Build, projectDir string, gitDir string) {
	w.IfDirectory(gitDir)
	w.Notice("Fetching changes...")
	w.Cd(projectDir)
	w.Command("git", "clean", "-ffdx")
	w.Command("git", "reset", "--hard")
	w.Command("git", "remote", "set-url", "origin", build.RepoURL)
	w.Command("git", "fetch", "origin", "--prune", "+refs/heads/*:refs/remotes/origin/*", "+refs/tags/*:refs/tags/*")
	w.Else()
	b.writeCloneCmd(w, build, projectDir)
	w.EndIf()
}

func (b *AbstractShell) writeCheckoutCmd(w ShellWriter, build *common.Build) {
	w.Notice("Checking out %s as %s...", build.Sha[0:8], build.RefName)
	// We remove a git index file, this is required if `git checkout` is terminated
	w.RmFile(".git/index.lock")
	w.Command("git", "checkout", build.Sha)
}

func (b *AbstractShell) cacheFile(build *common.Build, userKey string) (key, file string) {
	// For tags we don't create cache
	if build.Tag || build.CacheDir == "" {
		return
	}

	// Deduce cache key
	key = path.Join(build.Name, build.RefName)
	if userKey != "" {
		key = build.GetAllVariables().ExpandValue(userKey)
	}

	// Ignore cache without the key
	if key == "" {
		return
	}

	file = path.Join(build.CacheDir, key, "cache.zip")
	file, err := filepath.Rel(build.BuildDir, file)
	if err != nil {
		return "", ""
	}
	return
}

func (o *archivingOptions) CommandArguments() (args []string) {
	for _, path := range o.Paths {
		args = append(args, "--path", path)
	}

	if o.Untracked {
		args = append(args, "--untracked")
	}
	return
}

func (b *AbstractShell) cacheExtractor(w ShellWriter, options *archivingOptions, info common.ShellScriptInfo) {
	if options == nil {
		return
	}
	if info.RunnerCommand == "" {
		w.Warning("The cache is not supported in this executor.")
		return
	}

	// Skip restoring cache if no cache is defined
	if archiverArgs := options.CommandArguments(); len(archiverArgs) == 0 {
		return
	}

	// Skip archiving if no cache is defined
	cacheKey, cacheFile := b.cacheFile(info.Build, options.Key)
	if cacheKey == "" {
		return
	}

	args := []string{
		"cache-extractor",
		"--file", cacheFile,
	}

	// Generate cache download address
	if url := getCacheDownloadURL(info.Build, cacheKey); url != "" {
		args = append(args, "--url", url)
	}

	// Execute archive command
	w.Notice("Checking cache for %s...", cacheKey)
	w.Command(info.RunnerCommand, args...)
}

func (b *AbstractShell) downloadArtifacts(w ShellWriter, build *common.BuildInfo, info common.ShellScriptInfo) {
	if info.RunnerCommand == "" {
		w.Warning("The artifacts downloading is not supported in this executor.")
		return
	}

	args := []string{
		"artifacts-downloader",
		"--url",
		info.Build.Runner.URL,
		"--token",
		build.Token,
		"--id",
		strconv.Itoa(build.ID),
	}

	w.Notice("Downloading artifacts for %s (%d)...", build.Name, build.ID)
	w.Command(info.RunnerCommand, args...)
}

func (b *AbstractShell) downloadAllArtifacts(w ShellWriter, dependencies *dependencies, info common.ShellScriptInfo) {
	for _, otherBuild := range info.Build.DependsOnBuilds {
		if otherBuild.Artifacts == nil || otherBuild.Artifacts.Filename == "" {
			continue
		}
		if !dependencies.IsDependent(otherBuild.Name) {
			continue
		}
		b.downloadArtifacts(w, &otherBuild, info)
	}
}

func (b *AbstractShell) GeneratePreBuild(w ShellWriter, info common.ShellScriptInfo) {
	b.writeExports(w, info)

	build := info.Build
	projectDir := build.FullProjectDir()
	gitDir := path.Join(build.FullProjectDir(), ".git")

	b.writeTLSCAInfo(w, info.Build, "GIT_SSL_CAINFO")
	b.writeTLSCAInfo(w, info.Build, "CI_SERVER_TLS_CA_FILE")

	if build.AllowGitFetch {
		b.writeFetchCmd(w, build, projectDir, gitDir)
	} else {
		b.writeCloneCmd(w, build, projectDir)
	}

	b.writeCheckoutCmd(w, build)

	// Parse options
	var options shellOptions
	info.Build.Options.Decode(&options)

	// Try to restore from main cache, if not found cache for master
	b.cacheExtractor(w, options.Cache, info)

	// Process all artifacts
	b.downloadAllArtifacts(w, options.Dependencies, info)
}

func (b *AbstractShell) GenerateCommands(w ShellWriter, info common.ShellScriptInfo) {
	b.writeExports(w, info)
	b.writeCdBuildDir(w, info)

	commands := info.Build.Commands
	commands = strings.TrimSpace(commands)
	for _, command := range strings.Split(commands, "\n") {
		command = strings.TrimSpace(command)
		if command != "" {
			w.Notice("$ %s", command)
		} else {
			w.EmptyLine()
		}
		w.Line(command)
	}
}

func (b *AbstractShell) cacheArchiver(w ShellWriter, options *archivingOptions, info common.ShellScriptInfo) {
	if options == nil {
		return
	}
	if info.RunnerCommand == "" {
		w.Warning("The cache is not supported in this executor.")
		return
	}

	// Skip archiving if no cache is defined
	cacheKey, cacheFile := b.cacheFile(info.Build, options.Key)
	if cacheKey == "" {
		return
	}

	args := []string{
		"cache-archiver",
		"--file", cacheFile,
	}

	// Create list of files to archive
	archiverArgs := options.CommandArguments()
	if len(archiverArgs) == 0 {
		// Skip creating archive
		return
	}
	args = append(args, archiverArgs...)

	// Generate cache upload address
	if url := getCacheUploadURL(info.Build, cacheKey); url != "" {
		args = append(args, "--url", url)
	}

	// Execute archive command
	w.Notice("Creating cache %s...", cacheKey)
	w.Command(info.RunnerCommand, args...)
}

func (b *AbstractShell) uploadArtifacts(w ShellWriter, options *archivingOptions, info common.ShellScriptInfo) {
	if options == nil {
		return
	}
	if info.Build.Runner.URL == "" {
		return
	}
	if info.RunnerCommand == "" {
		w.Warning("The artifacts uploading is not supported in this executor.")
		return
	}

	args := []string{
		"artifacts-uploader",
		"--url",
		info.Build.Runner.URL,
		"--token",
		info.Build.Token,
		"--id",
		strconv.Itoa(info.Build.ID),
	}

	// Create list of files to archive
	archiverArgs := options.CommandArguments()
	if len(archiverArgs) == 0 {
		// Skip creating archive
		return
	}
	args = append(args, archiverArgs...)

	// Get artifacts:name
	if name, ok := info.Build.Options.GetString("artifacts", "name"); ok && name != "" {
		args = append(args, "--name", name)
	}

	w.Notice("Uploading artifacts...")
	w.Command(info.RunnerCommand, args...)
}

func (b *AbstractShell) GeneratePostBuild(w ShellWriter, info common.ShellScriptInfo) {
	b.writeExports(w, info)
	b.writeCdBuildDir(w, info)
	b.writeTLSCAInfo(w, info.Build, "CI_SERVER_TLS_CA_FILE")

	// Parse options
	var options shellOptions
	info.Build.Options.Decode(&options)

	// Find cached files and archive them
	b.cacheArchiver(w, options.Cache, info)

	// Upload artifacts
	b.uploadArtifacts(w, options.Artifacts, info)
}
<commit_msg>Create cache also for tags<commit_after>package shells

import (
	"path"
	"path/filepath"
	"strconv"
	"strings"

	"gitlab.com/gitlab-org/gitlab-ci-multi-runner/common"
)

type AbstractShell struct {
}

func (b *AbstractShell) GetFeatures(features *common.FeaturesInfo) {
	features.Artifacts = true
	features.Cache = true
}

func (b *AbstractShell) GetSupportedOptions() []string {
	return []string{"artifacts", "cache", "dependencies"}
}

func (b *AbstractShell) writeCdBuildDir(w ShellWriter, info common.ShellScriptInfo) {
	w.Cd(info.Build.FullProjectDir())
}

func (b *AbstractShell) writeExports(w ShellWriter, info common.ShellScriptInfo) {
	for _, variable := range info.Build.GetAllVariables() {
		w.Variable(variable)
	}
}

func (b *AbstractShell) writeTLSCAInfo(w ShellWriter, build *common.Build, key string) {
	if build.TLSCAChain != "" {
		w.Variable(common.BuildVariable{
			Key:      key,
			Value:    build.TLSCAChain,
			Public:   true,
			Internal: true,
			File:     true,
		})
	}
}

func (b *AbstractShell) writeCloneCmd(w ShellWriter, build *common.Build, projectDir string) {
	w.Notice("Cloning repository...")
	w.RmDir(projectDir)
	w.Command("git", "clone", build.RepoURL, projectDir)
	w.Cd(projectDir)
}

func (b *AbstractShell) writeFetchCmd(w ShellWriter, build *common.Build, projectDir string, gitDir string) {
	w.IfDirectory(gitDir)
	w.Notice("Fetching changes...")
	w.Cd(projectDir)
	w.Command("git", "clean", "-ffdx")
	w.Command("git", "reset", "--hard")
	w.Command("git", "remote", "set-url", "origin", build.RepoURL)
	w.Command("git", "fetch", "origin", "--prune", "+refs/heads/*:refs/remotes/origin/*", "+refs/tags/*:refs/tags/*")
	w.Else()
	b.writeCloneCmd(w, build, projectDir)
	w.EndIf()
}

func (b *AbstractShell) writeCheckoutCmd(w ShellWriter, build *common.Build) {
	w.Notice("Checking out %s as %s...", build.Sha[0:8], build.RefName)
	// We remove a git index file, this is required if `git checkout` is terminated
	w.RmFile(".git/index.lock")
	w.Command("git", "checkout", build.Sha)
}

func (b *AbstractShell) cacheFile(build *common.Build, userKey string) (key, file string) {
	if build.CacheDir == "" {
		return
	}

	// Deduce cache key
	key = path.Join(build.Name, build.RefName)
	if userKey != "" {
		key = build.GetAllVariables().ExpandValue(userKey)
	}

	// Ignore cache without the key
	if key == "" {
		return
	}

	file = path.Join(build.CacheDir, key, "cache.zip")
	file, err := filepath.Rel(build.BuildDir, file)
	if err != nil {
		return "", ""
	}
	return
}

func (o *archivingOptions) CommandArguments() (args []string) {
	for _, path := range o.Paths {
		args = append(args, "--path", path)
	}

	if o.Untracked {
		args = append(args, "--untracked")
	}
	return
}

func (b *AbstractShell) cacheExtractor(w ShellWriter, options *archivingOptions, info common.ShellScriptInfo) {
	if options == nil {
		return
	}
	if info.RunnerCommand == "" {
		w.Warning("The cache is not supported in this executor.")
		return
	}

	// Skip restoring cache if no cache is defined
	if archiverArgs := options.CommandArguments(); len(archiverArgs) == 0 {
		return
	}

	// Skip archiving if no cache is defined
	cacheKey, cacheFile := b.cacheFile(info.Build, options.Key)
	if cacheKey == "" {
		return
	}

	args := []string{
		"cache-extractor",
		"--file", cacheFile,
	}

	// Generate cache download address
	if url := getCacheDownloadURL(info.Build, cacheKey); url != "" {
		args = append(args, "--url", url)
	}

	// Execute archive command
	w.Notice("Checking cache for %s...", cacheKey)
	w.Command(info.RunnerCommand, args...)
}

func (b *AbstractShell) downloadArtifacts(w ShellWriter, build *common.BuildInfo, info common.ShellScriptInfo) {
	if info.RunnerCommand == "" {
		w.Warning("The artifacts downloading is not supported in this executor.")
		return
	}

	args := []string{
		"artifacts-downloader",
		"--url",
		info.Build.Runner.URL,
		"--token",
		build.Token,
		"--id",
		strconv.Itoa(build.ID),
	}

	w.Notice("Downloading artifacts for %s (%d)...", build.Name, build.ID)
	w.Command(info.RunnerCommand, args...)
}

func (b *AbstractShell) downloadAllArtifacts(w ShellWriter, dependencies *dependencies, info common.ShellScriptInfo) {
	for _, otherBuild := range info.Build.DependsOnBuilds {
		if otherBuild.Artifacts == nil || otherBuild.Artifacts.Filename == "" {
			continue
		}
		if !dependencies.IsDependent(otherBuild.Name) {
			continue
		}
		b.downloadArtifacts(w, &otherBuild, info)
	}
}

func (b *AbstractShell) GeneratePreBuild(w ShellWriter, info common.ShellScriptInfo) {
	b.writeExports(w, info)

	build := info.Build
	projectDir := build.FullProjectDir()
	gitDir := path.Join(build.FullProjectDir(), ".git")

	b.writeTLSCAInfo(w, info.Build, "GIT_SSL_CAINFO")
	b.writeTLSCAInfo(w, info.Build, "CI_SERVER_TLS_CA_FILE")

	if build.AllowGitFetch {
		b.writeFetchCmd(w, build, projectDir, gitDir)
	} else {
		b.writeCloneCmd(w, build, projectDir)
	}

	b.writeCheckoutCmd(w, build)

	// Parse options
	var options shellOptions
	info.Build.Options.Decode(&options)

	// Try to restore from main cache, if not found cache for master
	b.cacheExtractor(w, options.Cache, info)

	// Process all artifacts
	b.downloadAllArtifacts(w, options.Dependencies, info)
}

func (b *AbstractShell) GenerateCommands(w ShellWriter, info common.ShellScriptInfo) {
	b.writeExports(w, info)
	b.writeCdBuildDir(w, info)

	commands := info.Build.Commands
	commands = strings.TrimSpace(commands)
	for _, command := range strings.Split(commands, "\n") {
		command = strings.TrimSpace(command)
		if command != "" {
			w.Notice("$ %s", command)
		} else {
			w.EmptyLine()
		}
		w.Line(command)
	}
}

func (b *AbstractShell) cacheArchiver(w ShellWriter, options *archivingOptions, info common.ShellScriptInfo) {
	if options == nil {
		return
	}
	if info.RunnerCommand == "" {
		w.Warning("The cache is not supported in this executor.")
		return
	}

	// Skip archiving if no cache is defined
	cacheKey, cacheFile := b.cacheFile(info.Build, options.Key)
	if cacheKey == "" {
		return
	}

	args := []string{
		"cache-archiver",
		"--file", cacheFile,
	}

	// Create list of files to archive
	archiverArgs := options.CommandArguments()
	if len(archiverArgs) == 0 {
		// Skip creating archive
		return
	}
	args = append(args, archiverArgs...)

	// Generate cache upload address
	if url := getCacheUploadURL(info.Build, cacheKey); url != "" {
		args = append(args, "--url", url)
	}

	// Execute archive command
	w.Notice("Creating cache %s...", cacheKey)
	w.Command(info.RunnerCommand, args...)
}

func (b *AbstractShell) uploadArtifacts(w ShellWriter, options *archivingOptions, info common.ShellScriptInfo) {
	if options == nil {
		return
	}
	if info.Build.Runner.URL == "" {
		return
	}
	if info.RunnerCommand == "" {
		w.Warning("The artifacts uploading is not supported in this executor.")
		return
	}

	args := []string{
		"artifacts-uploader",
		"--url",
		info.Build.Runner.URL,
		"--token",
		info.Build.Token,
		"--id",
		strconv.Itoa(info.Build.ID),
	}

	// Create list of files to archive
	archiverArgs := options.CommandArguments()
	if len(archiverArgs) == 0 {
		// Skip creating archive
		return
	}
	args = append(args, archiverArgs...)

	// Get artifacts:name
	if name, ok := info.Build.Options.GetString("artifacts", "name"); ok && name != "" {
		args = append(args, "--name", name)
	}

	w.Notice("Uploading artifacts...")
	w.Command(info.RunnerCommand, args...)
}

func (b *AbstractShell) GeneratePostBuild(w ShellWriter, info common.ShellScriptInfo) {
	b.writeExports(w, info)
	b.writeCdBuildDir(w, info)
	b.writeTLSCAInfo(w, info.Build, "CI_SERVER_TLS_CA_FILE")

	// Parse options
	var options shellOptions
	info.Build.Options.Decode(&options)

	// Find cached files and archive them
	b.cacheArchiver(w, options.Cache, info)

	// Upload artifacts
	b.uploadArtifacts(w, options.Artifacts, info)
}
<|endoftext|>


<commit_before>package e2e

import (
	"context"
	"fmt"
	"strings"
	"time"

	. "github.com/onsi/gomega" // nolint
	v1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/api/resource"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/wait"
	"k8s.io/client-go/kubernetes"
	"k8s.io/cloud-provider/volume/helpers"
	"k8s.io/kubernetes/test/e2e/framework"
	e2elog "k8s.io/kubernetes/test/e2e/framework/log"
)

func expandPVCSize(c kubernetes.Interface, pvc *v1.PersistentVolumeClaim, size string, t int) error {
	pvcName := pvc.Name
	updatedPVC := pvc.DeepCopy()
	var err error

	updatedPVC, err = c.CoreV1().PersistentVolumeClaims(pvc.Namespace).Get(context.TODO(), pvcName, metav1.GetOptions{})
	if err != nil {
		return fmt.Errorf("error fetching pvc %q with %w", pvcName, err)
	}
	timeout := time.Duration(t) * time.Minute

	updatedPVC.Spec.Resources.Requests[v1.ResourceStorage] = resource.MustParse(size)
	_, err = c.CoreV1().PersistentVolumeClaims(updatedPVC.Namespace).Update(context.TODO(), updatedPVC, metav1.UpdateOptions{})
	Expect(err).Should(BeNil())

	start := time.Now()
	e2elog.Logf("Waiting up to %v to be in Resized state", pvc)
	return wait.PollImmediate(poll, timeout, func() (bool, error) {
		e2elog.Logf("waiting for PVC %s (%d seconds elapsed)", updatedPVC.Name, int(time.Since(start).Seconds()))
		updatedPVC, err = c.CoreV1().PersistentVolumeClaims(updatedPVC.Namespace).Get(context.TODO(), pvcName, metav1.GetOptions{})
		if err != nil {
			e2elog.Logf("Error getting pvc in namespace: '%s': %v", updatedPVC.Namespace, err)
			if isRetryableAPIError(err) {
				return false, nil
			}
			return false, err
		}
		pvcConditions := updatedPVC.Status.Conditions
		if len(pvcConditions) > 0 {
			e2elog.Logf("pvc state %v", pvcConditions[0].Type)
			if pvcConditions[0].Type == v1.PersistentVolumeClaimResizing || pvcConditions[0].Type == v1.PersistentVolumeClaimFileSystemResizePending {
				return false, nil
			}
		}

		if updatedPVC.Status.Capacity[v1.ResourceStorage] != resource.MustParse(size) {
			e2elog.Logf("current size in status %v,expected size %v", updatedPVC.Status.Capacity[v1.ResourceStorage], resource.MustParse(size))
			return false, nil
		}
		return true, nil
	})
}

func resizePVCAndValidateSize(pvcPath, appPath string, f *framework.Framework) error {
	size := "1Gi"
	expandSize := "10Gi"
	pvc, err := loadPVC(pvcPath)
	if err != nil {
		return err
	}
	pvc.Namespace = f.UniqueName

	resizePvc, err := loadPVC(pvcPath)
	if err != nil {
		return err
	}
	resizePvc.Namespace = f.UniqueName

	app, err := loadApp(appPath)
	if err != nil {
		return err
	}
	pvc.Spec.Resources.Requests[v1.ResourceStorage] = resource.MustParse(size)
	app.Labels = map[string]string{"app": "resize-pvc"}
	app.Namespace = f.UniqueName

	err = createPVCAndApp("", f, pvc, app, deployTimeout)
	if err != nil {
		return err
	}

	opt := metav1.ListOptions{
		LabelSelector: "app=resize-pvc",
	}

	pvc, err = f.ClientSet.CoreV1().PersistentVolumeClaims(pvc.Namespace).Get(context.TODO(), pvc.Name, metav1.GetOptions{})
	if err != nil {
		return err
	}
	if *pvc.Spec.VolumeMode == v1.PersistentVolumeFilesystem {
		err = checkDirSize(app, f, &opt, size)
		if err != nil {
			return err
		}
	}

	if *pvc.Spec.VolumeMode == v1.PersistentVolumeBlock {
		err = checkDeviceSize(app, f, &opt, size)
		if err != nil {
			return err
		}
	}
	// resize PVC
	err = expandPVCSize(f.ClientSet, resizePvc, expandSize, deployTimeout)
	if err != nil {
		return err
	}
	// wait for application pod to come up after resize
	err = waitForPodInRunningState(app.Name, app.Namespace, f.ClientSet, deployTimeout)
	if err != nil {
		return err
	}
	if *pvc.Spec.VolumeMode == v1.PersistentVolumeFilesystem {
		err = checkDirSize(app, f, &opt, expandSize)
		if err != nil {
			return err
		}
	}

	if *pvc.Spec.VolumeMode == v1.PersistentVolumeBlock {
		err = checkDeviceSize(app, f, &opt, expandSize)
		if err != nil {
			return err
		}
	}
	err = deletePVCAndApp("", f, resizePvc, app)
	return err
}

func checkDirSize(app *v1.Pod, f *framework.Framework, opt *metav1.ListOptions, size string) error {
	cmd := getDirSizeCheckCmd(app.Spec.Containers[0].VolumeMounts[0].MountPath)
	return checkAppMntSize(f, opt, size, cmd, app.Namespace, deployTimeout)
}

func checkDeviceSize(app *v1.Pod, f *framework.Framework, opt *metav1.ListOptions, size string) error {
	cmd := getDeviceSizeCheckCmd(app.Spec.Containers[0].VolumeDevices[0].DevicePath)
	return checkAppMntSize(f, opt, size, cmd, app.Namespace, deployTimeout)
}

func getDirSizeCheckCmd(dirPath string) string {
	return fmt.Sprintf("df -h|grep %s |awk '{print $2}'", dirPath)
}

func getDeviceSizeCheckCmd(devPath string) string {
	return fmt.Sprintf("blockdev --getsize64 %s", devPath)
}

func checkAppMntSize(f *framework.Framework, opt *metav1.ListOptions, size, cmd, ns string, t int) error {
	timeout := time.Duration(t) * time.Minute
	start := time.Now()

	return wait.PollImmediate(poll, timeout, func() (bool, error) {
		e2elog.Logf("executing cmd %s (%d seconds elapsed)", cmd, int(time.Since(start).Seconds()))
		output, stdErr, err := execCommandInPod(f, cmd, ns, opt)
		if err != nil {
			return false, err
		}
		if stdErr != "" {
			e2elog.Logf("failed to execute command in app pod %v", stdErr)
			return false, nil
		}
		s := resource.MustParse(strings.TrimSpace(output))
		actualSize, err := helpers.RoundUpToGiB(s)
		if err != nil {
			return false, err
		}
		s = resource.MustParse(size)
		expectedSize, err := helpers.RoundUpToGiB(s)
		if err != nil {
			return false, err
		}
		if actualSize != expectedSize {
			e2elog.Logf("expected size %s found %s information", size, output)
			return false, nil
		}
		return true, nil
	})
}
<commit_msg>e2e: compare resource.Quantity with Equals() instead of operator<commit_after>package e2e

import (
	"context"
	"fmt"
	"strings"
	"time"

	. "github.com/onsi/gomega" // nolint
	v1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/api/resource"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/wait"
	"k8s.io/client-go/kubernetes"
	"k8s.io/cloud-provider/volume/helpers"
	"k8s.io/kubernetes/test/e2e/framework"
	e2elog "k8s.io/kubernetes/test/e2e/framework/log"
)

func expandPVCSize(c kubernetes.Interface, pvc *v1.PersistentVolumeClaim, size string, t int) error {
	pvcName := pvc.Name
	updatedPVC := pvc.DeepCopy()
	var err error

	updatedPVC, err = c.CoreV1().PersistentVolumeClaims(pvc.Namespace).Get(context.TODO(), pvcName, metav1.GetOptions{})
	if err != nil {
		return fmt.Errorf("error fetching pvc %q with %w", pvcName, err)
	}
	timeout := time.Duration(t) * time.Minute

	updatedPVC.Spec.Resources.Requests[v1.ResourceStorage] = resource.MustParse(size)
	_, err = c.CoreV1().PersistentVolumeClaims(updatedPVC.Namespace).Update(context.TODO(), updatedPVC, metav1.UpdateOptions{})
	Expect(err).Should(BeNil())

	start := time.Now()
	e2elog.Logf("Waiting up to %v to be in Resized state", pvc)
	return wait.PollImmediate(poll, timeout, func() (bool, error) {
		e2elog.Logf("waiting for PVC %s (%d seconds elapsed)", updatedPVC.Name, int(time.Since(start).Seconds()))
		updatedPVC, err = c.CoreV1().PersistentVolumeClaims(updatedPVC.Namespace).Get(context.TODO(), pvcName, metav1.GetOptions{})
		if err != nil {
			e2elog.Logf("Error getting pvc in namespace: '%s': %v", updatedPVC.Namespace, err)
			if isRetryableAPIError(err) {
				return false, nil
			}
			return false, err
		}
		pvcConditions := updatedPVC.Status.Conditions
		if len(pvcConditions) > 0 {
			e2elog.Logf("pvc state %v", pvcConditions[0].Type)
			if pvcConditions[0].Type == v1.PersistentVolumeClaimResizing || pvcConditions[0].Type == v1.PersistentVolumeClaimFileSystemResizePending {
				return false, nil
			}
		}

		if !updatedPVC.Status.Capacity[v1.ResourceStorage].Equal(resource.MustParse(size)) {
			e2elog.Logf("current size in status %v,expected size %v", updatedPVC.Status.Capacity[v1.ResourceStorage], resource.MustParse(size))
			return false, nil
		}
		return true, nil
	})
}

func resizePVCAndValidateSize(pvcPath, appPath string, f *framework.Framework) error {
	size := "1Gi"
	expandSize := "10Gi"
	pvc, err := loadPVC(pvcPath)
	if err != nil {
		return err
	}
	pvc.Namespace = f.UniqueName

	resizePvc, err := loadPVC(pvcPath)
	if err != nil {
		return err
	}
	resizePvc.Namespace = f.UniqueName

	app, err := loadApp(appPath)
	if err != nil {
		return err
	}
	pvc.Spec.Resources.Requests[v1.ResourceStorage] = resource.MustParse(size)
	app.Labels = map[string]string{"app": "resize-pvc"}
	app.Namespace = f.UniqueName

	err = createPVCAndApp("", f, pvc, app, deployTimeout)
	if err != nil {
		return err
	}

	opt := metav1.ListOptions{
		LabelSelector: "app=resize-pvc",
	}

	pvc, err = f.ClientSet.CoreV1().PersistentVolumeClaims(pvc.Namespace).Get(context.TODO(), pvc.Name, metav1.GetOptions{})
	if err != nil {
		return err
	}
	if *pvc.Spec.VolumeMode == v1.PersistentVolumeFilesystem {
		err = checkDirSize(app, f, &opt, size)
		if err != nil {
			return err
		}
	}

	if *pvc.Spec.VolumeMode == v1.PersistentVolumeBlock {
		err = checkDeviceSize(app, f, &opt, size)
		if err != nil {
			return err
		}
	}
	// resize PVC
	err = expandPVCSize(f.ClientSet, resizePvc, expandSize, deployTimeout)
	if err != nil {
		return err
	}
	// wait for application pod to come up after resize
	err = waitForPodInRunningState(app.Name, app.Namespace, f.ClientSet, deployTimeout)
	if err != nil {
		return err
	}
	if *pvc.Spec.VolumeMode == v1.PersistentVolumeFilesystem {
		err = checkDirSize(app, f, &opt, expandSize)
		if err != nil {
			return err
		}
	}

	if *pvc.Spec.VolumeMode == v1.PersistentVolumeBlock {
		err = checkDeviceSize(app, f, &opt, expandSize)
		if err != nil {
			return err
		}
	}
	err = deletePVCAndApp("", f, resizePvc, app)
	return err
}

func checkDirSize(app *v1.Pod, f *framework.Framework, opt *metav1.ListOptions, size string) error {
	cmd := getDirSizeCheckCmd(app.Spec.Containers[0].VolumeMounts[0].MountPath)
	return checkAppMntSize(f, opt, size, cmd, app.Namespace, deployTimeout)
}

func checkDeviceSize(app *v1.Pod, f *framework.Framework, opt *metav1.ListOptions, size string) error {
	cmd := getDeviceSizeCheckCmd(app.Spec.Containers[0].VolumeDevices[0].DevicePath)
	return checkAppMntSize(f, opt, size, cmd, app.Namespace, deployTimeout)
}

func getDirSizeCheckCmd(dirPath string) string {
	return fmt.Sprintf("df -h|grep %s |awk '{print $2}'", dirPath)
}

func getDeviceSizeCheckCmd(devPath string) string {
	return fmt.Sprintf("blockdev --getsize64 %s", devPath)
}

func checkAppMntSize(f *framework.Framework, opt *metav1.ListOptions, size, cmd, ns string, t int) error {
	timeout := time.Duration(t) * time.Minute
	start := time.Now()

	return wait.PollImmediate(poll, timeout, func() (bool, error) {
		e2elog.Logf("executing cmd %s (%d seconds elapsed)", cmd, int(time.Since(start).Seconds()))
		output, stdErr, err := execCommandInPod(f, cmd, ns, opt)
		if err != nil {
			return false, err
		}
		if stdErr != "" {
			e2elog.Logf("failed to execute command in app pod %v", stdErr)
			return false, nil
		}
		s := resource.MustParse(strings.TrimSpace(output))
		actualSize, err := helpers.RoundUpToGiB(s)
		if err != nil {
			return false, err
		}
		s = resource.MustParse(size)
		expectedSize, err := helpers.RoundUpToGiB(s)
		if err != nil {
			return false, err
		}
		if actualSize != expectedSize {
			e2elog.Logf("expected size %s found %s information", size, output)
			return false, nil
		}
		return true, nil
	})
}
<|endoftext|>


<commit_before>package main

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

import (
	"database/sql"
	"fmt"
	"github.com/apache/incubator-trafficcontrol/traffic_monitor_golang/common/log"
	"github.com/apache/incubator-trafficcontrol/traffic_ops/tocookie"
	"net/http"
	"time"
)

const ServerName = "traffic_ops_golang" + "/" + Version

func wrapHeaders(h RegexHandlerFunc) RegexHandlerFunc {
	return func(w http.ResponseWriter, r *http.Request, p ParamMap) {
		w.Header().Set("Access-Control-Allow-Credentials", "true")
		w.Header().Set("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept")
		w.Header().Set("Access-Control-Allow-Methods", "POST,GET,OPTIONS,PUT,DELETE")
		w.Header().Set("Access-Control-Allow-Origin", "*")
		w.Header().Set("X-Server-Name", ServerName)
		h(w, r, p)
	}
}

func wrapAuth(h RegexHandlerFunc, noAuth bool, secret string, privLevelStmt *sql.Stmt, privLevelRequired int) RegexHandlerFunc {
	if noAuth {
		return h
	}
	return func(w http.ResponseWriter, r *http.Request, p ParamMap) {
		// TODO remove, and make username available to wrapLogTime
		start := time.Now()
		iw := &Interceptor{w: w}
		w = iw
		username := "-"
		defer func() {
			log.EventfRaw(`%s - %s [%s] "%v %v HTTP/1.1" %v %v %v "%v"`, r.RemoteAddr, username, time.Now().Format(AccessLogTimeFormat), r.Method, r.URL.Path, iw.code, iw.byteCount, int(time.Now().Sub(start)/time.Millisecond), r.UserAgent())
		}()

		handleUnauthorized := func(reason string) {
			status := http.StatusUnauthorized
			w.WriteHeader(status)
			fmt.Fprintf(w, http.StatusText(status))
		}

		cookie, err := r.Cookie(tocookie.Name)
		if err != nil {
			handleUnauthorized("error getting cookie: " + err.Error())
			return
		}

		if cookie == nil {
			handleUnauthorized("no auth cookie")
			return
		}

		oldCookie, err := tocookie.Parse(secret, cookie.Value)
		if err != nil {
			handleUnauthorized("cookie error: " + err.Error())
			return
		}

		username = oldCookie.AuthData
		if !hasPrivLevel(privLevelStmt, username, privLevelRequired) {
			handleUnauthorized("insufficient privileges")
			return
		}

		newCookieVal := tocookie.Refresh(oldCookie, secret)
		http.SetCookie(w, &http.Cookie{Name: tocookie.Name, Value: newCookieVal})

		h(w, r, p)
	}
}

const AccessLogTimeFormat = "02/Jan/2006:15:04:05 -0700"

func wrapAccessLog(secret string, h http.Handler) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		iw := &Interceptor{w: w}
		user := "-"
		cookie, err := r.Cookie(tocookie.Name)
		if err == nil && cookie != nil {
			cookie, err := tocookie.Parse(secret, cookie.Value)
			if err == nil {
				user = cookie.AuthData
			}
		}
		start := time.Now()
		defer func() {
			log.EventfRaw(`%s - %s [%s] "%v %v HTTP/1.1" %v %v %v "%v"`, r.RemoteAddr, user, time.Now().Format(AccessLogTimeFormat), r.Method, r.URL.Path, iw.code, iw.byteCount, int(time.Now().Sub(start)/time.Millisecond), r.UserAgent())
		}()
		h.ServeHTTP(iw, r)
	}
}

type Interceptor struct {
	w         http.ResponseWriter
	code      int
	byteCount int
}

func (i *Interceptor) WriteHeader(rc int) {
	i.w.WriteHeader(rc)
	i.code = rc
}

func (i *Interceptor) Write(b []byte) (int, error) {
	wi, werr := i.w.Write(b)
	i.byteCount += wi
	if i.code == 0 {
		i.code = 200
	}
	return wi, werr
}

func (i *Interceptor) Header() http.Header {
	return i.w.Header()
}
<commit_msg>Add TO Golang Set-Cookie to CORS allow headers<commit_after>package main

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

import (
	"database/sql"
	"fmt"
	"github.com/apache/incubator-trafficcontrol/traffic_monitor_golang/common/log"
	"github.com/apache/incubator-trafficcontrol/traffic_ops/tocookie"
	"net/http"
	"time"
)

const ServerName = "traffic_ops_golang" + "/" + Version

func wrapHeaders(h RegexHandlerFunc) RegexHandlerFunc {
	return func(w http.ResponseWriter, r *http.Request, p ParamMap) {
		w.Header().Set("Access-Control-Allow-Credentials", "true")
		w.Header().Set("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Set-Cookie, Cookie")
		w.Header().Set("Access-Control-Allow-Methods", "POST,GET,OPTIONS,PUT,DELETE")
		w.Header().Set("Access-Control-Allow-Origin", "*")
		w.Header().Set("X-Server-Name", ServerName)
		h(w, r, p)
	}
}

func wrapAuth(h RegexHandlerFunc, noAuth bool, secret string, privLevelStmt *sql.Stmt, privLevelRequired int) RegexHandlerFunc {
	if noAuth {
		return h
	}
	return func(w http.ResponseWriter, r *http.Request, p ParamMap) {
		// TODO remove, and make username available to wrapLogTime
		start := time.Now()
		iw := &Interceptor{w: w}
		w = iw
		username := "-"
		defer func() {
			log.EventfRaw(`%s - %s [%s] "%v %v HTTP/1.1" %v %v %v "%v"`, r.RemoteAddr, username, time.Now().Format(AccessLogTimeFormat), r.Method, r.URL.Path, iw.code, iw.byteCount, int(time.Now().Sub(start)/time.Millisecond), r.UserAgent())
		}()

		handleUnauthorized := func(reason string) {
			status := http.StatusUnauthorized
			w.WriteHeader(status)
			fmt.Fprintf(w, http.StatusText(status))
		}

		cookie, err := r.Cookie(tocookie.Name)
		if err != nil {
			handleUnauthorized("error getting cookie: " + err.Error())
			return
		}

		if cookie == nil {
			handleUnauthorized("no auth cookie")
			return
		}

		oldCookie, err := tocookie.Parse(secret, cookie.Value)
		if err != nil {
			handleUnauthorized("cookie error: " + err.Error())
			return
		}

		username = oldCookie.AuthData
		if !hasPrivLevel(privLevelStmt, username, privLevelRequired) {
			handleUnauthorized("insufficient privileges")
			return
		}

		newCookieVal := tocookie.Refresh(oldCookie, secret)
		http.SetCookie(w, &http.Cookie{Name: tocookie.Name, Value: newCookieVal})

		h(w, r, p)
	}
}

const AccessLogTimeFormat = "02/Jan/2006:15:04:05 -0700"

func wrapAccessLog(secret string, h http.Handler) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		iw := &Interceptor{w: w}
		user := "-"
		cookie, err := r.Cookie(tocookie.Name)
		if err == nil && cookie != nil {
			cookie, err := tocookie.Parse(secret, cookie.Value)
			if err == nil {
				user = cookie.AuthData
			}
		}
		start := time.Now()
		defer func() {
			log.EventfRaw(`%s - %s [%s] "%v %v HTTP/1.1" %v %v %v "%v"`, r.RemoteAddr, user, time.Now().Format(AccessLogTimeFormat), r.Method, r.URL.Path, iw.code, iw.byteCount, int(time.Now().Sub(start)/time.Millisecond), r.UserAgent())
		}()
		h.ServeHTTP(iw, r)
	}
}

type Interceptor struct {
	w         http.ResponseWriter
	code      int
	byteCount int
}

func (i *Interceptor) WriteHeader(rc int) {
	i.w.WriteHeader(rc)
	i.code = rc
}

func (i *Interceptor) Write(b []byte) (int, error) {
	wi, werr := i.w.Write(b)
	i.byteCount += wi
	if i.code == 0 {
		i.code = 200
	}
	return wi, werr
}

func (i *Interceptor) Header() http.Header {
	return i.w.Header()
}
<|endoftext|>


<commit_before>package ohauth

import (
	"encoding/json"
	"errors"
	"net/url"
	"strings"
)

var ErrNotAbsoluteURL = errors.New("absolute urls with host are required")

// StrictURL is similar to the standard net/url.URL type except that it can be
// json marshalled and unmarshalled and forces all parsed urls to https protocol
type StrictURL url.URL

func ParseURL(raw string) (*StrictURL, error) {
	u, err := url.Parse(raw)
	if err != nil {
		return nil, err
	}
	u.Host = strings.TrimSpace(u.Host)
	u.Scheme = "https"
	u.RawQuery = ""
	u.Fragment = "_=_"
	if u.Host == "" || !u.IsAbs() {
		return nil, ErrNotAbsoluteURL
	}
	return (*StrictURL)(u), err
}

func MustParseURL(raw string) *StrictURL {
	u, err := ParseURL(raw)
	if err != nil {
		panic(err)
	}
	return u
}

func (u *StrictURL) MarshalJSON() ([]byte, error) {
	c := (*url.URL)(u)
	return json.Marshal(c.String())
}

func (u *StrictURL) UnmarshalJSON(b []byte) error {
	var s string
	if err := json.Unmarshal(b, &s); err != nil {
		return err
	}
	in, err := url.Parse(s)
	if err != nil {
		return err
	}
	*u = StrictURL(*in)
	return nil
}

func (u *StrictURL) Unbox() *url.URL {
	return (*url.URL)(u)
}

func (u *StrictURL) String() string {
	if u == nil {
		return ""
	}
	return u.Unbox().String()
}

func (u *StrictURL) Compare(u2 *StrictURL) bool {
	if u == nil || u2 == nil {
		return false
	}
	s1 := u.String()
	s2 := u2.String()
	return s1 != "" && s2 != "" && s1 == s2
}

func (u *StrictURL) Clone() *StrictURL {
	c, err := ParseURL(u.String())
	if err != nil {
		panic(err)
	}
	return c
}

func (u *StrictURL) StringWithParams(v url.Values) string {
	c := u.Clone()
	c.RawQuery = v.Encode()
	return c.String()
}

func (u *StrictURL) StringWithFragment(v url.Values) string {
	c := u.Clone()
	c.Fragment = v.Encode()
	return c.String()
}
<commit_msg>added comments<commit_after>package ohauth

import (
	"encoding/json"
	"errors"
	"net/url"
	"strings"
)

// ErrNotAbsoluteURL is returned when a parsed URL is not absolute i.e. does not
// have scheme or host
var ErrNotAbsoluteURL = errors.New("absolute urls with host are required")

// StrictURL is similar to the standard net/url.URL type except that it can be
// json marshalled and unmarshalled and forces all parsed urls to https protocol
type StrictURL url.URL

// ParseURL parses a string url and coerces the scheme to https, clears the
// querystring, sets fragment to '_=_' to create a StrictURL instance. The raw
// url must be absolute (host and scheme must be set)
func ParseURL(raw string) (*StrictURL, error) {
	u, err := url.Parse(raw)
	if err != nil {
		return nil, err
	}
	u.Host = strings.TrimSpace(u.Host)
	u.Scheme = "https"
	u.RawQuery = ""
	u.Fragment = "_=_"
	if u.Host == "" || !u.IsAbs() {
		return nil, ErrNotAbsoluteURL
	}
	return (*StrictURL)(u), err
}

// MustParseURL is the same as ParseURL but panic on error instead
func MustParseURL(raw string) *StrictURL {
	u, err := ParseURL(raw)
	if err != nil {
		panic(err)
	}
	return u
}

// MarshalJSON implements the json.Marshaler interface
func (u *StrictURL) MarshalJSON() ([]byte, error) {
	c := (*url.URL)(u)
	return json.Marshal(c.String())
}

// UnmarshalJSON implements the json.Unmarshaler that correctly parses a
// StrictURL
func (u *StrictURL) UnmarshalJSON(b []byte) error {
	var s string
	if err := json.Unmarshal(b, &s); err != nil {
		return err
	}
	in, err := url.Parse(s)
	if err != nil {
		return err
	}
	*u = StrictURL(*in)
	return nil
}

func (u *StrictURL) String() string {
	if u == nil {
		return ""
	}
	unbox := (*url.URL)(u)

	return unbox.String()
}

// Compare determines if two StrictURL's are the same using simple string
// comparison. If either instance is nil the result is false.
func (u *StrictURL) Compare(u2 *StrictURL) bool {
	if u == nil || u2 == nil {
		return false
	}
	s1 := u.String()
	s2 := u2.String()
	return s1 != "" && s2 != "" && s1 == s2
}

// Clone creates a new copy of the StrictURL
func (u *StrictURL) Clone() *StrictURL {
	c, err := ParseURL(u.String())
	if err != nil {
		panic(err)
	}
	return c
}

// StringWithParams returns a string representation of a StrictURL with
// the specified query parameters
func (u *StrictURL) StringWithParams(v url.Values) string {
	c := u.Clone()
	c.RawQuery = v.Encode()
	return c.String()
}

// StringWithFragment returns a string representation of a StrictURL with
// the specified fragment
func (u *StrictURL) StringWithFragment(v url.Values) string {
	c := u.Clone()
	c.Fragment = v.Encode()
	return c.String()
}
<|endoftext|>


<commit_before>package collection

import (
	"fmt"

	"github.com/ivanilves/lstags/repository"
	"github.com/ivanilves/lstags/tag"
)

func refHasTags(ref string, tags map[string][]*tag.Tag) bool {
	for r := range tags {
		if r == ref {
			return true
		}
	}

	return false
}

func contains(slice []string, str string) bool {
	for _, s := range slice {
		if s == str {
			return true
		}
	}

	return false
}

// New creates a new collection of API resources
func New(refs []string, tags map[string][]*tag.Tag) (*Collection, error) {
	repos := make(map[string]*repository.Repository)

	for _, ref := range refs {
		repo, err := repository.ParseRef(ref)
		if err != nil {
			return nil, err
		}

		repos[ref] = repo

		if !refHasTags(ref, tags) {
			return nil, fmt.Errorf("repository reference has no tags: %s", ref)
		}
	}

	for ref := range tags {
		if !contains(refs, ref) {
			return nil, fmt.Errorf("repository has tags, but not referenced: %s", ref)
		}
	}

	return &Collection{refs: refs, repos: repos, tags: tags}, nil
}

// Collection of API resources received from a registry or Docker daemon query
type Collection struct {
	refs  []string
	repos map[string]*repository.Repository
	tags  map[string][]*tag.Tag
}

// Refs returns all repository references from collection
func (cn *Collection) Refs() []string {
	return cn.refs
}

// Repos returns all repository structures from collection
func (cn *Collection) Repos() []*repository.Repository {
	repos := make([]*repository.Repository, cn.RepoCount())

	for i, ref := range cn.Refs() {
		repos[i] = cn.repos[ref]
	}

	return repos
}

// Repo returns repo structure, if it is present in collection (nil if not)
func (cn *Collection) Repo(ref string) *repository.Repository {
	for _, r := range cn.Refs() {
		if r == ref {
			return cn.repos[ref]
		}
	}

	return nil
}

// Tags returns slice of tag structures, if it is present in collection (nil if not)
func (cn *Collection) Tags(ref string) []*tag.Tag {
	repo := cn.Repo(ref)
	if repo == nil {
		return nil
	}

	return cn.tags[ref]
}

// TagMap returns [name]*Tag map of tag structures, if it is present in collection (nil if not)
func (cn *Collection) TagMap(ref string) map[string]*tag.Tag {
	tags := cn.Tags(ref)
	if tags == nil {
		return nil
	}

	tagMap := make(map[string]*tag.Tag)
	for _, tg := range tags {
		tagMap[tg.Name()] = tg
	}

	return tagMap
}

// RepoCount counts total repo number inside the collection
func (cn *Collection) RepoCount() int {
	return len(cn.refs)
}

// TagCount counts total tag number inside the collection
func (cn *Collection) TagCount() int {
	i := 0

	for _, v := range cn.tags {
		i += len(v)
	}

	return i
}

// TaggedRefs returns a slice of [REGISTRY/]REPOSITORY:TAG references for all tags present in collection
func (cn *Collection) TaggedRefs() []string {
	taggedRefs := make([]string, 0)

	for _, ref := range cn.Refs() {
		repo := cn.Repo(ref)

		for _, tg := range cn.Tags(ref) {
			taggedRef := fmt.Sprintf("%s:%s", repo.Name(), tg.Name())
			taggedRefs = append(taggedRefs, taggedRef)
		}
	}

	return taggedRefs
}
<commit_msg>docs(api/v1/collection): update comments for GoDoc<commit_after>// Package collection provides a "container" structure to store Docker
// registry query results in a well organized and easily accessible form.
package collection

import (
	"fmt"

	"github.com/ivanilves/lstags/repository"
	"github.com/ivanilves/lstags/tag"
)

func refHasTags(ref string, tags map[string][]*tag.Tag) bool {
	for r := range tags {
		if r == ref {
			return true
		}
	}

	return false
}

func contains(slice []string, str string) bool {
	for _, s := range slice {
		if s == str {
			return true
		}
	}

	return false
}

// New creates a collection of API resources from passed repository references and tags
func New(refs []string, tags map[string][]*tag.Tag) (*Collection, error) {
	repos := make(map[string]*repository.Repository)

	for _, ref := range refs {
		repo, err := repository.ParseRef(ref)
		if err != nil {
			return nil, err
		}

		repos[ref] = repo

		if !refHasTags(ref, tags) {
			return nil, fmt.Errorf("repository reference has no tags: %s", ref)
		}
	}

	for ref := range tags {
		if !contains(refs, ref) {
			return nil, fmt.Errorf("repository has tags, but not referenced: %s", ref)
		}
	}

	return &Collection{refs: refs, repos: repos, tags: tags}, nil
}

// Collection of API resources received from a registry or Docker daemon query
type Collection struct {
	refs  []string
	repos map[string]*repository.Repository
	tags  map[string][]*tag.Tag
}

// Refs returns all repository references from collection
func (cn *Collection) Refs() []string {
	return cn.refs
}

// Repos returns all repository structures from collection
func (cn *Collection) Repos() []*repository.Repository {
	repos := make([]*repository.Repository, cn.RepoCount())

	for i, ref := range cn.Refs() {
		repos[i] = cn.repos[ref]
	}

	return repos
}

// Repo returns repo structure, if it is present in collection (nil if not)
func (cn *Collection) Repo(ref string) *repository.Repository {
	for _, r := range cn.Refs() {
		if r == ref {
			return cn.repos[ref]
		}
	}

	return nil
}

// Tags returns slice of tag structures, if it is present in collection (nil if not)
func (cn *Collection) Tags(ref string) []*tag.Tag {
	repo := cn.Repo(ref)
	if repo == nil {
		return nil
	}

	return cn.tags[ref]
}

// TagMap returns [name]*Tag map of tag structures, if it is present in collection (nil if not)
func (cn *Collection) TagMap(ref string) map[string]*tag.Tag {
	tags := cn.Tags(ref)
	if tags == nil {
		return nil
	}

	tagMap := make(map[string]*tag.Tag)
	for _, tg := range tags {
		tagMap[tg.Name()] = tg
	}

	return tagMap
}

// RepoCount counts total repo number inside the collection
func (cn *Collection) RepoCount() int {
	return len(cn.refs)
}

// TagCount counts total tag number inside the collection
func (cn *Collection) TagCount() int {
	i := 0

	for _, v := range cn.tags {
		i += len(v)
	}

	return i
}

// TaggedRefs returns a slice of [REGISTRY/]REPOSITORY:TAG references for all tags present in collection
func (cn *Collection) TaggedRefs() []string {
	taggedRefs := make([]string, 0)

	for _, ref := range cn.Refs() {
		repo := cn.Repo(ref)

		for _, tg := range cn.Tags(ref) {
			taggedRef := fmt.Sprintf("%s:%s", repo.Name(), tg.Name())
			taggedRefs = append(taggedRefs, taggedRef)
		}
	}

	return taggedRefs
}
<|endoftext|>


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

package common

import "github.com/juju/juju/state"

var (
	MachineJobFromParams = machineJobFromParams
	ValidateNewFacade    = validateNewFacade
	WrapNewFacade        = wrapNewFacade
	NilFacadeRecord      = facadeRecord{}
	EnvtoolsFindTools    = &envtoolsFindTools
	SendMetrics          = &sendMetrics
)

type Patcher interface {
	PatchValue(dest, value interface{})
}

// SanitizeFacades patches Facades so that for the lifetime of the test we get
// a clean slate to work from, and will not accidentally overrite/mutate the
// real facade registry.
func SanitizeFacades(patcher Patcher) {
	emptyFacades := &FacadeRegistry{}
	patcher.PatchValue(&Facades, emptyFacades)
}

type Versions versions

func DescriptionFromVersions(name string, vers Versions) FacadeDescription {
	return descriptionFromVersions(name, versions(vers))
}

func NewMultiNotifyWatcher(w ...state.NotifyWatcher) state.NotifyWatcher {
	mw := newMultiNotifyWatcher(w...)
	return mw
}
<commit_msg>apiserver/common: fix tests<commit_after>// Copyright 2014 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package common

var (
	MachineJobFromParams = machineJobFromParams
	ValidateNewFacade    = validateNewFacade
	WrapNewFacade        = wrapNewFacade
	NilFacadeRecord      = facadeRecord{}
	EnvtoolsFindTools    = &envtoolsFindTools
	SendMetrics          = &sendMetrics
)

type Patcher interface {
	PatchValue(dest, value interface{})
}

// SanitizeFacades patches Facades so that for the lifetime of the test we get
// a clean slate to work from, and will not accidentally overrite/mutate the
// real facade registry.
func SanitizeFacades(patcher Patcher) {
	emptyFacades := &FacadeRegistry{}
	patcher.PatchValue(&Facades, emptyFacades)
}

type Versions versions

func DescriptionFromVersions(name string, vers Versions) FacadeDescription {
	return descriptionFromVersions(name, versions(vers))
}
<|endoftext|>


<commit_before>package main

const FragmentShader = `
#version 100

precision mediump float;

varying vec3 v_color;

void main() {
	gl_FragColor = vec4(v_color, 1.0);
}
`
<commit_msg>make things that are farther way slightly darker<commit_after>package main

const FragmentShader = `
#version 100

precision mediump float;

varying vec3 v_color;

void main() {
	gl_FragColor = vec4(v_color - (0.01 / gl_FragCoord.w), 1.0);
}
`
<|endoftext|>