<commit_before>package vcs

import (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"text/template"
	"time"

	"github.com/hashicorp/errwrap"
)

var TimeSpentNotesRef = "time-spent"

var PostCheckoutTmpl = template.Must(template.New("name").Parse(`#!/bin/sh
# when checkout is a branch, start timer
if [ $3 -eq 1 ]; then
   glass start;
fi
`))

var PrepCommitTmpl = template.Must(template.New("name").Parse(`#!/bin/sh
# only add time to template and message sources
# @see http://git-scm.com/docs/githooks#_prepare_commit_msg
case "$2" in
message|template)
	printf "$(cat $1)$(glass status --time-only)" > "$1" ;;
esac
`))

var PostCommitTmpl = template.Must(template.New("name").Parse(`#!/bin/sh
#always reset after commit
glass lap
`))

type Git struct {
	dir string
}

func NewGit(dir string) *Git {
	return &Git{
		dir: filepath.Join(dir, ".git"),
	}
}

func (g *Git) DefaultRemote() string { return "origin" }
func (g *Git) Name() string          { return "git" }
func (g *Git) Supported() bool {
	fi, err := os.Stat(g.dir)
	if err != nil || !fi.IsDir() {
		return false
	}

	return true
}

func (g *Git) Log(t time.Duration) error {
	args := []string{"notes", "--ref=" + TimeSpentNotesRef, "add", "-f", "-m", fmt.Sprintf("total=%s", t)}
	cmd := exec.Command("git", args...)
	err := cmd.Run()
	if err != nil {
		return errwrap.Wrapf(fmt.Sprintf("Failed to log time '%s' using git command %s: {{err}}", t, args), err)
	}

	return nil
}

