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

// Package create provides functions to create new content.
package create

import (
	"bytes"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"strings"

	"github.com/gohugoio/hugo/hugofs/glob"

	"github.com/gohugoio/hugo/common/paths"

	"github.com/pkg/errors"

	"github.com/gohugoio/hugo/common/hexec"
	"github.com/gohugoio/hugo/hugofs/files"

	"github.com/gohugoio/hugo/hugofs"

	"github.com/gohugoio/hugo/helpers"
	"github.com/gohugoio/hugo/hugolib"
	"github.com/spf13/afero"
)

const (
	// DefaultArchetypeTemplateTemplate is the template used in 'hugo new site'
	// and the template we use as a fall back.
	DefaultArchetypeTemplateTemplate = `---
title: "{{ replace .Name "-" " " | title }}"
date: {{ .Date }}
draft: true
---

`
)

// NewContent creates a new content file in h (or a full bundle if the archetype is a directory)
// in targetPath.
func NewContent(h *hugolib.HugoSites, kind, targetPath string) error {
	if h.BaseFs.Content.Dirs == nil {
		return errors.New("no existing content directory configured for this project")
	}

	cf := hugolib.NewContentFactory(h)

	if kind == "" {
		kind = cf.SectionFromFilename(targetPath)
	}

	b := &contentBuilder{
		archeTypeFs: h.PathSpec.BaseFs.Archetypes.Fs,
		sourceFs:    h.PathSpec.Fs.Source,
		ps:          h.PathSpec,
		h:           h,
		cf:          cf,

		kind:       kind,
		targetPath: targetPath,
	}

	ext := paths.Ext(targetPath)

	b.setArcheTypeFilenameToUse(ext)

	withBuildLock := func() (string, error) {
		unlock, err := h.BaseFs.LockBuild()
		if err != nil {
			return "", fmt.Errorf("failed to acquire a build lock: %s", err)
		}
		defer unlock()

		if b.isDir {
			return "", b.buildDir()
		}

		if ext == "" {
			return "", errors.Errorf("failed to resolve %q to a archetype template", targetPath)
		}

		if !files.IsContentFile(b.targetPath) {
			return "", errors.Errorf("target path %q is not a known content format", b.targetPath)
		}

		return b.buildFile()

	}

	filename, err := withBuildLock()
	if err != nil {
		return err
	}

	if filename != "" {
		return b.openInEditorIfConfigured(filename)
	}

	return nil

}

type contentBuilder struct {
	archeTypeFs afero.Fs
	sourceFs    afero.Fs

	ps *helpers.PathSpec
	h  *hugolib.HugoSites
	cf hugolib.ContentFactory

	// Builder state
	archetypeFilename string
	targetPath        string
	kind              string
	isDir             bool
	dirMap            archetypeMap
}

func (b *contentBuilder) buildDir() error {
	// Split the dir into content files and the rest.
	if err := b.mapArcheTypeDir(); err != nil {
		return err
	}

	var contentTargetFilenames []string
	var baseDir string

	for _, fi := range b.dirMap.contentFiles {
		targetFilename := filepath.Join(b.targetPath, strings.TrimPrefix(fi.Meta().Path, b.archetypeFilename))
		abs, err := b.cf.CreateContentPlaceHolder(targetFilename)
		if err != nil {
			return err
		}
		if baseDir == "" {
			baseDir = strings.TrimSuffix(abs, targetFilename)
		}

		contentTargetFilenames = append(contentTargetFilenames, abs)
	}

	var contentInclusionFilter *glob.FilenameFilter
	if !b.dirMap.siteUsed {
		// We don't need to build everything.
		contentInclusionFilter = glob.NewFilenameFilterForInclusionFunc(func(filename string) bool {
			filename = strings.TrimPrefix(filename, string(os.PathSeparator))
			for _, cn := range contentTargetFilenames {
				if strings.Contains(cn, filename) {
					return true
				}
			}
			return false
		})

	}

	if err := b.h.Build(hugolib.BuildCfg{NoBuildLock: true, SkipRender: true, ContentInclusionFilter: contentInclusionFilter}); err != nil {
		return err
	}

	for i, filename := range contentTargetFilenames {
		if err := b.applyArcheType(filename, b.dirMap.contentFiles[i].Meta().Path); err != nil {
			return err
		}
	}

	// Copy the rest as is.
	for _, f := range b.dirMap.otherFiles {
		meta := f.Meta()
		filename := meta.Path

		in, err := meta.Open()
		if err != nil {
			return errors.Wrap(err, "failed to open non-content file")
		}

		targetFilename := filepath.Join(baseDir, b.targetPath, strings.TrimPrefix(filename, b.archetypeFilename))
		targetDir := filepath.Dir(targetFilename)

		if err := b.sourceFs.MkdirAll(targetDir, 0o777); err != nil && !os.IsExist(err) {
			return errors.Wrapf(err, "failed to create target directory for %q", targetDir)
		}

		out, err := b.sourceFs.Create(targetFilename)
		if err != nil {
			return err
		}

		_, err = io.Copy(out, in)
		if err != nil {
			return err
		}

		in.Close()
		out.Close()
	}
	return nil
}

func (b *contentBuilder) buildFile() (string, error) {
	contentPlaceholderAbsFilename, err := b.cf.CreateContentPlaceHolder(b.targetPath)
	if err != nil {
		return "", err
	}

	usesSite, err := b.usesSiteVar(b.archetypeFilename)
	if err != nil {
		return "", err
	}

	var contentInclusionFilter *glob.FilenameFilter
	if !usesSite {
		// We don't need to build everything.
		contentInclusionFilter = glob.NewFilenameFilterForInclusionFunc(func(filename string) bool {
			filename = strings.TrimPrefix(filename, string(os.PathSeparator))
			return strings.Contains(contentPlaceholderAbsFilename, filename)
		})
	}

	if err := b.h.Build(hugolib.BuildCfg{NoBuildLock: true, SkipRender: true, ContentInclusionFilter: contentInclusionFilter}); err != nil {
		return "", err
	}

	if err := b.applyArcheType(contentPlaceholderAbsFilename, b.archetypeFilename); err != nil {
		return "", err
	}

	b.h.Log.Infof("Content %q created", contentPlaceholderAbsFilename)

	return contentPlaceholderAbsFilename, nil
}

func (b *contentBuilder) setArcheTypeFilenameToUse(ext string) {
	var pathsToCheck []string

	if b.kind != "" {
		pathsToCheck = append(pathsToCheck, b.kind+ext)
	}
	pathsToCheck = append(pathsToCheck, "default"+ext, "default")

	for _, p := range pathsToCheck {
		fi, err := b.archeTypeFs.Stat(p)
		if err == nil {
			b.archetypeFilename = p
			b.isDir = fi.IsDir()
			return
		}
	}

}

func (b *contentBuilder) applyArcheType(contentFilename, archetypeFilename string) error {
	p := b.h.GetContentPage(contentFilename)
	if p == nil {
		panic(fmt.Sprintf("[BUG] no Page found for %q", contentFilename))
	}

	f, err := b.sourceFs.Create(contentFilename)
	if err != nil {
		return err
	}
	defer f.Close()

	if archetypeFilename == "" {
		return b.cf.AppplyArchetypeTemplate(f, p, b.kind, DefaultArchetypeTemplateTemplate)
	}

	return b.cf.AppplyArchetypeFilename(f, p, b.kind, archetypeFilename)

}

func (b *contentBuilder) mapArcheTypeDir() error {
	var m archetypeMap

	walkFn := func(path string, fi hugofs.FileMetaInfo, err error) error {
		if err != nil {
			return err
		}

		if fi.IsDir() {
			return nil
		}

		fil := fi.(hugofs.FileMetaInfo)

		if files.IsContentFile(path) {
			m.contentFiles = append(m.contentFiles, fil)
			if !m.siteUsed {
				m.siteUsed, err = b.usesSiteVar(path)
				if err != nil {
					return err
				}
			}
			return nil
		}

		m.otherFiles = append(m.otherFiles, fil)

		return nil
	}

	walkCfg := hugofs.WalkwayConfig{
		WalkFn: walkFn,
		Fs:     b.archeTypeFs,
		Root:   b.archetypeFilename,
	}

	w := hugofs.NewWalkway(walkCfg)

	if err := w.Walk(); err != nil {
		return errors.Wrapf(err, "failed to walk archetype dir %q", b.archetypeFilename)
	}

	b.dirMap = m

	return nil
}

func (b *contentBuilder) openInEditorIfConfigured(filename string) error {
	editor := b.h.Cfg.GetString("newContentEditor")
	if editor == "" {
		return nil
	}

	b.h.Log.Infof("Editing %q with %q ...\n", filename, editor)

	cmd, err := hexec.SafeCommand(editor, filename)
	if err != nil {
		return err
	}

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

	return cmd.Run()
}

func (b *contentBuilder) usesSiteVar(filename string) (bool, error) {
	if filename == "" {
		return false, nil
	}
	bb, err := afero.ReadFile(b.archeTypeFs, filename)
	if err != nil {
		return false, errors.Wrap(err, "failed to open archetype file")
	}

	return bytes.Contains(bb, []byte(".Site")) || bytes.Contains(bb, []byte("site.")), nil

}

type archetypeMap struct {
	// These needs to be parsed and executed as Go templates.
	contentFiles []hugofs.FileMetaInfo
	// These are just copied to destination.
	otherFiles []hugofs.FileMetaInfo
	// If the templates needs a fully built site. This can potentially be
	// expensive, so only do when needed.
	siteUsed bool
}
<commit_msg>create: Always print "Content ... created"<commit_after>// Copyright 2019 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package create provides functions to create new content.
package create

import (
	"bytes"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"strings"

	"github.com/gohugoio/hugo/hugofs/glob"

	"github.com/gohugoio/hugo/common/paths"

	"github.com/pkg/errors"

	"github.com/gohugoio/hugo/common/hexec"
	"github.com/gohugoio/hugo/hugofs/files"

	"github.com/gohugoio/hugo/hugofs"

	"github.com/gohugoio/hugo/helpers"
	"github.com/gohugoio/hugo/hugolib"
	"github.com/spf13/afero"
)

const (
	// DefaultArchetypeTemplateTemplate is the template used in 'hugo new site'
	// and the template we use as a fall back.
	DefaultArchetypeTemplateTemplate = `---
title: "{{ replace .Name "-" " " | title }}"
date: {{ .Date }}
draft: true
---

`
)

// NewContent creates a new content file in h (or a full bundle if the archetype is a directory)
// in targetPath.
func NewContent(h *hugolib.HugoSites, kind, targetPath string) error {
	if h.BaseFs.Content.Dirs == nil {
		return errors.New("no existing content directory configured for this project")
	}

	cf := hugolib.NewContentFactory(h)

	if kind == "" {
		kind = cf.SectionFromFilename(targetPath)
	}

	b := &contentBuilder{
		archeTypeFs: h.PathSpec.BaseFs.Archetypes.Fs,
		sourceFs:    h.PathSpec.Fs.Source,
		ps:          h.PathSpec,
		h:           h,
		cf:          cf,

		kind:       kind,
		targetPath: targetPath,
	}

	ext := paths.Ext(targetPath)

	b.setArcheTypeFilenameToUse(ext)

	withBuildLock := func() (string, error) {
		unlock, err := h.BaseFs.LockBuild()
		if err != nil {
			return "", fmt.Errorf("failed to acquire a build lock: %s", err)
		}
		defer unlock()

		if b.isDir {
			return "", b.buildDir()
		}

		if ext == "" {
			return "", errors.Errorf("failed to resolve %q to a archetype template", targetPath)
		}

		if !files.IsContentFile(b.targetPath) {
			return "", errors.Errorf("target path %q is not a known content format", b.targetPath)
		}

		return b.buildFile()

	}

	filename, err := withBuildLock()
	if err != nil {
		return err
	}

	if filename != "" {
		return b.openInEditorIfConfigured(filename)
	}

	return nil

}

type contentBuilder struct {
	archeTypeFs afero.Fs
	sourceFs    afero.Fs

	ps *helpers.PathSpec
	h  *hugolib.HugoSites
	cf hugolib.ContentFactory

	// Builder state
	archetypeFilename string
	targetPath        string
	kind              string
	isDir             bool
	dirMap            archetypeMap
}

