<commit_before>// Copyright 2011, Bryan Matsuo. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
/*
*  File: project.go
*  Author: Bryan Matsuo [bmatsuo@soe.ucsc.edu]
*  Created: Sat Jul  2 20:28:54 PDT 2011
 */
import (
    "os"
    "fmt"
    "log"
    "time"
)

var (
    NoUserNameError        = os.NewError("Missing remote repository username.")
    NoRemoteError          = os.NewError("Missing remote repository url")
    DirPermissions  uint32 = 0755
    FilePermissions uint32 = 0644
)

type ProjectType int

const (
    NilProjectType ProjectType = iota
    CmdType
    PkgType
    //LibType
    //MainType
)

func (ptype ProjectType) String() string {
    switch ptype {
    case CmdType:
        return "cmd"
    case PkgType:
        return "pkg"
    }
    return ""
}

func DefaultTarget(pname string) string {
    // TODO strip special characters from the prjoect name.
    return pname
}

type Project struct {
    Name    string
    Target  string
    User    string
    Remote  string
    License LicenseType
    Type    ProjectType
    Host    RepoHost
    Repo    RepoType
}

func (p Project) Create() os.Error {
    var dict = p.GenerateDictionary()
    var errMkdir, errChdir, errFiles, errRepo, errChdirBack os.Error

    // Make the directory and change the working directory.
    if DEBUG || VERBOSE {
        fmt.Print("Creating project directory.\n")
    }
    errMkdir = os.Mkdir(p.Name, DirPermissions)
    if errMkdir != nil {
        return errMkdir
    }
    if DEBUG || VERBOSE {
        fmt.Print("Entering project directory.\n")
    }
    errChdir = os.Chdir(p.Name)
    if errChdir != nil {
        return errChdir
    }
    errFiles = p.CreateFiles(dict)
    if errFiles != nil {
        return errFiles
    }
    if userepo {
        errRepo = p.InitializeRepo(true, true, true)
        if errRepo != nil {
            return errRepo
        }
    }
    if DEBUG || VERBOSE {
        fmt.Print("Leaving project directory.\n")
    }
    errChdirBack = os.Chdir("..")
    return errChdirBack
}
func (p Project) CreateFiles(dict map[string]string) os.Error {
    var errMake, errMain, errOpt, errDoc, errLic, errTest, errReadme, errOther os.Error
    errMake = p.CreateMakefile(dict)
    if errMake != nil {
        return errMake
    }
    errMain = p.CreateMainFile(dict)
    if errMain != nil {
        return errMain
    }
    errOpt = p.CreateOptionsFile(dict)
    if errOpt != nil {
        return errOpt
    }
    errDoc = p.CreateDocFile(dict)
    if errDoc != nil {
        return errDoc
    }
    errTest = p.CreateTestFile(dict)
    if errTest != nil {
        return errTest
    }
    errReadme = p.CreateReadme(dict)
    if errReadme != nil {
        return errReadme
    }
    errOther = p.CreateOtherFiles(dict)
    if errOther != nil {
        return errOther
    }
    errLic = p.CreateLicense(dict)
    if errLic != nil {
        return errLic
    }
    return nil
}

func (p Project) GenerateDictionary() map[string]string {
    var td = make(map[string]string, 9)
    td["project"] = p.Name
    td["name"] = AppConfig.Name
    td["email"] = AppConfig.Email
    td["gotarget"] = p.Target
    td["main"] = p.MainFilename()
    td["type"] = p.Type.String()
    td["repo"] = p.HostRepoString()
    td["year"] = YearString()
    td["date"] = DateString()
    return td
}

func (p Project) CreateMakefile(dict map[string]string) os.Error {
    var (
        templatePath = p.MakefileTemplatePath()
        errWrite     = WriteTemplate("Makefile", "makefile", dict, templatePath...)
    )
    return errWrite
}
func (p Project) CreateMainFile(dict map[string]string) os.Error {
    var (
        mainfile            = p.MainFilename()
        ltemplateName       = p.GofileLicenseHeadTemplateName()
        templatePath        = p.MainTemplatePath()
        errWrite, errAppend os.Error
    )
    if ltemplateName == "" {
        if DEBUG {
            log.Print("No license template found for %s", p.License.String())
        }
        errWrite = WriteTemplate(mainfile, "main file", dict, templatePath...)
        return errWrite
    }
    var ltemplatePath = []string{"licenses", ltemplateName}
    errWrite = WriteTemplate(mainfile, "main file license", dict, ltemplatePath...)
    if errWrite != nil {
        return errWrite
    }
    errAppend = AppendTemplate(mainfile, "main file contents", dict, templatePath...)
    return errAppend
}
func (p Project) CreateTestFile(dict map[string]string) os.Error {
    if !AppConfig.MakeTest {
        if DEBUG || VERBOSE {
            fmt.Printf("Skipping test file generation.")
        }
        return nil
    }
    var (
        testfile            = p.TestFilename()
        ltemplateName       = p.GofileLicenseHeadTemplateName()
        templatePath        = p.TestTemplatePath()
        errWrite, errAppend os.Error
    )
    if ltemplateName == "" {
        if DEBUG {
            log.Print("No license template found for %s", p.License.String())
        }
        errWrite = WriteTemplate(testfile, "test file", dict, templatePath...)
        return errWrite
    }
    var ltemplatePath = []string{"licenses", ltemplateName}
    errWrite = WriteTemplate(testfile, "test file license", dict, ltemplatePath...)
    if errWrite != nil {
        return errWrite
    }
    errAppend = AppendTemplate(testfile, "test file contents", dict, templatePath...)
    return errAppend
}
func (p Project) CreateReadme(dict map[string]string) os.Error {
    var (
        templatePath = p.ReadmeTemplatePath()
        readme       = p.ReadmeFilename()
    )
    var errWrite = WriteTemplate(readme, "README", dict, templatePath...)
    if errWrite != nil {
        return errWrite
    }
    if p.License == NilLicenseType {
        return nil
    }
    var (
        ltemplatePath = []string{"licenses", p.ReadmeLicenseTailTemplateName()}
        errAppend     = AppendTemplate(readme, "README license tail", dict, ltemplatePath...)
    )
    return errAppend
}
func (p Project) CreateLicense(dict map[string]string) os.Error {
    var (
        templatePath = []string{"licenses", p.LicenseTemplateName()}
        license      = "LICENSE"
    )
    var errWrite = WriteTemplate(license, "license", dict, templatePath...)
    return errWrite
}
func (p Project) CreateOptionsFile(dict map[string]string) os.Error {
    if p.Type == PkgType {
        return nil
    }
    var (
        doc          = "options.go"
        templatePath = p.OptionsTemplatePath()
        errWrite     = WriteTemplate(doc, "option parsing file", dict, templatePath...)
    )
    return errWrite
}
func (p Project) CreateDocFile(dict map[string]string) os.Error {
    if p.Type == PkgType {
        return nil
    }
    var (
        doc          = "doc.go"
        templatePath = p.DocTemplatePath()
        errWrite     = WriteTemplate(doc, "documentation file", dict, templatePath...)
    )
    return errWrite
}
func (p Project) CreateOtherFiles(dict map[string]string) os.Error {
    var templatePaths = p.OtherTemplatePaths()
    if templatePaths == nil {
        return nil
    }
    for _, path := range templatePaths {
        var errWrite = WriteTemplate(path[0], "other file", dict, path[1:]...)
        if errWrite != nil {
            return errWrite
        }
    }
    return nil
}
func (p Project) InitializeRepo(add, commit, push bool) os.Error {
    switch p.Repo {
    case GitType:
        var git = GitRepository{}
        git.Initialize(add, commit)
    case MercurialType:
        var hg = MercurialRepository{}
        hg.Initialize(add, commit)
    }
    switch p.Host {
    case GitHubHost:
        var origin = p.Remote
        if origin == "" {
            return nil
        }
        var github = GitHubRepository{p}
        var errGHInit = github.Init(origin)
        if errGHInit != nil {
            return errGHInit
        }
        if push {
            var errPush = github.Push()
            if errPush != nil {
                return errPush
            }
        }
        return nil
    }
    return nil
}

func (p Project) MainFilename() string {
    return p.Target + ".go"
}
func (p Project) TestFilename() string {
    switch p.Type {
    case CmdType:
        return "main_test.go"
    case PkgType:
        return p.Target + "_test.go"
    }
    return p.Target + "_test.go"
}
func (p Project) ReadmeFilename() string {
    if p.ReadmeIsMarkdown() {
        return "README.md"
    }
    return "README"
}

func (p Project) LicenseTemplateName() string {
    var lstring = p.License.TemplateNamePrefix()
    if lstring == "" {
        return ""
    }
    return lstring + ".t"
}
func (p Project) GofileLicenseHeadTemplateName() string {
    var lstring = p.License.TemplateNamePrefix()
    if lstring == "" {
        return ""
    }
    return lstring + ".gohead.t"
}
func (p Project) ReadmeLicenseTailTemplateName() string {
    var lstring = p.License.TemplateNamePrefix()
    if lstring == "" {
        return ""
    }
    if p.ReadmeIsMarkdown() {
        return lstring + ".readme.md.t"
    }
    return lstring + ".readme.t"
}
func (p Project) MainTemplateName() string {
    switch p.Type {
    case PkgType:
        return "pkg.t"
    case CmdType:
        return "cmd.t"
    }
    return ""
}
func (p Project) TestTemplateName() string {
    switch p.Type {
    case PkgType:
        return "pkg.t"
    case CmdType:
        return "cmd.t"
    }
    return ""
}
func (p Project) ReadmeTemplateName() string {
    switch p.Type {
    case PkgType:
        if p.ReadmeIsMarkdown() {
            return "pkg.md.t"
        } else {
            return "pkg.t"
        }
    case CmdType:
        if p.ReadmeIsMarkdown() {
            return "cmd.md.t"
        } else {
            return "cmd.t"
        }
    }
    return ""
}

func (p Project) MakefileTemplatePath() []string {
    return []string{"makefiles", p.Type.String() + ".t"}
}
func (p Project) MainTemplatePath() []string {
    return []string{"gofiles", p.MainTemplateName()}
}
func (p Project) TestTemplatePath() []string {
    return []string{"testfiles", p.TestTemplateName()}
}
func (p Project) ReadmeTemplatePath() []string {
    return []string{"README", p.ReadmeTemplateName()}
}
func (p Project) OptionsTemplatePath() []string {
    return []string{"gofiles", "options.t"}
}
func (p Project) DocTemplatePath() []string {
    return []string{"gofiles", "doc.t"}
}
func (p Project) OtherTemplatePaths() [][]string {
    var others = make([][]string, 0, 1)
    switch p.Repo {
    case GitType:
        others = append(others, []string{".gitignore", "otherfiles", "gitignore.t"})
    case MercurialType:
        others = append(others, []string{".hgignore", "otherfiles", "hgignore.t"})
    }
    if len(others) == 0 {
        return nil
    }
    return others
}

func (p Project) HostString() string {
    switch p.Host {
    case GitHubHost:
        if p.User == "" {
            return ""
        }
        return "github.com/" + p.User
    }
    return "<INSERT REPO HOST HERE>"
}
func (p Project) HostRepoString() string {
    switch p.Host {
    case GitHubHost:
        if p.User == "" {
            return ""
        }
        return "github.com/" + p.User + "/" + p.Target
    }
    return "<INSERT REPO HOST HERE>"
}
func YearString() string {
    return time.LocalTime().Format("2006")
}
func DateString() string {
    return time.LocalTime().String()
}
func (p Project) ReadmeIsMarkdown() bool {
    return userepo && p.Host == GitHubHost
}
<commit_msg>Clean up (*Project) CreateProject().<commit_after>// Copyright 2011, Bryan Matsuo. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
/*
*  File: project.go
*  Author: Bryan Matsuo [bmatsuo@soe.ucsc.edu]
*  Created: Sat Jul  2 20:28:54 PDT 2011
 */
import (
    "os"
    "fmt"
    "log"
    "time"
)

var (
    NoUserNameError        = os.NewError("Missing remote repository username.")
    NoRemoteError          = os.NewError("Missing remote repository url")
    DirPermissions  uint32 = 0755
    FilePermissions uint32 = 0644
)

type ProjectType int

const (
    NilProjectType ProjectType = iota
    CmdType
    PkgType
    //LibType
    //MainType
)

func (ptype ProjectType) String() string {
    switch ptype {
    case CmdType:
        return "cmd"
    case PkgType:
        return "pkg"
    }
    return ""
}

func DefaultTarget(pname string) string {
    // TODO strip special characters from the prjoect name.
    return pname
}

type Project struct {
    Name    string
    Target  string
    User    string
    Remote  string
    License LicenseType
    Type    ProjectType
    Host    RepoHost
    Repo    RepoType
}