func (g *Git) Fetch(remote string) error {
	args := []string{"fetch", remote, fmt.Sprintf("refs/notes/%s:refs/notes/%s", TimeSpentNotesRef, TimeSpentNotesRef)}
	cmd := exec.Command("git", args...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	err := cmd.Run()
	if err != nil {
		return errwrap.Wrapf(fmt.Sprintf("Failed to fetch from remote '%s' using git command %s: {{err}}", remote, args), err)
	}

	return nil
}

func (g *Git) Push(remote string) error {
	args := []string{"push", remote, fmt.Sprintf("refs/notes/%s", TimeSpentNotesRef)}
	cmd := exec.Command("git", args...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	err := cmd.Run()
	if err != nil {
		return errwrap.Wrapf(fmt.Sprintf("Failed to push to remote '%s' using git command %s: {{err}}", remote, args), err)
	}

	return nil
}

func (g *Git) Hook() error {
	hpath := filepath.Join(g.dir, "hooks")

	//post checkout: start()
	postchf, err := os.Create(filepath.Join(hpath, "post-checkout"))
	if err != nil {
		return errwrap.Wrapf(fmt.Sprintf("Failed to create post-checkout '%s': {{err}}", postchf.Name()), err)
	}

	err = postchf.Chmod(0766)
	if err != nil {
		return errwrap.Wrapf(fmt.Sprintf("Failed to make post-checkout file '%s' executable: {{err}}", hpath), err)
	}

	err = PostCheckoutTmpl.Execute(postchf, struct{}{})
	if err != nil {
		return errwrap.Wrapf("Failed to run post-checkout template: {{err}}", err)
	}

	//prepare commit msg: status()
	prepcof, err := os.Create(filepath.Join(hpath, "prepare-commit-msg"))
	if err != nil {
		return errwrap.Wrapf(fmt.Sprintf("Failed to create prepare-commit-msg  '%s': {{err}}", postchf.Name()), err)
	}

	err = prepcof.Chmod(0766)
	if err != nil {
		return errwrap.Wrapf(fmt.Sprintf("Failed to make prepare-commit-msg file '%s' executable: {{err}}", hpath), err)
	}

	err = PrepCommitTmpl.Execute(prepcof, struct{}{})
	if err != nil {
		return errwrap.Wrapf("Failed to run post-commit template: {{err}}", err)
	}

	//post commit: lap()
	postcof, err := os.Create(filepath.Join(hpath, "post-commit"))
	if err != nil {
		return errwrap.Wrapf(fmt.Sprintf("Failed to create post-commit  '%s': {{err}}", postchf.Name()), err)
	}

	err = postcof.Chmod(0766)
	if err != nil {
		return errwrap.Wrapf(fmt.Sprintf("Failed to make post-commit file '%s' executable: {{err}}", hpath), err)
	}

	err = PostCommitTmpl.Execute(postcof, struct{}{})
	if err != nil {
		return errwrap.Wrapf("Failed to run post-commit template: {{err}}", err)
	}

	return nil
}
<commit_msg>now installs a post-update hook that automatically pushes time data as well [spent 9m20s]<commit_after>package vcs

import (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"text/template"
	"time"

	"github.com/hashicorp/errwrap"
)

var TimeSpentNotesRef = "time-spent"

var PostCheckoutTmpl = template.Must(template.New("name").Parse(`#!/bin/sh
# when checkout is a branch, start timer
if [ $3 -eq 1 ]; then
   glass start;
fi
`))

var PrepCommitTmpl = template.Must(template.New("name").Parse(`#!/bin/sh
# only add time to template and message sources
# @see http://git-scm.com/docs/githooks#_prepare_commit_msg
case "$2" in
message|template)
	printf "$(cat $1)$(glass status --time-only)" > "$1" ;;
esac
`))

var PostCommitTmpl = template.Must(template.New("name").Parse(`#!/bin/sh
#always reset after commit
glass lap
`))

var PostUpdateTmpl = template.Must(template.New("name").Parse(`#!/bin/sh
#push time data after push
glass push
`))

type Git struct {
	dir string
}

func NewGit(dir string) *Git {
	return &Git{
		dir: filepath.Join(dir, ".git"),
	}
}

func (g *Git) DefaultRemote() string { return "origin" }
func (g *Git) Name() string          { return "git" }
func (g *Git) Supported() bool {
	fi, err := os.Stat(g.dir)
	if err != nil || !fi.IsDir() {
		return false
	}

	return true
}

func (g *Git) Log(t time.Duration) error {
	args := []string{"notes", "--ref=" + TimeSpentNotesRef, "add", "-f", "-m", fmt.Sprintf("total=%s", t)}
	cmd := exec.Command("git", args...)
	err := cmd.Run()
	if err != nil {
		return errwrap.Wrapf(fmt.Sprintf("Failed to log time '%s' using git command %s: {{err}}", t, args), err)
	}

	return nil
}

func (g *Git) Fetch(remote string) error {
	args := []string{"fetch", remote, fmt.Sprintf("refs/notes/%s:refs/notes/%s", TimeSpentNotesRef, TimeSpentNotesRef)}
	cmd := exec.Command("git", args...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	err := cmd.Run()
	if err != nil {
		return errwrap.Wrapf(fmt.Sprintf("Failed to fetch from remote '%s' using git command %s: {{err}}", remote, args), err)
	}

	return nil
}

func (g *Git) Push(remote string) error {
	args := []string{"push", remote, fmt.Sprintf("refs/notes/%s", TimeSpentNotesRef)}
	cmd := exec.Command("git", args...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	err := cmd.Run()
	if err != nil {
		return errwrap.Wrapf(fmt.Sprintf("Failed to push to remote '%s' using git command %s: {{err}}", remote, args), err)
	}

	return nil
}

func (g *Git) Hook() error {
	hpath := filepath.Join(g.dir, "hooks")

	//post checkout: start()
	postchf, err := os.Create(filepath.Join(hpath, "post-checkout"))
	if err != nil {
		return errwrap.Wrapf(fmt.Sprintf("Failed to create post-checkout '%s': {{err}}", postchf.Name()), err)
	}

	err = postchf.Chmod(0766)
	if err != nil {
		return errwrap.Wrapf(fmt.Sprintf("Failed to make post-checkout file '%s' executable: {{err}}", hpath), err)
	}

	err = PostCheckoutTmpl.Execute(postchf, struct{}{})
	if err != nil {
		return errwrap.Wrapf("Failed to run post-checkout template: {{err}}", err)
	}

	//prepare commit msg: status()
	prepcof, err := os.Create(filepath.Join(hpath, "prepare-commit-msg"))
	if err != nil {
		return errwrap.Wrapf(fmt.Sprintf("Failed to create prepare-commit-msg  '%s': {{err}}", postchf.Name()), err)
	}

	err = prepcof.Chmod(0766)
	if err != nil {
		return errwrap.Wrapf(fmt.Sprintf("Failed to make prepare-commit-msg file '%s' executable: {{err}}", hpath), err)
	}

	err = PrepCommitTmpl.Execute(prepcof, struct{}{})
	if err != nil {
		return errwrap.Wrapf("Failed to run post-commit template: {{err}}", err)
	}

	//post commit: lap()
	postcof, err := os.Create(filepath.Join(hpath, "post-commit"))
	if err != nil {
		return errwrap.Wrapf(fmt.Sprintf("Failed to create post-commit  '%s': {{err}}", postchf.Name()), err)
	}

	err = postcof.Chmod(0766)
	if err != nil {
		return errwrap.Wrapf(fmt.Sprintf("Failed to make post-commit file '%s' executable: {{err}}", hpath), err)
	}

	err = PostCommitTmpl.Execute(postcof, struct{}{})
	if err != nil {
		return errwrap.Wrapf("Failed to run post-commit template: {{err}}", err)
	}

	//post update: push()
	postuf, err := os.Create(filepath.Join(hpath, "post-update"))
	if err != nil {
		return errwrap.Wrapf(fmt.Sprintf("Failed to create post-update  '%s': {{err}}", postchf.Name()), err)
	}

	err = postuf.Chmod(0766)
	if err != nil {
		return errwrap.Wrapf(fmt.Sprintf("Failed to make post-update file '%s' executable: {{err}}", hpath), err)
	}

	err = PostUpdateTmpl.Execute(postuf, struct{}{})
	if err != nil {
		return errwrap.Wrapf("Failed to run post-update template: {{err}}", err)
	}

	return nil
}
<|endoftext|>


<commit_before>// --------  DO NOT EDIT --------
// This file is autogenerated by genversion.go during the release process.

package main

// Version autogenerated
const Version = "2015-08-28T19:20:08.123385413Z"
<commit_msg>Bump to new version<commit_after>// --------  DO NOT EDIT --------
// This file is autogenerated by genversion.go during the release process.

package main

// Version autogenerated
const Version = "2015-09-05T22:02:22.436080641Z"
<|endoftext|>


<commit_before>package main

const Version = "1.12"
<commit_msg>Bump version to 1.13<commit_after>package main

const Version = "1.13"
<|endoftext|>


<commit_before>package main

import (
	"fmt"

	"github.com/miquella/vaulted/lib"
)

const (
	VERSION = "2.4.unstable"
)

type Version struct{}

func (l *Version) Run(store vaulted.Store) error {
	fmt.Printf("Vaulted v%s\n", VERSION)
	return nil
}
<commit_msg>Bump version to v3.0.unstable<commit_after>package main

import (
	"fmt"

	"github.com/miquella/vaulted/lib"
)

const (
	VERSION = "3.0.unstable"
)

type Version struct{}

func (l *Version) Run(store vaulted.Store) error {
	fmt.Printf("Vaulted v%s\n", VERSION)
	return nil
}
<|endoftext|>


<commit_before>package main

const (
	GOMIG_MAJ_VERSION = 0
	GOMIG_MIN_VERSION = 2
)
<commit_msg>version: 0.3<commit_after>package main

const (
	GOMIG_MAJ_VERSION = 0
	GOMIG_MIN_VERSION = 3
)
<|endoftext|>


<commit_before>package main

const VERSION = "0.6.2-alpha3"
<commit_msg>:+1: Bump up the version 0.6.2<commit_after>package main

const VERSION = "0.6.2"
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013, 2014 The btcsuite developers
 * Copyright (c) 2015 The Decred developers
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

package main

import (
	"bytes"
	"fmt"
	"strings"
)

// semanticAlphabet
const semanticAlphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-"

// These constants define the application version and follow the semantic
// versioning 2.0.0 spec (http://semver.org/).
const (
	appMajor uint = 0
	appMinor uint = 0
	appPatch uint = 5

	// appPreRelease MUST only contain characters from semanticAlphabet
	// per the semantic versioning spec.
	appPreRelease = "alpha"
)

// appBuild is defined as a variable so it can be overridden during the build
// process with '-ldflags "-X main.appBuild foo' if needed.  It MUST only
// contain characters from semanticAlphabet per the semantic versioning spec.
var appBuild string

// version returns the application version as a properly formed string per the
// semantic versioning 2.0.0 spec (http://semver.org/).
func version() string {
	// Start with the major, minor, and path versions.
	version := fmt.Sprintf("%d.%d.%d", appMajor, appMinor, appPatch)

	// Append pre-release version if there is one.  The hyphen called for
	// by the semantic versioning spec is automatically appended and should
	// not be contained in the pre-release string.  The pre-release version
	// is not appended if it contains invalid characters.
	preRelease := normalizeVerString(appPreRelease)
	if preRelease != "" {
		version = fmt.Sprintf("%s-%s", version, preRelease)
	}

	// Append build metadata if there is any.  The plus called for
	// by the semantic versioning spec is automatically appended and should
	// not be contained in the build metadata string.  The build metadata
	// string is not appended if it contains invalid characters.
	build := normalizeVerString(appBuild)
	if build != "" {
		version = fmt.Sprintf("%s+%s", version, build)
	}

	return version
}

// normalizeVerString returns the passed string stripped of all characters which
// are not valid according to the semantic versioning guidelines for pre-release
// version and build metadata strings.  In particular they MUST only contain
// characters in semanticAlphabet.
func normalizeVerString(str string) string {
	result := bytes.Buffer{}
	for _, r := range str {
		if strings.ContainsRune(semanticAlphabet, r) {
			_, err := result.WriteRune(r)
			// Writing to a bytes.Buffer panics on OOM, and all
			// errors are unexpected.
			if err != nil {
				panic(err)
			}
		}
	}
	return result.String()
}
<commit_msg>Update to 0.0.6 for new release.<commit_after>/*
 * Copyright (c) 2013, 2014 The btcsuite developers
 * Copyright (c) 2015 The Decred developers
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

package main

import (
	"bytes"
	"fmt"
	"strings"
)

// semanticAlphabet
const semanticAlphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-"

// These constants define the application version and follow the semantic
// versioning 2.0.0 spec (http://semver.org/).
const (
	appMajor uint = 0
	appMinor uint = 0
	appPatch uint = 6

	// appPreRelease MUST only contain characters from semanticAlphabet
	// per the semantic versioning spec.
	appPreRelease = "alpha"
)

// appBuild is defined as a variable so it can be overridden during the build
// process with '-ldflags "-X main.appBuild foo' if needed.  It MUST only
// contain characters from semanticAlphabet per the semantic versioning spec.
var appBuild string

// version returns the application version as a properly formed string per the
// semantic versioning 2.0.0 spec (http://semver.org/).
func version() string {
	// Start with the major, minor, and path versions.
	version := fmt.Sprintf("%d.%d.%d", appMajor, appMinor, appPatch)

	// Append pre-release version if there is one.  The hyphen called for
	// by the semantic versioning spec is automatically appended and should
	// not be contained in the pre-release string.  The pre-release version
	// is not appended if it contains invalid characters.
	preRelease := normalizeVerString(appPreRelease)
	if preRelease != "" {
		version = fmt.Sprintf("%s-%s", version, preRelease)
	}

	// Append build metadata if there is any.  The plus called for
	// by the semantic versioning spec is automatically appended and should
	// not be contained in the build metadata string.  The build metadata
	// string is not appended if it contains invalid characters.
	build := normalizeVerString(appBuild)
	if build != "" {
		version = fmt.Sprintf("%s+%s", version, build)
	}

	return version
}

// normalizeVerString returns the passed string stripped of all characters which
// are not valid according to the semantic versioning guidelines for pre-release
// version and build metadata strings.  In particular they MUST only contain
// characters in semanticAlphabet.
func normalizeVerString(str string) string {
	result := bytes.Buffer{}
	for _, r := range str {
		if strings.ContainsRune(semanticAlphabet, r) {
			_, err := result.WriteRune(r)
			// Writing to a bytes.Buffer panics on OOM, and all
			// errors are unexpected.
			if err != nil {
				panic(err)
			}
		}
	}
	return result.String()
}
<|endoftext|>


<commit_before>package dns

import "fmt"

// Version is current version of this library.
var Version = v{1, 1, 30}

// v holds the version of this library.
type v struct {
	Major, Minor, Patch int
}

func (v v) String() string {
	return fmt.Sprintf("%d.%d.%d", v.Major, v.Minor, v.Patch)
}
<commit_msg>Release 1.1.31<commit_after>package dns

import "fmt"

// Version is current version of this library.
var Version = v{1, 1, 31}

// v holds the version of this library.
type v struct {
	Major, Minor, Patch int
}

func (v v) String() string {
	return fmt.Sprintf("%d.%d.%d", v.Major, v.Minor, v.Patch)
}
<|endoftext|>


<commit_before>package csvutil

import "github.com/coreos/go-semver/semver"

// Version of csvutil.
var Version = semver.Version{
	Major: 0,
	Minor: 13,
	Patch: 0,
}
<commit_msg>Version up to 0.14.0<commit_after>package csvutil

import "github.com/coreos/go-semver/semver"

// Version of csvutil.
var Version = semver.Version{
	Major: 0,
	Minor: 14,
	Patch: 0,
}
<|endoftext|>


<commit_before>package main

const VERSION = "0.9.0"
<commit_msg>:+1: Bump up the version to 0.9.1-alpha1<commit_after>package main

const VERSION = "0.9.1-alpha1"
<|endoftext|>


<commit_before>package sorg

const (
	// Release is the asset version of the site. Bump when any assets are
	// updated to blow away any browser caches.
	Release = "27"
)
<commit_msg>Bump version to refresh assets<commit_after>package sorg

const (
	// Release is the asset version of the site. Bump when any assets are
	// updated to blow away any browser caches.
	Release = "28"
)
<|endoftext|>


<commit_before>package main

var GitCommit string

const Version = "0.7.10"
<commit_msg>version 0.7.11<commit_after>package main

var GitCommit string

const Version = "0.7.11"
<|endoftext|>


<commit_before>package brig

import "fmt"

const (
	MajorVersion = 0
	MinorVersion = 0
	PatchVersion = 0
)

func Version() (int, int, int) {
	return MajorVersion, MinorVersion, PatchVersion
}

func VersingString() string {
	return fmt.Sprintf("%d.%d.%d", MajorVersion, MinorVersion, PatchVersion)
}
<commit_msg>version.go: Typo fixed.<commit_after>package brig

import "fmt"

const (
	MajorVersion = 0
	MinorVersion = 0
	PatchVersion = 0
)

func Version() (int, int, int) {
	return MajorVersion, MinorVersion, PatchVersion
}

func VersionString() string {
	return fmt.Sprintf("%d.%d.%d", MajorVersion, MinorVersion, PatchVersion)
}
<|endoftext|>


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

package opml

import (
	"os"
	"testing"
)

func TestNewOPMLFromFile(t *testing.T) {
	doc, err := NewOPMLFromFile(
		os.Getenv("GOPATH") + "/src/github.com/gilliek/go-opml/testdata/feeds.xml")
	if err != nil {
		t.Fatal(err)
	}

	version := doc.Root.Version
	if version != "1.0" {
		t.Errorf("Wrong OPML version: expected '1.0', found '%s'", version)
	}

	title := doc.Root.Head.Title
	if title != "Foobar" {
		t.Errorf("Wrong title version: expected 'Foobar', found '%s'", title)
	}

	outlines := doc.Outlines()
	if len(outlines) != 1 {
		t.Fatalf("Invalid number of outlines: expected 1, found %d", len(outlines))
	}

	if outlines[0].Text != "foo" {
		t.Errorf("Wrong outline text: expected 'foo', found '%s'", outlines[0].Text)
	}

	if outlines[0].Title != "bar" {
		t.Errorf("Wrong outline title: expected 'foo', found '%s'", outlines[0].Title)
	}

	if outlines[0].Type != "rss" {
		t.Errorf("Wrong outline type: expected 'rss', found '%s'", outlines[0].Type)
	}

	if outlines[0].XMLURL != "http://www.gilliek.ch/feeds" {
		t.Errorf("Wrong outline XML URL: expected 'http://www.gilliek.ch/feeds', found '%s'",
			outlines[0].XMLURL)
	}

	if outlines[0].HTMLURL != "http://www.gilliek.ch" {
		t.Errorf("Wrong outline HTML URL: expected 'http://www.gilliek.ch', found '%s'",
			outlines[0].HTMLURL)
	}
}
<commit_msg>added test for failure<commit_after>// Copyright 2014 The project AUTHORS. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package opml

import (
	"os"
	"testing"
)

func TestNewOPMLFromFile(t *testing.T) {
	testSuccess(t)
	testFailure(t)
}

func testSuccess(t *testing.T) {
	doc, err := NewOPMLFromFile(
		os.Getenv("GOPATH") + "/src/github.com/gilliek/go-opml/testdata/feeds.xml")
	if err != nil {
		t.Fatal(err)
	}

	version := doc.Root.Version
	if version != "1.0" {
		t.Errorf("Wrong OPML version: expected '1.0', found '%s'", version)
	}

	title := doc.Root.Head.Title
	if title != "Foobar" {
		t.Errorf("Wrong title version: expected 'Foobar', found '%s'", title)
	}

	outlines := doc.Outlines()
	if len(outlines) != 1 {
		t.Fatalf("Invalid number of outlines: expected 1, found %d", len(outlines))
	}

	if outlines[0].Text != "foo" {
		t.Errorf("Wrong outline text: expected 'foo', found '%s'", outlines[0].Text)
	}

	if outlines[0].Title != "bar" {
		t.Errorf("Wrong outline title: expected 'foo', found '%s'", outlines[0].Title)
	}

	if outlines[0].Type != "rss" {
		t.Errorf("Wrong outline type: expected 'rss', found '%s'", outlines[0].Type)
	}

	if outlines[0].XMLURL != "http://www.gilliek.ch/feeds" {
		t.Errorf("Wrong outline XML URL: expected 'http://www.gilliek.ch/feeds', found '%s'",
			outlines[0].XMLURL)
	}

	if outlines[0].HTMLURL != "http://www.gilliek.ch" {
		t.Errorf("Wrong outline HTML URL: expected 'http://www.gilliek.ch', found '%s'",
			outlines[0].HTMLURL)
	}

}

func testFailure(t *testing.T) {
	_, err := NewOPMLFromFile(
		os.Getenv("GOPATH") + "/src/github.com/gilliek/go-opml/testdata/does_not_exist.xml")
	if err == nil {
		t.Error("Expected failure!")
	}
}
<|endoftext|>


<commit_before>package require

import (
	"github.com/stretchr/testify/assert"
	"time"
)

type TestingT interface {
	Errorf(format string, args ...interface{})
	FailNow()
}

// Fail reports a failure through
func FailNow(t TestingT, failureMessage string, msgAndArgs ...interface{}) {
	assert.Fail(t, failureMessage, msgAndArgs...)
	t.FailNow()
}

// Implements asserts that an object is implemented by the specified interface.
//
//    require.Implements(t, (*MyInterface)(nil), new(MyObject), "MyObject")
func Implements(t TestingT, interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) {
	if !assert.Implements(t, interfaceObject, object, msgAndArgs...) {
		t.FailNow()
	}
}

// IsType asserts that the specified objects are of the same type.
func IsType(t TestingT, expectedType interface{}, object interface{}, msgAndArgs ...interface{}) {
	if !assert.IsType(t, expectedType, object, msgAndArgs...) {
		t.FailNow()
	}
}

// Equal asserts that two objects are equal.
//
//    require.Equal(t, 123, 123, "123 and 123 should be equal")
//
// Returns whether the assertion was successful (true) or not (false).
func Equal(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) {
	if !assert.Equal(t, expected, actual, msgAndArgs...) {
		t.FailNow()
	}
}

// Exactly asserts that two objects are equal is value and type.
//
//    require.Exactly(t, int32(123), int64(123), "123 and 123 should NOT be equal")
//
// Returns whether the assertion was successful (true) or not (false).
func Exactly(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) {
	if !assert.Exactly(t, expected, actual, msgAndArgs...) {
		t.FailNow()
	}
}

// NotNil asserts that the specified object is not nil.
//
//    require.NotNil(t, err, "err should be something")
//
// Returns whether the assertion was successful (true) or not (false).
func NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) {
	if !assert.NotNil(t, object, msgAndArgs...) {
		t.FailNow()
	}
}

// Nil asserts that the specified object is nil.
//
//    require.Nil(t, err, "err should be nothing")
//
// Returns whether the assertion was successful (true) or not (false).
func Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) {
	if !assert.Nil(t, object, msgAndArgs...) {
		t.FailNow()
	}
}

// Empty asserts that the specified object is empty.  I.e. nil, "", false, 0 or either
// a slice or a channel with len == 0.
//
// require.Empty(t, obj)
//
// Returns whether the assertion was successful (true) or not (false).
func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) {
	if !assert.Empty(t, object, msgAndArgs...) {
		t.FailNow()
	}
}

// NotEmpty asserts that the specified object is NOT empty.  I.e. not nil, "", false, 0 or either
// a slice or a channel with len == 0.
//
// require.NotEmpty(t, obj)
// require.Equal(t, "one", obj[0])
//
// Returns whether the assertion was successful (true) or not (false).
func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) {
	if !assert.NotEmpty(t, object, msgAndArgs...) {
		t.FailNow()
	}
}

// True asserts that the specified value is true.
//
//    require.True(t, myBool, "myBool should be true")
//
// Returns whether the assertion was successful (true) or not (false).
func True(t TestingT, value bool, msgAndArgs ...interface{}) {
	if !assert.True(t, value, msgAndArgs...) {
		t.FailNow()
	}
}

// False asserts that the specified value is true.
//
//    require.False(t, myBool, "myBool should be false")
//
// Returns whether the assertion was successful (true) or not (false).
func False(t TestingT, value bool, msgAndArgs ...interface{}) {
	if !assert.False(t, value, msgAndArgs...) {
		t.FailNow()
	}
}

// NotEqual asserts that the specified values are NOT equal.
//
//    require.NotEqual(t, obj1, obj2, "two objects shouldn't be equal")
//
// Returns whether the assertion was successful (true) or not (false).
func NotEqual(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) {
	if !assert.NotEqual(t, expected, actual, msgAndArgs...) {
		t.FailNow()
	}
}

// Contains asserts that the specified string contains the specified substring.
//
//    require.Contains(t, "Hello World", "World", "But 'Hello World' does contain 'World'")
//
// Returns whether the assertion was successful (true) or not (false).
func Contains(t TestingT, s, contains string, msgAndArgs ...interface{}) {
	if !assert.Contains(t, s, contains, msgAndArgs...) {
		t.FailNow()
	}
}

// NotContains asserts that the specified string does NOT contain the specified substring.
//
//    require.NotContains(t, "Hello World", "Earth", "But 'Hello World' does NOT contain 'Earth'")
//
// Returns whether the assertion was successful (true) or not (false).
func NotContains(t TestingT, s, contains string, msgAndArgs ...interface{}) {
	if !assert.NotContains(t, s, contains, msgAndArgs...) {
		t.FailNow()
	}
}

// Condition uses a Comparison to assert a complex condition.
func Condition(t TestingT, comp assert.Comparison, msgAndArgs ...interface{}) {
	if !assert.Condition(t, comp, msgAndArgs...) {
		t.FailNow()
	}
}

// Panics asserts that the code inside the specified PanicTestFunc panics.
//
//   require.Panics(t, func(){
//     GoCrazy()
//   }, "Calling GoCrazy() should panic")
//
// Returns whether the assertion was successful (true) or not (false).
func Panics(t TestingT, f assert.PanicTestFunc, msgAndArgs ...interface{}) {
	if !assert.Panics(t, f, msgAndArgs...) {
		t.FailNow()
	}
}

// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic.
//
//   require.NotPanics(t, func(){
//     RemainCalm()
//   }, "Calling RemainCalm() should NOT panic")
//
// Returns whether the assertion was successful (true) or not (false).
func NotPanics(t TestingT, f assert.PanicTestFunc, msgAndArgs ...interface{}) {
	if !assert.NotPanics(t, f, msgAndArgs...) {
		t.FailNow()
	}
}

// WithinDuration asserts that the two times are within duration delta of each other.
//
//   require.WithinDuration(t, time.Now(), time.Now(), 10*time.Second, "The difference should not be more than 10s")
//
// Returns whether the assertion was successful (true) or not (false).
func WithinDuration(t TestingT, expected, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) {
	if !assert.WithinDuration(t, expected, actual, delta, msgAndArgs...) {
		t.FailNow()
	}
}

// InDelta asserts that the two numerals are within delta of each other.
//
//   require.InDelta(t, math.Pi, (22 / 7.0), 0.01)
//
// Returns whether the assertion was successful (true) or not (false).
func InDelta(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) {
	if !assert.InDelta(t, expected, actual, delta, msgAndArgs...) {
		t.FailNow()
	}
}

// InEpsilon asserts that expected and actual have a relative error less than epsilon
//
// Returns whether the assertion was successful (true) or not (false).
func InEpsilon(t TestingT, expected, actual interface{}, epsilon float64, msgAndArgs ...interface{}) {
	if !assert.InEpsilon(t, expected, actual, epsilon, msgAndArgs...) {
		t.FailNow()
	}
}

/*
	Errors
*/

// NoError asserts that a function returned no error (i.e. `nil`).
//
//   actualObj, err := SomeFunction()
//   require.NoError(t, err)
//   require.Equal(t, actualObj, expectedObj)
//
// Returns whether the assertion was successful (true) or not (false).
func NoError(t TestingT, err error, msgAndArgs ...interface{}) {
	if !assert.NoError(t, err, msgAndArgs...) {
		t.FailNow()
	}
}

// Error asserts that a function returned an error (i.e. not `nil`).
//
//   actualObj, err := SomeFunction()
//   require.Error(t, err, "An error was expected")
//   require.Equal(t, err, expectedError)
//   }
//
// Returns whether the assertion was successful (true) or not (false).
func Error(t TestingT, err error, msgAndArgs ...interface{}) {
	if !assert.Error(t, err, msgAndArgs...) {
		t.FailNow()
	}
}

// EqualError asserts that a function returned an error (i.e. not `nil`)
// and that it is equal to the provided error.
//
//   actualObj, err := SomeFunction()
//   require.Error(t, err, "An error was expected")
//   require.Equal(t, err, expectedError)
//   }
//
// Returns whether the assertion was successful (true) or not (false).
func EqualError(t TestingT, theError error, errString string, msgAndArgs ...interface{}) {
	if !assert.EqualError(t, theError, errString, msgAndArgs...) {
		t.FailNow()
	}
}
<commit_msg>Remove false documentation.<commit_after>package require

import (
	"github.com/stretchr/testify/assert"
	"time"
)

type TestingT interface {
	Errorf(format string, args ...interface{})
	FailNow()
}

// Fail reports a failure through
func FailNow(t TestingT, failureMessage string, msgAndArgs ...interface{}) {
	assert.Fail(t, failureMessage, msgAndArgs...)
	t.FailNow()
}

// Implements asserts that an object is implemented by the specified interface.
//
//    require.Implements(t, (*MyInterface)(nil), new(MyObject), "MyObject")
func Implements(t TestingT, interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) {
	if !assert.Implements(t, interfaceObject, object, msgAndArgs...) {
		t.FailNow()
	}
}

// IsType asserts that the specified objects are of the same type.
func IsType(t TestingT, expectedType interface{}, object interface{}, msgAndArgs ...interface{}) {
	if !assert.IsType(t, expectedType, object, msgAndArgs...) {
		t.FailNow()
	}
}

// Equal asserts that two objects are equal.
//
//    require.Equal(t, 123, 123, "123 and 123 should be equal")
func Equal(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) {
	if !assert.Equal(t, expected, actual, msgAndArgs...) {
		t.FailNow()
	}
}

// Exactly asserts that two objects are equal is value and type.
//
//    require.Exactly(t, int32(123), int64(123), "123 and 123 should NOT be equal")
func Exactly(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) {
	if !assert.Exactly(t, expected, actual, msgAndArgs...) {
		t.FailNow()
	}
}

// NotNil asserts that the specified object is not nil.
//
//    require.NotNil(t, err, "err should be something")
func NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) {
	if !assert.NotNil(t, object, msgAndArgs...) {
		t.FailNow()
	}
}

// Nil asserts that the specified object is nil.
//
//    require.Nil(t, err, "err should be nothing")
func Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) {
	if !assert.Nil(t, object, msgAndArgs...) {
		t.FailNow()
	}
}

// Empty asserts that the specified object is empty.  I.e. nil, "", false, 0 or either
// a slice or a channel with len == 0.
//
// require.Empty(t, obj)
func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) {
	if !assert.Empty(t, object, msgAndArgs...) {
		t.FailNow()
	}
}

// NotEmpty asserts that the specified object is NOT empty.  I.e. not nil, "", false, 0 or either
// a slice or a channel with len == 0.
//
// require.NotEmpty(t, obj)
// require.Equal(t, "one", obj[0])
func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) {
	if !assert.NotEmpty(t, object, msgAndArgs...) {
		t.FailNow()
	}
}