func (b *contentBuilder) buildDir() error {
	// Split the dir into content files and the rest.
	if err := b.mapArcheTypeDir(); err != nil {
		return err
	}

	var contentTargetFilenames []string
	var baseDir string

	for _, fi := range b.dirMap.contentFiles {
		targetFilename := filepath.Join(b.targetPath, strings.TrimPrefix(fi.Meta().Path, b.archetypeFilename))
		abs, err := b.cf.CreateContentPlaceHolder(targetFilename)
		if err != nil {
			return err
		}
		if baseDir == "" {
			baseDir = strings.TrimSuffix(abs, targetFilename)
		}

		contentTargetFilenames = append(contentTargetFilenames, abs)
	}

	var contentInclusionFilter *glob.FilenameFilter
	if !b.dirMap.siteUsed {
		// We don't need to build everything.
		contentInclusionFilter = glob.NewFilenameFilterForInclusionFunc(func(filename string) bool {
			filename = strings.TrimPrefix(filename, string(os.PathSeparator))
			for _, cn := range contentTargetFilenames {
				if strings.Contains(cn, filename) {
					return true
				}
			}
			return false
		})

	}

	if err := b.h.Build(hugolib.BuildCfg{NoBuildLock: true, SkipRender: true, ContentInclusionFilter: contentInclusionFilter}); err != nil {
		return err
	}

	for i, filename := range contentTargetFilenames {
		if err := b.applyArcheType(filename, b.dirMap.contentFiles[i].Meta().Path); err != nil {
			return err
		}
	}

	// Copy the rest as is.
	for _, f := range b.dirMap.otherFiles {
		meta := f.Meta()
		filename := meta.Path

		in, err := meta.Open()
		if err != nil {
			return errors.Wrap(err, "failed to open non-content file")
		}

		targetFilename := filepath.Join(baseDir, b.targetPath, strings.TrimPrefix(filename, b.archetypeFilename))
		targetDir := filepath.Dir(targetFilename)

		if err := b.sourceFs.MkdirAll(targetDir, 0o777); err != nil && !os.IsExist(err) {
			return errors.Wrapf(err, "failed to create target directory for %q", targetDir)
		}

		out, err := b.sourceFs.Create(targetFilename)
		if err != nil {
			return err
		}

		_, err = io.Copy(out, in)
		if err != nil {
			return err
		}

		in.Close()
		out.Close()
	}
	return nil
}

func (b *contentBuilder) buildFile() (string, error) {
	contentPlaceholderAbsFilename, err := b.cf.CreateContentPlaceHolder(b.targetPath)
	if err != nil {
		return "", err
	}

	usesSite, err := b.usesSiteVar(b.archetypeFilename)
	if err != nil {
		return "", err
	}

	var contentInclusionFilter *glob.FilenameFilter
	if !usesSite {
		// We don't need to build everything.
		contentInclusionFilter = glob.NewFilenameFilterForInclusionFunc(func(filename string) bool {
			filename = strings.TrimPrefix(filename, string(os.PathSeparator))
			return strings.Contains(contentPlaceholderAbsFilename, filename)
		})
	}

	if err := b.h.Build(hugolib.BuildCfg{NoBuildLock: true, SkipRender: true, ContentInclusionFilter: contentInclusionFilter}); err != nil {
		return "", err
	}

	if err := b.applyArcheType(contentPlaceholderAbsFilename, b.archetypeFilename); err != nil {
		return "", err
	}

	b.h.Log.Printf("Content %q created", contentPlaceholderAbsFilename)

	return contentPlaceholderAbsFilename, nil
}

func (b *contentBuilder) setArcheTypeFilenameToUse(ext string) {
	var pathsToCheck []string

	if b.kind != "" {
		pathsToCheck = append(pathsToCheck, b.kind+ext)
	}
	pathsToCheck = append(pathsToCheck, "default"+ext, "default")

	for _, p := range pathsToCheck {
		fi, err := b.archeTypeFs.Stat(p)
		if err == nil {
			b.archetypeFilename = p
			b.isDir = fi.IsDir()
			return
		}
	}

}

func (b *contentBuilder) applyArcheType(contentFilename, archetypeFilename string) error {
	p := b.h.GetContentPage(contentFilename)
	if p == nil {
		panic(fmt.Sprintf("[BUG] no Page found for %q", contentFilename))
	}

	f, err := b.sourceFs.Create(contentFilename)
	if err != nil {
		return err
	}
	defer f.Close()

	if archetypeFilename == "" {
		return b.cf.AppplyArchetypeTemplate(f, p, b.kind, DefaultArchetypeTemplateTemplate)
	}

	return b.cf.AppplyArchetypeFilename(f, p, b.kind, archetypeFilename)

}

func (b *contentBuilder) mapArcheTypeDir() error {
	var m archetypeMap

	walkFn := func(path string, fi hugofs.FileMetaInfo, err error) error {
		if err != nil {
			return err
		}

		if fi.IsDir() {
			return nil
		}

		fil := fi.(hugofs.FileMetaInfo)

		if files.IsContentFile(path) {
			m.contentFiles = append(m.contentFiles, fil)
			if !m.siteUsed {
				m.siteUsed, err = b.usesSiteVar(path)
				if err != nil {
					return err
				}
			}
			return nil
		}

		m.otherFiles = append(m.otherFiles, fil)

		return nil
	}

	walkCfg := hugofs.WalkwayConfig{
		WalkFn: walkFn,
		Fs:     b.archeTypeFs,
		Root:   b.archetypeFilename,
	}

	w := hugofs.NewWalkway(walkCfg)

	if err := w.Walk(); err != nil {
		return errors.Wrapf(err, "failed to walk archetype dir %q", b.archetypeFilename)
	}

	b.dirMap = m

	return nil
}

func (b *contentBuilder) openInEditorIfConfigured(filename string) error {
	editor := b.h.Cfg.GetString("newContentEditor")
	if editor == "" {
		return nil
	}

	b.h.Log.Printf("Editing %q with %q ...\n", filename, editor)

	cmd, err := hexec.SafeCommand(editor, filename)
	if err != nil {
		return err
	}

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

	return cmd.Run()
}

func (b *contentBuilder) usesSiteVar(filename string) (bool, error) {
	if filename == "" {
		return false, nil
	}
	bb, err := afero.ReadFile(b.archeTypeFs, filename)
	if err != nil {
		return false, errors.Wrap(err, "failed to open archetype file")
	}

	return bytes.Contains(bb, []byte(".Site")) || bytes.Contains(bb, []byte("site.")), nil

}

type archetypeMap struct {
	// These needs to be parsed and executed as Go templates.
	contentFiles []hugofs.FileMetaInfo
	// These are just copied to destination.
	otherFiles []hugofs.FileMetaInfo
	// If the templates needs a fully built site. This can potentially be
	// expensive, so only do when needed.
	siteUsed bool
}
<|endoftext|>


<commit_before>// Copyright © 2014 Steve Francia <spf@spf13.com>.
//
// Licensed under the Simple Public 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://opensource.org/licenses/Simple-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 create

import (
	"bytes"
	"io/ioutil"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"strings"
	"time"

	"github.com/spf13/cast"
	"github.com/spf13/hugo/helpers"
	"github.com/spf13/hugo/hugofs"
	"github.com/spf13/hugo/hugolib"
	"github.com/spf13/hugo/parser"
	jww "github.com/spf13/jwalterweatherman"
	"github.com/spf13/viper"
)

func NewContent(kind, name string) (err error) {
	jww.INFO.Println("attempting to create ", name, "of", kind)

	location := FindArchetype(kind)

	var by []byte

	if location != "" {
		by, err = ioutil.ReadFile(location)
		if err != nil {
			jww.ERROR.Println(err)
		}
	}
	if location == "" || err != nil {
		by = []byte("+++\n title = \"title\"\n draft = true \n+++\n")
	}

	psr, err := parser.ReadFrom(bytes.NewReader(by))
	if err != nil {
		return err
	}
	metadata, err := psr.Metadata()
	if err != nil {
		return err
	}
	newmetadata, err := cast.ToStringMapE(metadata)
	if err != nil {
		jww.ERROR.Println("Error processing archetype file:", location)
		return err
	}

	for k, _ := range newmetadata {
		switch strings.ToLower(k) {
		case "date":
			newmetadata[k] = time.Now()
		case "title":
			newmetadata[k] = helpers.MakeTitle(helpers.Filename(name))
		}
	}

	caseimatch := func(m map[string]interface{}, key string) bool {
		for k, _ := range m {
			if strings.ToLower(k) == strings.ToLower(key) {
				return true
			}
		}
		return false
	}

	if !caseimatch(newmetadata, "date") {
		newmetadata["date"] = time.Now()
	}

	if !caseimatch(newmetadata, "title") {
		newmetadata["title"] = helpers.MakeTitle(helpers.Filename(name))
	}

	page, err := hugolib.NewPage(name)
	if err != nil {
		return err
	}

	if x := viper.GetString("MetaDataFormat"); x == "json" || x == "yaml" || x == "toml" {
		newmetadata["date"] = time.Now().Format(time.RFC3339)
	}

	//page.Dir = viper.GetString("sourceDir")
	page.SetSourceMetaData(newmetadata, parser.FormatToLeadRune(viper.GetString("MetaDataFormat")))
	page.SetSourceContent(psr.Content())
	if err = page.SafeSaveSourceAs(filepath.Join(viper.GetString("contentDir"), name)); err != nil {
		return
	}
	jww.FEEDBACK.Println(helpers.AbsPathify(filepath.Join(viper.GetString("contentDir"), name)), "created")

	editor := viper.GetString("NewContentEditor")

	if editor != "" {
		jww.FEEDBACK.Printf("Editing %s in %s.\n", name, editor)

		cmd := exec.Command(editor, path.Join(viper.GetString("contentDir"), name))
		cmd.Stdin = os.Stdin
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr

		if err = cmd.Run(); err != nil {
			return
		}
	}

	return nil
}

func FindArchetype(kind string) (outpath string) {
	search := []string{helpers.AbsPathify(viper.GetString("archetypeDir"))}

	if viper.GetString("theme") != "" {
		themeDir := filepath.Join(helpers.AbsPathify("themes/"+viper.GetString("theme")), "/archetypes/")
		if _, err := os.Stat(themeDir); os.IsNotExist(err) {
			jww.ERROR.Println("Unable to find archetypes directory for theme :", viper.GetString("theme"), "in", themeDir)
		} else {
			search = append(search, themeDir)
		}
	}

	for _, x := range search {
		// If the new content isn't in a subdirectory, kind == "".
		// Therefore it should be excluded otherwise `is a directory`
		// error will occur. github.com/spf13/hugo/issues/411
		var pathsToCheck []string

		if kind == "" {
			pathsToCheck = []string{"default.md", "default"}
		} else {
			pathsToCheck = []string{kind + ".md", kind, "default.md", "default"}
		}
		for _, p := range pathsToCheck {
			curpath := filepath.Join(x, p)
			jww.DEBUG.Println("checking", curpath, "for archetypes")
			if exists, _ := helpers.Exists(curpath, hugofs.SourceFs); exists {
				jww.INFO.Println("curpath: " + curpath)
				return curpath
			}
		}
	}

	return ""
}
<commit_msg>Handle empty front matter in archetype.<commit_after>// Copyright © 2014 Steve Francia <spf@spf13.com>.
//
// Licensed under the Simple Public 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://opensource.org/licenses/Simple-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 create

import (
	"bytes"
	"io/ioutil"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"strings"
	"time"

	"github.com/spf13/cast"
	"github.com/spf13/hugo/helpers"
	"github.com/spf13/hugo/hugofs"
	"github.com/spf13/hugo/hugolib"
	"github.com/spf13/hugo/parser"
	jww "github.com/spf13/jwalterweatherman"
	"github.com/spf13/viper"
)

func NewContent(kind, name string) (err error) {
	jww.INFO.Println("attempting to create ", name, "of", kind)

	location := FindArchetype(kind)

	var by []byte

	if location != "" {
		by, err = ioutil.ReadFile(location)
		if err != nil {
			jww.ERROR.Println(err)
		}
	}
	if location == "" || err != nil {
		by = []byte("+++\n title = \"title\"\n draft = true \n+++\n")
	}

	psr, err := parser.ReadFrom(bytes.NewReader(by))
	if err != nil {
		return err
	}
	metadata, err := psr.Metadata()
	if err != nil {
		return err
	}
	newmetadata, err := cast.ToStringMapE(metadata)
	if err != nil {
		jww.ERROR.Println("Error processing archetype file:", location)
		return err
	}

	for k, _ := range newmetadata {
		switch strings.ToLower(k) {
		case "date":
			newmetadata[k] = time.Now()
		case "title":
			newmetadata[k] = helpers.MakeTitle(helpers.Filename(name))
		}
	}

	caseimatch := func(m map[string]interface{}, key string) bool {
		for k, _ := range m {
			if strings.ToLower(k) == strings.ToLower(key) {
				return true
			}
		}
		return false
	}

	if newmetadata == nil {
		newmetadata = make(map[string]interface{})
	}

	if !caseimatch(newmetadata, "date") {
		newmetadata["date"] = time.Now()
	}

	if !caseimatch(newmetadata, "title") {
		newmetadata["title"] = helpers.MakeTitle(helpers.Filename(name))
	}

	page, err := hugolib.NewPage(name)
	if err != nil {
		return err
	}

	if x := viper.GetString("MetaDataFormat"); x == "json" || x == "yaml" || x == "toml" {
		newmetadata["date"] = time.Now().Format(time.RFC3339)
	}

	//page.Dir = viper.GetString("sourceDir")
	page.SetSourceMetaData(newmetadata, parser.FormatToLeadRune(viper.GetString("MetaDataFormat")))
	page.SetSourceContent(psr.Content())
	if err = page.SafeSaveSourceAs(filepath.Join(viper.GetString("contentDir"), name)); err != nil {
		return
	}
	jww.FEEDBACK.Println(helpers.AbsPathify(filepath.Join(viper.GetString("contentDir"), name)), "created")

	editor := viper.GetString("NewContentEditor")

	if editor != "" {
		jww.FEEDBACK.Printf("Editing %s in %s.\n", name, editor)

		cmd := exec.Command(editor, path.Join(viper.GetString("contentDir"), name))
		cmd.Stdin = os.Stdin
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr

		if err = cmd.Run(); err != nil {
			return
		}
	}

	return nil
}