func (p Project) Create() os.Error {
    var dict = p.GenerateDictionary()
    var errMkdir, errChdir, errFiles, errRepo, errChdirBack os.Error

    // Make the directory and change the working directory.
    if DEBUG || VERBOSE {
        fmt.Print("Creating project directory.\n")
    }
    errMkdir = os.Mkdir(p.Name, DirPermissions)
    if errMkdir != nil {
        return errMkdir
    }
    if DEBUG || VERBOSE {
        fmt.Print("Entering project directory.\n")
    }
    errChdir = os.Chdir(p.Name)
    if errChdir != nil {
        return errChdir
    }
    errFiles = p.CreateFiles(dict)
    if errFiles != nil {
        return errFiles
    }
    if userepo {
        errRepo = p.InitializeRepo(true, true, true)
        if errRepo != nil {
            return errRepo
        }
    }
    if DEBUG || VERBOSE {
        fmt.Print("Leaving project directory.\n")
    }
    errChdirBack = os.Chdir("..")
    return errChdirBack
}
func (p Project) CreateFiles(dict map[string]string) os.Error {
    if errMake = p.CreateMakefile(dict); errMake != nil {
        return errMake
    }
    if errMain = p.CreateMainFile(dict); errMain != nil {
        return errMain
    }
    if errOpt = p.CreateOptionsFile(dict); errOpt != nil {
        return errOpt
    }
    if errDoc = p.CreateDocFile(dict); errDoc != nil {
        return errDoc
    }
    if errTest = p.CreateTestFile(dict); errTest != nil {
        return errTest
    }
    if errReadme = p.CreateReadme(dict); errReadme != nil {
        return errReadme
    }
    if errOther = p.CreateOtherFiles(dict); errOther != nil {
        return errOther
    }
    if errLic = p.CreateLicense(dict); errLic != nil {
        return errLic
    }
    return nil
}

func (p Project) GenerateDictionary() map[string]string {
    var td = make(map[string]string, 9)
    td["project"] = p.Name
    td["name"] = AppConfig.Name
    td["email"] = AppConfig.Email
    td["gotarget"] = p.Target
    td["main"] = p.MainFilename()
    td["type"] = p.Type.String()
    td["repo"] = p.HostRepoString()
    td["year"] = YearString()
    td["date"] = DateString()
    return td
}

func (p Project) CreateMakefile(dict map[string]string) os.Error {
    var (
        templatePath = p.MakefileTemplatePath()
        errWrite     = WriteTemplate("Makefile", "makefile", dict, templatePath...)
    )
    return errWrite
}
func (p Project) CreateMainFile(dict map[string]string) os.Error {
    var (
        mainfile            = p.MainFilename()
        ltemplateName       = p.GofileLicenseHeadTemplateName()
        templatePath        = p.MainTemplatePath()
        errWrite, errAppend os.Error
    )
    if ltemplateName == "" {
        if DEBUG {
            log.Print("No license template found for %s", p.License.String())
        }
        errWrite = WriteTemplate(mainfile, "main file", dict, templatePath...)
        return errWrite
    }
    var ltemplatePath = []string{"licenses", ltemplateName}
    errWrite = WriteTemplate(mainfile, "main file license", dict, ltemplatePath...)
    if errWrite != nil {
        return errWrite
    }
    errAppend = AppendTemplate(mainfile, "main file contents", dict, templatePath...)
    return errAppend
}
func (p Project) CreateTestFile(dict map[string]string) os.Error {
    if !AppConfig.MakeTest {
        if DEBUG || VERBOSE {
            fmt.Printf("Skipping test file generation.")
        }
        return nil
    }
    var (
        testfile            = p.TestFilename()
        ltemplateName       = p.GofileLicenseHeadTemplateName()
        templatePath        = p.TestTemplatePath()
        errWrite, errAppend os.Error
    )
    if ltemplateName == "" {
        if DEBUG {
            log.Print("No license template found for %s", p.License.String())
        }
        errWrite = WriteTemplate(testfile, "test file", dict, templatePath...)
        return errWrite
    }
    var ltemplatePath = []string{"licenses", ltemplateName}
    errWrite = WriteTemplate(testfile, "test file license", dict, ltemplatePath...)
    if errWrite != nil {
        return errWrite
    }
    errAppend = AppendTemplate(testfile, "test file contents", dict, templatePath...)
    return errAppend
}
func (p Project) CreateReadme(dict map[string]string) os.Error {
    var (
        templatePath = p.ReadmeTemplatePath()
        readme       = p.ReadmeFilename()
    )
    var errWrite = WriteTemplate(readme, "README", dict, templatePath...)
    if errWrite != nil {
        return errWrite
    }
    if p.License == NilLicenseType {
        return nil
    }
    var (
        ltemplatePath = []string{"licenses", p.ReadmeLicenseTailTemplateName()}
        errAppend     = AppendTemplate(readme, "README license tail", dict, ltemplatePath...)
    )
    return errAppend
}
func (p Project) CreateLicense(dict map[string]string) os.Error {
    var (
        templatePath = []string{"licenses", p.LicenseTemplateName()}
        license      = "LICENSE"
    )
    var errWrite = WriteTemplate(license, "license", dict, templatePath...)
    return errWrite
}
func (p Project) CreateOptionsFile(dict map[string]string) os.Error {
    if p.Type == PkgType {
        return nil
    }
    var (
        doc          = "options.go"
        templatePath = p.OptionsTemplatePath()
        errWrite     = WriteTemplate(doc, "option parsing file", dict, templatePath...)
    )
    return errWrite
}
func (p Project) CreateDocFile(dict map[string]string) os.Error {
    if p.Type == PkgType {
        return nil
    }
    var (
        doc          = "doc.go"
        templatePath = p.DocTemplatePath()
        errWrite     = WriteTemplate(doc, "documentation file", dict, templatePath...)
    )
    return errWrite
}
func (p Project) CreateOtherFiles(dict map[string]string) os.Error {
    var templatePaths = p.OtherTemplatePaths()
    if templatePaths == nil {
        return nil
    }
    for _, path := range templatePaths {
        var errWrite = WriteTemplate(path[0], "other file", dict, path[1:]...)
        if errWrite != nil {
            return errWrite
        }
    }
    return nil
}
func (p Project) InitializeRepo(add, commit, push bool) os.Error {
    switch p.Repo {
    case GitType:
        var git = GitRepository{}
        git.Initialize(add, commit)
    case MercurialType:
        var hg = MercurialRepository{}
        hg.Initialize(add, commit)
    }
    switch p.Host {
    case GitHubHost:
        var origin = p.Remote
        if origin == "" {
            return nil
        }
        var github = GitHubRepository{p}
        var errGHInit = github.Init(origin)
        if errGHInit != nil {
            return errGHInit
        }
        if push {
            var errPush = github.Push()
            if errPush != nil {
                return errPush
            }
        }
        return nil
    }
    return nil
}

func (p Project) MainFilename() string {
    return p.Target + ".go"
}
func (p Project) TestFilename() string {
    switch p.Type {
    case CmdType:
        return "main_test.go"
    case PkgType:
        return p.Target + "_test.go"
    }
    return p.Target + "_test.go"
}
func (p Project) ReadmeFilename() string {
    if p.ReadmeIsMarkdown() {
        return "README.md"
    }
    return "README"
}

func (p Project) LicenseTemplateName() string {
    var lstring = p.License.TemplateNamePrefix()
    if lstring == "" {
        return ""
    }
    return lstring + ".t"
}
func (p Project) GofileLicenseHeadTemplateName() string {
    var lstring = p.License.TemplateNamePrefix()
    if lstring == "" {
        return ""
    }
    return lstring + ".gohead.t"
}
func (p Project) ReadmeLicenseTailTemplateName() string {
    var lstring = p.License.TemplateNamePrefix()
    if lstring == "" {
        return ""
    }
    if p.ReadmeIsMarkdown() {
        return lstring + ".readme.md.t"
    }
    return lstring + ".readme.t"
}
func (p Project) MainTemplateName() string {
    switch p.Type {
    case PkgType:
        return "pkg.t"
    case CmdType:
        return "cmd.t"
    }
    return ""
}
func (p Project) TestTemplateName() string {
    switch p.Type {
    case PkgType:
        return "pkg.t"
    case CmdType:
        return "cmd.t"
    }
    return ""
}
func (p Project) ReadmeTemplateName() string {
    switch p.Type {
    case PkgType:
        if p.ReadmeIsMarkdown() {
            return "pkg.md.t"
        } else {
            return "pkg.t"
        }
    case CmdType:
        if p.ReadmeIsMarkdown() {
            return "cmd.md.t"
        } else {
            return "cmd.t"
        }
    }
    return ""
}

func (p Project) MakefileTemplatePath() []string {
    return []string{"makefiles", p.Type.String() + ".t"}
}
func (p Project) MainTemplatePath() []string {
    return []string{"gofiles", p.MainTemplateName()}
}
func (p Project) TestTemplatePath() []string {
    return []string{"testfiles", p.TestTemplateName()}
}
func (p Project) ReadmeTemplatePath() []string {
    return []string{"README", p.ReadmeTemplateName()}
}
func (p Project) OptionsTemplatePath() []string {
    return []string{"gofiles", "options.t"}
}
func (p Project) DocTemplatePath() []string {
    return []string{"gofiles", "doc.t"}
}
func (p Project) OtherTemplatePaths() [][]string {
    var others = make([][]string, 0, 1)
    switch p.Repo {
    case GitType:
        others = append(others, []string{".gitignore", "otherfiles", "gitignore.t"})
    case MercurialType:
        others = append(others, []string{".hgignore", "otherfiles", "hgignore.t"})
    }
    if len(others) == 0 {
        return nil
    }
    return others
}

func (p Project) HostString() string {
    switch p.Host {
    case GitHubHost:
        if p.User == "" {
            return ""
        }
        return "github.com/" + p.User
    }
    return "<INSERT REPO HOST HERE>"
}
func (p Project) HostRepoString() string {
    switch p.Host {
    case GitHubHost:
        if p.User == "" {
            return ""
        }
        return "github.com/" + p.User + "/" + p.Target
    }
    return "<INSERT REPO HOST HERE>"
}
func YearString() string {
    return time.LocalTime().Format("2006")
}
func DateString() string {
    return time.LocalTime().String()
}
func (p Project) ReadmeIsMarkdown() bool {
    return userepo && p.Host == GitHubHost
}
<|endoftext|>


<commit_before>// +build ignore

// Builds Gohai with version information
package main

import (
	"fmt"
	"log"
	"os"
	"os/exec"
	"strings"
	"time"
)

func commandOutput(name string, args ...string) string {
	out, err := exec.Command(name, args...).Output()
	if err != nil {
		log.Fatal(err)
	}

	return strings.TrimSpace(string(out))
}