// True asserts that the specified value is true.
//
//    require.True(t, myBool, "myBool should be true")
func True(t TestingT, value bool, msgAndArgs ...interface{}) {
	if !assert.True(t, value, msgAndArgs...) {
		t.FailNow()
	}
}

// False asserts that the specified value is true.
//
//    require.False(t, myBool, "myBool should be false")
func False(t TestingT, value bool, msgAndArgs ...interface{}) {
	if !assert.False(t, value, msgAndArgs...) {
		t.FailNow()
	}
}

// NotEqual asserts that the specified values are NOT equal.
//
//    require.NotEqual(t, obj1, obj2, "two objects shouldn't be equal")
func NotEqual(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) {
	if !assert.NotEqual(t, expected, actual, msgAndArgs...) {
		t.FailNow()
	}
}

// Contains asserts that the specified string contains the specified substring.
//
//    require.Contains(t, "Hello World", "World", "But 'Hello World' does contain 'World'")
func Contains(t TestingT, s, contains string, msgAndArgs ...interface{}) {
	if !assert.Contains(t, s, contains, msgAndArgs...) {
		t.FailNow()
	}
}

// NotContains asserts that the specified string does NOT contain the specified substring.
//
//    require.NotContains(t, "Hello World", "Earth", "But 'Hello World' does NOT contain 'Earth'")
func NotContains(t TestingT, s, contains string, msgAndArgs ...interface{}) {
	if !assert.NotContains(t, s, contains, msgAndArgs...) {
		t.FailNow()
	}
}

// Condition uses a Comparison to assert a complex condition.
func Condition(t TestingT, comp assert.Comparison, msgAndArgs ...interface{}) {
	if !assert.Condition(t, comp, msgAndArgs...) {
		t.FailNow()
	}
}

// Panics asserts that the code inside the specified PanicTestFunc panics.
//
//   require.Panics(t, func(){
//     GoCrazy()
//   }, "Calling GoCrazy() should panic")
func Panics(t TestingT, f assert.PanicTestFunc, msgAndArgs ...interface{}) {
	if !assert.Panics(t, f, msgAndArgs...) {
		t.FailNow()
	}
}

// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic.
//
//   require.NotPanics(t, func(){
//     RemainCalm()
//   }, "Calling RemainCalm() should NOT panic")
func NotPanics(t TestingT, f assert.PanicTestFunc, msgAndArgs ...interface{}) {
	if !assert.NotPanics(t, f, msgAndArgs...) {
		t.FailNow()
	}
}

// WithinDuration asserts that the two times are within duration delta of each other.
//
//   require.WithinDuration(t, time.Now(), time.Now(), 10*time.Second, "The difference should not be more than 10s")
func WithinDuration(t TestingT, expected, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) {
	if !assert.WithinDuration(t, expected, actual, delta, msgAndArgs...) {
		t.FailNow()
	}
}

// InDelta asserts that the two numerals are within delta of each other.
//
//   require.InDelta(t, math.Pi, (22 / 7.0), 0.01)
func InDelta(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) {
	if !assert.InDelta(t, expected, actual, delta, msgAndArgs...) {
		t.FailNow()
	}
}

// InEpsilon asserts that expected and actual have a relative error less than epsilon
func InEpsilon(t TestingT, expected, actual interface{}, epsilon float64, msgAndArgs ...interface{}) {
	if !assert.InEpsilon(t, expected, actual, epsilon, msgAndArgs...) {
		t.FailNow()
	}
}

/*
	Errors
*/