func FindArchetype(kind string) (outpath string) {
	search := []string{helpers.AbsPathify(viper.GetString("archetypeDir"))}

	if viper.GetString("theme") != "" {
		themeDir := filepath.Join(helpers.AbsPathify("themes/"+viper.GetString("theme")), "/archetypes/")
		if _, err := os.Stat(themeDir); os.IsNotExist(err) {
			jww.ERROR.Println("Unable to find archetypes directory for theme :", viper.GetString("theme"), "in", themeDir)
		} else {
			search = append(search, themeDir)
		}
	}

	for _, x := range search {
		// If the new content isn't in a subdirectory, kind == "".
		// Therefore it should be excluded otherwise `is a directory`
		// error will occur. github.com/spf13/hugo/issues/411
		var pathsToCheck []string

		if kind == "" {
			pathsToCheck = []string{"default.md", "default"}
		} else {
			pathsToCheck = []string{kind + ".md", kind, "default.md", "default"}
		}
		for _, p := range pathsToCheck {
			curpath := filepath.Join(x, p)
			jww.DEBUG.Println("checking", curpath, "for archetypes")
			if exists, _ := helpers.Exists(curpath, hugofs.SourceFs); exists {
				jww.INFO.Println("curpath: " + curpath)
				return curpath
			}
		}
	}

	return ""
}
<|endoftext|>


<commit_before>package crypto

import (
	"crypto/ecdsa"
	"crypto/x509"
	"encoding/pem"
	"fmt"
	"io/ioutil"
	"path/filepath"
	"sync"
)

const (
	pemKeyPath = "priv_key.pem"
)

type PemKey struct {
	l    sync.Mutex
	path string
}

func NewPemKey(base string) *PemKey {
	path := filepath.Join(base, pemKeyPath)
	pemKey := &PemKey{
		path: path,
	}
	return pemKey
}

func (k *PemKey) ReadKey() (*ecdsa.PrivateKey, error) {
	k.l.Lock()
	defer k.l.Unlock()

	// Read the file
	buf, err := ioutil.ReadFile(k.path)
	if err != nil {
		return nil, err
	}

	// Check for no key
	if len(buf) == 0 {
		return nil, nil
	}

	// Decode the PEM key
	block, _ := pem.Decode(buf)
	if block == nil {
		return nil, fmt.Errorf("Error decoding PEM block from data")
	}
	return x509.ParseECPrivateKey(block.Bytes)
}

func (k *PemKey) WriteKey(key *ecdsa.PrivateKey) error {
	k.l.Lock()
	defer k.l.Unlock()

	b, err := x509.MarshalECPrivateKey(key)
	if err != nil {
		return err
	}
	pemBlock := &pem.Block{Type: "EC PRIVATE KEY", Bytes: b}
	data := pem.EncodeToMemory(pemBlock)
	return ioutil.WriteFile(k.path, data, 0755)
}

type PemDump struct {
	PublicKey  string
	PrivateKey string
}

func GeneratePemKey() (*PemDump, error) {
	key, err := GenerateECDSAKey()
	if err != nil {
		return nil, err
	}

	pub := fmt.Sprintf("0x%X", FromECDSAPub(&key.PublicKey))

	b, err := x509.MarshalECPrivateKey(key)
	if err != nil {
		return nil, err
	}
	pemBlock := &pem.Block{Type: "EC PRIVATE KEY", Bytes: b}
	data := pem.EncodeToMemory(pemBlock)

	pemDump := PemDump{
		PublicKey:  pub,
		PrivateKey: string(data),
	}

	return &pemDump, err
}
<commit_msg>Added exported method to read the private key from buffer<commit_after>package crypto

import (
	"crypto/ecdsa"
	"crypto/x509"
	"encoding/pem"
	"fmt"
	"io/ioutil"
	"path/filepath"
	"sync"
)

const (
	pemKeyPath = "priv_key.pem"
)

type PemKey struct {
	l    sync.Mutex
	path string
}

func NewPemKey(base string) *PemKey {
	path := filepath.Join(base, pemKeyPath)
	pemKey := &PemKey{
		path: path,
	}
	return pemKey
}

func (k *PemKey) ReadKey() (*ecdsa.PrivateKey, error) {
	k.l.Lock()
	defer k.l.Unlock()

	// Read the file
	buf, err := ioutil.ReadFile(k.path)
	if err != nil {
		return nil, err
	}

	return k.ReadKeyFromBuf(buf)
}

func (k *PemKey) ReadKeyFromBuf(buf []byte) (*ecdsa.PrivateKey, error) {
	if len(buf) == 0 {
		return nil, nil
	}

	block, _ := pem.Decode(buf)
	if block == nil {
		return nil, fmt.Errorf("Error decoding PEM block from data")
	}
	return x509.ParseECPrivateKey(block.Bytes)
}

func (k *PemKey) WriteKey(key *ecdsa.PrivateKey) error {
	k.l.Lock()
	defer k.l.Unlock()

	b, err := x509.MarshalECPrivateKey(key)
	if err != nil {
		return err
	}
	pemBlock := &pem.Block{Type: "EC PRIVATE KEY", Bytes: b}
	data := pem.EncodeToMemory(pemBlock)
	return ioutil.WriteFile(k.path, data, 0755)
}

type PemDump struct {
	PublicKey  string
	PrivateKey string
}

func GeneratePemKey() (*PemDump, error) {
	key, err := GenerateECDSAKey()
	if err != nil {
		return nil, err
	}

	pub := fmt.Sprintf("0x%X", FromECDSAPub(&key.PublicKey))

	b, err := x509.MarshalECPrivateKey(key)
	if err != nil {
		return nil, err
	}
	pemBlock := &pem.Block{Type: "EC PRIVATE KEY", Bytes: b}
	data := pem.EncodeToMemory(pemBlock)

	pemDump := PemDump{
		PublicKey:  pub,
		PrivateKey: string(data),
	}

	return &pemDump, err
}
<|endoftext|>


<commit_before>package sysinfo

import (
	"bufio"

	"os"
	"strconv"
	"strings"

	"github.com/adrg/unit"
)

type Memory struct {
	Total      uint64
	Free       uint64
	Used       uint64
	Cached     uint64
	Active     uint64
	Inactive   uint64
	SwapTotal  uint64
	SwapFree   uint64
	SwapUsed   uint64
	SwapCached uint64
	Buffers    uint64

	Unit unit.Memory
}

func (m *Memory) PercentUsed() float64 {
	return float64(m.Used) / float64(m.Total) * 100.0
}

func (m *Memory) PercentFree() float64 {
	return float64(m.Free) / float64(m.Total) * 100.0
}

func (m *Memory) PercentSwapUsed() float64 {
	return float64(m.SwapUsed) / float64(m.SwapTotal) * 100.0
}

func (m *Memory) PercentSwapFree() float64 {
	return float64(m.SwapFree) / float64(m.SwapTotal) * 100.0
}

func MemoryInfo() (*Memory, error) {
	mem := &Memory{Unit: unit.Kibibyte}

	file, err := os.Open("/proc/meminfo")
	if err != nil {
		return nil, err
	}
	defer file.Close()

	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		fields := strings.Fields(scanner.Text())
		if len(fields) < 2 {
			return nil, ErrInvalidFileFormat
		}

		value, err := strconv.ParseUint(fields[1], 10, 64)
		if err != nil {
			return nil, ErrInvalidFileFormat
		}

		key := strings.ToLower(strings.TrimSuffix(fields[0], ":"))
		switch key {
		case "memtotal":
			mem.Total = value
		case "memfree":
			mem.Free = value
		case "cached":
			mem.Cached = value
		case "swaptotal":
			mem.SwapTotal = value
		case "swapfree":
			mem.SwapFree = value
		case "swapcached":
			mem.SwapCached = value
		case "buffers":
			mem.Buffers = value
		case "active":
			mem.Active = value
		case "inactive":
			mem.Inactive = value
		}
	}

	if err = scanner.Err(); err != nil {
		return nil, err
	}

	mem.Free = mem.Free + mem.Cached + mem.Buffers
	mem.Used = mem.Total - mem.Free
	mem.SwapUsed = mem.SwapTotal - mem.SwapFree

	return mem, nil
}
<commit_msg>Remove unit of measurement from Memory structure<commit_after>package sysinfo

import (
	"bufio"

	"os"
	"strconv"
	"strings"
)

type Memory struct {
	Total      uint64
	Free       uint64
	Used       uint64
	Cached     uint64
	Active     uint64
	Inactive   uint64
	SwapTotal  uint64
	SwapFree   uint64
	SwapUsed   uint64
	SwapCached uint64
	Buffers    uint64
}

func (m *Memory) PercentUsed() float64 {
	return float64(m.Used) / float64(m.Total) * 100.0
}

func (m *Memory) PercentFree() float64 {
	return float64(m.Free) / float64(m.Total) * 100.0
}

func (m *Memory) PercentSwapUsed() float64 {
	return float64(m.SwapUsed) / float64(m.SwapTotal) * 100.0
}

func (m *Memory) PercentSwapFree() float64 {
	return float64(m.SwapFree) / float64(m.SwapTotal) * 100.0
}

func MemoryInfo() (*Memory, error) {
	mem := &Memory{}

	file, err := os.Open("/proc/meminfo")
	if err != nil {
		return nil, err
	}
	defer file.Close()

	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		fields := strings.Fields(scanner.Text())
		if len(fields) < 2 {
			return nil, ErrInvalidFileFormat
		}

		value, err := strconv.ParseUint(fields[1], 10, 64)
		if err != nil {
			return nil, ErrInvalidFileFormat
		}

		key := strings.ToLower(strings.TrimSuffix(fields[0], ":"))
		switch key {
		case "memtotal":
			mem.Total = value
		case "memfree":
			mem.Free = value
		case "cached":
			mem.Cached = value
		case "swaptotal":
			mem.SwapTotal = value
		case "swapfree":
			mem.SwapFree = value
		case "swapcached":
			mem.SwapCached = value
		case "buffers":
			mem.Buffers = value
		case "active":
			mem.Active = value
		case "inactive":
			mem.Inactive = value
		}
	}

	if err = scanner.Err(); err != nil {
		return nil, err
	}

	mem.Free = mem.Free + mem.Cached + mem.Buffers
	mem.Used = mem.Total - mem.Free
	mem.SwapUsed = mem.SwapTotal - mem.SwapFree

	return mem, nil
}
<|endoftext|>


<commit_before>// Copyright (c) 2021 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package yarpcerrors

import (
	"fmt"
	"strconv"
	"strings"
)

const (
	// CodeOK means no error; returned on success
	CodeOK Code = 0

	// CodeCancelled means the operation was cancelled, typically by the caller.
	CodeCancelled Code = 1

	// CodeUnknown means an unknown error. Errors raised by APIs
	// that do not return enough error information
	// may be converted to this error.
	CodeUnknown Code = 2

	// CodeInvalidArgument means the client specified an invalid argument.
	// Note that this differs from `FailedPrecondition`. `InvalidArgument`
	// indicates arguments that are problematic regardless of the state of
	// the system (e.g., a malformed file name).
	CodeInvalidArgument Code = 3

	// CodeDeadlineExceeded means the deadline expired before the operation could
	// complete. For operations that change the state of the system, this error
	// may be returned even if the operation has completed successfully. For example,
	// a successful response from a server could have been delayed long
	// enough for the deadline to expire.
	CodeDeadlineExceeded Code = 4

	// CodeNotFound means some requested entity (e.g., file or directory) was not found.
	// For privacy reasons, this code *may* be returned when the client
	// does not have the access rights to the entity, though such usage is
	// discouraged.
	CodeNotFound Code = 5

	// CodeAlreadyExists means the entity that a client attempted to create
	// (e.g., file or directory) already exists.
	CodeAlreadyExists Code = 6

	// CodePermissionDenied means the caller does not have permission to execute
	// the specified operation. `PermissionDenied` must not be used for rejections
	// caused by exhausting some resource (use `ResourceExhausted`
	// instead for those errors). `PermissionDenied` must not be
	// used if the caller can not be identified (use `Unauthenticated`
	// instead for those errors).
	CodePermissionDenied Code = 7

	// CodeResourceExhausted means some resource has been exhausted, perhaps a per-user
	// quota, or perhaps the entire file system is out of space.
	CodeResourceExhausted Code = 8

	// CodeFailedPrecondition means the operation was rejected because the system is not
	// in a state required for the operation's execution. For example, the directory
	// to be deleted is non-empty, an rmdir operation is applied to
	// a non-directory, etc.
	//
	// Service implementors can use the following guidelines to decide
	// between `FailedPrecondition`, `Aborted`, and `Unavailable`:
	//  (a) Use `Unavailable` if the client can retry just the failing call.
	//  (b) Use `Aborted` if the client should retry at a higher level
	//      (e.g., restarting a read-modify-write sequence).
	//  (c) Use `FailedPrecondition` if the client should not retry until
	//      the system state has been explicitly fixed. E.g., if an "rmdir"
	//      fails because the directory is non-empty, `FailedPrecondition`
	//      should be returned since the client should not retry unless
	//      the files are deleted from the directory.
	CodeFailedPrecondition Code = 9

	// CodeAborted means the operation was aborted, typically due to a concurrency issue
	// such as a sequencer check failure or transaction abort.
	//
	// See the guidelines above for deciding between `FailedPrecondition`,
	// `Aborted`, and `Unavailable`.
	CodeAborted Code = 10

	// CodeOutOfRange means the operation was attempted past the valid range.
	// E.g., seeking or reading past end-of-file.
	//
	// Unlike `InvalidArgument`, this error indicates a problem that may
	// be fixed if the system state changes. For example, a 32-bit file
	// system will generate `InvalidArgument` if asked to read at an
	// offset that is not in the range [0,2^32-1], but it will generate
	// `OutOfRange` if asked to read from an offset past the current
	// file size.
	//
	// There is a fair bit of overlap between `FailedPrecondition` and
	// `OutOfRange`.  We recommend using `OutOfRange` (the more specific
	// error) when it applies so that callers who are iterating through
	// a space can easily look for an `OutOfRange` error to detect when
	// they are done.
	CodeOutOfRange Code = 11

	// CodeUnimplemented means the operation is not implemented or is not
	// supported/enabled in this service.
	CodeUnimplemented Code = 12

	// CodeInternal means an internal error. This means that some invariants expected
	// by the underlying system have been broken. This error code is reserved
	// for serious errors.
	CodeInternal Code = 13

	// CodeUnavailable means the service is currently unavailable. This is most likely a
	// transient condition, which can be corrected by retrying with a backoff.
	//
	// See the guidelines above for deciding between `FailedPrecondition`,
	// `Aborted`, and `Unavailable`.
	CodeUnavailable Code = 14

	// CodeDataLoss means unrecoverable data loss or corruption.
	CodeDataLoss Code = 15

	// CodeUnauthenticated means the request does not have valid authentication
	// credentials for the operation.
	CodeUnauthenticated Code = 16
)