func main() {
	gobin := "go"
	if len(os.Args) > 1 {
		gobin = os.Args[1]
	}

	date := time.Now().Format(time.UnixDate)
	commit := commandOutput("git", "rev-parse", "--short", "HEAD")
	branch := commandOutput("git", "rev-parse", "--abbrev-ref", "HEAD")
	go_version := commandOutput(gobin, "version")

	// NB: Starting from Go 1.5, the syntax of these ldflags changes from `-X main.var 'value'` to `-X 'main.var=value'`
	// For reference see https://github.com/golang/go/issues/12338
	ldflags := fmt.Sprintf("-X main.buildDate '%s' -X main.gitCommit '%s' -X main.gitBranch '%s' -X main.goVersion '%s'", date, commit, branch, go_version)

	cmd := exec.Command(gobin, []string{"build", "-a", "-ldflags", ldflags}...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	err := cmd.Run()
	if err != nil {
		os.Exit(1)
	}
}
<commit_msg>Make make.go compatible with go 1.10 (#59)<commit_after>// +build ignore

// Builds Gohai with version information
package main

import (
	"fmt"
	"log"
	"os"
	"os/exec"
	"strings"
	"time"
)

func commandOutput(name string, args ...string) string {
	out, err := exec.Command(name, args...).Output()
	if err != nil {
		log.Fatal(err)
	}

	return strings.TrimSpace(string(out))
}

func main() {
	gobin := "go"
	if len(os.Args) > 1 {
		gobin = os.Args[1]
	}

	date := time.Now().Format(time.UnixDate)
	commit := commandOutput("git", "rev-parse", "--short", "HEAD")
	branch := commandOutput("git", "rev-parse", "--abbrev-ref", "HEAD")
	go_version := commandOutput(gobin, "version")

	ldflags := fmt.Sprintf("\"-X main.buildDate='%s' -X=main.gitCommit='%s' -X main.gitBranch='%s' -X main.goVersion='%s'\"", date, commit, branch, go_version)

	cmd := exec.Command(gobin, []string{"build", "-a", "-ldflags", ldflags}...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	err := cmd.Run()
	if err != nil {
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package actions

import (
	"bufio"
	"bytes"
	"crypto/sha512"
	"encoding/base64"
	"fmt"
	"os"

	. "github.com/polydawn/gosh"
	"github.com/ugorji/go/codec"
	"github.com/urfave/cli"
	rdef "go.polydawn.net/repeatr/api/def"
	rhitch "go.polydawn.net/repeatr/api/hitch"

	"go.polydawn.net/reppl/model"
)

func Eval(c *cli.Context) error {
	// open the formula file
	formulaFileName := c.Args().Get(0)
	pinFileName := formulaFileName + ".pin"
	f, err := os.Open(formulaFileName)
	if err != nil {
		panic("could not open formula")
	}
	defer f.Close()

	// decode the formula file into a formula
	var frm rdef.Formula
	rhitch.DecodeYaml(f, &frm)

	// get our project definition
	p := model.FromFile(".reppl")

	// create the pinned formulas
	pinnedFrm := createPinnedFormula(&p, frm)

	// check if this formula is up to date
	formulaHash := getHash(pinnedFrm)
	if _, exists := p.Memos[formulaHash]; exists {
		fmt.Println("formula already up to date!")
		return nil
	}

	// write the pinned formula file as JSON
	writeFormula(&pinnedFrm, pinFileName)

	// make repeatr go now!
	rr := invokeRepeatr(pinFileName)

	// add the formula hash to the run record
	rr.FormulaHID = formulaHash
	// add the run record hash to the run record
	rr.HID = getHash(rr)

	// save tagged outputs
	for outputName, output := range frm.Outputs {
		if output.Tag != "" {
			p.PutResult(output.Tag, outputName, &rr)
		}
	}

	p.WriteFile(".reppl")

	return nil
}

func getHash(v interface{}) string {
	hash := sha512.New384()
	enc := codec.NewEncoder(hash, &codec.JsonHandle{})
	err := enc.Encode(v)
	if err != nil {
		panic("could not hash struct")
	}
	return base64.URLEncoding.EncodeToString(hash.Sum(nil))
}

func createPinnedFormula(p *model.Project, frm rdef.Formula) rdef.Formula {
	// add our hashes by tags
	for _, input := range frm.Inputs {
		if input.Tag != "" {
			ware, err := p.GetWareByTag(input.Tag)
			if err == nil {
				input.Hash = ware.Hash
				input.Type = ware.Type
			}
		}
	}
	return frm
}

func invokeRepeatr(formulaFileName string) rdef.RunRecord {
	rrBuf := &bytes.Buffer{}
	cmd := Gosh("repeatr", "run", formulaFileName,
		Opts{
			Out: rrBuf,
			Err: os.Stderr,
		},
	).Bake()
	cmd.Run()

	fmt.Println(rrBuf.String())
	var rr rdef.RunRecord
	dec := codec.NewDecoder(rrBuf, &codec.JsonHandle{})
	err := dec.Decode(&rr)
	if err != nil {
		panic("error reading run record: " + err.Error())
	}
	return rr
}

func writeFormula(frm *rdef.Formula, fileName string) {
	f, err := os.Create(fileName)
	if err != nil {
		panic("error opening pin file")
	}
	defer f.Close()

	w := bufio.NewWriter(f)
	defer w.Flush()

	enc := codec.NewEncoder(w, &codec.JsonHandle{Indent: -1})
	err = enc.Encode(frm)
	if err != nil {
		panic("could not write pin file")
	}
	w.Write([]byte{'\n'})
}
<commit_msg>Only panic when repeatr errors, vs job inside errors.<commit_after>package actions

import (
	"bufio"
	"bytes"
	"crypto/sha512"
	"encoding/base64"
	"fmt"
	"os"

	. "github.com/polydawn/gosh"
	"github.com/ugorji/go/codec"
	"github.com/urfave/cli"
	rdef "go.polydawn.net/repeatr/api/def"
	rhitch "go.polydawn.net/repeatr/api/hitch"

	"go.polydawn.net/reppl/model"
)

func Eval(c *cli.Context) error {
	// open the formula file
	formulaFileName := c.Args().Get(0)
	pinFileName := formulaFileName + ".pin"
	f, err := os.Open(formulaFileName)
	if err != nil {
		panic("could not open formula")
	}
	defer f.Close()

	// decode the formula file into a formula
	var frm rdef.Formula
	rhitch.DecodeYaml(f, &frm)

	// get our project definition
	p := model.FromFile(".reppl")

	// create the pinned formulas
	pinnedFrm := createPinnedFormula(&p, frm)

	// check if this formula is up to date
	formulaHash := getHash(pinnedFrm)
	if _, exists := p.Memos[formulaHash]; exists {
		fmt.Println("formula already up to date!")
		return nil
	}

	// write the pinned formula file as JSON
	writeFormula(&pinnedFrm, pinFileName)

	// make repeatr go now!
	rr := invokeRepeatr(pinFileName)

	// add the formula hash to the run record
	rr.FormulaHID = formulaHash
	// add the run record hash to the run record
	rr.HID = getHash(rr)

	// save tagged outputs
	for outputName, output := range frm.Outputs {
		if output.Tag != "" {
			p.PutResult(output.Tag, outputName, &rr)
		}
	}

	p.WriteFile(".reppl")

	return nil
}

func getHash(v interface{}) string {
	hash := sha512.New384()
	enc := codec.NewEncoder(hash, &codec.JsonHandle{})
	err := enc.Encode(v)
	if err != nil {
		panic("could not hash struct")
	}
	return base64.URLEncoding.EncodeToString(hash.Sum(nil))
}

func createPinnedFormula(p *model.Project, frm rdef.Formula) rdef.Formula {
	// add our hashes by tags
	for _, input := range frm.Inputs {
		if input.Tag != "" {
			ware, err := p.GetWareByTag(input.Tag)
			if err == nil {
				input.Hash = ware.Hash
				input.Type = ware.Type
			}
		}
	}
	return frm
}

func invokeRepeatr(formulaFileName string) rdef.RunRecord {
	rrBuf := &bytes.Buffer{}
	cmd := Gosh("repeatr", "run", "--ignore-job-exit", formulaFileName,
		Opts{
			Out: rrBuf,
			Err: os.Stderr,
		},
	).Bake()
	cmd.Run()

	fmt.Println(rrBuf.String())
	var rr rdef.RunRecord
	dec := codec.NewDecoder(rrBuf, &codec.JsonHandle{})
	err := dec.Decode(&rr)
	if err != nil {
		panic("error reading run record: " + err.Error())
	}
	return rr
}

func writeFormula(frm *rdef.Formula, fileName string) {
	f, err := os.Create(fileName)
	if err != nil {
		panic("error opening pin file")
	}
	defer f.Close()

	w := bufio.NewWriter(f)
	defer w.Flush()

	enc := codec.NewEncoder(w, &codec.JsonHandle{Indent: -1})
	err = enc.Encode(frm)
	if err != nil {
		panic("could not write pin file")
	}
	w.Write([]byte{'\n'})
}
<|endoftext|>


<commit_before>package main

import (
	"net/http"
)

/*
import (
	"os"
	"github.com/russross/blackfriday"
	"path/filepath"
	"io/ioutil"
	"fmt"
)
*/

func commits(w http.ResponseWriter, r *http.Request) {
	if(r.URL.Path[1:] == "") {
		// add something
	}
}

func status(w http.ResponseWriter, r *http.Request) {
	if(r.URL.Path[1:] == "") {
		// add something
	}
}

func details(w http.ResponseWriter, r *http.Request) {
	if(r.URL.Path[1:] == "") {
		// add something
	}
}

func diff(w http.ResponseWriter, r *http.Request) {
	if(r.URL.Path[1:] == "") {
		// add something
	}
}

func pull(w http.ResponseWriter, r *http.Request) {
	if(r.URL.Path[1:] == "") {
		// add something
	}
}

func push(w http.ResponseWriter, r *http.Request) {
	if(r.URL.Path[1:] == "") {
		// add something
	}
}

func checkout(w http.ResponseWriter, r *http.Request) {
	if(r.URL.Path[1:] == "") {
		// add something
	}
}

func create_branch(w http.ResponseWriter, r *http.Request) {
	if(r.URL.Path[1:] == "") {
		// add something
	}
}

func diff_stat(w http.ResponseWriter, r *http.Request) {
	if(r.URL.Path[1:] == "") {
		// add something
	}
}

func stage(w http.ResponseWriter, r *http.Request) {
	if(r.URL.Path[1:] == "") {
		// add something
	}
}

func unstage(w http.ResponseWriter, r *http.Request) {
	if(r.URL.Path[1:] == "") {
		// add something
	}
}

func get_heads_with_commit(w http.ResponseWriter, r *http.Request) {
	if(r.URL.Path[1:] == "") {
		// add something
	}
}

func get_branches_in_remote(w http.ResponseWriter, r *http.Request) {
	if(r.URL.Path[1:] == "") {
		// add something
	}
}

func merge(w http.ResponseWriter, r *http.Request) {
	if(r.URL.Path[1:] == "") {
		// add something
	}
}

func open(w http.ResponseWriter, r *http.Request) {
	if(r.URL.Path[1:] == "") {
		// add something
	}
}

func run(w http.ResponseWriter, r *http.Request) {
	if(r.URL.Path[1:] == "") {
		// add something
	}
}

func stop(w http.ResponseWriter, r *http.Request) {
	if(r.URL.Path[1:] == "") {
		// add something
	}
}

func stopped(w http.ResponseWriter, r *http.Request) {
	if(r.URL.Path[1:] == "") {
		// add something
	}
}

func index(w http.ResponseWriter, r *http.Request) {
	if(r.URL.Path[1:] == "") {
		// add something
	}
}

func exit(w http.ResponseWriter, r *http.Request) {
	if(r.URL.Path[1:] == "") {
		// add something
	}
}

func only_server(w http.ResponseWriter, r *http.Request) {
	if(r.URL.Path[1:] == "") {
		// add something
	}
}

func terminate_gitj_sig(w http.ResponseWriter, r *http.Request) {
	if(r.URL.Path[1:] == "") {
		// add something
	}
}

func terminate_gitj(w http.ResponseWriter, r *http.Request) {
	if(r.URL.Path[1:] == "") {
		// add something
	}
}

func main() {

	// Adding function handlers
	// For Testing the Go Build
	http.HandleFunc("/static/templates/_commits.html", commits);

	// TODO: Add more...

	// Event Listener
    http.ListenAndServe(":8080", http.FileServer(http.Dir(".")))
}
<commit_msg>add something<commit_after>package main

import (
	"net/http"
)

/*
import (
	"os"
	"github.com/russross/blackfriday"
	"path/filepath"
	"io/ioutil"
	"fmt"
)
*/

func commits(w http.ResponseWriter, r *http.Request) {
	if(r.URL.Path[1:] == "") {
		// add something
	}
}

func status(w http.ResponseWriter, r *http.Request) {
	if(r.URL.Path[1:] == "") {
		// add something
	}
}

func details(w http.ResponseWriter, r *http.Request) {
	if(r.URL.Path[1:] == "") {
		// add something
	}
}

func diff(w http.ResponseWriter, r *http.Request) {
	if(r.URL.Path[1:] == "") {
		// add something
	}
}

func pull(w http.ResponseWriter, r *http.Request) {
	if(r.URL.Path[1:] == "") {
		// add something
	}
}

func push(w http.ResponseWriter, r *http.Request) {
	if(r.URL.Path[1:] == "") {
		// add something
	}
}

func checkout(w http.ResponseWriter, r *http.Request) {
	if(r.URL.Path[1:] == "") {
		// add something
	}
}

func create_branch(w http.ResponseWriter, r *http.Request) {
	if(r.URL.Path[1:] == "") {
		// add something
	}
}

func diff_stat(w http.ResponseWriter, r *http.Request) {
	if(r.URL.Path[1:] == "") {
		// add something
	}
}

func stage(w http.ResponseWriter, r *http.Request) {
	if(r.URL.Path[1:] == "") {
		// add something
	}
}

func unstage(w http.ResponseWriter, r *http.Request) {
	if(r.URL.Path[1:] == "") {
		// add something
	}
}

func get_heads_with_commit(w http.ResponseWriter, r *http.Request) {
	if(r.URL.Path[1:] == "") {
		// add something
	}
}

func get_branches_in_remote(w http.ResponseWriter, r *http.Request) {
	if(r.URL.Path[1:] == "") {
		// add something
	}
}

func merge(w http.ResponseWriter, r *http.Request) {
	if(r.URL.Path[1:] == "") {
		// add something
	}
}

func open(w http.ResponseWriter, r *http.Request) {
	if(r.URL.Path[1:] == "") {
		// add something
	}
}

func run(w http.ResponseWriter, r *http.Request) {
	if(r.URL.Path[1:] == "") {
		// add something
	}
}

func stop(w http.ResponseWriter, r *http.Request) {
	if(r.URL.Path[1:] == "") {
		// add something
	}
}

func stopped(w http.ResponseWriter, r *http.Request) {
	if(r.URL.Path[1:] == "") {
		// add something
	}
}

func index(w http.ResponseWriter, r *http.Request) {
	if(r.URL.Path[1:] == "") {
		// add something
	}
}

func exit(w http.ResponseWriter, r *http.Request) {
	if(r.URL.Path[1:] == "") {
		// add something
	}
}

func only_server(w http.ResponseWriter, r *http.Request) {
	if(r.URL.Path[1:] == "") {
		// add something
	}
}

func terminate_gitj_sig() {
	//terminate_gitj()
}

func terminate_gitj(w http.ResponseWriter, r *http.Request) {
	//exit()
}

func main() {

	// Adding function handlers
	// For Testing the Go Build
	http.HandleFunc("/static/templates/_commits.html", commits)
	http.HandleFunc("/static/templates/_status.html", status)
	http.HandleFunc("/static/templates/_details.html", details)

	// TODO: Add more...

	// Event Listener
    http.ListenAndServe(":8080", http.FileServer(http.Dir(".")))
}
<|endoftext|>


<commit_before>package gwr

import "text/template"

const metaNounName = "/meta/nouns"

var nounsTextTemplate = template.Must(template.New("meta_nouns_text").Parse(`
{{- define "get" -}}
{{ range $name, $info := . -}}
- {{ $name }} formats: {{ $info.Formats }}
{{ end -}}
{{- end -}}
`))

type dataSourceUpdate struct {
	Type string
	Info DataSourceInfo
}

type metaNounDataSource struct {
	sources *DataSources
	watcher GenericDataWatcher
}

func (nds *metaNounDataSource) Info() GenericDataSourceInfo {
	return GenericDataSourceInfo{
		Name:         metaNounName,
		Attrs:        nil,
		TextTemplate: nounsTextTemplate,
	}
}

func (nds *metaNounDataSource) Get() interface{} {
	sources := nds.sources.sources
	info := make(map[string]DataSourceInfo, len(sources))
	for name, ds := range sources {
		info[name] = ds.Info()
	}
	return info
}

func (nds *metaNounDataSource) GetInit() interface{} {
	return nds.Get()
}

func (nds *metaNounDataSource) Watch(watcher GenericDataWatcher) {
	nds.watcher = watcher
}

func (nds *metaNounDataSource) dataSourceAdded(ds DataSource) {
	if nds.watcher != nil {
		update := dataSourceUpdate{"add", ds.Info()}
		nds.watcher(update)
	}
}
<commit_msg>metaNounDataSource.dataSourceAdded: trivial cleanup<commit_after>package gwr

import "text/template"

const metaNounName = "/meta/nouns"

var nounsTextTemplate = template.Must(template.New("meta_nouns_text").Parse(`
{{- define "get" -}}
{{ range $name, $info := . -}}
- {{ $name }} formats: {{ $info.Formats }}
{{ end -}}
{{- end -}}
`))

type dataSourceUpdate struct {
	Type string
	Info DataSourceInfo
}

type metaNounDataSource struct {
	sources *DataSources
	watcher GenericDataWatcher
}

func (nds *metaNounDataSource) Info() GenericDataSourceInfo {
	return GenericDataSourceInfo{
		Name:         metaNounName,
		Attrs:        nil,
		TextTemplate: nounsTextTemplate,
	}
}

func (nds *metaNounDataSource) Get() interface{} {
	sources := nds.sources.sources
	info := make(map[string]DataSourceInfo, len(sources))
	for name, ds := range sources {
		info[name] = ds.Info()
	}
	return info
}

func (nds *metaNounDataSource) GetInit() interface{} {
	return nds.Get()
}

func (nds *metaNounDataSource) Watch(watcher GenericDataWatcher) {
	nds.watcher = watcher
}

func (nds *metaNounDataSource) dataSourceAdded(ds DataSource) {
	if nds.watcher != nil {
		nds.watcher(dataSourceUpdate{"add", ds.Info()})
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"runtime"
	"syscall"

	"github.com/RoaringBitmap/gocroaring"
)

func main() {
	var rusage syscall.Rusage

	fmt.Printf("Starting execution... ")
	if err := syscall.Getrusage(syscall.RUSAGE_SELF, &rusage); err != nil {
		fmt.Printf("Getrusage failed with error: %s\n", err)
		os.Exit(1)
	}
	fmt.Printf("max RSS: %d bytes\n", rusage.Maxrss)

	bitmap := gocroaring.New()
	for i := uint32(0); i < 100000; i++ {
		bitmap.Add(i*10)
	}
	fmt.Printf("Created reference bitmap... ")
	if err := syscall.Getrusage(syscall.RUSAGE_SELF, &rusage); err != nil {
		fmt.Printf("Getrusage failed with error: %s\n", err)
		os.Exit(1)
	}
	fmt.Printf("max RSS: %d bytes\n", rusage.Maxrss)

	const N = 100000
	bitmaps := make([]*gocroaring.Bitmap, N)
	fmt.Printf("Allocated slice for %d bitmap pointers... ", N)
	if err := syscall.Getrusage(syscall.RUSAGE_SELF, &rusage); err != nil {
		fmt.Printf("Getrusage failed with error: %s\n", err)
		os.Exit(1)
	}
	fmt.Printf("max RSS: %d bytes\n", rusage.Maxrss)

	for i := range bitmaps {
		bitmaps[i] = bitmap.Clone()
		bitmaps[i].Free()
	}
	fmt.Printf("Copied then explicitly freed %d bitmaps... ", N)
	if err := syscall.Getrusage(syscall.RUSAGE_SELF, &rusage); err != nil {
		fmt.Printf("Getrusage failed with error: %s\n", err)
		os.Exit(1)
	}
	fmt.Printf("max RSS: %d bytes\n", rusage.Maxrss)

	bitmaps = nil
	runtime.GC()
	fmt.Printf("GC'd old bitmaps... ")
	if err := syscall.Getrusage(syscall.RUSAGE_SELF, &rusage); err != nil {
		fmt.Printf("Getrusage failed with error: %s\n", err)
		os.Exit(1)
	}
	fmt.Printf("max RSS: %d bytes\n", rusage.Maxrss)

	bitmaps = make([]*gocroaring.Bitmap, N)
	fmt.Printf("Allocated slice for %d bitmap pointers... ", N)
	if err := syscall.Getrusage(syscall.RUSAGE_SELF, &rusage); err != nil {
		fmt.Printf("Getrusage failed with error: %s\n", err)
		os.Exit(1)
	}
	fmt.Printf("max RSS: %d bytes\n", rusage.Maxrss)

	for i := range bitmaps {
		bitmaps[i] = bitmap.Clone()
	}
	bitmaps = nil
	runtime.GC()
	fmt.Printf("Copied then GC'd %d bitmaps... ", N)
	if err := syscall.Getrusage(syscall.RUSAGE_SELF, &rusage); err != nil {
		fmt.Printf("Getrusage failed with error: %s\n", err)
		os.Exit(1)
	}
	fmt.Printf("max RSS: %d bytes\n", rusage.Maxrss)
}
<commit_msg>Reduce free test memory usage and add comparison<commit_after>package main

import (
	"fmt"
	"os"
	"runtime"
	"syscall"

	"github.com/RoaringBitmap/gocroaring"
)

// Exits with code 0 on success, 1 on test failure
// or 2 on program failure (e.g. OOM or syscall error).

func main() {
	const (
		N = 10000
		M = 10000
	)

	var rusage syscall.Rusage
	var maxrss_0, maxrss_free, maxrss_gc int64

	fmt.Printf("Starting execution... ")
	if err := syscall.Getrusage(syscall.RUSAGE_SELF, &rusage); err != nil {
		fmt.Printf("Getrusage failed with error: %s\n", err)
		os.Exit(2)
	}
	maxrss_0 = rusage.Maxrss
	fmt.Printf("max RSS: %d bytes\n", maxrss_0)

	bitmap := gocroaring.New()
	for i := uint32(0); i < M; i++ {
		bitmap.Add(i*10)
	}
	fmt.Printf("Created reference bitmap... ")
	if err := syscall.Getrusage(syscall.RUSAGE_SELF, &rusage); err != nil {
		fmt.Printf("Getrusage failed with error: %s\n", err)
		os.Exit(2)
	}
	fmt.Printf("max RSS: %d bytes\n", rusage.Maxrss)

	bitmaps := make([]*gocroaring.Bitmap, N)
	fmt.Printf("Allocated slice for %d bitmap pointers... ", N)
	if err := syscall.Getrusage(syscall.RUSAGE_SELF, &rusage); err != nil {
		fmt.Printf("Getrusage failed with error: %s\n", err)
		os.Exit(2)
	}
	maxrss_free = rusage.Maxrss
	fmt.Printf("max RSS: %d bytes\n", maxrss_free)

	for i := range bitmaps {
		bitmaps[i] = bitmap.Clone()
		bitmaps[i].Free()
	}
	fmt.Printf("Copied then explicitly freed %d bitmaps... ", N)
	if err := syscall.Getrusage(syscall.RUSAGE_SELF, &rusage); err != nil {
		fmt.Printf("Getrusage failed with error: %s\n", err)
		os.Exit(2)
	}
	fmt.Printf("max RSS: %d bytes\n", rusage.Maxrss)

	bitmaps = nil
	runtime.GC()
	fmt.Printf("GC'd old bitmaps... ")
	if err := syscall.Getrusage(syscall.RUSAGE_SELF, &rusage); err != nil {
		fmt.Printf("Getrusage failed with error: %s\n", err)
		os.Exit(2)
	}
	fmt.Printf("max RSS: %d bytes\n", rusage.Maxrss)

	bitmaps = make([]*gocroaring.Bitmap, N)
	fmt.Printf("Allocated slice for %d bitmap pointers... ", N)
	if err := syscall.Getrusage(syscall.RUSAGE_SELF, &rusage); err != nil {
		fmt.Printf("Getrusage failed with error: %s\n", err)
		os.Exit(2)
	}
	fmt.Printf("max RSS: %d bytes\n", rusage.Maxrss)

	for i := range bitmaps {
		bitmaps[i] = bitmap.Clone()
	}
	bitmaps = nil
	runtime.GC()
	fmt.Printf("Copied then GC'd %d bitmaps... ", N)
	if err := syscall.Getrusage(syscall.RUSAGE_SELF, &rusage); err != nil {
		fmt.Printf("Getrusage failed with error: %s\n", err)
		os.Exit(2)
	}
	maxrss_gc = rusage.Maxrss
	fmt.Printf("max RSS: %d bytes\n", maxrss_gc)

	ballpark_free := maxrss_free - maxrss_0
	ballpark_gc := maxrss_gc - maxrss_0
	fmt.Printf("Used ~%d bytes with explicit free\n", ballpark_free)
	fmt.Printf("Used ~%d bytes without explicit free\n", ballpark_gc)

	if ballpark_gc < 100*ballpark_free {
		fmt.Printf("Expected a much greater difference!\n")
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 Pagoda Box Inc
//
// This Source Code Form is subject to the terms of the Mozilla Public License, v.
// 2.0. If a copy of the MPL was not distributed with this file, You can obtain one
// at http://mozilla.org/MPL/2.0/.
//

package mist

import (
	"fmt"
	"sync"

	"github.com/pagodabox/golang-hatchet"
)

//
const (
	DefaultPort = "1445"
	Version     = "0.0.1"
)

//
type (

	//
	Mist struct {
		sync.Mutex

		log           hatchet.Logger //
		port          string
		Subscriptions map[string]map[chan Message]string //
	}

	//
	Subscription struct {
		Tags []string     `json:"tags"`
		Sub  chan Message `json:"channel"`
	}

	//
	Message struct {
		Tags []string `json:"tags"`
		Data string   `json:"data, string"`
	}
)

//
func New(port string, logger hatchet.Logger) *Mist {

	//
	if logger == nil {
		logger = hatchet.DevNullLogger{}
	}

	mist := &Mist{
		log:           logger,
		port:          port,
		Subscriptions: make(map[string]map[chan Message]string),
	}

	mist.start()

	return mist
}

// Publish takes a list of tags and iterates through Mist's list of subscriptions,
// looking for matching subscriptions to publish messages too. It ensures that the
// list of recipients is a unique set, so as not to publish the same message more
// than once over a channel
func (m *Mist) Publish(tags []string, data string) {

	m.log.Info("PUBLISH!! %v, %v", tags, data)

	// create a message
	msg := Message{Tags: tags, Data: data}

	m.log.Info("MSG: %#v\n", msg)

	// a unique list of recipients (may contain duplicate channels from multiple
	// subscriptions)
	recipients := make(map[chan Message]int)

	// iterate through each provided tag looking for subscriptions to publish to
	for _, tag := range tags {

		// keep track of how many times a subscription is requested
		used := 0

		// iterate through any matching subscriptions and add all of that subscriptions
		// channels to the list of recipients
		if sub, ok := m.Subscriptions[tag]; ok {

			for ch, _ := range sub {

				// ensure that we keep the list of recipients unique, by checking each
				// match against a temporary map of found channels.
				if _, ok := recipients[ch]; !ok {
					used++

					m.log.Info("PUBLISH!!! %#v\n", msg)

					//
					m.log.Debug("[MIST] Publishing: %+v\n", msg)
					go func(ch chan Message) { ch <- msg }(ch)

					// update our list of found channels, with a value of how many times
					// that channel has been subscribed to
					recipients[ch] = used
				}
			}
		}
	}
}

// Subscribe
func (m *Mist) Subscribe(sub Subscription) {
	m.Lock()

	//
	m.log.Debug("[MIST] Subscribe: %+v\n", sub.Tags)

	// iterate over each subscription, adding it to our list of subscriptions (if
	// not already found), and then adding the channel into the subscription's list
	// of subscribers.
	for _, tag := range sub.Tags {

		// if we don't find a subscription, make one (type []chan Message), and add
		// it to our list of subscriptions
		if _, ok := m.Subscriptions[tag]; !ok {
			m.Subscriptions[tag] = make(map[chan Message]string)
			m.log.Debug("[MIST] Created new subscription '%+v'\n", tag)
		}

		// add the channel to each subscription...
		m.Subscriptions[tag][sub.Sub] = ""
		m.log.Debug("[MIST] Subscribed '%+v' to '%+v'\n", sub.Sub, tag)
	}

	m.Unlock()
}

// Unsubscribe
func (m *Mist) Unsubscribe(sub Subscription) {
	m.Lock()

	//
	m.log.Debug("[MIST] Unsubscribing '%+v' from '%+v'\n", sub.Sub, sub.Tags)

	//
	for _, tag := range sub.Tags {

		//
		if s, ok := m.Subscriptions[tag]; ok {
			delete(s, sub.Sub)
			m.log.Debug("[MIST] Unsubscribed '%+v' from '%+v'\n", sub.Sub, s)
		}

		//
		if len(m.Subscriptions[tag]) <= 0 {
			delete(m.Subscriptions, tag)
			m.log.Debug("[MIST] Removed empty subscription '%+v'\n", tag)
		}
	}

	m.Unlock()
}

// List
func (m *Mist) List() {
	fmt.Println(m.Subscriptions)
}
<commit_msg>remove the space to match the godoc<commit_after>// Copyright (c) 2015 Pagoda Box Inc
//
// This Source Code Form is subject to the terms of the Mozilla Public License, v.
// 2.0. If a copy of the MPL was not distributed with this file, You can obtain one
// at http://mozilla.org/MPL/2.0/.
//

package mist

import (
	"fmt"
	"sync"

	"github.com/pagodabox/golang-hatchet"
)

//
const (
	DefaultPort = "1445"
	Version     = "0.0.1"
)

//
type (

	//
	Mist struct {
		sync.Mutex

		log           hatchet.Logger //
		port          string
		Subscriptions map[string]map[chan Message]string //
	}

	//
	Subscription struct {
		Tags []string     `json:"tags"`
		Sub  chan Message `json:"channel"`
	}

	//
	Message struct {
		Tags []string `json:"tags"`
		Data string   `json:"data,string"`
	}
)

//
func New(port string, logger hatchet.Logger) *Mist {

	//
	if logger == nil {
		logger = hatchet.DevNullLogger{}
	}

	mist := &Mist{
		log:           logger,
		port:          port,
		Subscriptions: make(map[string]map[chan Message]string),
	}

	mist.start()

	return mist
}

// Publish takes a list of tags and iterates through Mist's list of subscriptions,
// looking for matching subscriptions to publish messages too. It ensures that the
// list of recipients is a unique set, so as not to publish the same message more
// than once over a channel
func (m *Mist) Publish(tags []string, data string) {

	m.log.Info("PUBLISH!! %v, %v", tags, data)

	// create a message
	msg := Message{Tags: tags, Data: data}

	m.log.Info("MSG: %#v\n", msg)

	// a unique list of recipients (may contain duplicate channels from multiple
	// subscriptions)
	recipients := make(map[chan Message]int)

	// iterate through each provided tag looking for subscriptions to publish to
	for _, tag := range tags {

		// keep track of how many times a subscription is requested
		used := 0

		// iterate through any matching subscriptions and add all of that subscriptions
		// channels to the list of recipients
		if sub, ok := m.Subscriptions[tag]; ok {

			for ch, _ := range sub {

				// ensure that we keep the list of recipients unique, by checking each
				// match against a temporary map of found channels.
				if _, ok := recipients[ch]; !ok {
					used++

					m.log.Info("PUBLISH!!! %#v\n", msg)

					//
					m.log.Debug("[MIST] Publishing: %+v\n", msg)
					go func(ch chan Message) { ch <- msg }(ch)

					// update our list of found channels, with a value of how many times
					// that channel has been subscribed to
					recipients[ch] = used
				}
			}
		}
	}
}

// Subscribe
func (m *Mist) Subscribe(sub Subscription) {
	m.Lock()

	//
	m.log.Debug("[MIST] Subscribe: %+v\n", sub.Tags)

	// iterate over each subscription, adding it to our list of subscriptions (if
	// not already found), and then adding the channel into the subscription's list
	// of subscribers.
	for _, tag := range sub.Tags {

		// if we don't find a subscription, make one (type []chan Message), and add
		// it to our list of subscriptions
		if _, ok := m.Subscriptions[tag]; !ok {
			m.Subscriptions[tag] = make(map[chan Message]string)
			m.log.Debug("[MIST] Created new subscription '%+v'\n", tag)
		}

		// add the channel to each subscription...
		m.Subscriptions[tag][sub.Sub] = ""
		m.log.Debug("[MIST] Subscribed '%+v' to '%+v'\n", sub.Sub, tag)
	}

	m.Unlock()
}

// Unsubscribe
func (m *Mist) Unsubscribe(sub Subscription) {
	m.Lock()

	//
	m.log.Debug("[MIST] Unsubscribing '%+v' from '%+v'\n", sub.Sub, sub.Tags)

	//
	for _, tag := range sub.Tags {

		//
		if s, ok := m.Subscriptions[tag]; ok {
			delete(s, sub.Sub)
			m.log.Debug("[MIST] Unsubscribed '%+v' from '%+v'\n", sub.Sub, s)
		}

		//
		if len(m.Subscriptions[tag]) <= 0 {
			delete(m.Subscriptions, tag)
			m.log.Debug("[MIST] Removed empty subscription '%+v'\n", tag)
		}
	}

	m.Unlock()
}

// List
func (m *Mist) List() {
	fmt.Println(m.Subscriptions)
}
<|endoftext|>


<commit_before>// Package bot provides the interfaces for creating a chatops
// bot.
package bot

/* bot.go defines core data structures and public methods for startup.
   handler.go has the methods for callbacks from the connector, */

import (
	"fmt"
	"log"
	"math/rand"
	"net/http"
	"os"
	"os/signal"
	"regexp"
	"sync"
	"syscall"
	"time"
)

type VersionInfo struct {
	Version, Commit string
}

// configPath is optional, installPath is where gopherbot(.exe) is
var configPath, installPath string

var botVersion VersionInfo

var random *rand.Rand

var connectors = make(map[string]func(Handler, *log.Logger) Connector)

// RegisterConnector should be called in an init function to register a type
// of connector. Currently only Slack is implemented.
func RegisterConnector(name string, connstarter func(Handler, *log.Logger) Connector) {
	if stopRegistrations {
		return
	}
	if connectors[name] != nil {
		log.Fatal("Attempted registration of duplicate connector:", name)
	}
	connectors[name] = connstarter
}

// robot holds all the interal data relevant to the Bot. Most of it is populated
// by loadConfig, other stuff is populated by the connector.
var robot struct {
	Connector                             // Connector interface, implemented by each specific protocol
	adminUsers           []string         // List of users with access to administrative commands
	alias                rune             // single-char alias for addressing the bot
	name                 string           // e.g. "Gort"
	fullName             string           // e.g. "Robbie Robot"
	adminContact         string           // who to contact for problems with the robot.
	email                string           // the from: when the robot sends email
	mailConf             botMailer        // configuration to use when sending email
	ignoreUsers          []string         // list of users to never listen to, like other bots
	preRegex             *regexp.Regexp   // regex for matching prefixed commands, e.g. "Gort, drop your weapon"
	postRegex            *regexp.Regexp   // regex for matching, e.g. "open the pod bay doors, hal"
	bareRegex            *regexp.Regexp   // regex for matching the robot's bare name, if you forgot it in the previous command
	joinChannels         []string         // list of channels to join
	defaultAllowDirect   bool             // whether plugins are available in DM by default
	defaultMessageFormat MessageFormat    // Raw unless set to Variable or Fixed
	plugChannels         []string         // list of channels where plugins are available by default
	protocol             string           // Name of the protocol, e.g. "slack"
	brainProvider        string           // Type of Brain provider to use
	brain                SimpleBrain      // Interface for robot to Store and Retrieve data
	brainKey             string           // Configured brain key
	historyProvider      string           // Name of the history provider to use
	history              HistoryProvider  // Provider for storing and retrieving job / plugin histories
	defaultElevator      string           // Plugin name for performing elevation
	defaultAuthorizer    string           // Plugin name for performing authorization
	externalPlugins      []externalPlugin // List of external plugins to load
	externalJobs         []externalJob    // List of external jobs to load
	scheduledTasks       []scheduledTask  // List of scheduled tasks
	port                 string           // Localhost port to listen on
	stop                 chan struct{}    // stop channel for stopping the connector
	done                 chan struct{}    // channel closed when robot finishes shutting down
	timeZone             *time.Location   // for forcing the TimeZone, Unix only
	defaultJobChannel    string           // where job statuses will post if not otherwise specified
	shuttingDown         bool             // to prevent new plugins from starting
	pluginsRunning       int              // a count of how many plugins are currently running
	paused               bool             // it's a Windows thing
	sync.WaitGroup                        // for keeping track of running plugins
	sync.RWMutex                          // for safe updating of bot data structures
}

var listening bool // for tests where initBot runs multiple times

// initBot sets up the global robot and loads
// configuration.
func initBot(cpath, epath string, logger *log.Logger) {
	stopRegistrations = true
	// Seed the pseudo-random number generator, for plugin IDs, RandomString, etc.
	random = rand.New(rand.NewSource(time.Now().UnixNano()))

	botLogger.l = logger

	configPath = cpath
	installPath = epath
	robot.stop = make(chan struct{})
	robot.done = make(chan struct{})
	robot.shuttingDown = false

	handle := handler{}
	bot := &botContext{
		environment: make(map[string]string),
	}
	if err := bot.loadConfig(true); err != nil {
		Log(Fatal, fmt.Sprintf("Error loading initial configuration: %v", err))
	}

	if len(robot.brainProvider) > 0 {
		if bprovider, ok := brains[robot.brainProvider]; !ok {
			Log(Fatal, fmt.Sprintf("No provider registered for brain: \"%s\"", robot.brainProvider))
		} else {
			brain := bprovider(handle, logger)
			robot.brain = brain
		}
	} else {
		bprovider, _ := brains["mem"]
		robot.brain = bprovider(handle, logger)
		Log(Error, "No brain configured, falling back to default 'mem' brain - no memories will persist")
	}
	if encryptBrain {
		if len(robot.brainKey) > 0 {
			if initializeEncryption(robot.brainKey) {
				Log(Info, "Successfully initialized brain encryption")
			} else {
				Log(Error, "Failed to initialize brain encryption with configured BrainKey")
			}
		} else {
			Log(Warn, "Brain encryption specified but no key configured; use 'initialize brain <key>' to initialize the encrypted brain")
		}
	}
	if len(robot.historyProvider) > 0 {
		if hprovider, ok := historyProviders[robot.historyProvider]; !ok {
			Log(Fatal, fmt.Sprintf("No provider registered for history type: \"%s\"", robot.historyProvider))
		} else {
			hp := hprovider(handle)
			robot.history = hp
		}
	}
	if !listening {
		listening = true
		go func() {
			h := handler{}
			http.Handle("/json", h)
			Log(Fatal, http.ListenAndServe(robot.port, nil))
		}()
	}
}

// set connector sets the connector, which should already be initialized
func setConnector(c Connector) {
	robot.Lock()
	robot.Connector = c
	robot.Unlock()
}

// run starts all the loops and returns a channel that closes when the robot
// shuts down. It should return after the connector loop has started and
// plugins are initialized.
func run() <-chan struct{} {
	bot := &botContext{
		environment: make(map[string]string),
	}
	bot.registerActive()
	bot.loadConfig(false)
	bot.deregister()

	var cl []string
	robot.RLock()
	cl = append(cl, robot.joinChannels...)
	robot.RUnlock()
	for _, channel := range cl {
		robot.JoinChannel(channel)
	}

	// Start the brain loop
	go runBrain()

	// signal handler
	go func() {
		robot.RLock()
		done := robot.done
		robot.RUnlock()
		sigs := make(chan os.Signal, 1)

		signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)

	loop:
		for {
			select {
			case sig := <-sigs:
				robot.Lock()
				if robot.shuttingDown {
					Log(Warn, "Received SIGINT/SIGTERM while shutdown in progress")
					robot.Unlock()
				} else {
					robot.shuttingDown = true
					robot.Unlock()
					signal.Stop(sigs)
					Log(Info, fmt.Sprintf("Exiting on signal: %s", sig))
					stop()
				}
			case <-done:
				break loop
			}
		}
	}()

	// connector loop
	robot.RLock()
	go func(conn Connector, stop <-chan struct{}, done chan<- struct{}) {
		conn.Run(stop)
		close(done)
	}(robot.Connector, robot.stop, robot.done)
	robot.RUnlock()

	initializePlugins()
	robot.RLock()
	defer robot.RUnlock()
	return robot.done
}

// stop is called whenever the robot needs to shut down gracefully. All callers
// should lock the bot and check the value of robot.shuttingDown; see
// builtins.go and win_svc_run.go
func stop() {
	robot.RLock()
	pr := robot.pluginsRunning
	stop := robot.stop
	robot.RUnlock()
	Log(Debug, fmt.Sprintf("stop called with %d plugins running", pr))
	robot.Wait()
	brainQuit()
	close(stop)
}
<commit_msg>Start the brain before trying to use it<commit_after>// Package bot provides the interfaces for creating a chatops
// bot.
package bot

/* bot.go defines core data structures and public methods for startup.
   handler.go has the methods for callbacks from the connector, */

import (
	"fmt"
	"log"
	"math/rand"
	"net/http"
	"os"
	"os/signal"
	"regexp"
	"sync"
	"syscall"
	"time"
)

type VersionInfo struct {
	Version, Commit string
}

// configPath is optional, installPath is where gopherbot(.exe) is
var configPath, installPath string

var botVersion VersionInfo

var random *rand.Rand

var connectors = make(map[string]func(Handler, *log.Logger) Connector)

// RegisterConnector should be called in an init function to register a type
// of connector. Currently only Slack is implemented.
func RegisterConnector(name string, connstarter func(Handler, *log.Logger) Connector) {
	if stopRegistrations {
		return
	}
	if connectors[name] != nil {
		log.Fatal("Attempted registration of duplicate connector:", name)
	}
	connectors[name] = connstarter
}

// robot holds all the interal data relevant to the Bot. Most of it is populated
// by loadConfig, other stuff is populated by the connector.
var robot struct {
	Connector                             // Connector interface, implemented by each specific protocol
	adminUsers           []string         // List of users with access to administrative commands
	alias                rune             // single-char alias for addressing the bot
	name                 string           // e.g. "Gort"
	fullName             string           // e.g. "Robbie Robot"
	adminContact         string           // who to contact for problems with the robot.
	email                string           // the from: when the robot sends email
	mailConf             botMailer        // configuration to use when sending email
	ignoreUsers          []string         // list of users to never listen to, like other bots
	preRegex             *regexp.Regexp   // regex for matching prefixed commands, e.g. "Gort, drop your weapon"
	postRegex            *regexp.Regexp   // regex for matching, e.g. "open the pod bay doors, hal"
	bareRegex            *regexp.Regexp   // regex for matching the robot's bare name, if you forgot it in the previous command
	joinChannels         []string         // list of channels to join
	defaultAllowDirect   bool             // whether plugins are available in DM by default
	defaultMessageFormat MessageFormat    // Raw unless set to Variable or Fixed
	plugChannels         []string         // list of channels where plugins are available by default
	protocol             string           // Name of the protocol, e.g. "slack"
	brainProvider        string           // Type of Brain provider to use
	brain                SimpleBrain      // Interface for robot to Store and Retrieve data
	brainKey             string           // Configured brain key
	historyProvider      string           // Name of the history provider to use
	history              HistoryProvider  // Provider for storing and retrieving job / plugin histories
	defaultElevator      string           // Plugin name for performing elevation
	defaultAuthorizer    string           // Plugin name for performing authorization
	externalPlugins      []externalPlugin // List of external plugins to load
	externalJobs         []externalJob    // List of external jobs to load
	scheduledTasks       []scheduledTask  // List of scheduled tasks
	port                 string           // Localhost port to listen on
	stop                 chan struct{}    // stop channel for stopping the connector
	done                 chan struct{}    // channel closed when robot finishes shutting down
	timeZone             *time.Location   // for forcing the TimeZone, Unix only
	defaultJobChannel    string           // where job statuses will post if not otherwise specified
	shuttingDown         bool             // to prevent new plugins from starting
	pluginsRunning       int              // a count of how many plugins are currently running
	paused               bool             // it's a Windows thing
	sync.WaitGroup                        // for keeping track of running plugins
	sync.RWMutex                          // for safe updating of bot data structures
}

var listening bool // for tests where initBot runs multiple times

// initBot sets up the global robot and loads
// configuration.
func initBot(cpath, epath string, logger *log.Logger) {
	stopRegistrations = true
	// Seed the pseudo-random number generator, for plugin IDs, RandomString, etc.
	random = rand.New(rand.NewSource(time.Now().UnixNano()))

	botLogger.l = logger

	configPath = cpath
	installPath = epath
	robot.stop = make(chan struct{})
	robot.done = make(chan struct{})
	robot.shuttingDown = false

	handle := handler{}
	bot := &botContext{
		environment: make(map[string]string),
	}
	if err := bot.loadConfig(true); err != nil {
		Log(Fatal, fmt.Sprintf("Error loading initial configuration: %v", err))
	}

	if len(robot.brainProvider) > 0 {
		if bprovider, ok := brains[robot.brainProvider]; !ok {
			Log(Fatal, fmt.Sprintf("No provider registered for brain: \"%s\"", robot.brainProvider))
		} else {
			brain := bprovider(handle, logger)
			robot.brain = brain
		}
	} else {
		bprovider, _ := brains["mem"]
		robot.brain = bprovider(handle, logger)
		Log(Error, "No brain configured, falling back to default 'mem' brain - no memories will persist")
	}
	if encryptBrain {
		if len(robot.brainKey) > 0 {
			if initializeEncryption(robot.brainKey) {
				Log(Info, "Successfully initialized brain encryption")
			} else {
				Log(Error, "Failed to initialize brain encryption with configured BrainKey")
			}
		} else {
			Log(Warn, "Brain encryption specified but no key configured; use 'initialize brain <key>' to initialize the encrypted brain")
		}
	}
	if len(robot.historyProvider) > 0 {
		if hprovider, ok := historyProviders[robot.historyProvider]; !ok {
			Log(Fatal, fmt.Sprintf("No provider registered for history type: \"%s\"", robot.historyProvider))
		} else {
			hp := hprovider(handle)
			robot.history = hp
		}
	}
	if !listening {
		listening = true
		go func() {
			h := handler{}
			http.Handle("/json", h)
			Log(Fatal, http.ListenAndServe(robot.port, nil))
		}()
	}
}

// set connector sets the connector, which should already be initialized
func setConnector(c Connector) {
	robot.Lock()
	robot.Connector = c
	robot.Unlock()
}

// run starts all the loops and returns a channel that closes when the robot
// shuts down. It should return after the connector loop has started and
// plugins are initialized.
func run() <-chan struct{} {
	// Start the brain loop
	go runBrain()

	bot := &botContext{
		environment: make(map[string]string),
	}
	bot.registerActive()
	bot.loadConfig(false)
	bot.deregister()

	var cl []string
	robot.RLock()
	cl = append(cl, robot.joinChannels...)
	robot.RUnlock()
	for _, channel := range cl {
		robot.JoinChannel(channel)
	}

	// signal handler
	go func() {
		robot.RLock()
		done := robot.done
		robot.RUnlock()
		sigs := make(chan os.Signal, 1)

		signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)

	loop:
		for {
			select {
			case sig := <-sigs:
				robot.Lock()
				if robot.shuttingDown {
					Log(Warn, "Received SIGINT/SIGTERM while shutdown in progress")
					robot.Unlock()
				} else {
					robot.shuttingDown = true
					robot.Unlock()
					signal.Stop(sigs)
					Log(Info, fmt.Sprintf("Exiting on signal: %s", sig))
					stop()
				}
			case <-done:
				break loop
			}
		}
	}()

	// connector loop
	robot.RLock()
	go func(conn Connector, stop <-chan struct{}, done chan<- struct{}) {
		conn.Run(stop)
		close(done)
	}(robot.Connector, robot.stop, robot.done)
	robot.RUnlock()

	initializePlugins()
	robot.RLock()
	defer robot.RUnlock()
	return robot.done
}

// stop is called whenever the robot needs to shut down gracefully. All callers
// should lock the bot and check the value of robot.shuttingDown; see
// builtins.go and win_svc_run.go
func stop() {
	robot.RLock()
	pr := robot.pluginsRunning
	stop := robot.stop
	robot.RUnlock()
	Log(Debug, fmt.Sprintf("stop called with %d plugins running", pr))
	robot.Wait()
	brainQuit()
	close(stop)
}
<|endoftext|>


<commit_before>// Go Riemann client
package raidman

import (
	"bytes"
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"net"
	"os"
	"reflect"
	"sync"

	pb "code.google.com/p/goprotobuf/proto"
	"github.com/amir/raidman/proto"
)

type network interface {
	Send(message *proto.Msg, conn net.Conn) (*proto.Msg, error)
}

type tcp struct{}

type udp struct{}

// Client represents a connection to a Riemann server
type Client struct {
	sync.Mutex
	net        network
	connection net.Conn
}

// An Event represents a single Riemann event
type Event struct {
	Ttl         float32
	Time        int64
	Tags        []string
	Host        string // Defaults to os.Hostname()
	State       string
	Service     string
	Metric      interface{} // Could be Int, Float32, Float64
	Description string
}

// Dial establishes a connection to a Riemann server at addr, on the network
// netwrk.
//
// Known networks are "tcp", "tcp4", "tcp6", "udp", "udp4", and "udp6".
func Dial(netwrk, addr string) (c *Client, err error) {
	c = new(Client)

	var cnet network
	switch netwrk {
	case "tcp", "tcp4", "tcp6":
		cnet = new(tcp)
	case "udp", "udp4", "udp6":
		cnet = new(udp)
	default:
		return nil, fmt.Errorf("dial %q: unsupported network %q", netwrk, netwrk)
	}

	c.net = cnet
	c.connection, err = net.Dial(netwrk, addr)
	if err != nil {
		return nil, err
	}

	return c, nil
}

func (network *tcp) Send(message *proto.Msg, conn net.Conn) (*proto.Msg, error) {
	msg := &proto.Msg{}
	data, err := pb.Marshal(message)
	if err != nil {
		return msg, err
	}
	b := new(bytes.Buffer)
	if err = binary.Write(b, binary.BigEndian, uint32(len(data))); err != nil {
		return msg, err
	}
	if _, err = conn.Write(b.Bytes()); err != nil {
		return msg, err
	}
	if _, err = conn.Write(data); err != nil {
		return msg, err
	}
	var header uint32
	if err = binary.Read(conn, binary.BigEndian, &header); err != nil {
		return msg, err
	}
	response := make([]byte, header)
	if err = readFully(conn, response); err != nil {
		return msg, err
	}
	if err = pb.Unmarshal(response, msg); err != nil {
		return msg, err
	}
	if msg.GetOk() != true {
		return msg, errors.New(msg.GetError())
	}
	return msg, nil
}

func readFully(r io.Reader, p []byte) error {
	for len(p) > 0 {
		n, err := r.Read(p)
		p = p[n:]
		if err != nil {
			return err
		}
	}
	return nil
}

func (network *udp) Send(message *proto.Msg, conn net.Conn) (*proto.Msg, error) {
	data, err := pb.Marshal(message)
	if err != nil {
		return nil, err
	}
	if _, err = conn.Write(data); err != nil {
		return nil, err
	}

	return nil, nil
}

func eventToPbEvent(event *Event) (*proto.Event, error) {
	var e proto.Event

	if event.Host == "" {
		event.Host, _ = os.Hostname()
	}
	t := reflect.ValueOf(&e).Elem()
	s := reflect.ValueOf(event).Elem()
	typeOfEvent := s.Type()
	for i := 0; i < s.NumField(); i++ {
		f := s.Field(i)
		value := reflect.ValueOf(f.Interface())
		if reflect.Zero(f.Type()) != value && f.Interface() != nil {
			name := typeOfEvent.Field(i).Name
			switch name {
			case "State", "Service", "Host", "Description":
				tmp := reflect.ValueOf(pb.String(value.String()))
				t.FieldByName(name).Set(tmp)
			case "Ttl":
				tmp := reflect.ValueOf(pb.Float32(float32(value.Float())))
				t.FieldByName(name).Set(tmp)
			case "Time":
				tmp := reflect.ValueOf(pb.Int64(value.Int()))
				t.FieldByName(name).Set(tmp)
			case "Tags":
				tmp := reflect.ValueOf(value.Interface().([]string))
				t.FieldByName(name).Set(tmp)
			case "Metric":
				switch reflect.TypeOf(f.Interface()).Kind() {
				case reflect.Int:
					tmp := reflect.ValueOf(pb.Int64(int64(value.Int())))
					t.FieldByName("MetricSint64").Set(tmp)
				case reflect.Float32:
					tmp := reflect.ValueOf(pb.Float32(float32(value.Float())))
					t.FieldByName("MetricF").Set(tmp)
				case reflect.Float64:
					tmp := reflect.ValueOf(pb.Float64(value.Float()))
					t.FieldByName("MetricD").Set(tmp)
				default:
					return nil, fmt.Errorf("Metric of invalid type (type %v)",
						reflect.TypeOf(f.Interface()).Kind())
				}
			}
		}
	}

	return &e, nil
}

func pbEventsToEvents(pbEvents []*proto.Event) []Event {
	var events []Event

	for _, event := range pbEvents {
		e := Event{
			State:       event.GetState(),
			Service:     event.GetService(),
			Host:        event.GetHost(),
			Description: event.GetDescription(),
			Ttl:         event.GetTtl(),
			Time:        event.GetTime(),
			Tags:        event.GetTags(),
		}
		if event.MetricF != nil {
			e.Metric = event.GetMetricF()
		} else if event.MetricD != nil {
			e.Metric = event.GetMetricD()
		} else {
			e.Metric = event.GetMetricSint64()
		}

		events = append(events, e)
	}

	return events
}

// Send sends an event to Riemann
func (c *Client) Send(event *Event) error {
	e, err := eventToPbEvent(event)
	if err != nil {
		return err
	}
	message := &proto.Msg{}
	message.Events = append(message.Events, e)
	c.Lock()
	defer c.Unlock()
	_, err = c.net.Send(message, c.connection)
	if err != nil {
		return err
	}

	return nil
}

// Query returns a list of events matched by query
func (c *Client) Query(q string) ([]Event, error) {
	switch c.net.(type) {
	case *udp:
		return nil, errors.New("Querying over UDP is not supported")
	}
	query := &proto.Query{}
	query.String_ = pb.String(q)
	message := &proto.Msg{}
	message.Query = query
	c.Lock()
	defer c.Unlock()
	response, err := c.net.Send(message, c.connection)
	if err != nil {
		return nil, err
	}
	return pbEventsToEvents(response.GetEvents()), nil
}

// Close closes the connection to Riemann
func (c *Client) Close() {
	c.Lock()
	c.connection.Close()
	c.Unlock()
}
<commit_msg>made proto a relative import<commit_after>// Go Riemann client
package raidman

import (
	"bytes"
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"net"
	"os"
	"reflect"
	"sync"

	pb "code.google.com/p/goprotobuf/proto"
	"./proto"
)

type network interface {
	Send(message *proto.Msg, conn net.Conn) (*proto.Msg, error)
}

type tcp struct{}

type udp struct{}

// Client represents a connection to a Riemann server
type Client struct {
	sync.Mutex
	net        network
	connection net.Conn
}

// An Event represents a single Riemann event
type Event struct {
	Ttl         float32
	Time        int64
	Tags        []string
	Host        string // Defaults to os.Hostname()
	State       string
	Service     string
	Metric      interface{} // Could be Int, Float32, Float64
	Description string
}

// Dial establishes a connection to a Riemann server at addr, on the network
// netwrk.
//
// Known networks are "tcp", "tcp4", "tcp6", "udp", "udp4", and "udp6".
func Dial(netwrk, addr string) (c *Client, err error) {
	c = new(Client)

	var cnet network
	switch netwrk {
	case "tcp", "tcp4", "tcp6":
		cnet = new(tcp)
	case "udp", "udp4", "udp6":
		cnet = new(udp)
	default:
		return nil, fmt.Errorf("dial %q: unsupported network %q", netwrk, netwrk)
	}

	c.net = cnet
	c.connection, err = net.Dial(netwrk, addr)
	if err != nil {
		return nil, err
	}

	return c, nil
}

func (network *tcp) Send(message *proto.Msg, conn net.Conn) (*proto.Msg, error) {
	msg := &proto.Msg{}
	data, err := pb.Marshal(message)
	if err != nil {
		return msg, err
	}
	b := new(bytes.Buffer)
	if err = binary.Write(b, binary.BigEndian, uint32(len(data))); err != nil {
		return msg, err
	}
	if _, err = conn.Write(b.Bytes()); err != nil {
		return msg, err
	}
	if _, err = conn.Write(data); err != nil {
		return msg, err
	}
	var header uint32
	if err = binary.Read(conn, binary.BigEndian, &header); err != nil {
		return msg, err
	}
	response := make([]byte, header)
	if err = readFully(conn, response); err != nil {
		return msg, err
	}
	if err = pb.Unmarshal(response, msg); err != nil {
		return msg, err
	}
	if msg.GetOk() != true {
		return msg, errors.New(msg.GetError())
	}
	return msg, nil
}

func readFully(r io.Reader, p []byte) error {
	for len(p) > 0 {
		n, err := r.Read(p)
		p = p[n:]
		if err != nil {
			return err
		}
	}
	return nil
}

func (network *udp) Send(message *proto.Msg, conn net.Conn) (*proto.Msg, error) {
	data, err := pb.Marshal(message)
	if err != nil {
		return nil, err
	}
	if _, err = conn.Write(data); err != nil {
		return nil, err
	}

	return nil, nil
}

func eventToPbEvent(event *Event) (*proto.Event, error) {
	var e proto.Event

	if event.Host == "" {
		event.Host, _ = os.Hostname()
	}
	t := reflect.ValueOf(&e).Elem()
	s := reflect.ValueOf(event).Elem()
	typeOfEvent := s.Type()
	for i := 0; i < s.NumField(); i++ {
		f := s.Field(i)
		value := reflect.ValueOf(f.Interface())
		if reflect.Zero(f.Type()) != value && f.Interface() != nil {
			name := typeOfEvent.Field(i).Name
			switch name {
			case "State", "Service", "Host", "Description":
				tmp := reflect.ValueOf(pb.String(value.String()))
				t.FieldByName(name).Set(tmp)
			case "Ttl":
				tmp := reflect.ValueOf(pb.Float32(float32(value.Float())))
				t.FieldByName(name).Set(tmp)
			case "Time":
				tmp := reflect.ValueOf(pb.Int64(value.Int()))
				t.FieldByName(name).Set(tmp)
			case "Tags":
				tmp := reflect.ValueOf(value.Interface().([]string))
				t.FieldByName(name).Set(tmp)
			case "Metric":
				switch reflect.TypeOf(f.Interface()).Kind() {
				case reflect.Int:
					tmp := reflect.ValueOf(pb.Int64(int64(value.Int())))
					t.FieldByName("MetricSint64").Set(tmp)
				case reflect.Float32:
					tmp := reflect.ValueOf(pb.Float32(float32(value.Float())))
					t.FieldByName("MetricF").Set(tmp)
				case reflect.Float64:
					tmp := reflect.ValueOf(pb.Float64(value.Float()))
					t.FieldByName("MetricD").Set(tmp)
				default:
					return nil, fmt.Errorf("Metric of invalid type (type %v)",
						reflect.TypeOf(f.Interface()).Kind())
				}
			}
		}
	}

	return &e, nil
}

func pbEventsToEvents(pbEvents []*proto.Event) []Event {
	var events []Event

	for _, event := range pbEvents {
		e := Event{
			State:       event.GetState(),
			Service:     event.GetService(),
			Host:        event.GetHost(),
			Description: event.GetDescription(),
			Ttl:         event.GetTtl(),
			Time:        event.GetTime(),
			Tags:        event.GetTags(),
		}
		if event.MetricF != nil {
			e.Metric = event.GetMetricF()
		} else if event.MetricD != nil {
			e.Metric = event.GetMetricD()
		} else {
			e.Metric = event.GetMetricSint64()
		}

		events = append(events, e)
	}

	return events
}

// Send sends an event to Riemann
func (c *Client) Send(event *Event) error {
	e, err := eventToPbEvent(event)
	if err != nil {
		return err
	}
	message := &proto.Msg{}
	message.Events = append(message.Events, e)
	c.Lock()
	defer c.Unlock()
	_, err = c.net.Send(message, c.connection)
	if err != nil {
		return err
	}

	return nil
}

// Query returns a list of events matched by query
func (c *Client) Query(q string) ([]Event, error) {
	switch c.net.(type) {
	case *udp:
		return nil, errors.New("Querying over UDP is not supported")
	}
	query := &proto.Query{}
	query.String_ = pb.String(q)
	message := &proto.Msg{}
	message.Query = query
	c.Lock()
	defer c.Unlock()
	response, err := c.net.Send(message, c.connection)
	if err != nil {
		return nil, err
	}
	return pbEventsToEvents(response.GetEvents()), nil
}

// Close closes the connection to Riemann
func (c *Client) Close() {
	c.Lock()
	c.connection.Close()
	c.Unlock()
}
<|endoftext|>


<commit_before>package termite

import (
	"fmt"
	"log"
	"os"
	"path/filepath"
	"strings"
	"syscall"
	"time"
)

var _ = log.Println

func (me *Master) MaybeRunInMaster(req *WorkRequest, rep *WorkResponse) bool {
	binary := req.Binary
	_, binary = filepath.Split(binary)

	switch binary {
	case "mkdir":
		return mkdirMaybeMasterRun(me, req, rep)
	case "rm":
		return rmMaybeMasterRun(me, req, rep)
	}
	return false
}

func recurseNames(master *Master, name string) (names []string) {
	a := master.fileServer.attr.GetDir(name)

	for n, m := range a.NameModeMap {
		if m.IsDirectory() {
			names = append(names, recurseNames(master, filepath.Join(name, n))...)
		} else {
			names = append(names, filepath.Join(name, n))
		}
	}
	names = append(names, name)
	return
}

func rmMaybeMasterRun(master *Master, req *WorkRequest, rep *WorkResponse) bool {
	g := Getopt(req.Argv[1:], nil, nil, true)

	force := g.HasLong("force") || g.HasShort('f')
	g.Long["force"] = "", false
	g.Short['f'] = "", false

	recursive := g.HasLong("recursive") || g.HasShort('r') || g.HasShort('R')
	g.Long["recursive"] = "", false
	g.Short['R'] = "", false
	g.Short['r'] = "", false

	if g.HasOptions() {
		return false
	}

	todo := []string{}
	for _, a := range g.Args {
		if a[0] != '/' {
			a = filepath.Join(req.Dir, a)
		}
		a = strings.TrimLeft(a, "/")
		todo = append(todo, a)
	}

	fs := FileSet{}
	msgs := []string{}
	status := 0
	if recursive {
		for _, t := range todo {
			for _, n := range recurseNames(master, t) {
				fs.Files = append(fs.Files, &FileAttr{
					Path: n,
				})
			}
		}
	} else {
		for _, p := range todo {
			attr := master.fileServer.attr.GetDir(p)
			switch {
			case attr.Deletion():
				msgs = append(msgs, fmt.Sprintf("rm: no such file or directory: %s", p))
				if !force {
					status = 1
				}
			case attr.IsDirectory() && !recursive:
				msgs = append(msgs, fmt.Sprintf("rm: is a directory: %s", p))
				status = 1
			default:
				fs.Files = append(fs.Files, &FileAttr{Path: p})
			}
		}
	}
	fs.Sort()
	master.replay(fs)
	master.mirrors.queueFiles(nil, fs)

	rep.Stderr = strings.Join(msgs, "\n")
	rep.Exit.WaitStatus = syscall.WaitStatus(status << 8)
	return true
}

func mkdirMaybeMasterRun(master *Master, req *WorkRequest, rep *WorkResponse) bool {
	g := Getopt(req.Argv[1:], nil, nil, true)

	hasParent := g.HasLong("parent") || g.HasShort('p')

	g.Long["parent"] = "", false
	g.Short['p'] = "", false

	if len(g.Short) > 0 || len(g.Long) > 0 {
		return false
	}
	for _, a := range g.Args {
		if a[0] != '/' {
			a = filepath.Join(req.Dir, a)
		}
		if hasParent {
			mkdirParentMasterRun(master, a, rep)
		} else {
			mkdirNormalMasterRun(master, a, rep)
		}
	}
	return true
}

func mkdirParentMasterRun(master *Master, arg string, rep *WorkResponse) {
	rootless := strings.TrimLeft(arg, "/")
	components := strings.Split(rootless, "/")

	fs := FileSet{}
	msgs := []string{}
	for i := range components {
		p := strings.Join(components[:i+1], "/")

		dirAttr := master.fileServer.attr.Get(p)
		if dirAttr.Deletion() {
			fs.Files = append(fs.Files, mkdirEntry(p))
		} else if dirAttr.IsDirectory() {
			// ok.
		} else {
			msgs = append(msgs, fmt.Sprintf("Not a directory: /%s", p))
		}
	}

	master.replay(fs)
	master.mirrors.queueFiles(nil, fs)

	if len(msgs) > 0 {
		rep.Stderr = strings.Join(msgs, "\n")
		rep.Exit.WaitStatus = 1 << 8
	}

}

func mkdirEntry(rootless string) *FileAttr {
	now := time.Nanoseconds()
	// TODO - could do without these.
	uid := os.Getuid()
	gid := os.Getgid()

	return &FileAttr{
		Path: rootless,
		FileInfo: &os.FileInfo{
			Mode:     syscall.S_IFDIR | 0755,
			Atime_ns: now,
			Ctime_ns: now,
			Mtime_ns: now,
			Uid:      uid,
			Gid:      gid,
		},
	}
}

func mkdirNormalMasterRun(master *Master, arg string, rep *WorkResponse) {
	rootless := strings.TrimLeft(arg, "/")
	dir, _ := SplitPath(rootless)
	dirAttr := master.fileServer.attr.Get(dir)
	if dirAttr.Deletion() {
		rep.Stderr = fmt.Sprintf("File not found: /%s", dir)
		rep.Exit = os.Waitmsg{
			WaitStatus: (1 << 8),
		}
		return
	}
	if !dirAttr.IsDirectory() {
		rep.Stderr = fmt.Sprintf("Is not a directory: /%s", dir)
		rep.Exit = os.Waitmsg{
			WaitStatus: (1 << 8),
		}
		return
	}

	chAttr := mkdirEntry(rootless)

	fs := FileSet{}
	fs.Files = append(fs.Files, chAttr)
	master.replay(fs)
	master.mirrors.queueFiles(nil, fs)
}
<commit_msg>Only print rm warnings if -f is not given.<commit_after>package termite

import (
	"fmt"
	"log"
	"os"
	"path/filepath"
	"strings"
	"syscall"
	"time"
)

var _ = log.Println

func (me *Master) MaybeRunInMaster(req *WorkRequest, rep *WorkResponse) bool {
	binary := req.Binary
	_, binary = filepath.Split(binary)

	switch binary {
	case "mkdir":
		return mkdirMaybeMasterRun(me, req, rep)
	case "rm":
		return rmMaybeMasterRun(me, req, rep)
	}
	return false
}

func recurseNames(master *Master, name string) (names []string) {
	a := master.fileServer.attr.GetDir(name)

	for n, m := range a.NameModeMap {
		if m.IsDirectory() {
			names = append(names, recurseNames(master, filepath.Join(name, n))...)
		} else {
			names = append(names, filepath.Join(name, n))
		}
	}
	names = append(names, name)
	return
}

func rmMaybeMasterRun(master *Master, req *WorkRequest, rep *WorkResponse) bool {
	g := Getopt(req.Argv[1:], nil, nil, true)

	force := g.HasLong("force") || g.HasShort('f')
	g.Long["force"] = "", false
	g.Short['f'] = "", false

	recursive := g.HasLong("recursive") || g.HasShort('r') || g.HasShort('R')
	g.Long["recursive"] = "", false
	g.Short['R'] = "", false
	g.Short['r'] = "", false

	if g.HasOptions() {
		return false
	}

	todo := []string{}
	for _, a := range g.Args {
		if a[0] != '/' {
			a = filepath.Join(req.Dir, a)
		}
		a = strings.TrimLeft(a, "/")
		todo = append(todo, a)
	}

	fs := FileSet{}
	msgs := []string{}
	status := 0
	if recursive {
		for _, t := range todo {
			for _, n := range recurseNames(master, t) {
				fs.Files = append(fs.Files, &FileAttr{
					Path: n,
				})
			}
		}
	} else {
		for _, p := range todo {
			attr := master.fileServer.attr.GetDir(p)
			switch {
			case attr.Deletion():
				if !force {
					msgs = append(msgs, fmt.Sprintf("rm: no such file or directory: %s", p))
					status = 1
				}
			case attr.IsDirectory() && !recursive:
				msgs = append(msgs, fmt.Sprintf("rm: is a directory: %s", p))
				status = 1
			default:
				fs.Files = append(fs.Files, &FileAttr{Path: p})
			}
		}
	}
	fs.Sort()
	master.replay(fs)
	master.mirrors.queueFiles(nil, fs)

	rep.Stderr = strings.Join(msgs, "\n")
	rep.Exit.WaitStatus = syscall.WaitStatus(status << 8)
	return true
}

func mkdirMaybeMasterRun(master *Master, req *WorkRequest, rep *WorkResponse) bool {
	g := Getopt(req.Argv[1:], nil, nil, true)

	hasParent := g.HasLong("parent") || g.HasShort('p')

	g.Long["parent"] = "", false
	g.Short['p'] = "", false

	if len(g.Short) > 0 || len(g.Long) > 0 {
		return false
	}
	for _, a := range g.Args {
		if a[0] != '/' {
			a = filepath.Join(req.Dir, a)
		}
		if hasParent {
			mkdirParentMasterRun(master, a, rep)
		} else {
			mkdirNormalMasterRun(master, a, rep)
		}
	}
	return true
}

func mkdirParentMasterRun(master *Master, arg string, rep *WorkResponse) {
	rootless := strings.TrimLeft(arg, "/")
	components := strings.Split(rootless, "/")

	fs := FileSet{}
	msgs := []string{}
	for i := range components {
		p := strings.Join(components[:i+1], "/")

		dirAttr := master.fileServer.attr.Get(p)
		if dirAttr.Deletion() {
			fs.Files = append(fs.Files, mkdirEntry(p))
		} else if dirAttr.IsDirectory() {
			// ok.
		} else {
			msgs = append(msgs, fmt.Sprintf("Not a directory: /%s", p))
		}
	}

	master.replay(fs)
	master.mirrors.queueFiles(nil, fs)

	if len(msgs) > 0 {
		rep.Stderr = strings.Join(msgs, "\n")
		rep.Exit.WaitStatus = 1 << 8
	}

}

func mkdirEntry(rootless string) *FileAttr {
	now := time.Nanoseconds()
	// TODO - could do without these.
	uid := os.Getuid()
	gid := os.Getgid()

	return &FileAttr{
		Path: rootless,
		FileInfo: &os.FileInfo{
			Mode:     syscall.S_IFDIR | 0755,
			Atime_ns: now,
			Ctime_ns: now,
			Mtime_ns: now,
			Uid:      uid,
			Gid:      gid,
		},
	}
}

func mkdirNormalMasterRun(master *Master, arg string, rep *WorkResponse) {
	rootless := strings.TrimLeft(arg, "/")
	dir, _ := SplitPath(rootless)
	dirAttr := master.fileServer.attr.Get(dir)
	if dirAttr.Deletion() {
		rep.Stderr = fmt.Sprintf("File not found: /%s", dir)
		rep.Exit = os.Waitmsg{
			WaitStatus: (1 << 8),
		}
		return
	}
	if !dirAttr.IsDirectory() {
		rep.Stderr = fmt.Sprintf("Is not a directory: /%s", dir)
		rep.Exit = os.Waitmsg{
			WaitStatus: (1 << 8),
		}
		return
	}

	chAttr := mkdirEntry(rootless)

	fs := FileSet{}
	fs.Files = append(fs.Files, chAttr)
	master.replay(fs)
	master.mirrors.queueFiles(nil, fs)
}
<|endoftext|>


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

package v2

import (
	. "gopkg.in/check.v1"

	apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

type CiliumV2RegisterSuite struct{}

var _ = Suite(&CiliumV2RegisterSuite{})

func (s *CiliumV2RegisterSuite) getTestUpToDateDefinition() *apiextensionsv1beta1.CustomResourceDefinition {
	return &apiextensionsv1beta1.CustomResourceDefinition{
		ObjectMeta: metav1.ObjectMeta{
			Labels: map[string]string{
				CustomResourceDefinitionSchemaVersionKey: CustomResourceDefinitionSchemaVersion,
			},
		},
		Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{
			Validation: &cnpCRV,
		},
	}
}

func (s *CiliumV2RegisterSuite) TestNeedsUpdateNoValidation(c *C) {
	crd := s.getTestUpToDateDefinition()

	crd.Spec.Validation = nil

	c.Assert(needsUpdate(crd), Equals, true)
}

func (s *CiliumV2RegisterSuite) TestNeedsUpdateNoLabels(c *C) {
	crd := s.getTestUpToDateDefinition()

	crd.Labels = nil

	c.Assert(needsUpdate(crd), Equals, true)
}

func (s *CiliumV2RegisterSuite) TestNeedsUpdateNoVersionLabel(c *C) {
	crd := s.getTestUpToDateDefinition()

	crd.Labels = map[string]string{"test": "test"}

	c.Assert(needsUpdate(crd), Equals, true)
}

func (s *CiliumV2RegisterSuite) TestNeedsUpdateOlderVersion(c *C) {
	crd := s.getTestUpToDateDefinition()

	crd.Labels[CustomResourceDefinitionSchemaVersionKey] = "0.9"

	c.Assert(needsUpdate(crd), Equals, true)
}

func (s *CiliumV2RegisterSuite) TestNeedsUpdateCorruptedVersion(c *C) {
	crd := s.getTestUpToDateDefinition()

	crd.Labels[CustomResourceDefinitionSchemaVersionKey] = "totally-not-semver"

	c.Assert(needsUpdate(crd), Equals, true)
}
<commit_msg>k8s: Add CRD IP address validation unit tests<commit_after>// Copyright 2018 Authors of Cilium
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package v2

import (
	"regexp"

	. "gopkg.in/check.v1"
	apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

type CiliumV2RegisterSuite struct{}

var _ = Suite(&CiliumV2RegisterSuite{})

func (s *CiliumV2RegisterSuite) getTestUpToDateDefinition() *apiextensionsv1beta1.CustomResourceDefinition {
	return &apiextensionsv1beta1.CustomResourceDefinition{
		ObjectMeta: metav1.ObjectMeta{
			Labels: map[string]string{
				CustomResourceDefinitionSchemaVersionKey: CustomResourceDefinitionSchemaVersion,
			},
		},
		Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{
			Validation: &cnpCRV,
		},
	}
}

func (s *CiliumV2RegisterSuite) TestNeedsUpdateNoValidation(c *C) {
	crd := s.getTestUpToDateDefinition()

	crd.Spec.Validation = nil

	c.Assert(needsUpdate(crd), Equals, true)
}

func (s *CiliumV2RegisterSuite) TestNeedsUpdateNoLabels(c *C) {
	crd := s.getTestUpToDateDefinition()

	crd.Labels = nil

	c.Assert(needsUpdate(crd), Equals, true)
}

func (s *CiliumV2RegisterSuite) TestNeedsUpdateNoVersionLabel(c *C) {
	crd := s.getTestUpToDateDefinition()

	crd.Labels = map[string]string{"test": "test"}

	c.Assert(needsUpdate(crd), Equals, true)
}

func (s *CiliumV2RegisterSuite) TestNeedsUpdateOlderVersion(c *C) {
	crd := s.getTestUpToDateDefinition()

	crd.Labels[CustomResourceDefinitionSchemaVersionKey] = "0.9"

	c.Assert(needsUpdate(crd), Equals, true)
}

func (s *CiliumV2RegisterSuite) TestNeedsUpdateCorruptedVersion(c *C) {
	crd := s.getTestUpToDateDefinition()

	crd.Labels[CustomResourceDefinitionSchemaVersionKey] = "totally-not-semver"

	c.Assert(needsUpdate(crd), Equals, true)
}

func (s *CiliumV2RegisterSuite) TestCIDRRegex(c *C) {
	goodCIDRs := []string{
		"192.0.2.3/32",
		"192.0.2.0/24",
		"0.0.0.0/0",
		"::/0",
		"::cafe/128",
		"::f00d:cafe/128",
		"0:0:0:0:0:0:0:cafe/128",
		"cafe:cafe:cafe:cafe:cafe:cafe:cafe:cafe/128",
		"bad:f00d:cafe:0:0:0:0:add/64",
		"bad:f00d:cafe::bad/64",
		"f00d::/64",
		"f00d::0:0/120",
		"f00d:cafe::1:2/120",
	}

continueTest:
	for _, input := range goodCIDRs {
		for _, prop := range CIDR.OneOf {
			matched, err := regexp.MatchString(prop.Pattern, input)
			c.Assert(err, IsNil)
			if matched {
				continue continueTest
			}
		}
		// The below is always false, valid CIDR prefixes should
		// always skip this by continuing in the above loop.
		c.Assert(input, Equals, "failed to match CIDR.OneOf[*].Pattern")
	}

	badCIDRs := []string{
		"192.0.2.3",
		"192.0.2.3/",
		"abcdef",
		"0.0.0.0/0/0",
		"::",
		":",
		":/",
		"0:0",
		"::cafe/128/12",
		"abc:def",
		"abc:def/64",
		"f00d::/",
		"f00d::0:0",
		"bad.f00d.cafe.0.0.0.0.add/20",
		"::192.0.2.3/128",
		"::ffff:192.0.2.3/128",
		"abcd:192.0.2.3/128",
		":abcd:192.0.2.3/128",
		"abcd::192.0.2.3/128",
		":abcd::192.0.2.3/128",
		"bad::f00d::cafe/1",
		":bad::f00d::cafe/1",
		"::bad::f00d::cafe/1",
		"::bad::food::cafe/1",
	}

	for _, input := range badCIDRs {
		for _, prop := range CIDR.OneOf {
			matched, err := regexp.MatchString(prop.Pattern, input)
			c.Assert(err, IsNil)
			if matched {
				// The below is always false, invalid CIDR
				// prefixes are not supposed to match the regex.
				c.Assert(input, Equals, "unexpectedly matched CIDR.OneOf[*].Pattern")
			}
		}
	}
}
<|endoftext|>