// NoError asserts that a function returned no error (i.e. `nil`).
//
//   actualObj, err := SomeFunction()
//   require.NoError(t, err)
//   require.Equal(t, actualObj, expectedObj)
//
// Returns whether the assertion was successful (true) or not (false).
func NoError(t TestingT, err error, msgAndArgs ...interface{}) {
	if !assert.NoError(t, err, msgAndArgs...) {
		t.FailNow()
	}
}

// Error asserts that a function returned an error (i.e. not `nil`).
//
//   actualObj, err := SomeFunction()
//   require.Error(t, err, "An error was expected")
//   require.Equal(t, err, expectedError)
//   }
func Error(t TestingT, err error, msgAndArgs ...interface{}) {
	if !assert.Error(t, err, msgAndArgs...) {
		t.FailNow()
	}
}

// EqualError asserts that a function returned an error (i.e. not `nil`)
// and that it is equal to the provided error.
//
//   actualObj, err := SomeFunction()
//   require.Error(t, err, "An error was expected")
//   require.Equal(t, err, expectedError)
//   }
func EqualError(t TestingT, theError error, errString string, msgAndArgs ...interface{}) {
	if !assert.EqualError(t, theError, errString, msgAndArgs...) {
		t.FailNow()
	}
}
<|endoftext|>


<commit_before>package vfs

import (
	"bytes"
	"errors"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"time"

	"github.com/gsdocker/gserrors"
	"github.com/gsdocker/gslogger"
	"github.com/gsdocker/gsos/fs"
	"github.com/gsdocker/gsos/uuid"
)

// ErrGitFS .
var (
	ErrGitFS = errors.New("git fs error")
)

// GitFS git fs for gsmake vfs
type GitFS struct {
	gslogger.Log // Mixin log APIs
}

// NewGitFS create new gitfs system
func NewGitFS() *GitFS {
	return &GitFS{
		Log: gslogger.Get("gitfs"),
	}
}

// Mount implement UserFS
func (gitFS *GitFS) String() string {
	return "git"
}

// Mount implement UserFS
func (gitFS *GitFS) Mount(rootfs RootFS, src, target *Entry) error {

	remote := src.Query().Get("remote")

	if remote == "" {
		return gserrors.Newf(ErrGitFS, "expect remoet url \n%s", src)
	}

	version := src.Query().Get("version")

	if version == "" {
		return gserrors.Newf(ErrGitFS, "expect remote repo version \n%s", src)
	}

	if version == "current" {
		version = "master"
	}

	cachepath := rootfs.CacheRoot(src)

	gitFS.D("mount remote url :%s", remote)

	gitFS.D("mount cache dir :%s", cachepath)

	// check if repo already exists

	if !fs.Exists(cachepath) {

		dirname := filepath.Base(uuid.New())

		rundir := os.TempDir()

		gitFS.I("cache package: %s:%s", filepath.Base(cachepath), version)

		startime := time.Now()

		if err := gitFS.clone(remote, rundir, dirname, true); err != nil {
			return gserrors.Newf(err, "clone cached repo error")
		}

		remote2 := filepath.Join(rundir, dirname)
		rundir = filepath.Dir(cachepath)
		dirname = filepath.Base(cachepath)

		if err := gitFS.clone(remote2, rundir, dirname, true); err != nil {
			return gserrors.Newf(err, "clone cached repo error")
		}

		if err := gitFS.setRemote(cachepath, "origin", remote); err != nil {
			return gserrors.Newf(err, "clone cached repo error")
		}

		gitFS.I("cache package -- success %s", time.Now().Sub(startime))

		if err := rootfs.Cached(src); err != nil {
			return err
		}
	}

	gitFS.D("mount target dir :%s", target.Mapping)

	rundir := filepath.Dir(target.Mapping)
	dirname := filepath.Base(target.Mapping)

	gitFS.I("clone cached package to userspace : %s", dirname)

	startime := time.Now()

	if err := gitFS.clone(cachepath, rundir, dirname, false); err != nil {
		return gserrors.Newf(err, "clone cached repo error")
	}

	gitFS.I("clone cached package to userspace -- success %s", time.Now().Sub(startime))

	// checkout version
	if err := gitFS.checkout(target.Mapping, version); err != nil {
		return gserrors.Newf(err, "checkout %s error", version)
	}

	return nil
}

func (gitFS *GitFS) clone(remote, rundir, dirname string, bare bool) error {

	if !fs.Exists(rundir) {
		if err := fs.MkdirAll(rundir, 0755); err != nil {
			return gserrors.Newf(err, "make clone target dir error")
		}
	}

	path := filepath.Join(rundir, dirname)

	if fs.Exists(path) {
		if err := fs.RemoveAll(path); err != nil {
			return gserrors.Newf(err, "remove exists repo error")
		}
	}

	var cmd *exec.Cmd

	cmd = exec.Command("git", "clone", remote, dirname)

	// if !bare {
	// 	cmd = exec.Command("git", "clone", remote, dirname)
	// } else {
	// 	cmd = exec.Command("git", "clone", "--bare", remote, dirname)
	// }

	cmd.Stderr = os.Stderr
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout

	cmd.Dir = rundir

	return cmd.Run()
}

func (gitFS *GitFS) setRemote(rundir string, name string, url string) error {

	gitFS.D("change remote :\n\trepo:%s\n\tname:%s\n\turl:%s", rundir, name, url)

	cmd := exec.Command("git", "remote")

	var buff bytes.Buffer

	cmd.Stdout = &buff

	cmd.Stderr = os.Stderr

	cmd.Dir = rundir

	err := cmd.Run()

	if err != nil {
		return err
	}

	if !strings.Contains(buff.String(), name) {

		cmd = exec.Command("git", "remote", "add", name, url)

		cmd.Stderr = os.Stderr
		cmd.Stdin = os.Stdin
		cmd.Stdout = os.Stdout

		cmd.Dir = rundir

		return cmd.Run()
	}

	cmd = exec.Command("git", "remote", "set-url", name, url)

	cmd.Stderr = os.Stderr
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout

	cmd.Dir = rundir

	return cmd.Run()
}

func (gitFS *GitFS) fetch(rundir string) error {

	cmd := exec.Command("git", "fetch", "--tag", "--all")

	cmd.Stderr = os.Stderr
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout

	cmd.Dir = rundir

	return cmd.Run()
}

func (gitFS *GitFS) pull(rundir string) error {

	cmd := exec.Command("git", "pull")

	cmd.Stderr = os.Stderr
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout

	cmd.Dir = rundir

	return cmd.Run()
}

func (gitFS *GitFS) checkout(rundir string, version string) error {

	cmd := exec.Command("git", "checkout", version)

	var buff bytes.Buffer

	cmd.Stderr = &buff

	cmd.Dir = rundir

	if err := cmd.Run(); err != nil {
		return gserrors.Newf(err, buff.String())
	}

	return nil
}

// Dismount implement UserFS
func (gitFS *GitFS) Dismount(rootfs RootFS, src, target *Entry) error {

	gitFS.D("dismount dir :%s", target.Mapping)

	if fs.Exists(target.Mapping) {
		return fs.RemoveAll(target.Mapping)
	}

	return nil
}

// UpdateCache implement UserFS
func (gitFS *GitFS) UpdateCache(rootfs RootFS, cachepath string) error {

	gitFS.I("update cached package : %s", cachepath)

	startime := time.Now()

	if err := gitFS.pull(filepath.Join(cachepath)); err != nil {
		return gserrors.Newf(err, "pull remote repo error")
	}

	gitFS.I("update cached package -- success %s", time.Now().Sub(startime))

	return nil
}

// Update implement UserFS
func (gitFS *GitFS) Update(rootfs RootFS, src, target *Entry, nocache bool) error {
	gserrors.Require(target.Scheme == FSGSMake, "target must be rootfs node")
	gserrors.Require(src.Scheme == "git", "src must be gitfs node")

	version := src.Query().Get("version")

	if version == "" {
		return gserrors.Newf(ErrGitFS, "expect remote repo version \n%s", src)
	}

	if version == "current" {
		version = "master"
	}

	cachepath := rootfs.CacheRoot(src)

	if nocache {

		if err := gitFS.UpdateCache(rootfs, cachepath); err != nil {
			return err
		}
	}

	rundir := filepath.Dir(target.Mapping)
	dirname := filepath.Base(target.Mapping)

	gitFS.D("clone rundir :%s ", rundir)
	gitFS.D("clone dirname :%s ", dirname)

	gitFS.I("clone cached package to userspace : %s", dirname)

	startime := time.Now()

	if err := gitFS.clone(cachepath, rundir, dirname, false); err != nil {
		return gserrors.Newf(err, "clone cached repo error")
	}
	gitFS.I("clone cached package to userspace -- success %s", time.Now().Sub(startime))

	// checkout version
	if err := gitFS.checkout(target.Mapping, version); err != nil {
		return gserrors.Newf(err, "checkout %s error", version)
	}

	return nil
}
<commit_msg>fix update bug<commit_after>package vfs

import (
	"bytes"
	"errors"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"time"

	"github.com/gsdocker/gserrors"
	"github.com/gsdocker/gslogger"
	"github.com/gsdocker/gsos/fs"
	"github.com/gsdocker/gsos/uuid"
)

// ErrGitFS .
var (
	ErrGitFS = errors.New("git fs error")
)

// GitFS git fs for gsmake vfs
type GitFS struct {
	gslogger.Log // Mixin log APIs
}

// NewGitFS create new gitfs system
func NewGitFS() *GitFS {
	return &GitFS{
		Log: gslogger.Get("gitfs"),
	}
}

// Mount implement UserFS
func (gitFS *GitFS) String() string {
	return "git"
}

// Mount implement UserFS
func (gitFS *GitFS) Mount(rootfs RootFS, src, target *Entry) error {

	remote := src.Query().Get("remote")

	if remote == "" {
		return gserrors.Newf(ErrGitFS, "expect remoet url \n%s", src)
	}

	version := src.Query().Get("version")

	if version == "" {
		return gserrors.Newf(ErrGitFS, "expect remote repo version \n%s", src)
	}

	if version == "current" {
		version = "master"
	}

	cachepath := rootfs.CacheRoot(src)

	gitFS.D("mount remote url :%s", remote)

	gitFS.D("mount cache dir :%s", cachepath)

	// check if repo already exists

	if !fs.Exists(cachepath) {

		dirname := filepath.Base(uuid.New())

		rundir := os.TempDir()

		gitFS.I("cache package: %s:%s", filepath.Base(cachepath), version)

		startime := time.Now()

		if err := gitFS.clone(remote, rundir, dirname, true); err != nil {
			return gserrors.Newf(err, "clone cached repo error")
		}

		remote2 := filepath.Join(rundir, dirname)
		rundir = filepath.Dir(cachepath)
		dirname = filepath.Base(cachepath)

		if err := gitFS.clone(remote2, rundir, dirname, true); err != nil {
			return gserrors.Newf(err, "clone cached repo error")
		}

		if err := gitFS.setRemote(cachepath, "origin", remote); err != nil {
			return gserrors.Newf(err, "clone cached repo error")
		}

		gitFS.I("cache package -- success %s", time.Now().Sub(startime))

		if err := rootfs.Cached(src); err != nil {
			return err
		}
	}

	gitFS.D("mount target dir :%s", target.Mapping)

	rundir := filepath.Dir(target.Mapping)
	dirname := filepath.Base(target.Mapping)

	gitFS.I("clone cached package to userspace : %s", dirname)

	startime := time.Now()

	if err := gitFS.clone(cachepath, rundir, dirname, false); err != nil {
		return gserrors.Newf(err, "clone cached repo error")
	}

	gitFS.I("clone cached package to userspace -- success %s", time.Now().Sub(startime))

	// checkout version
	if err := gitFS.checkout(target.Mapping, version); err != nil {
		return gserrors.Newf(err, "checkout %s error", version)
	}

	return nil
}

func (gitFS *GitFS) clone(remote, rundir, dirname string, bare bool) error {

	if !fs.Exists(rundir) {
		if err := fs.MkdirAll(rundir, 0755); err != nil {
			return gserrors.Newf(err, "make clone target dir error")
		}
	}

	path := filepath.Join(rundir, dirname)

	if fs.Exists(path) {
		if err := fs.RemoveAll(path); err != nil {
			return gserrors.Newf(err, "remove exists repo error")
		}
	}

	var cmd *exec.Cmd

	cmd = exec.Command("git", "clone", remote, dirname)

	if !bare {
		cmd = exec.Command("git", "clone", remote, dirname)
	} else {
		cmd = exec.Command("git", "clone", "--mirror", remote, dirname)
	}

	cmd.Stderr = os.Stderr
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout

	cmd.Dir = rundir

	return cmd.Run()
}