var (
	_codeToString = map[Code]string{
		CodeOK:                 "ok",
		CodeCancelled:          "cancelled",
		CodeUnknown:            "unknown",
		CodeInvalidArgument:    "invalid-argument",
		CodeDeadlineExceeded:   "deadline-exceeded",
		CodeNotFound:           "not-found",
		CodeAlreadyExists:      "already-exists",
		CodePermissionDenied:   "permission-denied",
		CodeResourceExhausted:  "resource-exhausted",
		CodeFailedPrecondition: "failed-precondition",
		CodeAborted:            "aborted",
		CodeOutOfRange:         "out-of-range",
		CodeUnimplemented:      "unimplemented",
		CodeInternal:           "internal",
		CodeUnavailable:        "unavailable",
		CodeDataLoss:           "data-loss",
		CodeUnauthenticated:    "unauthenticated",
	}
	_stringToCode = map[string]Code{
		"ok":                  CodeOK,
		"cancelled":           CodeCancelled,
		"unknown":             CodeUnknown,
		"invalid-argument":    CodeInvalidArgument,
		"deadline-exceeded":   CodeDeadlineExceeded,
		"not-found":           CodeNotFound,
		"already-exists":      CodeAlreadyExists,
		"permission-denied":   CodePermissionDenied,
		"resource-exhausted":  CodeResourceExhausted,
		"failed-precondition": CodeFailedPrecondition,
		"aborted":             CodeAborted,
		"out-of-range":        CodeOutOfRange,
		"unimplemented":       CodeUnimplemented,
		"internal":            CodeInternal,
		"unavailable":         CodeUnavailable,
		"data-loss":           CodeDataLoss,
		"unauthenticated":     CodeUnauthenticated,
	}
)

// Code represents the type of error for an RPC call.
//
// Sometimes multiple error codes may apply. Services should return
// the most specific error code that applies. For example, prefer
// `OutOfRange` over `FailedPrecondition` if both codes apply.
// Similarly prefer `NotFound` or `AlreadyExists` over `FailedPrecondition`.
//
// These codes are meant to match gRPC status codes.
// https://godoc.org/google.golang.org/grpc/codes#Code
type Code int

// String returns the the string representation of the Code.
func (c Code) String() string {
	s, ok := _codeToString[c]
	if ok {
		return s
	}
	return strconv.Itoa(int(c))
}

// MarshalText implements encoding.TextMarshaler.
func (c Code) MarshalText() ([]byte, error) {
	s, ok := _codeToString[c]
	if ok {
		return []byte(s), nil
	}
	return nil, fmt.Errorf("unknown code: %d", int(c))
}

// UnmarshalText implements encoding.TextUnmarshaler.
func (c *Code) UnmarshalText(text []byte) error {
	i, ok := _stringToCode[strings.ToLower(string(text))]
	if !ok {
		return fmt.Errorf("unknown code string: %s", string(text))
	}
	*c = i
	return nil
}

// MarshalJSON implements json.Marshaler.
func (c Code) MarshalJSON() ([]byte, error) {
	s, ok := _codeToString[c]
	if ok {
		return []byte(`"` + s + `"`), nil
	}
	return nil, fmt.Errorf("unknown code: %d", int(c))
}