func (gitFS *GitFS) setRemote(rundir string, name string, url string) error {

	gitFS.D("change remote :\n\trepo:%s\n\tname:%s\n\turl:%s", rundir, name, url)

	cmd := exec.Command("git", "remote")

	var buff bytes.Buffer

	cmd.Stdout = &buff

	cmd.Stderr = os.Stderr

	cmd.Dir = rundir

	err := cmd.Run()

	if err != nil {
		return err
	}

	if !strings.Contains(buff.String(), name) {

		cmd = exec.Command("git", "remote", "add", name, url)

		cmd.Stderr = os.Stderr
		cmd.Stdin = os.Stdin
		cmd.Stdout = os.Stdout

		cmd.Dir = rundir

		return cmd.Run()
	}

	cmd = exec.Command("git", "remote", "set-url", name, url)

	cmd.Stderr = os.Stderr
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout

	cmd.Dir = rundir

	return cmd.Run()
}

func (gitFS *GitFS) fetch(rundir string) error {

	gitFS.D("git remote update :%s", rundir)

	cmd := exec.Command("git", "remote", "update")

	cmd.Stderr = os.Stderr
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout

	cmd.Dir = rundir

	return cmd.Run()
}

func (gitFS *GitFS) pull(rundir string) error {

	cmd := exec.Command("git", "pull")

	cmd.Stderr = os.Stderr
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout

	cmd.Dir = rundir

	return cmd.Run()
}

func (gitFS *GitFS) checkout(rundir string, version string) error {

	cmd := exec.Command("git", "checkout", version)

	var buff bytes.Buffer

	cmd.Stderr = &buff

	cmd.Dir = rundir

	if err := cmd.Run(); err != nil {
		return gserrors.Newf(err, buff.String())
	}

	return nil
}

// Dismount implement UserFS
func (gitFS *GitFS) Dismount(rootfs RootFS, src, target *Entry) error {

	gitFS.D("dismount dir :%s", target.Mapping)

	if fs.Exists(target.Mapping) {
		return fs.RemoveAll(target.Mapping)
	}

	return nil
}

// UpdateCache implement UserFS
func (gitFS *GitFS) UpdateCache(rootfs RootFS, cachepath string) error {

	gitFS.I("update cached package : %s", cachepath)

	startime := time.Now()

	if err := gitFS.fetch(filepath.Join(cachepath)); err != nil {
		return gserrors.Newf(err, "pull remote repo error")
	}

	gitFS.I("update cached package -- success %s", time.Now().Sub(startime))

	return nil
}

// Update implement UserFS
func (gitFS *GitFS) Update(rootfs RootFS, src, target *Entry, nocache bool) error {
	gserrors.Require(target.Scheme == FSGSMake, "target must be rootfs node")
	gserrors.Require(src.Scheme == "git", "src must be gitfs node")

	version := src.Query().Get("version")

	if version == "" {
		return gserrors.Newf(ErrGitFS, "expect remote repo version \n%s", src)
	}

	if version == "current" {
		version = "master"
	}

	cachepath := rootfs.CacheRoot(src)

	if nocache {

		if err := gitFS.UpdateCache(rootfs, cachepath); err != nil {
			return err
		}
	}

	rundir := filepath.Dir(target.Mapping)
	dirname := filepath.Base(target.Mapping)

	gitFS.D("clone rundir :%s ", rundir)
	gitFS.D("clone dirname :%s ", dirname)

	gitFS.I("clone cached package to userspace : %s", dirname)

	startime := time.Now()

	if err := gitFS.clone(cachepath, rundir, dirname, false); err != nil {
		return gserrors.Newf(err, "clone cached repo error")
	}
	gitFS.I("clone cached package to userspace -- success %s", time.Now().Sub(startime))

	// checkout version
	if err := gitFS.checkout(target.Mapping, version); err != nil {
		return gserrors.Newf(err, "checkout %s error", version)
	}

	return nil
}
<|endoftext|>


<commit_before>package term

import (
	"testing"

	"src.elv.sh/pkg/sys/ewindows"
	"src.elv.sh/pkg/tt"
)

var Args = tt.Args

func TestConvertEvent(t *testing.T) {
	tt.Test(t, tt.Fn("convertEvent", convertEvent), tt.Table{
		// Only convert KeyEvent
		Args(&ewindows.MouseEvent{}).Rets(nil),
		// Only convert KeyDown events
		Args(&ewindows.KeyEvent{BKeyDown: 0}).Rets(nil),

		Args(&ewindows.KeyEvent{BKeyDown: 1, UChar: [2]byte{'a', 0}}).Rets(K('a')),
	})
}
<commit_msg>pkg/cli/term: More tests for convertEvent in reader_windows.go.<commit_after>package term

import (
	"testing"

	"src.elv.sh/pkg/sys/ewindows"
	"src.elv.sh/pkg/tt"
	"src.elv.sh/pkg/ui"
)

var Args = tt.Args

func TestConvertEvent(t *testing.T) {
	tt.Test(t, tt.Fn("convertEvent", convertEvent), tt.Table{
		// Only convert KeyEvent
		Args(&ewindows.MouseEvent{}).Rets(nil),
		// Only convert KeyDown events
		Args(&ewindows.KeyEvent{BKeyDown: 0}).Rets(nil),

		Args(charKeyEvent('a', 0)).Rets(K('a')),
		Args(charKeyEvent('A', shift)).Rets(K('A')),
		Args(charKeyEvent('µ', leftCtrl|rightAlt)).Rets(K('µ')),
		Args(charKeyEvent('ẞ', leftCtrl|rightAlt|shift)).Rets(K('ẞ')),

		Args(funcKeyEvent(0x1b, 0)).Rets(K('[', ui.Ctrl)),

		// Functional key with modifiers
		Args(funcKeyEvent(0x08, 0)).Rets(K(ui.Backspace)),
		Args(funcKeyEvent(0x08, leftCtrl)).Rets(K(ui.Backspace, ui.Ctrl)),
		Args(funcKeyEvent(0x08, leftCtrl|leftAlt|shift)).Rets(K(ui.Backspace, ui.Ctrl, ui.Alt, ui.Shift)),

		// Functional keys with an alphanumeric base
		Args(funcKeyEvent('2', leftCtrl)).Rets(K('2', ui.Ctrl)),
		Args(funcKeyEvent('A', leftCtrl)).Rets(K('A', ui.Ctrl)),
		Args(funcKeyEvent('A', leftAlt)).Rets(K('a', ui.Alt)),

		// Unrecognized functional key
		Args(funcKeyEvent(0, 0)).Rets(nil),
	})
}

func charKeyEvent(r uint16, mod uint32) *ewindows.KeyEvent {
	return &ewindows.KeyEvent{
		BKeyDown: 1, DwControlKeyState: mod, UChar: [2]byte{byte(r), byte(r >> 8)}}
}

func funcKeyEvent(code uint16, mod uint32) *ewindows.KeyEvent {
	return &ewindows.KeyEvent{
		BKeyDown: 1, DwControlKeyState: mod, WVirtualKeyCode: code}
}
<|endoftext|>


<commit_before>/*
Copyright 2018 The OpenEBS Authors

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

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

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

// TODO
// Move this file to pkg/k8sresource/v1alpha1

package v1alpha1

import (
	"strings"

	"github.com/pkg/errors"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime/schema"
)

// ResourceCreator abstracts creating an unstructured instance in kubernetes
// cluster
type ResourceCreator interface {
	Create(obj *unstructured.Unstructured, subresources ...string) (*unstructured.Unstructured, error)
}

// ResourceGetter abstracts fetching an unstructured instance from kubernetes
// cluster
type ResourceGetter interface {
	Get(name string, options metav1.GetOptions, subresources ...string) (*unstructured.Unstructured, error)
}

// ResourceLister abstracts fetching an unstructured list of instance from kubernetes
// cluster
type ResourceLister interface {
	List(options metav1.ListOptions) (*unstructured.UnstructuredList, error)
}

// ResourceUpdater abstracts updating an unstructured instance found in
// kubernetes cluster
type ResourceUpdater interface {
	Update(oldobj, newobj *unstructured.Unstructured, subresources ...string) (u *unstructured.Unstructured, err error)
}

// ResourceApplier abstracts applying an unstructured instance that may or may
// not be available in kubernetes cluster
type ResourceApplier interface {
	Apply(obj *unstructured.Unstructured, subresources ...string) (*unstructured.Unstructured, error)
}

// ResourceDeleter abstracts deletes an unstructured instance that is available in kubernetes cluster
type ResourceDeleter interface {
	Delete(obj *unstructured.Unstructured, subresources ...string) error
}

type resource struct {
	gvr       schema.GroupVersionResource // identify a resource
	namespace string                      // namespace where this resource is to be operated at
}

// Resource returns a new resource instance
func Resource(gvr schema.GroupVersionResource, namespace string) *resource {
	return &resource{gvr: gvr, namespace: namespace}
}

// Create creates a new resource in kubernetes cluster
func (r *resource) Create(obj *unstructured.Unstructured, subresources ...string) (u *unstructured.Unstructured, err error) {
	if obj == nil {
		err = errors.Errorf("nil resource instance: failed to create resource '%s' at '%s'", r.gvr, r.namespace)
		return
	}
	dynamic, err := Dynamic().Provide()
	if err != nil {
		err = errors.Wrapf(err, "failed to create resource '%s' '%s' at '%s'", r.gvr, obj.GetName(), r.namespace)
		return
	}
	u, err = dynamic.Resource(r.gvr).Namespace(r.namespace).Create(obj, metav1.CreateOptions{}, subresources...)
	if err != nil {
		err = errors.Wrapf(err, "failed to create resource '%s' '%s' at '%s'", r.gvr, obj.GetName(), r.namespace)
		return
	}
	return
}

// Delete deletes a existing resource in kubernetes cluster
func (r *resource) Delete(obj *unstructured.Unstructured, subresources ...string) error {
	if obj == nil {
		return errors.Errorf("nil resource instance: failed to delete resource '%s' at '%s'", r.gvr, r.namespace)
	}
	dynamic, err := Dynamic().Provide()
	if err != nil {
		return errors.Wrapf(err, "failed to delete resource '%s' '%s' at '%s'", r.gvr, obj.GetName(), r.namespace)
	}
	err = dynamic.Resource(r.gvr).Namespace(r.namespace).Delete(obj.GetName(), &metav1.DeleteOptions{})
	if err != nil {
		return errors.Wrapf(err, "failed to delete resource '%s' '%s' at '%s'", r.gvr, obj.GetName(), r.namespace)
	}
	return nil
}

// Get returns a specific resource from kubernetes cluster
func (r *resource) Get(name string, opts metav1.GetOptions, subresources ...string) (u *unstructured.Unstructured, err error) {
	if len(strings.TrimSpace(name)) == 0 {
		err = errors.Errorf("missing resource name: failed to get resource '%s' at '%s'", r.gvr, r.namespace)
		return
	}
	dynamic, err := Dynamic().Provide()
	if err != nil {
		err = errors.Wrapf(err, "failed to get resource '%s' '%s' at '%s'", r.gvr, name, r.namespace)
		return
	}
	u, err = dynamic.Resource(r.gvr).Namespace(r.namespace).Get(name, opts, subresources...)
	if err != nil {
		err = errors.Wrapf(err, "failed to get resource '%s' '%s' at '%s'", r.gvr, name, r.namespace)
		return
	}
	return
}

// Update updates the resource at kubernetes cluster
func (r *resource) Update(oldobj, newobj *unstructured.Unstructured, subresources ...string) (u *unstructured.Unstructured, err error) {
	if oldobj == nil {
		err = errors.Errorf("nil old resource instance: failed to update resource '%s' at '%s'", r.gvr, r.namespace)
		return
	}
	if newobj == nil {
		err = errors.Errorf("nil new resource instance: failed to update resource '%s' at '%s'", r.gvr, r.namespace)
		return
	}
	dynamic, err := Dynamic().Provide()
	if err != nil {
		err = errors.Wrapf(err, "failed to update resource '%s' '%s' at '%s'", r.gvr, oldobj.GetName(), r.namespace)
		return
	}

	resourceVersion := oldobj.GetResourceVersion()
	newobj.SetResourceVersion(resourceVersion)

	u, err = dynamic.Resource(r.gvr).Namespace(r.namespace).Update(newobj, metav1.UpdateOptions{}, subresources...)
	if err != nil {
		err = errors.Wrapf(err, "failed to update resource '%s' '%s' at '%s'", r.gvr, oldobj.GetName(), r.namespace)
		return
	}
	return
}

// List returns a list of specific resource at kubernetes cluster
func (r *resource) List(opts metav1.ListOptions) (u *unstructured.UnstructuredList, err error) {
	dynamic, err := Dynamic().Provide()
	if err != nil {
		err = errors.Wrapf(err, "failed to list resource '%s'  at '%s'", r.gvr, r.namespace)
		return
	}
	u, err = dynamic.Resource(r.gvr).Namespace(r.namespace).List(opts)
	if err != nil {
		err = errors.Wrapf(err, "failed to list resource '%s'  at '%s'", r.gvr, r.namespace)
		return
	}
	return
}

// ResourceApplyOptions is a utility instance used during the resource's apply
// operation
type ResourceApplyOptions struct {
	Getter  ResourceGetter
	Creator ResourceCreator
	Updater ResourceUpdater
}

// createOrUpdate is a resource that is suitable to be executed as an apply
// operation
type createOrUpdate struct {
	*resource
	options ResourceApplyOptions // options used during resource's apply operation
}

// CreateOrUpdate returns a new instance of createOrUpdate resource
func CreateOrUpdate(gvr schema.GroupVersionResource, namespace string) *createOrUpdate {
	resource := Resource(gvr, namespace)
	options := ResourceApplyOptions{Getter: resource, Creator: resource, Updater: resource}
	return &createOrUpdate{resource: resource, options: options}
}

// Apply applies a resource to the kubernetes cluster. In other words, it
// creates a new resource if it does not exist or updates the existing resource.
func (r *createOrUpdate) Apply(obj *unstructured.Unstructured, subresources ...string) (resource *unstructured.Unstructured, err error) {
	if r.options.Getter == nil {
		err = errors.New("nil resource getter instance: failed to apply resource")
		return
	}
	if r.options.Creator == nil {
		err = errors.New("nil resource creator instance: failed to apply resource")
		return
	}
	if r.options.Updater == nil {
		err = errors.New("nil resource updater instance: failed to apply resource")
		return
	}
	if obj == nil {
		err = errors.New("nil resource instance: failed to apply resource")
		return
	}
	resource, err = r.options.Getter.Get(obj.GetName(), metav1.GetOptions{})
	if err != nil && apierrors.IsNotFound(errors.Cause(err)) {
		return r.options.Creator.Create(obj, subresources...)
	}
	return r.options.Updater.Update(resource, obj, subresources...)
}

// ResourceDeleteOptions is a utility instance used during the resource's delete operations
type ResourceDeleteOptions struct {
	Deleter ResourceDeleter
}

// Delete is a resource that is suitable to be executed as a Delete operation
type Delete struct {
	*resource
	options ResourceDeleteOptions
}

// DeleteResource returns a new instance of delete resource
func DeleteResource(gvr schema.GroupVersionResource, namespace string) *Delete {
	resource := Resource(gvr, namespace)
	options := ResourceDeleteOptions{Deleter: resource}
	return &Delete{resource: resource, options: options}
}

// Delete deletes a resource from a kubernetes cluster
func (d *Delete) Delete(obj *unstructured.Unstructured, subresources ...string) error {
	if d.options.Deleter == nil {
		return errors.New("nil resource deleter instance: failed to delete resource")
	} else if obj == nil {
		return errors.New("nil resource instance: failed to delete resource")
	}
	return d.options.Deleter.Delete(obj, subresources...)
}

// ResourceListOptions is a utility instance used during the resource's list operations
type ResourceListOptions struct {
	Lister ResourceLister
}

// List is a resource resource that is suitable to be executed as a List operation
type List struct {
	*resource
	options ResourceListOptions
}

// ListResource returns a new instance of list resource
func ListResource(gvr schema.GroupVersionResource, namespace string) *List {
	resource := Resource(gvr, namespace)
	options := ResourceListOptions{Lister: resource}
	return &List{resource: resource, options: options}
}

// List lists a resource from a kubernetes cluster
func (l *List) List(options metav1.ListOptions) (u *unstructured.UnstructuredList, err error) {
	if l.options.Lister == nil {
		err = errors.New("nil resource lister instance: failed to list resource")
		return
	}
	return l.options.Lister.List(options)
}

// ResourceGetOptions is a utility instance used during the resource's get operations
type ResourceGetOptions struct {
	Getter ResourceGetter
}

// Get is resource that is suitable to be executed as Get operation
type Get struct {
	*resource
	options ResourceGetOptions
}

// GetResource returns a new instance of get resource
func GetResource(gvr schema.GroupVersionResource, namespace string) *Get {
	resource := Resource(gvr, namespace)
	options := ResourceGetOptions{Getter: resource}
	return &Get{resource: resource, options: options}
}

// Get gets a resource from a kubernetes cluster
func (g *Get) Get(name string, opts metav1.GetOptions, subresources ...string) (u *unstructured.Unstructured, err error) {
	if g.options.Getter == nil {
		err = errors.New("nil resource getter instance: failed to get resource")
		return
	}
	return g.options.Getter.Get(name, opts, subresources...)
}
<commit_msg>fix(installer): improve error handling during installation of resources (#1048)<commit_after>/*
Copyright 2018 The OpenEBS Authors

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

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

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

// TODO
// Move this file to pkg/k8sresource/v1alpha1

package v1alpha1

import (
	"strings"

	"github.com/pkg/errors"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime/schema"
)

// ResourceCreator abstracts creating an unstructured instance in kubernetes
// cluster
type ResourceCreator interface {
	Create(obj *unstructured.Unstructured, subresources ...string) (*unstructured.Unstructured, error)
}

// ResourceGetter abstracts fetching an unstructured instance from kubernetes
// cluster
type ResourceGetter interface {
	Get(name string, options metav1.GetOptions, subresources ...string) (*unstructured.Unstructured, error)
}

// ResourceLister abstracts fetching an unstructured list of instance from kubernetes
// cluster
type ResourceLister interface {
	List(options metav1.ListOptions) (*unstructured.UnstructuredList, error)
}

// ResourceUpdater abstracts updating an unstructured instance found in
// kubernetes cluster
type ResourceUpdater interface {
	Update(oldobj, newobj *unstructured.Unstructured, subresources ...string) (u *unstructured.Unstructured, err error)
}

// ResourceApplier abstracts applying an unstructured instance that may or may
// not be available in kubernetes cluster
type ResourceApplier interface {
	Apply(obj *unstructured.Unstructured, subresources ...string) (*unstructured.Unstructured, error)
}

// ResourceDeleter abstracts deletes an unstructured instance that is available in kubernetes cluster
type ResourceDeleter interface {
	Delete(obj *unstructured.Unstructured, subresources ...string) error
}

type resource struct {
	gvr       schema.GroupVersionResource // identify a resource
	namespace string                      // namespace where this resource is to be operated at
}

// Resource returns a new resource instance
func Resource(gvr schema.GroupVersionResource, namespace string) *resource {
	return &resource{gvr: gvr, namespace: namespace}
}

// Create creates a new resource in kubernetes cluster
func (r *resource) Create(obj *unstructured.Unstructured, subresources ...string) (u *unstructured.Unstructured, err error) {
	if obj == nil {
		err = errors.Errorf("nil resource instance: failed to create resource '%s' at '%s'", r.gvr, r.namespace)
		return
	}
	dynamic, err := Dynamic().Provide()
	if err != nil {
		err = errors.Wrapf(err, "failed to create resource '%s' '%s' at '%s'", r.gvr, obj.GetName(), r.namespace)
		return
	}
	u, err = dynamic.Resource(r.gvr).Namespace(r.namespace).Create(obj, metav1.CreateOptions{}, subresources...)
	if err != nil {
		err = errors.Wrapf(err, "failed to create resource '%s' '%s' at '%s'", r.gvr, obj.GetName(), r.namespace)
		return
	}
	return
}

// Delete deletes a existing resource in kubernetes cluster
func (r *resource) Delete(obj *unstructured.Unstructured, subresources ...string) error {
	if obj == nil {
		return errors.Errorf("nil resource instance: failed to delete resource '%s' at '%s'", r.gvr, r.namespace)
	}
	dynamic, err := Dynamic().Provide()
	if err != nil {
		return errors.Wrapf(err, "failed to delete resource '%s' '%s' at '%s'", r.gvr, obj.GetName(), r.namespace)
	}
	err = dynamic.Resource(r.gvr).Namespace(r.namespace).Delete(obj.GetName(), &metav1.DeleteOptions{})
	if err != nil {
		return errors.Wrapf(err, "failed to delete resource '%s' '%s' at '%s'", r.gvr, obj.GetName(), r.namespace)
	}
	return nil
}

// Get returns a specific resource from kubernetes cluster
func (r *resource) Get(name string, opts metav1.GetOptions, subresources ...string) (u *unstructured.Unstructured, err error) {
	if len(strings.TrimSpace(name)) == 0 {
		err = errors.Errorf("missing resource name: failed to get resource '%s' at '%s'", r.gvr, r.namespace)
		return
	}
	dynamic, err := Dynamic().Provide()
	if err != nil {
		err = errors.Wrapf(err, "failed to get resource '%s' '%s' at '%s'", r.gvr, name, r.namespace)
		return
	}
	u, err = dynamic.Resource(r.gvr).Namespace(r.namespace).Get(name, opts, subresources...)
	if err != nil {
		err = errors.Wrapf(err, "failed to get resource '%s' '%s' at '%s'", r.gvr, name, r.namespace)
		return
	}
	return
}

// Update updates the resource at kubernetes cluster
func (r *resource) Update(oldobj, newobj *unstructured.Unstructured, subresources ...string) (u *unstructured.Unstructured, err error) {
	if oldobj == nil {
		err = errors.Errorf("nil old resource instance: failed to update resource '%s' at '%s'", r.gvr, r.namespace)
		return
	}
	if newobj == nil {
		err = errors.Errorf("nil new resource instance: failed to update resource '%s' at '%s'", r.gvr, r.namespace)
		return
	}
	dynamic, err := Dynamic().Provide()
	if err != nil {
		err = errors.Wrapf(err, "failed to update resource '%s' '%s' at '%s'", r.gvr, oldobj.GetName(), r.namespace)
		return
	}

	resourceVersion := oldobj.GetResourceVersion()
	newobj.SetResourceVersion(resourceVersion)

	u, err = dynamic.Resource(r.gvr).Namespace(r.namespace).Update(newobj, metav1.UpdateOptions{}, subresources...)
	if err != nil {
		err = errors.Wrapf(err, "failed to update resource '%s' '%s' at '%s'", r.gvr, oldobj.GetName(), r.namespace)
		return
	}
	return
}

// List returns a list of specific resource at kubernetes cluster
func (r *resource) List(opts metav1.ListOptions) (u *unstructured.UnstructuredList, err error) {
	dynamic, err := Dynamic().Provide()
	if err != nil {
		err = errors.Wrapf(err, "failed to list resource '%s'  at '%s'", r.gvr, r.namespace)
		return
	}
	u, err = dynamic.Resource(r.gvr).Namespace(r.namespace).List(opts)
	if err != nil {
		err = errors.Wrapf(err, "failed to list resource '%s'  at '%s'", r.gvr, r.namespace)
		return
	}
	return
}

// ResourceApplyOptions is a utility instance used during the resource's apply
// operation
type ResourceApplyOptions struct {
	Getter  ResourceGetter
	Creator ResourceCreator
	Updater ResourceUpdater
}

// createOrUpdate is a resource that is suitable to be executed as an apply
// operation
type createOrUpdate struct {
	*resource
	options ResourceApplyOptions // options used during resource's apply operation
}

// CreateOrUpdate returns a new instance of createOrUpdate resource
func CreateOrUpdate(gvr schema.GroupVersionResource, namespace string) *createOrUpdate {
	resource := Resource(gvr, namespace)
	options := ResourceApplyOptions{Getter: resource, Creator: resource, Updater: resource}
	return &createOrUpdate{resource: resource, options: options}
}

// Apply applies a resource to the kubernetes cluster. In other words, it
// creates a new resource if it does not exist or updates the existing resource.
func (r *createOrUpdate) Apply(obj *unstructured.Unstructured, subresources ...string) (resource *unstructured.Unstructured, err error) {
	if r.options.Getter == nil {
		err = errors.New("nil resource getter instance: failed to apply resource")
		return
	}
	if r.options.Creator == nil {
		err = errors.New("nil resource creator instance: failed to apply resource")
		return
	}
	if r.options.Updater == nil {
		err = errors.New("nil resource updater instance: failed to apply resource")
		return
	}
	if obj == nil {
		err = errors.New("nil resource instance: failed to apply resource")
		return
	}
	resource, err = r.options.Getter.Get(obj.GetName(), metav1.GetOptions{})
	if err != nil {
		if apierrors.IsNotFound(errors.Cause(err)) {
			return r.options.Creator.Create(obj, subresources...)
		}
		return nil, err
	}
	return r.options.Updater.Update(resource, obj, subresources...)
}

// ResourceDeleteOptions is a utility instance used during the resource's delete operations
type ResourceDeleteOptions struct {
	Deleter ResourceDeleter
}

// Delete is a resource that is suitable to be executed as a Delete operation
type Delete struct {
	*resource
	options ResourceDeleteOptions
}

// DeleteResource returns a new instance of delete resource
func DeleteResource(gvr schema.GroupVersionResource, namespace string) *Delete {
	resource := Resource(gvr, namespace)
	options := ResourceDeleteOptions{Deleter: resource}
	return &Delete{resource: resource, options: options}
}

// Delete deletes a resource from a kubernetes cluster
func (d *Delete) Delete(obj *unstructured.Unstructured, subresources ...string) error {
	if d.options.Deleter == nil {
		return errors.New("nil resource deleter instance: failed to delete resource")
	} else if obj == nil {
		return errors.New("nil resource instance: failed to delete resource")
	}
	return d.options.Deleter.Delete(obj, subresources...)
}

// ResourceListOptions is a utility instance used during the resource's list operations
type ResourceListOptions struct {
	Lister ResourceLister
}

// List is a resource resource that is suitable to be executed as a List operation
type List struct {
	*resource
	options ResourceListOptions
}

// ListResource returns a new instance of list resource
func ListResource(gvr schema.GroupVersionResource, namespace string) *List {
	resource := Resource(gvr, namespace)
	options := ResourceListOptions{Lister: resource}
	return &List{resource: resource, options: options}
}

// List lists a resource from a kubernetes cluster
func (l *List) List(options metav1.ListOptions) (u *unstructured.UnstructuredList, err error) {
	if l.options.Lister == nil {
		err = errors.New("nil resource lister instance: failed to list resource")
		return
	}
	return l.options.Lister.List(options)
}

// ResourceGetOptions is a utility instance used during the resource's get operations
type ResourceGetOptions struct {
	Getter ResourceGetter
}

// Get is resource that is suitable to be executed as Get operation
type Get struct {
	*resource
	options ResourceGetOptions
}

// GetResource returns a new instance of get resource
func GetResource(gvr schema.GroupVersionResource, namespace string) *Get {
	resource := Resource(gvr, namespace)
	options := ResourceGetOptions{Getter: resource}
	return &Get{resource: resource, options: options}
}

// Get gets a resource from a kubernetes cluster
func (g *Get) Get(name string, opts metav1.GetOptions, subresources ...string) (u *unstructured.Unstructured, err error) {
	if g.options.Getter == nil {
		err = errors.New("nil resource getter instance: failed to get resource")
		return
	}
	return g.options.Getter.Get(name, opts, subresources...)
}
<|endoftext|>


<commit_before>package file

import (
	"os"
	"sync"
	"time"

	"github.com/go-kit/kit/log"
	"github.com/go-kit/kit/log/level"
	"github.com/hpcloud/tail"
	"github.com/prometheus/common/model"
	"go.uber.org/atomic"

	"github.com/grafana/loki/pkg/logproto"
	"github.com/grafana/loki/pkg/promtail/api"
	"github.com/grafana/loki/pkg/promtail/positions"
	"github.com/grafana/loki/pkg/util"
)

type tailer struct {
	metrics   *Metrics
	logger    log.Logger
	handler   api.EntryHandler
	positions positions.Positions

	path string
	tail *tail.Tail

	posAndSizeMtx sync.Mutex
	stopOnce      sync.Once

	running *atomic.Bool
	posquit chan struct{}
	posdone chan struct{}
	done    chan struct{}
}

func newTailer(metrics *Metrics, logger log.Logger, handler api.EntryHandler, positions positions.Positions, path string) (*tailer, error) {
	// Simple check to make sure the file we are tailing doesn't
	// have a position already saved which is past the end of the file.
	fi, err := os.Stat(path)
	if err != nil {
		return nil, err
	}
	pos, err := positions.Get(path)
	if err != nil {
		return nil, err
	}

	if fi.Size() < pos {
		positions.Remove(path)
	}

	tail, err := tail.TailFile(path, tail.Config{
		Follow:    true,
		Poll:      true,
		ReOpen:    true,
		MustExist: true,
		Location: &tail.SeekInfo{
			Offset: pos,
			Whence: 0,
		},
		Logger: util.NewLogAdapter(logger),
	})
	if err != nil {
		return nil, err
	}

	logger = log.With(logger, "component", "tailer")
	tailer := &tailer{
		metrics:   metrics,
		logger:    logger,
		handler:   api.AddLabelsMiddleware(model.LabelSet{FilenameLabel: model.LabelValue(path)}).Wrap(handler),
		positions: positions,
		path:      path,
		tail:      tail,
		running:   atomic.NewBool(false),
		posquit:   make(chan struct{}),
		posdone:   make(chan struct{}),
		done:      make(chan struct{}),
	}

	go tailer.readLines()
	go tailer.updatePosition()
	metrics.filesActive.Add(1.)
	return tailer, nil
}

// updatePosition is run in a goroutine and checks the current size of the file and saves it to the positions file
// at a regular interval. If there is ever an error it stops the tailer and exits, the tailer will be re-opened
// by the filetarget sync method if it still exists and will start reading from the last successful entry in the
// positions file.
func (t *tailer) updatePosition() {
	positionSyncPeriod := t.positions.SyncPeriod()
	positionWait := time.NewTicker(positionSyncPeriod)
	defer func() {
		positionWait.Stop()
		level.Info(t.logger).Log("msg", "position timer: exited", "path", t.path)
		close(t.posdone)
	}()

	for {
		select {
		case <-positionWait.C:
			err := t.markPositionAndSize()
			if err != nil {
				level.Error(t.logger).Log("msg", "position timer: error getting tail position and/or size, stopping tailer", "path", t.path, "error", err)
				err := t.tail.Stop()
				if err != nil {
					level.Error(t.logger).Log("msg", "position timer: error stopping tailer", "path", t.path, "error", err)
				}
				return
			}
		case <-t.posquit:
			return
		}
	}
}

// readLines runs in a goroutine and consumes the t.tail.Lines channel from the underlying tailer.
// it will only exit when that channel is closed. This is important to avoid a deadlock in the underlying
// tailer which can happen if there are unread lines in this channel and the Stop method on the tailer
// is called, the underlying tailer will never exit if there are unread lines in the t.tail.Lines channel
func (t *tailer) readLines() {
	level.Info(t.logger).Log("msg", "tail routine: started", "path", t.path)

	t.running.Store(true)

	// This function runs in a goroutine, if it exits this tailer will never do any more tailing.
	// Clean everything up.
	defer func() {
		t.cleanupMetrics()
		t.running.Store(false)
		level.Info(t.logger).Log("msg", "tail routine: exited", "path", t.path)
		close(t.done)
	}()
	entries := t.handler.Chan()
	for {
		line, ok := <-t.tail.Lines
		if !ok {
			level.Info(t.logger).Log("msg", "tail routine: tail channel closed, stopping tailer", "path", t.path, "reason", t.tail.Tomb.Err())
			return
		}

		// Note currently the tail implementation hardcodes Err to nil, this should never hit.
		if line.Err != nil {
			level.Error(t.logger).Log("msg", "tail routine: error reading line", "path", t.path, "error", line.Err)
			continue
		}

		t.metrics.readLines.WithLabelValues(t.path).Inc()
		t.metrics.logLengthHistogram.WithLabelValues(t.path).Observe(float64(len(line.Text)))
		entries <- api.Entry{
			Labels: model.LabelSet{},
			Entry: logproto.Entry{
				Timestamp: line.Time,
				Line:      line.Text,
			},
		}

	}
}

func (t *tailer) markPositionAndSize() error {
	// Lock this update as there are 2 timers calling this routine, the sync in filetarget and the positions sync in this file.
	t.posAndSizeMtx.Lock()
	defer t.posAndSizeMtx.Unlock()

	size, err := t.tail.Size()
	if err != nil {
		// If the file no longer exists, no need to save position information
		if err == os.ErrNotExist {
			level.Info(t.logger).Log("msg", "skipping update of position for a file which does not currently exist")
			return nil
		}
		return err
	}
	t.metrics.totalBytes.WithLabelValues(t.path).Set(float64(size))

	pos, err := t.tail.Tell()
	if err != nil {
		return err
	}
	t.metrics.readBytes.WithLabelValues(t.path).Set(float64(pos))
	t.positions.Put(t.path, pos)

	return nil
}

func (t *tailer) stop() {
	// stop can be called by two separate threads in filetarget, to avoid a panic closing channels more than once
	// we wrap the stop in a sync.Once.
	t.stopOnce.Do(func() {
		// Shut down the position marker thread
		close(t.posquit)
		<-t.posdone

		// Save the current position before shutting down tailer
		err := t.markPositionAndSize()
		if err != nil {
			level.Error(t.logger).Log("msg", "error marking file position when stopping tailer", "path", t.path, "error", err)
		}

		// Stop the underlying tailer
		err = t.tail.Stop()
		if err != nil {
			level.Error(t.logger).Log("msg", "error stopping tailer", "path", t.path, "error", err)
		}
		// Wait for readLines() to consume all the remaining messages and exit when the channel is closed
		<-t.done
		level.Info(t.logger).Log("msg", "stopped tailing file", "path", t.path)
		t.handler.Stop()
	})
}

func (t *tailer) isRunning() bool {
	return t.running.Load()
}

// cleanupMetrics removes all metrics exported by this tailer
func (t *tailer) cleanupMetrics() {
	// When we stop tailing the file, also un-export metrics related to the file
	t.metrics.filesActive.Add(-1.)
	t.metrics.readLines.DeleteLabelValues(t.path)
	t.metrics.readBytes.DeleteLabelValues(t.path)
	t.metrics.totalBytes.DeleteLabelValues(t.path)
	t.metrics.logLengthHistogram.DeleteLabelValues(t.path)
}
<commit_msg>Added path information to deleted tailed file (#3457)<commit_after>package file

import (
	"os"
	"sync"
	"time"

	"github.com/go-kit/kit/log"
	"github.com/go-kit/kit/log/level"
	"github.com/hpcloud/tail"
	"github.com/prometheus/common/model"
	"go.uber.org/atomic"

	"github.com/grafana/loki/pkg/logproto"
	"github.com/grafana/loki/pkg/promtail/api"
	"github.com/grafana/loki/pkg/promtail/positions"
	"github.com/grafana/loki/pkg/util"
)

type tailer struct {
	metrics   *Metrics
	logger    log.Logger
	handler   api.EntryHandler
	positions positions.Positions

	path string
	tail *tail.Tail

	posAndSizeMtx sync.Mutex
	stopOnce      sync.Once

	running *atomic.Bool
	posquit chan struct{}
	posdone chan struct{}
	done    chan struct{}
}

func newTailer(metrics *Metrics, logger log.Logger, handler api.EntryHandler, positions positions.Positions, path string) (*tailer, error) {
	// Simple check to make sure the file we are tailing doesn't
	// have a position already saved which is past the end of the file.
	fi, err := os.Stat(path)
	if err != nil {
		return nil, err
	}
	pos, err := positions.Get(path)
	if err != nil {
		return nil, err
	}

	if fi.Size() < pos {
		positions.Remove(path)
	}

	tail, err := tail.TailFile(path, tail.Config{
		Follow:    true,
		Poll:      true,
		ReOpen:    true,
		MustExist: true,
		Location: &tail.SeekInfo{
			Offset: pos,
			Whence: 0,
		},
		Logger: util.NewLogAdapter(logger),
	})
	if err != nil {
		return nil, err
	}

	logger = log.With(logger, "component", "tailer")
	tailer := &tailer{
		metrics:   metrics,
		logger:    logger,
		handler:   api.AddLabelsMiddleware(model.LabelSet{FilenameLabel: model.LabelValue(path)}).Wrap(handler),
		positions: positions,
		path:      path,
		tail:      tail,
		running:   atomic.NewBool(false),
		posquit:   make(chan struct{}),
		posdone:   make(chan struct{}),
		done:      make(chan struct{}),
	}

	go tailer.readLines()
	go tailer.updatePosition()
	metrics.filesActive.Add(1.)
	return tailer, nil
}

// updatePosition is run in a goroutine and checks the current size of the file and saves it to the positions file
// at a regular interval. If there is ever an error it stops the tailer and exits, the tailer will be re-opened
// by the filetarget sync method if it still exists and will start reading from the last successful entry in the
// positions file.
func (t *tailer) updatePosition() {
	positionSyncPeriod := t.positions.SyncPeriod()
	positionWait := time.NewTicker(positionSyncPeriod)
	defer func() {
		positionWait.Stop()
		level.Info(t.logger).Log("msg", "position timer: exited", "path", t.path)
		close(t.posdone)
	}()

	for {
		select {
		case <-positionWait.C:
			err := t.markPositionAndSize()
			if err != nil {
				level.Error(t.logger).Log("msg", "position timer: error getting tail position and/or size, stopping tailer", "path", t.path, "error", err)
				err := t.tail.Stop()
				if err != nil {
					level.Error(t.logger).Log("msg", "position timer: error stopping tailer", "path", t.path, "error", err)
				}
				return
			}
		case <-t.posquit:
			return
		}
	}
}

// readLines runs in a goroutine and consumes the t.tail.Lines channel from the underlying tailer.
// it will only exit when that channel is closed. This is important to avoid a deadlock in the underlying
// tailer which can happen if there are unread lines in this channel and the Stop method on the tailer
// is called, the underlying tailer will never exit if there are unread lines in the t.tail.Lines channel
func (t *tailer) readLines() {
	level.Info(t.logger).Log("msg", "tail routine: started", "path", t.path)

	t.running.Store(true)

	// This function runs in a goroutine, if it exits this tailer will never do any more tailing.
	// Clean everything up.
	defer func() {
		t.cleanupMetrics()
		t.running.Store(false)
		level.Info(t.logger).Log("msg", "tail routine: exited", "path", t.path)
		close(t.done)
	}()
	entries := t.handler.Chan()
	for {
		line, ok := <-t.tail.Lines
		if !ok {
			level.Info(t.logger).Log("msg", "tail routine: tail channel closed, stopping tailer", "path", t.path, "reason", t.tail.Tomb.Err())
			return
		}

		// Note currently the tail implementation hardcodes Err to nil, this should never hit.
		if line.Err != nil {
			level.Error(t.logger).Log("msg", "tail routine: error reading line", "path", t.path, "error", line.Err)
			continue
		}

		t.metrics.readLines.WithLabelValues(t.path).Inc()
		t.metrics.logLengthHistogram.WithLabelValues(t.path).Observe(float64(len(line.Text)))
		entries <- api.Entry{
			Labels: model.LabelSet{},
			Entry: logproto.Entry{
				Timestamp: line.Time,
				Line:      line.Text,
			},
		}

	}
}

func (t *tailer) markPositionAndSize() error {
	// Lock this update as there are 2 timers calling this routine, the sync in filetarget and the positions sync in this file.
	t.posAndSizeMtx.Lock()
	defer t.posAndSizeMtx.Unlock()

	size, err := t.tail.Size()
	if err != nil {
		// If the file no longer exists, no need to save position information
		if err == os.ErrNotExist {
			level.Info(t.logger).Log("msg", "skipping update of position for a file which does not currently exist", "path", t.path)
			return nil
		}
		return err
	}
	t.metrics.totalBytes.WithLabelValues(t.path).Set(float64(size))

	pos, err := t.tail.Tell()
	if err != nil {
		return err
	}
	t.metrics.readBytes.WithLabelValues(t.path).Set(float64(pos))
	t.positions.Put(t.path, pos)

	return nil
}

func (t *tailer) stop() {
	// stop can be called by two separate threads in filetarget, to avoid a panic closing channels more than once
	// we wrap the stop in a sync.Once.
	t.stopOnce.Do(func() {
		// Shut down the position marker thread
		close(t.posquit)
		<-t.posdone

		// Save the current position before shutting down tailer
		err := t.markPositionAndSize()
		if err != nil {
			level.Error(t.logger).Log("msg", "error marking file position when stopping tailer", "path", t.path, "error", err)
		}

		// Stop the underlying tailer
		err = t.tail.Stop()
		if err != nil {
			level.Error(t.logger).Log("msg", "error stopping tailer", "path", t.path, "error", err)
		}
		// Wait for readLines() to consume all the remaining messages and exit when the channel is closed
		<-t.done
		level.Info(t.logger).Log("msg", "stopped tailing file", "path", t.path)
		t.handler.Stop()
	})
}

func (t *tailer) isRunning() bool {
	return t.running.Load()
}

// cleanupMetrics removes all metrics exported by this tailer
func (t *tailer) cleanupMetrics() {
	// When we stop tailing the file, also un-export metrics related to the file
	t.metrics.filesActive.Add(-1.)
	t.metrics.readLines.DeleteLabelValues(t.path)
	t.metrics.readBytes.DeleteLabelValues(t.path)
	t.metrics.totalBytes.DeleteLabelValues(t.path)
	t.metrics.logLengthHistogram.DeleteLabelValues(t.path)
}
<|endoftext|>


<commit_before>package ginkgo

import (
	"bytes"
	"fmt"
	"time"

	"k8s.io/client-go/rest"

	"github.com/openshift/origin/pkg/monitor/monitorapi"
)

// JUnitsForEvents returns a set of JUnit results for the provided events encountered
// during a test suite run.
type JUnitsForEvents interface {
	// JUnitsForEvents returns a set of additional test passes or failures implied by the
	// events sent during the test suite run. If passed is false, the entire suite is failed.
	// To set a test as flaky, return a passing and failing JUnitTestCase with the same name.
	JUnitsForEvents(events monitorapi.Intervals, duration time.Duration, kubeClientConfig *rest.Config, testSuite string) []*JUnitTestCase
}

// JUnitForEventsFunc converts a function into the JUnitForEvents interface.
// kubeClientConfig may or may not be present.  The JUnit evaluation needs to tolerate a missing *rest.Config
// and an unavailable cluster without crashing.
type JUnitForEventsFunc func(events monitorapi.Intervals, duration time.Duration, kubeClientConfig *rest.Config, testSuite string) []*JUnitTestCase

func (fn JUnitForEventsFunc) JUnitsForEvents(events monitorapi.Intervals, duration time.Duration, kubeClientConfig *rest.Config, testSuite string) []*JUnitTestCase {
	return fn(events, duration, kubeClientConfig, testSuite)
}

// JUnitsForAllEvents aggregates multiple JUnitsForEvent interfaces and returns
// the result of all invocations. It ignores nil interfaces.
type JUnitsForAllEvents []JUnitsForEvents

func (a JUnitsForAllEvents) JUnitsForEvents(events monitorapi.Intervals, duration time.Duration, kubeClientConfig *rest.Config, testSuite string) []*JUnitTestCase {
	var all []*JUnitTestCase
	for _, obj := range a {
		if obj == nil {
			continue
		}
		results := obj.JUnitsForEvents(events, duration, kubeClientConfig, testSuite)
		all = append(all, results...)
	}
	return all
}

func createSyntheticTestsFromMonitor(events monitorapi.Intervals, monitorDuration time.Duration) ([]*JUnitTestCase, *bytes.Buffer, *bytes.Buffer) {
	var syntheticTestResults []*JUnitTestCase

	buf, errBuf := &bytes.Buffer{}, &bytes.Buffer{}
	fmt.Fprintf(buf, "\nTimeline:\n\n")
	errorCount := 0
	for _, event := range events {
		if event.Level == monitorapi.Error {
			errorCount++
			fmt.Fprintln(errBuf, event.String())
		}
		fmt.Fprintln(buf, event.String())
	}
	fmt.Fprintln(buf)

	if errorCount > 0 {
		syntheticTestResults = append(
			syntheticTestResults,
			&JUnitTestCase{
				Name:      "[sig-arch] Monitor cluster while tests execute",
				SystemOut: buf.String(),
				Duration:  monitorDuration.Seconds(),
				FailureOutput: &FailureOutput{
					Output: fmt.Sprintf("%d error level events were detected during this test run:\n\n%s", errorCount, errBuf.String()),
				},
			},
			// write a passing test to trigger detection of this issue as a flake, indicating we have no idea whether
			// these are actual failures or not
			&JUnitTestCase{
				Name:     "[sig-arch] Monitor cluster while tests execute",
				Duration: monitorDuration.Seconds(),
			},
		)
	}

	return syntheticTestResults, buf, errBuf
}
<commit_msg>Always include event intervals in junit sysout even if no failures.<commit_after>package ginkgo

import (
	"bytes"
	"fmt"
	"time"

	"k8s.io/client-go/rest"

	"github.com/openshift/origin/pkg/monitor/monitorapi"
)

// JUnitsForEvents returns a set of JUnit results for the provided events encountered
// during a test suite run.
type JUnitsForEvents interface {
	// JUnitsForEvents returns a set of additional test passes or failures implied by the
	// events sent during the test suite run. If passed is false, the entire suite is failed.
	// To set a test as flaky, return a passing and failing JUnitTestCase with the same name.
	JUnitsForEvents(events monitorapi.Intervals, duration time.Duration, kubeClientConfig *rest.Config, testSuite string) []*JUnitTestCase
}

// JUnitForEventsFunc converts a function into the JUnitForEvents interface.
// kubeClientConfig may or may not be present.  The JUnit evaluation needs to tolerate a missing *rest.Config
// and an unavailable cluster without crashing.
type JUnitForEventsFunc func(events monitorapi.Intervals, duration time.Duration, kubeClientConfig *rest.Config, testSuite string) []*JUnitTestCase

func (fn JUnitForEventsFunc) JUnitsForEvents(events monitorapi.Intervals, duration time.Duration, kubeClientConfig *rest.Config, testSuite string) []*JUnitTestCase {
	return fn(events, duration, kubeClientConfig, testSuite)
}

// JUnitsForAllEvents aggregates multiple JUnitsForEvent interfaces and returns
// the result of all invocations. It ignores nil interfaces.
type JUnitsForAllEvents []JUnitsForEvents

func (a JUnitsForAllEvents) JUnitsForEvents(events monitorapi.Intervals, duration time.Duration, kubeClientConfig *rest.Config, testSuite string) []*JUnitTestCase {
	var all []*JUnitTestCase
	for _, obj := range a {
		if obj == nil {
			continue
		}
		results := obj.JUnitsForEvents(events, duration, kubeClientConfig, testSuite)
		all = append(all, results...)
	}
	return all
}

func createSyntheticTestsFromMonitor(events monitorapi.Intervals, monitorDuration time.Duration) ([]*JUnitTestCase, *bytes.Buffer, *bytes.Buffer) {
	var syntheticTestResults []*JUnitTestCase

	buf, errBuf := &bytes.Buffer{}, &bytes.Buffer{}
	fmt.Fprintf(buf, "\nTimeline:\n\n")
	errorCount := 0
	for _, event := range events {
		if event.Level == monitorapi.Error {
			errorCount++
			fmt.Fprintln(errBuf, event.String())
		}
		fmt.Fprintln(buf, event.String())
	}
	fmt.Fprintln(buf)

	monitorTestName := "[sig-arch] Monitor cluster while tests execute"
	if errorCount > 0 {
		syntheticTestResults = append(
			syntheticTestResults,
			&JUnitTestCase{
				Name:      monitorTestName,
				SystemOut: buf.String(),
				Duration:  monitorDuration.Seconds(),
				FailureOutput: &FailureOutput{
					Output: fmt.Sprintf("%d error level events were detected during this test run:\n\n%s", errorCount, errBuf.String()),
				},
			},
			// write a passing test to trigger detection of this issue as a flake, indicating we have no idea whether
			// these are actual failures or not
			&JUnitTestCase{
				Name:     monitorTestName,
				Duration: monitorDuration.Seconds(),
			},
		)
	} else {
		// even if no error events, add a passed test including the output so we can scan with search.ci:
		syntheticTestResults = append(
			syntheticTestResults,
			&JUnitTestCase{
				Name:      monitorTestName,
				Duration:  monitorDuration.Seconds(),
				SystemOut: buf.String(),
			},
		)
	}

	return syntheticTestResults, buf, errBuf
}
<|endoftext|>