// UnmarshalJSON implements json.Unmarshaler.
func (c *Code) UnmarshalJSON(text []byte) error {
	s := string(text)
	if len(s) < 3 || s[0] != '"' || s[len(s)-1] != '"' {
		return fmt.Errorf("invalid code string: %s", s)
	}
	i, ok := _stringToCode[strings.ToLower(s[1:len(s)-1])]
	if !ok {
		return fmt.Errorf("unknown code string: %s", s)
	}
	*c = i
	return nil
}
<commit_msg>Doc: added documentation to error to mention if they are considered as client or server error (#2050)<commit_after>// Copyright (c) 2021 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package yarpcerrors

import (
	"fmt"
	"strconv"
	"strings"
)

const (
	// CodeOK means no error; returned on success
	CodeOK Code = 0

	// CodeCancelled means the operation was cancelled, typically by the caller.
	// This is considered as a client error.
	CodeCancelled Code = 1

	// CodeUnknown means an unknown error. Errors raised by APIs
	// that do not return enough error information
	// may be converted to this error.
	// This is considered as a server error.
	CodeUnknown Code = 2

	// CodeInvalidArgument means the client specified an invalid argument.
	// Note that this differs from `FailedPrecondition`. `InvalidArgument`
	// indicates arguments that are problematic regardless of the state of
	// the system (e.g., a malformed file name).
	// This is considered as a client error.
	CodeInvalidArgument Code = 3

	// CodeDeadlineExceeded means the deadline expired before the operation could
	// complete. For operations that change the state of the system, this error
	// may be returned even if the operation has completed successfully. For example,
	// a successful response from a server could have been delayed long
	// enough for the deadline to expire.
	// This is considered as a server error.
	CodeDeadlineExceeded Code = 4

	// CodeNotFound means some requested entity (e.g., file or directory) was not found.
	// For privacy reasons, this code *may* be returned when the client
	// does not have the access rights to the entity, though such usage is
	// discouraged.
	// This is considered as a client error.
	CodeNotFound Code = 5

	// CodeAlreadyExists means the entity that a client attempted to create
	// (e.g., file or directory) already exists.
	// This is considered as a client error.
	CodeAlreadyExists Code = 6

	// CodePermissionDenied means the caller does not have permission to execute
	// the specified operation. `PermissionDenied` must not be used for rejections
	// caused by exhausting some resource (use `ResourceExhausted`
	// instead for those errors). `PermissionDenied` must not be
	// used if the caller can not be identified (use `Unauthenticated`
	// instead for those errors).
	// This is considered as a client error.
	CodePermissionDenied Code = 7

	// CodeResourceExhausted means some resource has been exhausted, perhaps a per-user
	// quota, or perhaps the entire file system is out of space.
	// This is considered as a client error.
	CodeResourceExhausted Code = 8

	// CodeFailedPrecondition means the operation was rejected because the system is not
	// in a state required for the operation's execution. For example, the directory
	// to be deleted is non-empty, an rmdir operation is applied to
	// a non-directory, etc.
	//
	// Service implementors can use the following guidelines to decide
	// between `FailedPrecondition`, `Aborted`, and `Unavailable`:
	//  (a) Use `Unavailable` if the client can retry just the failing call.
	//  (b) Use `Aborted` if the client should retry at a higher level
	//      (e.g., restarting a read-modify-write sequence).
	//  (c) Use `FailedPrecondition` if the client should not retry until
	//      the system state has been explicitly fixed. E.g., if an "rmdir"
	//      fails because the directory is non-empty, `FailedPrecondition`
	//      should be returned since the client should not retry unless
	//      the files are deleted from the directory.
	// This is considered as a client error.
	CodeFailedPrecondition Code = 9

	// CodeAborted means the operation was aborted, typically due to a concurrency issue
	// such as a sequencer check failure or transaction abort.
	//
	// See the guidelines above for deciding between `FailedPrecondition`,
	// `Aborted`, and `Unavailable`.
	// This is considered as a client error.
	CodeAborted Code = 10

	// CodeOutOfRange means the operation was attempted past the valid range.
	// E.g., seeking or reading past end-of-file.
	//
	// Unlike `InvalidArgument`, this error indicates a problem that may
	// be fixed if the system state changes. For example, a 32-bit file
	// system will generate `InvalidArgument` if asked to read at an
	// offset that is not in the range [0,2^32-1], but it will generate
	// `OutOfRange` if asked to read from an offset past the current
	// file size.
	//
	// There is a fair bit of overlap between `FailedPrecondition` and
	// `OutOfRange`.  We recommend using `OutOfRange` (the more specific
	// error) when it applies so that callers who are iterating through
	// a space can easily look for an `OutOfRange` error to detect when
	// they are done.
	// This is considered as a client error.
	CodeOutOfRange Code = 11

	// CodeUnimplemented means the operation is not implemented or is not
	// supported/enabled in this service.
	// This is considered as a client error.
	CodeUnimplemented Code = 12

	// CodeInternal means an internal error. This means that some invariants expected
	// by the underlying system have been broken. This error code is reserved
	// for serious errors.
	// This is considered as a server error.
	CodeInternal Code = 13

	// CodeUnavailable means the service is currently unavailable. This is most likely a
	// transient condition, which can be corrected by retrying with a backoff.
	//
	// See the guidelines above for deciding between `FailedPrecondition`,
	// `Aborted`, and `Unavailable`.
	// This is considered as a server error.
	CodeUnavailable Code = 14

	// CodeDataLoss means unrecoverable data loss or corruption.
	// This is considered as a server error.
	CodeDataLoss Code = 15

	// CodeUnauthenticated means the request does not have valid authentication
	// credentials for the operation.
	// This is considered as a client error.
	CodeUnauthenticated Code = 16
)

var (
	_codeToString = map[Code]string{
		CodeOK:                 "ok",
		CodeCancelled:          "cancelled",
		CodeUnknown:            "unknown",
		CodeInvalidArgument:    "invalid-argument",
		CodeDeadlineExceeded:   "deadline-exceeded",
		CodeNotFound:           "not-found",
		CodeAlreadyExists:      "already-exists",
		CodePermissionDenied:   "permission-denied",
		CodeResourceExhausted:  "resource-exhausted",
		CodeFailedPrecondition: "failed-precondition",
		CodeAborted:            "aborted",
		CodeOutOfRange:         "out-of-range",
		CodeUnimplemented:      "unimplemented",
		CodeInternal:           "internal",
		CodeUnavailable:        "unavailable",
		CodeDataLoss:           "data-loss",
		CodeUnauthenticated:    "unauthenticated",
	}
	_stringToCode = map[string]Code{
		"ok":                  CodeOK,
		"cancelled":           CodeCancelled,
		"unknown":             CodeUnknown,
		"invalid-argument":    CodeInvalidArgument,
		"deadline-exceeded":   CodeDeadlineExceeded,
		"not-found":           CodeNotFound,
		"already-exists":      CodeAlreadyExists,
		"permission-denied":   CodePermissionDenied,
		"resource-exhausted":  CodeResourceExhausted,
		"failed-precondition": CodeFailedPrecondition,
		"aborted":             CodeAborted,
		"out-of-range":        CodeOutOfRange,
		"unimplemented":       CodeUnimplemented,
		"internal":            CodeInternal,
		"unavailable":         CodeUnavailable,
		"data-loss":           CodeDataLoss,
		"unauthenticated":     CodeUnauthenticated,
	}
)

// Code represents the type of error for an RPC call.
//
// Sometimes multiple error codes may apply. Services should return
// the most specific error code that applies. For example, prefer
// `OutOfRange` over `FailedPrecondition` if both codes apply.
// Similarly prefer `NotFound` or `AlreadyExists` over `FailedPrecondition`.
//
// These codes are meant to match gRPC status codes.
// https://godoc.org/google.golang.org/grpc/codes#Code
type Code int

// String returns the the string representation of the Code.
func (c Code) String() string {
	s, ok := _codeToString[c]
	if ok {
		return s
	}
	return strconv.Itoa(int(c))
}

// MarshalText implements encoding.TextMarshaler.
func (c Code) MarshalText() ([]byte, error) {
	s, ok := _codeToString[c]
	if ok {
		return []byte(s), nil
	}
	return nil, fmt.Errorf("unknown code: %d", int(c))
}

// UnmarshalText implements encoding.TextUnmarshaler.
func (c *Code) UnmarshalText(text []byte) error {
	i, ok := _stringToCode[strings.ToLower(string(text))]
	if !ok {
		return fmt.Errorf("unknown code string: %s", string(text))
	}
	*c = i
	return nil
}

// MarshalJSON implements json.Marshaler.
func (c Code) MarshalJSON() ([]byte, error) {
	s, ok := _codeToString[c]
	if ok {
		return []byte(`"` + s + `"`), nil
	}
	return nil, fmt.Errorf("unknown code: %d", int(c))
}

// UnmarshalJSON implements json.Unmarshaler.
func (c *Code) UnmarshalJSON(text []byte) error {
	s := string(text)
	if len(s) < 3 || s[0] != '"' || s[len(s)-1] != '"' {
		return fmt.Errorf("invalid code string: %s", s)
	}
	i, ok := _stringToCode[strings.ToLower(s[1:len(s)-1])]
	if !ok {
		return fmt.Errorf("unknown code string: %s", s)
	}
	*c = i
	return nil
}
<|endoftext|>


<commit_before>package main

// index template
const index = `[[define "index"]]<!doctype html>

[[template "head" . ]]

<ng-include src="'pages/global.html'"></ng-include>

[[template "header" . ]]

[[end]]`

// head items
const head = `[[define "head"]]
<base href="/[[ .base ]]">
<title data-ng-bind="page.title">[[ .title ]]</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content="[[ .desc ]]" />[[if .nsfw -]]
<meta name="rating" content="adult" />
<meta name="rating" content="RTA-5042-1996-1400-1577-RTA" />
[[- end]]
<link rel="stylesheet" href="/assets/prim/[[ .primcss ]]" />
<link rel="stylesheet" href="/assets/styles/[[ .style ]]" />
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css">

[[template "angular" . ]][[template "headinclude" . ]]
[[end]]`

// angular config
const angular = `[[define "angular"]][[end]]`

// site header
const header = `[[define "header"]]

[[template "navmenuinclude" . ]][[template "navmenu" . ]]

<ng-include src="'pages/menus/nav.html'"></ng-include>

Sign in

<ng-include src="'pages/menus/user.html'"></ng-include>

[[end]]`

const navmenu = `[[define "navmenu"]][[ range $ib := .imageboards]]
[[ $ib.Title ]]

[[end]][[end]]`
<commit_msg>move stylesheets above js<commit_after>package main

// index template
const index = `[[define "index"]]<!doctype html>

[[template "head" . ]]

<ng-include src="'pages/global.html'"></ng-include>

[[template "header" . ]]

[[end]]`

// head items
const head = `[[define "head"]]
<base href="/[[ .base ]]">
<title data-ng-bind="page.title">[[ .title ]]</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content="[[ .desc ]]" />[[if .nsfw -]]
<meta name="rating" content="adult" />
<meta name="rating" content="RTA-5042-1996-1400-1577-RTA" />
[[- end]]
<link rel="stylesheet" href="/assets/prim/[[ .primcss ]]" />
<link rel="stylesheet" href="/assets/styles/[[ .style ]]" />
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css">

[[template "angular" . ]][[template "headinclude" . ]]
[[end]]`

// angular config
const angular = `[[define "angular"]][[end]]`

// site header
const header = `[[define "header"]]

[[template "navmenuinclude" . ]][[template "navmenu" . ]]

<ng-include src="'pages/menus/nav.html'"></ng-include>

Sign in

<ng-include src="'pages/menus/user.html'"></ng-include>

[[end]]`

const navmenu = `[[define "navmenu"]][[ range $ib := .imageboards]]
[[ $ib.Title ]]

[[end]][[end]]`
<|endoftext|>


<commit_before>package waveguide

import "html/template"

var tmpl = template.Must(template.New("").Parse(`
{{define "header"}}

                <title>Waveguide</title>

{{end}}

{{define "footer"}}

{{end}}

{{define "root"}}
{{template "header"}}

                	{{if .Spots}}

					Location
					Coordinates
					Conditions
					Wave Height
					Last Updated

					{{range .Spots}}

							{{.HTMLName}}

								{{if .HasCoordinates}}
									❌
									{{.FormattedCoordinates}}
								{{else}}
									<form action="/coords" method="post">
										<input type="hidden" name="path" value="{{.MswPath}}" />
										<input name="coordinates" />
										<button type="submit">Submit</button>
									</form>
								{{end}}

							{{.Cond.Stars}}
							{{.Cond.WaveHeight}}
							{{.Cond.HowLong}} ago

					{{end}}

			{{else}}
				There's no data yet. You can get some by visiting /update_all.
			{{end}}

{{template "footer"}}
{{end}}

{{define "action_response"}}
{{template "header"}}

← home

{{.Message}}

{{template "footer"}}
{{end}}

{{define "map"}}
<!DOCTYPE html>

    <title>Waveguide</title>
    <meta name="viewport" content="initial-scale=1.0">
    <meta charset="utf-8">

{{end}}
`))
<commit_msg>Clean up the map view by removing the labels and stars.<commit_after>package waveguide

import "html/template"

var tmpl = template.Must(template.New("").Parse(`
{{define "header"}}

                <title>Waveguide</title>

{{end}}

{{define "footer"}}

{{end}}

{{define "root"}}
{{template "header"}}

                	{{if .Spots}}

					Location
					Coordinates
					Conditions
					Wave Height
					Last Updated

					{{range .Spots}}

							{{.HTMLName}}

								{{if .HasCoordinates}}
									❌
									{{.FormattedCoordinates}}
								{{else}}
									<form action="/coords" method="post">
										<input type="hidden" name="path" value="{{.MswPath}}" />
										<input name="coordinates" />
										<button type="submit">Submit</button>
									</form>
								{{end}}

							{{.Cond.Stars}}
							{{.Cond.WaveHeight}}
							{{.Cond.HowLong}} ago

					{{end}}

			{{else}}
				There's no data yet. You can get some by visiting /update_all.
			{{end}}

{{template "footer"}}
{{end}}

{{define "action_response"}}
{{template "header"}}

← home

{{.Message}}

{{template "footer"}}
{{end}}

{{define "map"}}
<!DOCTYPE html>

    <title>Waveguide</title>
    <meta name="viewport" content="initial-scale=1.0">
    <meta charset="utf-8">

{{end}}
`))
<|endoftext|>


<commit_before>package main

var templContent = `<!doctype html>

    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="chrome=1">
    <title></title>

{{.Content}}

`<commit_msg>tabify<commit_after>package main

var templContent = `<!doctype html>

		<meta charset="utf-8">
		<meta http-equiv="X-UA-Compatible" content="chrome=1">
		<title></title>

{{.Content}}

`<|endoftext|>


<commit_before><commit_msg>refactor: Simplify condition<commit_after><|endoftext|>


<commit_before>// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0

package krusty_test

import (
	"testing"

	kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
)

func TestValidatingWebhookCombinedNamespaces(t *testing.T) {
  th := kusttest_test.MakeHarness(t)
  th.WriteK("base", `
resources:
- service.yaml
- validatingwebhook.yaml
`)
  th.WriteF("base/service.yaml", `
apiVersion: v1
kind: Service
metadata:
  name: admission
  namespace: base-namespace
spec:
  type: ClusterIP
  ports:
    - name: https-webhook
      port: 443
      targetPort: webhook
`)
    th.WriteF("base/validatingwebhook.yaml", `
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
  name: validatingwebhook
webhooks:
  - name: validate
    matchPolicy: Equivalent
    rules:
      - apiGroups:
          - networking.k8s.io
        apiVersions:
          - v1beta1
        operations:
          - CREATE
          - UPDATE
        resources:
          - ingresses
    failurePolicy: Fail
    sideEffects: None
    admissionReviewVersions:
      - v1
      - v1beta1
    clientConfig:
      service:
        namespace: base-namespace
        name: admission
        path: /networking/v1beta1/ingresses
`)
  th.WriteK("overlay", `
namespace: merge-namespace
resources:
- ../base
patchesStrategicMerge:
- validatingwebhookdelete.yaml
`)
    th.WriteF("overlay/validatingwebhookdelete.yaml", `
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
  name: validatingwebhook
$patch: delete
`)
	th.WriteK("combined", `
resources:
- ../base
- ../overlay
`)
	m := th.Run("combined", th.MakeDefaultOptions())
	th.AssertActualEqualsExpected(m, `
apiVersion: v1
kind: Service
metadata:
  name: admission
  namespace: base-namespace
spec:
  ports:
  - name: https-webhook
    port: 443
    targetPort: webhook
  type: ClusterIP
---
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
  name: validatingwebhook
webhooks:
- admissionReviewVersions:
  - v1
  - v1beta1
  clientConfig:
    service:
      name: admission
      namespace: base-namespace
      path: /networking/v1beta1/ingresses
  failurePolicy: Fail
  matchPolicy: Equivalent
  name: validate
  rules:
  - apiGroups:
    - networking.k8s.io
    apiVersions:
    - v1beta1
    operations:
    - CREATE
    - UPDATE
    resources:
    - ingresses
  sideEffects: None
---
apiVersion: v1
kind: Service
metadata:
  name: admission
  namespace: merge-namespace
spec:
  ports:
  - name: https-webhook
    port: 443
    targetPort: webhook
  type: ClusterIP
`)
}

<commit_msg>added comment referring test to issue 3732<commit_after>// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0

package krusty_test

import (
	"testing"

	kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
)

// Reproduce issue #3732
func TestValidatingWebhookCombinedNamespaces(t *testing.T) {
  th := kusttest_test.MakeHarness(t)
  th.WriteK("base", `
resources:
- service.yaml
- validatingwebhook.yaml
`)
  th.WriteF("base/service.yaml", `
apiVersion: v1
kind: Service
metadata:
  name: admission
  namespace: base-namespace
spec:
  type: ClusterIP
  ports:
    - name: https-webhook
      port: 443
      targetPort: webhook
`)
    th.WriteF("base/validatingwebhook.yaml", `
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
  name: validatingwebhook
webhooks:
  - name: validate
    matchPolicy: Equivalent
    rules:
      - apiGroups:
          - networking.k8s.io
        apiVersions:
          - v1beta1
        operations:
          - CREATE
          - UPDATE
        resources:
          - ingresses
    failurePolicy: Fail
    sideEffects: None
    admissionReviewVersions:
      - v1
      - v1beta1
    clientConfig:
      service:
        namespace: base-namespace
        name: admission
        path: /networking/v1beta1/ingresses
`)
  th.WriteK("overlay", `
namespace: merge-namespace
resources:
- ../base
patchesStrategicMerge:
- validatingwebhookdelete.yaml
`)
    th.WriteF("overlay/validatingwebhookdelete.yaml", `
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
  name: validatingwebhook
$patch: delete
`)
	th.WriteK("combined", `
resources:
- ../base
- ../overlay
`)
	m := th.Run("combined", th.MakeDefaultOptions())
	th.AssertActualEqualsExpected(m, `
apiVersion: v1
kind: Service
metadata:
  name: admission
  namespace: base-namespace
spec:
  ports:
  - name: https-webhook
    port: 443
    targetPort: webhook
  type: ClusterIP
---
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
  name: validatingwebhook
webhooks:
- admissionReviewVersions:
  - v1
  - v1beta1
  clientConfig:
    service:
      name: admission
      namespace: base-namespace
      path: /networking/v1beta1/ingresses
  failurePolicy: Fail
  matchPolicy: Equivalent
  name: validate
  rules:
  - apiGroups:
    - networking.k8s.io
    apiVersions:
    - v1beta1
    operations:
    - CREATE
    - UPDATE
    resources:
    - ingresses
  sideEffects: None
---
apiVersion: v1
kind: Service
metadata:
  name: admission
  namespace: merge-namespace
spec:
  ports:
  - name: https-webhook
    port: 443
    targetPort: webhook
  type: ClusterIP
`)
}

<|endoftext|>


<commit_before>// Code generated by goagen v1.1.0, command line:
// $ goagen
// --design=github.com/tikasan/eventory/design
// --out=$(GOPATH)
// --version=v1.1.0-dirty
//
// API "eventory": Models
//
// The content of this file is auto-generated, DO NOT MODIFY

package models

import (
	"time"

	"github.com/goadesign/goa"
	"github.com/jinzhu/gorm"
	"golang.org/x/net/context"
)

// ユーザーのキープ状態
type UserFollowEvent struct {
	ID             int `gorm:"primary_key"` // primary key
	BatchProcessed bool
	EventID        int // Belongs To Event
	Status         string
	UserID         int        // Belongs To User
	CreatedAt      time.Time  // timestamp
	DeletedAt      *time.Time // nullable timestamp (soft delete)
	UpdatedAt      time.Time  // timestamp
	Event          Event
	User           User
}

// TableName overrides the table name settings in Gorm to force a specific table name
// in the database.
func (m UserFollowEvent) TableName() string {
	return "user_follow_events"

}

// UserFollowEventDB is the implementation of the storage interface for
// UserFollowEvent.
type UserFollowEventDB struct {
	Db *gorm.DB
}

// NewUserFollowEventDB creates a new storage type.
func NewUserFollowEventDB(db *gorm.DB) *UserFollowEventDB {
	return &UserFollowEventDB{Db: db}
}

// DB returns the underlying database.
func (m *UserFollowEventDB) DB() interface{} {
	return m.Db
}

// UserFollowEventStorage represents the storage interface.
type UserFollowEventStorage interface {
	DB() interface{}
	List(ctx context.Context) ([]*UserFollowEvent, error)
	Get(ctx context.Context, id int) (*UserFollowEvent, error)
	Add(ctx context.Context, userfollowevent *UserFollowEvent) error
	Update(ctx context.Context, userfollowevent *UserFollowEvent) error
	Delete(ctx context.Context, id int) error
}

// TableName overrides the table name settings in Gorm to force a specific table name
// in the database.
func (m *UserFollowEventDB) TableName() string {
	return "user_follow_events"

}

// Belongs To Relationships

// UserFollowEventFilterByEvent is a gorm filter for a Belongs To relationship.
func UserFollowEventFilterByEvent(eventID int, originaldb *gorm.DB) func(db *gorm.DB) *gorm.DB {

	if eventID > 0 {

		return func(db *gorm.DB) *gorm.DB {
			return db.Where("event_id = ?", eventID)

		}
	}
	return func(db *gorm.DB) *gorm.DB { return db }
}

// Belongs To Relationships

// UserFollowEventFilterByUser is a gorm filter for a Belongs To relationship.
func UserFollowEventFilterByUser(userID int, originaldb *gorm.DB) func(db *gorm.DB) *gorm.DB {

	if userID > 0 {

		return func(db *gorm.DB) *gorm.DB {
			return db.Where("user_id = ?", userID)

		}
	}
	return func(db *gorm.DB) *gorm.DB { return db }
}

// CRUD Functions

// Get returns a single UserFollowEvent as a Database Model
// This is more for use internally, and probably not what you want in  your controllers

func (m *UserFollowEventDB) Get(ctx context.Context, id int) (*UserFollowEvent, error) {
	defer goa.MeasureSince([]string{"goa", "db", "userFollowEvent", "get"}, time.Now())

	var native UserFollowEvent
	err := m.Db.Table(m.TableName()).Where("id = ?", id).Find(&native).Error
	if err == gorm.ErrRecordNotFound {
		return nil, err
	}

	return &native, err
}

func (m *UserFollowEventDB) GetByUserAndEvent(ctx context.Context, userID int, eventID int) (*UserFollowEvent, error) {
	defer goa.MeasureSince([]string{"goa", "db", "userFollowEvent", "get"}, time.Now())

	var native UserFollowEvent
	err := m.Db.Table(m.TableName()).Where("user_id = ?", userID).Where("event_id = ?", eventID).Find(&native).Error
	if err == gorm.ErrRecordNotFound {
		return nil, err
	}
	return &native, err
}

// List returns an array of UserFollowEvent
func (m *UserFollowEventDB) List(ctx context.Context) ([]*UserFollowEvent, error) {
	defer goa.MeasureSince([]string{"goa", "db", "userFollowEvent", "list"}, time.Now())

	var objs []*UserFollowEvent
	err := m.Db.Table(m.TableName()).Find(&objs).Error
	if err != nil && err != gorm.ErrRecordNotFound {
		return nil, err
	}

	return objs, nil
}

// Add creates a new record.
func (m *UserFollowEventDB) Add(ctx context.Context, model *UserFollowEvent) error {
	defer goa.MeasureSince([]string{"goa", "db", "userFollowEvent", "add"}, time.Now())

	err := m.Db.Create(model).Error
	if err != nil {
		goa.LogError(ctx, "error adding UserFollowEvent", "error", err.Error())
		return err
	}

	return nil
}

// User Follow Genre
func (m *UserFollowEventDB) UserFollowEvent(ctx context.Context, model *UserFollowEvent) error {
	defer goa.MeasureSince([]string{"goa", "db", "userFollowGenre", "follow"}, time.Now())

	// 過去に一度でもフォロー操作をしたことがあるか
	ufe, err := m.GetByUserAndEvent(ctx, model.UserID, model.EventID)
	if err != nil {
		// レコードが存在しないので、フォローレコードを追加する
		err := m.Db.Create(model).Error
		if err != nil {
			goa.LogError(ctx, "error adding UserFollowGenre", "error", err.Error())
			return err
		}
	}
	// 過去に使ったレコードからdeleted_atをnullにして復活させる
	ufe.DeletedAt = nil
	err = m.Db.Model(ufe).Updates(model).Error
	return nil
}

func (m *UserFollowEventDB) UserUnfollowEvent(ctx context.Context, model *UserFollowEvent) error {
	defer goa.MeasureSince([]string{"goa", "db", "userFollowGenre", "unfollow"}, time.Now())

	var obj UserFollowGenre
	err := m.Db.Delete(&obj, m.Db.Where("user_id = ?", model.UserID).Where("genre_id = ?", model.EventID)).Error
	if err != nil {
		goa.LogError(ctx, "error deleting UserFollowGenre", "error", err.Error())
		return err
	}

	return nil
}

// Update modifies a single record.
func (m *UserFollowEventDB) Update(ctx context.Context, model *UserFollowEvent) error {
	defer goa.MeasureSince([]string{"goa", "db", "userFollowEvent", "update"}, time.Now())

	obj, err := m.Get(ctx, model.UserID)
	if err != nil {
		goa.LogError(ctx, "error updating UserFollowEvent", "error", err.Error())
		return err
	}
	err = m.Db.Model(obj).Updates(model).Error

	return err
}

// Upsert modifies a single record.
func (m *UserFollowEventDB) Upsert(ctx context.Context, model *UserFollowEvent) error {
	defer goa.MeasureSince([]string{"goa", "db", "userFollowEvent", "update"}, time.Now())

	err := m.Db.Create(model).Error
	if err != nil {
		obj, err := m.GetByUserAndEvent(ctx, model.UserID, model.EventID)
		if err != nil {
			goa.LogError(ctx, "error upsert UserFollowEvent", "error", err.Error())
			return err
		}
		err = m.Db.Model(obj).Updates(model).Error
	}
	return err
}

// Delete removes a single record.
func (m *UserFollowEventDB) Delete(ctx context.Context, id int) error {
	defer goa.MeasureSince([]string{"goa", "db", "userFollowEvent", "delete"}, time.Now())

	var obj UserFollowEvent

	err := m.Db.Delete(&obj, id).Error

	if err != nil {
		goa.LogError(ctx, "error deleting UserFollowEvent", "error", err.Error())
		return err
	}

	return nil
}

func (m *UserFollowEventDB) FixUserFollow(ctx context.Context) error {
	defer goa.MeasureSince([]string{"goa", "db", "userFollowEvent", "delete"}, time.Now())

	oneAgo := time.Now()
	oneAgo = oneAgo.AddDate(0, 0, -1)
	model := UserFollowEvent{}
	model.BatchProcessed = true
	err := m.Db.Table(m.TableName()).Updates(model).Where("created_at > ?", oneAgo).Error
	if err != nil {
		goa.LogError(ctx, "error updating UserFollowEvent", "error", err.Error())
		return err
	}
	return nil
}
<commit_msg>whereが効くように書き直した<commit_after>// Code generated by goagen v1.1.0, command line:
// $ goagen
// --design=github.com/tikasan/eventory/design
// --out=$(GOPATH)
// --version=v1.1.0-dirty
//
// API "eventory": Models
//
// The content of this file is auto-generated, DO NOT MODIFY

package models

import (
	"time"

	"github.com/goadesign/goa"
	"github.com/jinzhu/gorm"
	"golang.org/x/net/context"
)

// ユーザーのキープ状態
type UserFollowEvent struct {
	ID             int `gorm:"primary_key"` // primary key
	BatchProcessed bool
	EventID        int // Belongs To Event
	Status         string
	UserID         int        // Belongs To User
	CreatedAt      time.Time  // timestamp
	DeletedAt      *time.Time // nullable timestamp (soft delete)
	UpdatedAt      time.Time  // timestamp
	Event          Event
	User           User
}

// TableName overrides the table name settings in Gorm to force a specific table name
// in the database.
func (m UserFollowEvent) TableName() string {
	return "user_follow_events"

}

// UserFollowEventDB is the implementation of the storage interface for
// UserFollowEvent.
type UserFollowEventDB struct {
	Db *gorm.DB
}

// NewUserFollowEventDB creates a new storage type.
func NewUserFollowEventDB(db *gorm.DB) *UserFollowEventDB {
	return &UserFollowEventDB{Db: db}
}

// DB returns the underlying database.
func (m *UserFollowEventDB) DB() interface{} {
	return m.Db
}

// UserFollowEventStorage represents the storage interface.
type UserFollowEventStorage interface {
	DB() interface{}
	List(ctx context.Context) ([]*UserFollowEvent, error)
	Get(ctx context.Context, id int) (*UserFollowEvent, error)
	Add(ctx context.Context, userfollowevent *UserFollowEvent) error
	Update(ctx context.Context, userfollowevent *UserFollowEvent) error
	Delete(ctx context.Context, id int) error
}

// TableName overrides the table name settings in Gorm to force a specific table name
// in the database.
func (m *UserFollowEventDB) TableName() string {
	return "user_follow_events"

}

// Belongs To Relationships

// UserFollowEventFilterByEvent is a gorm filter for a Belongs To relationship.
func UserFollowEventFilterByEvent(eventID int, originaldb *gorm.DB) func(db *gorm.DB) *gorm.DB {

	if eventID > 0 {

		return func(db *gorm.DB) *gorm.DB {
			return db.Where("event_id = ?", eventID)

		}
	}
	return func(db *gorm.DB) *gorm.DB { return db }
}

// Belongs To Relationships

// UserFollowEventFilterByUser is a gorm filter for a Belongs To relationship.
func UserFollowEventFilterByUser(userID int, originaldb *gorm.DB) func(db *gorm.DB) *gorm.DB {

	if userID > 0 {

		return func(db *gorm.DB) *gorm.DB {
			return db.Where("user_id = ?", userID)

		}
	}
	return func(db *gorm.DB) *gorm.DB { return db }
}

// CRUD Functions

// Get returns a single UserFollowEvent as a Database Model
// This is more for use internally, and probably not what you want in  your controllers

func (m *UserFollowEventDB) Get(ctx context.Context, id int) (*UserFollowEvent, error) {
	defer goa.MeasureSince([]string{"goa", "db", "userFollowEvent", "get"}, time.Now())

	var native UserFollowEvent
	err := m.Db.Table(m.TableName()).Where("id = ?", id).Find(&native).Error
	if err == gorm.ErrRecordNotFound {
		return nil, err
	}

	return &native, err
}

func (m *UserFollowEventDB) GetByUserAndEvent(ctx context.Context, userID int, eventID int) (*UserFollowEvent, error) {
	defer goa.MeasureSince([]string{"goa", "db", "userFollowEvent", "get"}, time.Now())

	var native UserFollowEvent
	err := m.Db.Table(m.TableName()).Where("user_id = ?", userID).Where("event_id = ?", eventID).Find(&native).Error
	if err == gorm.ErrRecordNotFound {
		return nil, err
	}
	return &native, err
}

// List returns an array of UserFollowEvent
func (m *UserFollowEventDB) List(ctx context.Context) ([]*UserFollowEvent, error) {
	defer goa.MeasureSince([]string{"goa", "db", "userFollowEvent", "list"}, time.Now())

	var objs []*UserFollowEvent
	err := m.Db.Table(m.TableName()).Find(&objs).Error
	if err != nil && err != gorm.ErrRecordNotFound {
		return nil, err
	}

	return objs, nil
}

// Add creates a new record.
func (m *UserFollowEventDB) Add(ctx context.Context, model *UserFollowEvent) error {
	defer goa.MeasureSince([]string{"goa", "db", "userFollowEvent", "add"}, time.Now())

	err := m.Db.Create(model).Error
	if err != nil {
		goa.LogError(ctx, "error adding UserFollowEvent", "error", err.Error())
		return err
	}

	return nil
}

// User Follow Genre
func (m *UserFollowEventDB) UserFollowEvent(ctx context.Context, model *UserFollowEvent) error {
	defer goa.MeasureSince([]string{"goa", "db", "userFollowGenre", "follow"}, time.Now())

	// 過去に一度でもフォロー操作をしたことがあるか
	ufe, err := m.GetByUserAndEvent(ctx, model.UserID, model.EventID)
	if err != nil {
		// レコードが存在しないので、フォローレコードを追加する
		err := m.Db.Create(model).Error
		if err != nil {
			goa.LogError(ctx, "error adding UserFollowGenre", "error", err.Error())
			return err
		}
	}
	// 過去に使ったレコードからdeleted_atをnullにして復活させる
	ufe.DeletedAt = nil
	err = m.Db.Model(ufe).Updates(model).Error
	return nil
}

func (m *UserFollowEventDB) UserUnfollowEvent(ctx context.Context, model *UserFollowEvent) error {
	defer goa.MeasureSince([]string{"goa", "db", "userFollowGenre", "unfollow"}, time.Now())

	var obj UserFollowGenre
	err := m.Db.Delete(&obj, m.Db.Where("user_id = ?", model.UserID).Where("genre_id = ?", model.EventID)).Error
	if err != nil {
		goa.LogError(ctx, "error deleting UserFollowGenre", "error", err.Error())
		return err
	}

	return nil
}

// Update modifies a single record.
func (m *UserFollowEventDB) Update(ctx context.Context, model *UserFollowEvent) error {
	defer goa.MeasureSince([]string{"goa", "db", "userFollowEvent", "update"}, time.Now())

	obj, err := m.Get(ctx, model.UserID)
	if err != nil {
		goa.LogError(ctx, "error updating UserFollowEvent", "error", err.Error())
		return err
	}
	err = m.Db.Model(obj).Updates(model).Error

	return err
}

// Upsert modifies a single record.
func (m *UserFollowEventDB) Upsert(ctx context.Context, model *UserFollowEvent) error {
	defer goa.MeasureSince([]string{"goa", "db", "userFollowEvent", "update"}, time.Now())

	err := m.Db.Create(model).Error
	if err != nil {
		obj, err := m.GetByUserAndEvent(ctx, model.UserID, model.EventID)
		if err != nil {
			goa.LogError(ctx, "error upsert UserFollowEvent", "error", err.Error())
			return err
		}
		err = m.Db.Model(obj).Updates(model).Error
	}
	return err
}

// Delete removes a single record.
func (m *UserFollowEventDB) Delete(ctx context.Context, id int) error {
	defer goa.MeasureSince([]string{"goa", "db", "userFollowEvent", "delete"}, time.Now())

	var obj UserFollowEvent

	err := m.Db.Delete(&obj, id).Error

	if err != nil {
		goa.LogError(ctx, "error deleting UserFollowEvent", "error", err.Error())
		return err
	}

	return nil
}

func (m *UserFollowEventDB) FixUserFollow(ctx context.Context) error {
	defer goa.MeasureSince([]string{"goa", "db", "userFollowEvent", "delete"}, time.Now())

	oneAgo := time.Now()
	oneAgo = oneAgo.AddDate(0, 0, -1)
	model := UserFollowEvent{}
	model.BatchProcessed = true
	err := m.Db.Table(m.TableName()).Where("updated_at < ?", oneAgo.Format("2006-01-02 15:04:05")).Updates(model).Error
	if err != nil {
		goa.LogError(ctx, "error updating UserFollowEvent", "error", err.Error())
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package base

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

func TestEncodeMD5(t *testing.T) {
	if checksum := EncodeMD5("foobar"); checksum != "3858f62230ac3c915f300c664312c63f" {
		t.Errorf("got the wrong md5sum for string foobar: %s", checksum)
	}

}

func TestEncodeSha1(t *testing.T) {
	if checksum := EncodeSha1("foobar"); checksum != "8843d7f92416211de9ebb963ff4ce28125932878" {
		t.Errorf("got the wrong sha1sum for string foobar: %s", checksum)
	}
}

func TestShortSha(t *testing.T) {
	if result := ShortSha("veryverylong"); result != "veryverylo" {
		t.Errorf("got the wrong sha1sum for string foobar: %s", result)
	}
}

// TODO: Test DetectEncoding()

func TestBasicAuthDecode(t *testing.T) {
	if _, _, err := BasicAuthDecode("?"); err.Error() != "illegal base64 data at input byte 0" {
		t.Errorf("BasicAuthDecode should fail due to illeagl data: %v", err)
	}

	user, pass, err := BasicAuthDecode("Zm9vOmJhcg==")
	if err != nil {
		t.Errorf("err should be nil but is: %v", err)
	}
	if user != "foo" {
		t.Errorf("user should be foo but is: %s", user)
	}
	if pass != "bar" {
		t.Errorf("pass should be foo but is: %s", pass)
	}
}

func TestBasicAuthEncode(t *testing.T) {
	if auth := BasicAuthEncode("foo", "bar"); auth != "Zm9vOmJhcg==" {
		t.Errorf("auth should be Zm9vOmJhcg== but is: %s", auth)
	}
}

func TestGetRandomString(t *testing.T) {
	if len(GetRandomString(4)) != 4 {
		t.Error("expected GetRandomString to be of len 4")
	}
}

// TODO: Test PBKDF2()
// TODO: Test VerifyTimeLimitCode()
// TODO: Test CreateTimeLimitCode()

func TestHashEmail(t *testing.T) {
	if hash := HashEmail("lunny@gitea.io"); hash != "1b6d0c0e124d47ded12cd7115addeb11" {
		t.Errorf("unexpected email hash: %s", hash)
	}
}

// TODO: AvatarLink()
// TODO: computeTimeDiff()
// TODO: TimeSincePro()
// TODO: timeSince()
// TODO: RawTimeSince()
// TODO: TimeSince()
// TODO: logn()
// TODO: humanateBytes()

func TestFileSize(t *testing.T) {
	var size int64
	size = 512
	assert.Equal(t, "512B", FileSize(size))
	size = size * 1024
	assert.Equal(t, "512KB", FileSize(size))
	size = size * 1024
	assert.Equal(t, "512MB", FileSize(size))
	size = size * 1024
	assert.Equal(t, "512GB", FileSize(size))
	size = size * 1024
	assert.Equal(t, "512TB", FileSize(size))
	size = size * 1024
	assert.Equal(t, "512PB", FileSize(size))
	//size = size * 1024 TODO: Fix bug for EB
	//assert.Equal(t, "512EB", FileSize(size))
}

// TODO: Subtract()
// TODO: EllipsisString()
// TODO: TruncateString()
// TODO: StringsToInt64s()
// TODO: Int64sToStrings()
// TODO: Int64sToMap()
// TODO: IsLetter()
// TODO: IsTextFile()
// TODO: IsImageFile()
// TODO: IsPDFFile()
<commit_msg>Use testify/assert for all tests in tool_test.go<commit_after>package base

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

func TestEncodeMD5(t *testing.T) {
	assert.Equal(t, "3858f62230ac3c915f300c664312c63f", EncodeMD5("foobar"))
}

func TestEncodeSha1(t *testing.T) {
	assert.Equal(t, "8843d7f92416211de9ebb963ff4ce28125932878", EncodeSha1("foobar"))
}

func TestShortSha(t *testing.T) {
	assert.Equal(t, "veryverylo", ShortSha("veryverylong"))
}

// TODO: Test DetectEncoding()

func TestBasicAuthDecode(t *testing.T) {
	_, _, err := BasicAuthDecode("?")
	assert.Equal(t, "illegal base64 data at input byte 0", err.Error())

	user, pass, err := BasicAuthDecode("Zm9vOmJhcg==")
	assert.NoError(t, err)
	assert.Equal(t, "foo", user)
	assert.Equal(t, "bar", pass)
}

func TestBasicAuthEncode(t *testing.T) {
	assert.Equal(t, "Zm9vOmJhcg==", BasicAuthEncode("foo", "bar"))
}

func TestGetRandomString(t *testing.T) {
	assert.Len(t, GetRandomString(4), 4)
}

// TODO: Test PBKDF2()
// TODO: Test VerifyTimeLimitCode()
// TODO: Test CreateTimeLimitCode()

func TestHashEmail(t *testing.T) {
	assert.Equal(t, "d41d8cd98f00b204e9800998ecf8427e", HashEmail(""))
	assert.Equal(t, "353cbad9b58e69c96154ad99f92bedc7", HashEmail("gitea@example.com"))
}

// TODO: AvatarLink()
// TODO: computeTimeDiff()
// TODO: TimeSincePro()
// TODO: timeSince()
// TODO: RawTimeSince()
// TODO: TimeSince()
// TODO: logn()
// TODO: humanateBytes()

func TestFileSize(t *testing.T) {
	var size int64
	size = 512
	assert.Equal(t, "512B", FileSize(size))
	size = size * 1024
	assert.Equal(t, "512KB", FileSize(size))
	size = size * 1024
	assert.Equal(t, "512MB", FileSize(size))
	size = size * 1024
	assert.Equal(t, "512GB", FileSize(size))
	size = size * 1024
	assert.Equal(t, "512TB", FileSize(size))
	size = size * 1024
	assert.Equal(t, "512PB", FileSize(size))
	//size = size * 1024 TODO: Fix bug for EB
	//assert.Equal(t, "512EB", FileSize(size))
}

// TODO: Subtract()
// TODO: EllipsisString()
// TODO: TruncateString()
// TODO: StringsToInt64s()
// TODO: Int64sToStrings()
// TODO: Int64sToMap()
// TODO: IsLetter()
// TODO: IsTextFile()
// TODO: IsImageFile()
// TODO: IsPDFFile()
<|endoftext|>


<commit_before>package mc

import (
	"io/ioutil"
	"os"
	"path/filepath"

	"github.com/materials-commons/config"
	"github.com/materials-commons/mcstore/pkg/app"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("SqlProjectDBOpener", func() {
	Context("Open/Create Tests", func() {
		var (
			projectDBSpec ProjectDBSpec
			projectOpener sqlProjectDBOpener = sqlProjectDBOpener{
				configer: configConfiger{},
			}
		)
		BeforeEach(func() {
			config.Set("mcconfigdir", ".materialscommons")
			os.Mkdir(".materialscommons", 0777)
			projectDBSpec = ProjectDBSpec{
				Path:      "/tmp",
				Name:      "proj1",
				ProjectID: "proj1id",
			}
		})

		AfterEach(func() {
			os.RemoveAll(".materialscommons")
		})

		Describe("CreateProjectDB method tests", func() {
			It("Should return an error if the path doesn't exist", func() {
				os.RemoveAll(".materialscommons")
				pdb, err := projectOpener.CreateProjectDB(projectDBSpec)
				Expect(err).To(Equal(app.ErrNotFound))
				Expect(pdb).To(BeNil())
			})

			It("Should return an error if the project already exists", func() {
				ioutil.WriteFile(filepath.Join(".materialscommons", "proj1.db"), []byte("hello"), 0777)
				pdb, err := projectOpener.CreateProjectDB(projectDBSpec)
				Expect(err).To(Equal(app.ErrExists))
				Expect(pdb).To(BeNil())
			})

			It("Should create the project when it doesn't exist", func() {
				pdb, err := projectOpener.CreateProjectDB(projectDBSpec)
				Expect(err).To(BeNil())
				Expect(pdb).NotTo(BeNil())

				// Test the projects contents
				sqlpdb := pdb.(*sqlProjectDB)
				db := sqlpdb.db
				var projects []Project
				err = db.Select(&projects, "select * from project")
				Expect(err).To(BeNil())
				Expect(projects).To(HaveLen(1))
				proj := projects[0]
				Expect(proj.ProjectID).To(Equal("proj1id"))
				Expect(proj.Name).To(Equal("proj1"))
				Expect(proj.Path).To(Equal("/tmp"))
			})
		})

		Describe("OpenProjectDB method tests", func() {
			It("Should return an error when the project doesn't exist", func() {
				pdb, err := projectOpener.OpenProjectDB("does-not-exist")
				Expect(err).To(Equal(app.ErrNotFound))
				Expect(pdb).To(BeNil())
			})

			It("Should open an existing project", func() {
				// Create the project
				pdb, err := projectOpener.CreateProjectDB(projectDBSpec)
				Expect(err).To(BeNil())
				Expect(pdb).NotTo(BeNil())

				// Open the project and test its contents
				pdb, err = projectOpener.OpenProjectDB("proj1")
				Expect(err).To(BeNil())
				Expect(pdb).NotTo(BeNil())
				sqlpdb := pdb.(*sqlProjectDB)
				db := sqlpdb.db
				var projects []Project
				err = db.Select(&projects, "select * from project")
				Expect(err).To(BeNil())
				Expect(projects).To(HaveLen(1))
				proj := projects[0]
				Expect(proj.ProjectID).To(Equal("proj1id"))
				Expect(proj.Name).To(Equal("proj1"))
			})
		})
	})

	Describe("PathToName method tests", func() {
		var (
			projectOpener sqlProjectDBOpener = sqlProjectDBOpener{
				configer: configConfiger{},
			}
		)

		It("Should return last element of path that has .db extension without .db", func() {
			path := "/tmp/this.db"
			name := projectOpener.PathToName(path)
			Expect(name).To(Equal("this"))
		})

		It("Should return return last element of path for a name that has multiple dots without .db extension", func() {
			path := "/tmp/this.is.name.db"
			name := projectOpener.PathToName(path)
			Expect(name).To(Equal("this.is.name"))
		})
	})
})
<commit_msg>Formatting change add line between variable declarations and BeforeEach()<commit_after>package mc

import (
	"io/ioutil"
	"os"
	"path/filepath"

	"github.com/materials-commons/config"
	"github.com/materials-commons/mcstore/pkg/app"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("SqlProjectDBOpener", func() {
	Context("Open/Create Tests", func() {
		var (
			projectDBSpec ProjectDBSpec
			projectOpener sqlProjectDBOpener = sqlProjectDBOpener{
				configer: configConfiger{},
			}
		)

		BeforeEach(func() {
			config.Set("mcconfigdir", ".materialscommons")
			os.Mkdir(".materialscommons", 0777)
			projectDBSpec = ProjectDBSpec{
				Path:      "/tmp",
				Name:      "proj1",
				ProjectID: "proj1id",
			}
		})

		AfterEach(func() {
			os.RemoveAll(".materialscommons")
		})

		Describe("CreateProjectDB method tests", func() {
			It("Should return an error if the path doesn't exist", func() {
				os.RemoveAll(".materialscommons")
				pdb, err := projectOpener.CreateProjectDB(projectDBSpec)
				Expect(err).To(Equal(app.ErrNotFound))
				Expect(pdb).To(BeNil())
			})

			It("Should return an error if the project already exists", func() {
				ioutil.WriteFile(filepath.Join(".materialscommons", "proj1.db"), []byte("hello"), 0777)
				pdb, err := projectOpener.CreateProjectDB(projectDBSpec)
				Expect(err).To(Equal(app.ErrExists))
				Expect(pdb).To(BeNil())
			})

			It("Should create the project when it doesn't exist", func() {
				pdb, err := projectOpener.CreateProjectDB(projectDBSpec)
				Expect(err).To(BeNil())
				Expect(pdb).NotTo(BeNil())

				// Test the projects contents
				sqlpdb := pdb.(*sqlProjectDB)
				db := sqlpdb.db
				var projects []Project
				err = db.Select(&projects, "select * from project")
				Expect(err).To(BeNil())
				Expect(projects).To(HaveLen(1))
				proj := projects[0]
				Expect(proj.ProjectID).To(Equal("proj1id"))
				Expect(proj.Name).To(Equal("proj1"))
				Expect(proj.Path).To(Equal("/tmp"))
			})
		})

		Describe("OpenProjectDB method tests", func() {
			It("Should return an error when the project doesn't exist", func() {
				pdb, err := projectOpener.OpenProjectDB("does-not-exist")
				Expect(err).To(Equal(app.ErrNotFound))
				Expect(pdb).To(BeNil())
			})

			It("Should open an existing project", func() {
				// Create the project
				pdb, err := projectOpener.CreateProjectDB(projectDBSpec)
				Expect(err).To(BeNil())
				Expect(pdb).NotTo(BeNil())

				// Open the project and test its contents
				pdb, err = projectOpener.OpenProjectDB("proj1")
				Expect(err).To(BeNil())
				Expect(pdb).NotTo(BeNil())
				sqlpdb := pdb.(*sqlProjectDB)
				db := sqlpdb.db
				var projects []Project
				err = db.Select(&projects, "select * from project")
				Expect(err).To(BeNil())
				Expect(projects).To(HaveLen(1))
				proj := projects[0]
				Expect(proj.ProjectID).To(Equal("proj1id"))
				Expect(proj.Name).To(Equal("proj1"))
			})
		})
	})

	Describe("PathToName method tests", func() {
		var (
			projectOpener sqlProjectDBOpener = sqlProjectDBOpener{
				configer: configConfiger{},
			}
		)

		It("Should return last element of path that has .db extension without .db", func() {
			path := "/tmp/this.db"
			name := projectOpener.PathToName(path)
			Expect(name).To(Equal("this"))
		})

		It("Should return return last element of path for a name that has multiple dots without .db extension", func() {
			path := "/tmp/this.is.name.db"
			name := projectOpener.PathToName(path)
			Expect(name).To(Equal("this.is.name"))
		})
	})
})
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"errors"
	"flag"
	"fmt"
	"github.com/kless/term"
	"io/ioutil"
	"log"
	"os"
	"path"
	"strings"
	"syscall"
)

var argNum = 0

var ignorePackageName = flag.Bool("a", false, "always use all instances; ignore detected package name")
var args []string

func main() {
	log.SetFlags(0)

	flag.Parse()
	args = flag.Args()

	var cluster string

	envCluster := getNextArg("environment not given")
	envClusterSplit := strings.Split(envCluster, "/")
	env := envClusterSplit[0]
	if len(envClusterSplit) > 1 {
		cluster = envClusterSplit[1]
	}

	cmd := getNextArg("command not given")

	projectName, err := detectProjectName()
	if err != nil {
		log.Fatalln(err)
	}

	var packageName string
	if !*ignorePackageName {
		packageName, err = detectPackageName()
		if err != nil {
			log.Fatalln(err)
		}
	}

	awsConf, err := getAWSConf(projectName)
	if err != nil {
		log.Fatalln(err)
	}
	job, err := NewJob(awsConf, env, cluster, projectName, packageName,
		os.Stdout, term.IsTerminal(syscall.Stdout))
	if err != nil {
		log.Fatalln(err)
	}

	switch cmd {
	case "deploy":
		version := getNextArg("version not given")
		err = job.Deploy(version)
	case "exec":
		cmd := getRemainingArgsAsString("command not given")
		errs := job.Exec(cmd)
		if len(errs) > 0 {
			errStrings := make([]string, len(errs))
			for i, err := range errs {
				errStrings[i] = err.Error()
			}
			log.Fatalf(strings.Join(errStrings, "\n"))
		}
	case "ssh":
		hostName := getNextArg("")
		sshArgs := getRemainingArgsAsSlice("")
		err = job.Ssh(hostName, sshArgs)
	case "scp":
		if len(args) <= argNum {
			log.Fatalln("you must give at least one source file")
		}
		err = job.Scp(args[argNum:])
	case "ls":
		err = job.List()
	case "hostname":
		instanceName := getNextArg("instance name not given")
		err = job.Hostname(instanceName)
	default:
		log.Fatalf("command not recognised: %s\n", cmd)
	}

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

func fatalUsageError(errMsg string) {
	fmt.Fprintln(os.Stderr, "fatal: "+errMsg+"\n")
	usage()
	os.Exit(1)
}

func getNextArg(errMsg string) (val string) {
	if len(args) >= (argNum + 1) {
		val = args[argNum]
		argNum += 1
	} else if errMsg != "" {
		fatalUsageError(errMsg)
	}
	return
}

func getRemainingArgsAsString(errMsg string) (val string) {
	remainingArgs := args[argNum:]
	if len(remainingArgs) >= 1 {
		val = strings.Join(remainingArgs, " ")
	} else {
		log.Fatalln(errMsg)
	}
	return
}

func getRemainingArgsAsSlice(errMsg string) (val []string) {
	val = args[argNum:]
	if errMsg != "" && len(val) == 0 {
		log.Fatalln(errMsg)
	}
	return
}

func findDotfileAndRead(fn string, errName string) (value string, err error) {
	dir, err := os.Getwd()
	if err != nil {
		return
	}

	var newDir string
	for {
		if fBytes, err := ioutil.ReadFile(path.Join(dir, fn)); err == nil && len(fBytes) > 0 {
			return strings.TrimSpace(string(fBytes)), nil
		}

		newDir = path.Dir(dir)
		if dir == newDir {
			break
		}
		dir = newDir
	}

	return "", errors.New(
		fmt.Sprintf("%s not found. Please ensure your project is configured properly.", errName))
}

func detectProjectName() (projectName string, err error) {
	return findDotfileAndRead(".mxm-project", "Project name")
}

func detectPackageName() (packageName string, err error) {
	packageName, _ = findDotfileAndRead(".mxm-package", "Package name")
	return
}

func formatTable(fields [][]string) (out string) {
	if len(fields) == 0 {
		return
	}
	outBuf := new(bytes.Buffer)
	numFields := len(fields[0])
	maxIndex := numFields - 1
	maxWidths := make([]int, numFields)
	for _, f := range fields {
		for i, c := range f {
			if lenc := len(c); lenc > maxWidths[i] {
				maxWidths[i] = lenc
			}
		}
	}

	for _, f := range fields {
		for i := 0; i < numFields; i++ {
			c := f[i]
			outBuf.WriteString(c)
			if i < maxIndex {
				outBuf.Write(
					bytes.Repeat([]byte(" "), maxWidths[i] - len(c) + 2))
			}
		}
		outBuf.WriteRune('\n')
	}

	out = outBuf.String()

	return
}
<commit_msg>Don't filter by package by default<commit_after>package main

import (
	"bytes"
	"errors"
	"flag"
	"fmt"
	"github.com/kless/term"
	"io/ioutil"
	"log"
	"os"
	"path"
	"strings"
	"syscall"
)

var argNum = 0

var filterPackageName = flag.Bool("p", false, "filter by package name; detect it by default")
var packageName = flag.String("package", "", "package name to filter by")
var args []string

func main() {
	log.SetFlags(0)

	flag.Parse()
	args = flag.Args()

	var cluster string

	envCluster := getNextArg("environment not given")
	envClusterSplit := strings.Split(envCluster, "/")
	env := envClusterSplit[0]
	if len(envClusterSplit) > 1 {
		cluster = envClusterSplit[1]
	}

	cmd := getNextArg("command not given")

	projectName, err := detectProjectName()
	if err != nil {
		log.Fatalln(err)
	}

	if *filterPackageName && *packageName == "" {
		*packageName, err = detectPackageName()
		if err != nil {
			log.Fatalln(err)
		}
	}

	awsConf, err := getAWSConf(projectName)
	if err != nil {
		log.Fatalln(err)
	}
	job, err := NewJob(awsConf, env, cluster, projectName, *packageName,
		os.Stdout, term.IsTerminal(syscall.Stdout))
	if err != nil {
		log.Fatalln(err)
	}

	switch cmd {
	case "deploy":
		version := getNextArg("version not given")
		err = job.Deploy(version)
	case "exec":
		cmd := getRemainingArgsAsString("command not given")
		errs := job.Exec(cmd)
		if len(errs) > 0 {
			errStrings := make([]string, len(errs))
			for i, err := range errs {
				errStrings[i] = err.Error()
			}
			log.Fatalf(strings.Join(errStrings, "\n"))
		}
	case "ssh":
		hostName := getNextArg("")
		sshArgs := getRemainingArgsAsSlice("")
		err = job.Ssh(hostName, sshArgs)
	case "scp":
		if len(args) <= argNum {
			log.Fatalln("you must give at least one source file")
		}
		err = job.Scp(args[argNum:])
	case "ls":
		err = job.List()
	case "hostname":
		instanceName := getNextArg("instance name not given")
		err = job.Hostname(instanceName)
	default:
		log.Fatalf("command not recognised: %s\n", cmd)
	}

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

func fatalUsageError(errMsg string) {
	fmt.Fprintln(os.Stderr, "fatal: "+errMsg+"\n")
	usage()
	os.Exit(1)
}

func getNextArg(errMsg string) (val string) {
	if len(args) >= (argNum + 1) {
		val = args[argNum]
		argNum += 1
	} else if errMsg != "" {
		fatalUsageError(errMsg)
	}
	return
}

func getRemainingArgsAsString(errMsg string) (val string) {
	remainingArgs := args[argNum:]
	if len(remainingArgs) >= 1 {
		val = strings.Join(remainingArgs, " ")
	} else {
		log.Fatalln(errMsg)
	}
	return
}

func getRemainingArgsAsSlice(errMsg string) (val []string) {
	val = args[argNum:]
	if errMsg != "" && len(val) == 0 {
		log.Fatalln(errMsg)
	}
	return
}

func findDotfileAndRead(fn string, errName string) (value string, err error) {
	dir, err := os.Getwd()
	if err != nil {
		return
	}

	var newDir string
	for {
		if fBytes, err := ioutil.ReadFile(path.Join(dir, fn)); err == nil && len(fBytes) > 0 {
			return strings.TrimSpace(string(fBytes)), nil
		}

		newDir = path.Dir(dir)
		if dir == newDir {
			break
		}
		dir = newDir
	}

	return "", errors.New(
		fmt.Sprintf("%s not found. Please ensure your project is configured properly.", errName))
}

func detectProjectName() (projectName string, err error) {
	return findDotfileAndRead(".mxm-project", "Project name")
}

func detectPackageName() (packageName string, err error) {
	return findDotfileAndRead(".mxm-package", "Package name")
}

func formatTable(fields [][]string) (out string) {
	if len(fields) == 0 {
		return
	}
	outBuf := new(bytes.Buffer)
	numFields := len(fields[0])
	maxIndex := numFields - 1
	maxWidths := make([]int, numFields)
	for _, f := range fields {
		for i, c := range f {
			if lenc := len(c); lenc > maxWidths[i] {
				maxWidths[i] = lenc
			}
		}
	}

	for _, f := range fields {
		for i := 0; i < numFields; i++ {
			c := f[i]
			outBuf.WriteString(c)
			if i < maxIndex {
				outBuf.Write(
					bytes.Repeat([]byte(" "), maxWidths[i] - len(c) + 2))
			}
		}
		outBuf.WriteRune('\n')
	}

	out = outBuf.String()

	return
}
<|endoftext|>